The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/arch/um/os-Linux/start_up.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
    3  * Licensed under the GPL
    4  */
    5 
    6 #include <stdio.h>
    7 #include <stdlib.h>
    8 #include <stdarg.h>
    9 #include <unistd.h>
   10 #include <errno.h>
   11 #include <fcntl.h>
   12 #include <sched.h>
   13 #include <signal.h>
   14 #include <string.h>
   15 #include <sys/mman.h>
   16 #include <sys/stat.h>
   17 #include <sys/wait.h>
   18 #include <asm/unistd.h>
   19 #include <init.h>
   20 #include <os.h>
   21 #include <mem_user.h>
   22 #include <ptrace_user.h>
   23 #include <registers.h>
   24 #include <skas.h>
   25 #include <skas_ptrace.h>
   26 
   27 static void ptrace_child(void)
   28 {
   29         int ret;
   30         /* Calling os_getpid because some libcs cached getpid incorrectly */
   31         int pid = os_getpid(), ppid = getppid();
   32         int sc_result;
   33 
   34         if (change_sig(SIGWINCH, 0) < 0 ||
   35             ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) {
   36                 perror("ptrace");
   37                 kill(pid, SIGKILL);
   38         }
   39         kill(pid, SIGSTOP);
   40 
   41         /*
   42          * This syscall will be intercepted by the parent. Don't call more than
   43          * once, please.
   44          */
   45         sc_result = os_getpid();
   46 
   47         if (sc_result == pid)
   48                 /* Nothing modified by the parent, we are running normally. */
   49                 ret = 1;
   50         else if (sc_result == ppid)
   51                 /*
   52                  * Expected in check_ptrace and check_sysemu when they succeed
   53                  * in modifying the stack frame
   54                  */
   55                 ret = 0;
   56         else
   57                 /* Serious trouble! This could be caused by a bug in host 2.6
   58                  * SKAS3/2.6 patch before release -V6, together with a bug in
   59                  * the UML code itself.
   60                  */
   61                 ret = 2;
   62 
   63         exit(ret);
   64 }
   65 
   66 static void fatal_perror(const char *str)
   67 {
   68         perror(str);
   69         exit(1);
   70 }
   71 
   72 static void fatal(char *fmt, ...)
   73 {
   74         va_list list;
   75 
   76         va_start(list, fmt);
   77         vfprintf(stderr, fmt, list);
   78         va_end(list);
   79 
   80         exit(1);
   81 }
   82 
   83 static void non_fatal(char *fmt, ...)
   84 {
   85         va_list list;
   86 
   87         va_start(list, fmt);
   88         vfprintf(stderr, fmt, list);
   89         va_end(list);
   90 }
   91 
   92 static int start_ptraced_child(void)
   93 {
   94         int pid, n, status;
   95 
   96         pid = fork();
   97         if (pid == 0)
   98                 ptrace_child();
   99         else if (pid < 0)
  100                 fatal_perror("start_ptraced_child : fork failed");
  101 
  102         CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
  103         if (n < 0)
  104                 fatal_perror("check_ptrace : waitpid failed");
  105         if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP))
  106                 fatal("check_ptrace : expected SIGSTOP, got status = %d",
  107                       status);
  108 
  109         return pid;
  110 }
  111 
  112 /* When testing for SYSEMU support, if it is one of the broken versions, we
  113  * must just avoid using sysemu, not panic, but only if SYSEMU features are
  114  * broken.
  115  * So only for SYSEMU features we test mustpanic, while normal host features
  116  * must work anyway!
  117  */
  118 static int stop_ptraced_child(int pid, int exitcode, int mustexit)
  119 {
  120         int status, n, ret = 0;
  121 
  122         if (ptrace(PTRACE_CONT, pid, 0, 0) < 0) {
  123                 perror("stop_ptraced_child : ptrace failed");
  124                 return -1;
  125         }
  126         CATCH_EINTR(n = waitpid(pid, &status, 0));
  127         if (!WIFEXITED(status) || (WEXITSTATUS(status) != exitcode)) {
  128                 int exit_with = WEXITSTATUS(status);
  129                 if (exit_with == 2)
  130                         non_fatal("check_ptrace : child exited with status 2. "
  131                                   "\nDisabling SYSEMU support.\n");
  132                 non_fatal("check_ptrace : child exited with exitcode %d, while "
  133                           "expecting %d; status 0x%x\n", exit_with,
  134                           exitcode, status);
  135                 if (mustexit)
  136                         exit(1);
  137                 ret = -1;
  138         }
  139 
  140         return ret;
  141 }
  142 
  143 /* Changed only during early boot */
  144 int ptrace_faultinfo;
  145 static int disable_ptrace_faultinfo;
  146 
  147 int ptrace_ldt;
  148 static int disable_ptrace_ldt;
  149 
  150 int proc_mm;
  151 static int disable_proc_mm;
  152 
  153 int have_switch_mm;
  154 static int disable_switch_mm;
  155 
  156 int skas_needs_stub;
  157 
  158 static int __init skas0_cmd_param(char *str, int* add)
  159 {
  160         disable_ptrace_faultinfo = 1;
  161         disable_ptrace_ldt = 1;
  162         disable_proc_mm = 1;
  163         disable_switch_mm = 1;
  164 
  165         return 0;
  166 }
  167 
  168 /* The two __uml_setup would conflict, without this stupid alias. */
  169 
  170 static int __init mode_skas0_cmd_param(char *str, int* add)
  171         __attribute__((alias("skas0_cmd_param")));
  172 
  173 __uml_setup("skas0", skas0_cmd_param,
  174 "skas0\n"
  175 "    Disables SKAS3 and SKAS4 usage, so that SKAS0 is used\n\n");
  176 
  177 __uml_setup("mode=skas0", mode_skas0_cmd_param,
  178 "mode=skas0\n"
  179 "    Disables SKAS3 and SKAS4 usage, so that SKAS0 is used.\n\n");
  180 
  181 /* Changed only during early boot */
  182 static int force_sysemu_disabled = 0;
  183 
  184 static int __init nosysemu_cmd_param(char *str, int* add)
  185 {
  186         force_sysemu_disabled = 1;
  187         return 0;
  188 }
  189 
  190 __uml_setup("nosysemu", nosysemu_cmd_param,
  191 "nosysemu\n"
  192 "    Turns off syscall emulation patch for ptrace (SYSEMU) on.\n"
  193 "    SYSEMU is a performance-patch introduced by Laurent Vivier. It changes\n"
  194 "    behaviour of ptrace() and helps reducing host context switch rate.\n"
  195 "    To make it working, you need a kernel patch for your host, too.\n"
  196 "    See http://perso.wanadoo.fr/laurent.vivier/UML/ for further \n"
  197 "    information.\n\n");
  198 
  199 static void __init check_sysemu(void)
  200 {
  201         unsigned long regs[MAX_REG_NR];
  202         int pid, n, status, count=0;
  203 
  204         non_fatal("Checking syscall emulation patch for ptrace...");
  205         sysemu_supported = 0;
  206         pid = start_ptraced_child();
  207 
  208         if (ptrace(PTRACE_SYSEMU, pid, 0, 0) < 0)
  209                 goto fail;
  210 
  211         CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
  212         if (n < 0)
  213                 fatal_perror("check_sysemu : wait failed");
  214         if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP))
  215                 fatal("check_sysemu : expected SIGTRAP, got status = %d\n",
  216                       status);
  217 
  218         if (ptrace(PTRACE_GETREGS, pid, 0, regs) < 0)
  219                 fatal_perror("check_sysemu : PTRACE_GETREGS failed");
  220         if (PT_SYSCALL_NR(regs) != __NR_getpid) {
  221                 non_fatal("check_sysemu got system call number %d, "
  222                           "expected %d...", PT_SYSCALL_NR(regs), __NR_getpid);
  223                 goto fail;
  224         }
  225 
  226         n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET, os_getpid());
  227         if (n < 0) {
  228                 non_fatal("check_sysemu : failed to modify system call "
  229                           "return");
  230                 goto fail;
  231         }
  232 
  233         if (stop_ptraced_child(pid, 0, 0) < 0)
  234                 goto fail_stopped;
  235 
  236         sysemu_supported = 1;
  237         non_fatal("OK\n");
  238         set_using_sysemu(!force_sysemu_disabled);
  239 
  240         non_fatal("Checking advanced syscall emulation patch for ptrace...");
  241         pid = start_ptraced_child();
  242 
  243         if ((ptrace(PTRACE_OLDSETOPTIONS, pid, 0,
  244                    (void *) PTRACE_O_TRACESYSGOOD) < 0))
  245                 fatal_perror("check_sysemu: PTRACE_OLDSETOPTIONS failed");
  246 
  247         while (1) {
  248                 count++;
  249                 if (ptrace(PTRACE_SYSEMU_SINGLESTEP, pid, 0, 0) < 0)
  250                         goto fail;
  251                 CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
  252                 if (n < 0)
  253                         fatal_perror("check_sysemu: wait failed");
  254 
  255                 if (WIFSTOPPED(status) &&
  256                     (WSTOPSIG(status) == (SIGTRAP|0x80))) {
  257                         if (!count) {
  258                                 non_fatal("check_sysemu: SYSEMU_SINGLESTEP "
  259                                           "doesn't singlestep");
  260                                 goto fail;
  261                         }
  262                         n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET,
  263                                    os_getpid());
  264                         if (n < 0)
  265                                 fatal_perror("check_sysemu : failed to modify "
  266                                              "system call return");
  267                         break;
  268                 }
  269                 else if (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGTRAP))
  270                         count++;
  271                 else {
  272                         non_fatal("check_sysemu: expected SIGTRAP or "
  273                                   "(SIGTRAP | 0x80), got status = %d\n",
  274                                   status);
  275                         goto fail;
  276                 }
  277         }
  278         if (stop_ptraced_child(pid, 0, 0) < 0)
  279                 goto fail_stopped;
  280 
  281         sysemu_supported = 2;
  282         non_fatal("OK\n");
  283 
  284         if (!force_sysemu_disabled)
  285                 set_using_sysemu(sysemu_supported);
  286         return;
  287 
  288 fail:
  289         stop_ptraced_child(pid, 1, 0);
  290 fail_stopped:
  291         non_fatal("missing\n");
  292 }
  293 
  294 static void __init check_ptrace(void)
  295 {
  296         int pid, syscall, n, status;
  297 
  298         non_fatal("Checking that ptrace can change system call numbers...");
  299         pid = start_ptraced_child();
  300 
  301         if ((ptrace(PTRACE_OLDSETOPTIONS, pid, 0,
  302                    (void *) PTRACE_O_TRACESYSGOOD) < 0))
  303                 fatal_perror("check_ptrace: PTRACE_OLDSETOPTIONS failed");
  304 
  305         while (1) {
  306                 if (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
  307                         fatal_perror("check_ptrace : ptrace failed");
  308 
  309                 CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
  310                 if (n < 0)
  311                         fatal_perror("check_ptrace : wait failed");
  312 
  313                 if (!WIFSTOPPED(status) ||
  314                    (WSTOPSIG(status) != (SIGTRAP | 0x80)))
  315                         fatal("check_ptrace : expected (SIGTRAP|0x80), "
  316                                "got status = %d", status);
  317 
  318                 syscall = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_NR_OFFSET,
  319                                  0);
  320                 if (syscall == __NR_getpid) {
  321                         n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET,
  322                                    __NR_getppid);
  323                         if (n < 0)
  324                                 fatal_perror("check_ptrace : failed to modify "
  325                                              "system call");
  326                         break;
  327                 }
  328         }
  329         stop_ptraced_child(pid, 0, 1);
  330         non_fatal("OK\n");
  331         check_sysemu();
  332 }
  333 
  334 extern void check_tmpexec(void);
  335 
  336 static void __init check_coredump_limit(void)
  337 {
  338         struct rlimit lim;
  339         int err = getrlimit(RLIMIT_CORE, &lim);
  340 
  341         if (err) {
  342                 perror("Getting core dump limit");
  343                 return;
  344         }
  345 
  346         printf("Core dump limits :\n\tsoft - ");
  347         if (lim.rlim_cur == RLIM_INFINITY)
  348                 printf("NONE\n");
  349         else printf("%lu\n", lim.rlim_cur);
  350 
  351         printf("\thard - ");
  352         if (lim.rlim_max == RLIM_INFINITY)
  353                 printf("NONE\n");
  354         else printf("%lu\n", lim.rlim_max);
  355 }
  356 
  357 void __init os_early_checks(void)
  358 {
  359         int pid;
  360 
  361         /* Print out the core dump limits early */
  362         check_coredump_limit();
  363 
  364         check_ptrace();
  365 
  366         /* Need to check this early because mmapping happens before the
  367          * kernel is running.
  368          */
  369         check_tmpexec();
  370 
  371         pid = start_ptraced_child();
  372         if (init_registers(pid))
  373                 fatal("Failed to initialize default registers");
  374         stop_ptraced_child(pid, 1, 1);
  375 }
  376 
  377 static int __init noprocmm_cmd_param(char *str, int* add)
  378 {
  379         disable_proc_mm = 1;
  380         return 0;
  381 }
  382 
  383 __uml_setup("noprocmm", noprocmm_cmd_param,
  384 "noprocmm\n"
  385 "    Turns off usage of /proc/mm, even if host supports it.\n"
  386 "    To support /proc/mm, the host needs to be patched using\n"
  387 "    the current skas3 patch.\n\n");
  388 
  389 static int __init noptracefaultinfo_cmd_param(char *str, int* add)
  390 {
  391         disable_ptrace_faultinfo = 1;
  392         return 0;
  393 }
  394 
  395 __uml_setup("noptracefaultinfo", noptracefaultinfo_cmd_param,
  396 "noptracefaultinfo\n"
  397 "    Turns off usage of PTRACE_FAULTINFO, even if host supports\n"
  398 "    it. To support PTRACE_FAULTINFO, the host needs to be patched\n"
  399 "    using the current skas3 patch.\n\n");
  400 
  401 static int __init noptraceldt_cmd_param(char *str, int* add)
  402 {
  403         disable_ptrace_ldt = 1;
  404         return 0;
  405 }
  406 
  407 __uml_setup("noptraceldt", noptraceldt_cmd_param,
  408 "noptraceldt\n"
  409 "    Turns off usage of PTRACE_LDT, even if host supports it.\n"
  410 "    To support PTRACE_LDT, the host needs to be patched using\n"
  411 "    the current skas3 patch.\n\n");
  412 
  413 static inline void check_skas3_ptrace_faultinfo(void)
  414 {
  415         struct ptrace_faultinfo fi;
  416         int pid, n;
  417 
  418         non_fatal("  - PTRACE_FAULTINFO...");
  419         pid = start_ptraced_child();
  420 
  421         n = ptrace(PTRACE_FAULTINFO, pid, 0, &fi);
  422         if (n < 0) {
  423                 if (errno == EIO)
  424                         non_fatal("not found\n");
  425                 else
  426                         perror("not found");
  427         } else if (disable_ptrace_faultinfo)
  428                 non_fatal("found but disabled on command line\n");
  429         else {
  430                 ptrace_faultinfo = 1;
  431                 non_fatal("found\n");
  432         }
  433 
  434         stop_ptraced_child(pid, 1, 1);
  435 }
  436 
  437 static inline void check_skas3_ptrace_ldt(void)
  438 {
  439 #ifdef PTRACE_LDT
  440         int pid, n;
  441         unsigned char ldtbuf[40];
  442         struct ptrace_ldt ldt_op = (struct ptrace_ldt) {
  443                 .func = 2, /* read default ldt */
  444                 .ptr = ldtbuf,
  445                 .bytecount = sizeof(ldtbuf)};
  446 
  447         non_fatal("  - PTRACE_LDT...");
  448         pid = start_ptraced_child();
  449 
  450         n = ptrace(PTRACE_LDT, pid, 0, (unsigned long) &ldt_op);
  451         if (n < 0) {
  452                 if (errno == EIO)
  453                         non_fatal("not found\n");
  454                 else
  455                         perror("not found");
  456         } else if (disable_ptrace_ldt)
  457                 non_fatal("found, but use is disabled\n");
  458         else {
  459                 ptrace_ldt = 1;
  460                 non_fatal("found\n");
  461         }
  462 
  463         stop_ptraced_child(pid, 1, 1);
  464 #endif
  465 }
  466 
  467 static inline void check_skas3_proc_mm(void)
  468 {
  469         non_fatal("  - /proc/mm...");
  470         if (access("/proc/mm", W_OK) < 0)
  471                 perror("not found");
  472         else if (disable_proc_mm)
  473                 non_fatal("found but disabled on command line\n");
  474         else {
  475                 proc_mm = 1;
  476                 non_fatal("found\n");
  477         }
  478 }
  479 
  480 void can_do_skas(void)
  481 {
  482         non_fatal("Checking for the skas3 patch in the host:\n");
  483 
  484         check_skas3_proc_mm();
  485         check_skas3_ptrace_faultinfo();
  486         check_skas3_ptrace_ldt();
  487 
  488         if (!proc_mm || !ptrace_faultinfo || !ptrace_ldt)
  489                 skas_needs_stub = 1;
  490 }
  491 
  492 int __init parse_iomem(char *str, int *add)
  493 {
  494         struct iomem_region *new;
  495         struct stat64 buf;
  496         char *file, *driver;
  497         int fd, size;
  498 
  499         driver = str;
  500         file = strchr(str,',');
  501         if (file == NULL) {
  502                 fprintf(stderr, "parse_iomem : failed to parse iomem\n");
  503                 goto out;
  504         }
  505         *file = '\0';
  506         file++;
  507         fd = open(file, O_RDWR, 0);
  508         if (fd < 0) {
  509                 perror("parse_iomem - Couldn't open io file");
  510                 goto out;
  511         }
  512 
  513         if (fstat64(fd, &buf) < 0) {
  514                 perror("parse_iomem - cannot stat_fd file");
  515                 goto out_close;
  516         }
  517 
  518         new = malloc(sizeof(*new));
  519         if (new == NULL) {
  520                 perror("Couldn't allocate iomem_region struct");
  521                 goto out_close;
  522         }
  523 
  524         size = (buf.st_size + UM_KERN_PAGE_SIZE) & ~(UM_KERN_PAGE_SIZE - 1);
  525 
  526         *new = ((struct iomem_region) { .next           = iomem_regions,
  527                                         .driver         = driver,
  528                                         .fd             = fd,
  529                                         .size           = size,
  530                                         .phys           = 0,
  531                                         .virt           = 0 });
  532         iomem_regions = new;
  533         iomem_size += new->size + UM_KERN_PAGE_SIZE;
  534 
  535         return 0;
  536  out_close:
  537         close(fd);
  538  out:
  539         return 1;
  540 }

Cache object: bd257f20d42003aade78ba0212d53ea3


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.