LCOV - code coverage report
Current view: top level - arch/um/os-Linux - main.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 58 93 62.4 %
Date: 2023-03-27 20:00:47 Functions: 6 8 75.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0
       2             : /*
       3             :  * Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de)
       4             :  * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
       5             :  */
       6             : 
       7             : #include <stdio.h>
       8             : #include <stdlib.h>
       9             : #include <unistd.h>
      10             : #include <errno.h>
      11             : #include <signal.h>
      12             : #include <string.h>
      13             : #include <sys/resource.h>
      14             : #include <as-layout.h>
      15             : #include <init.h>
      16             : #include <kern_util.h>
      17             : #include <os.h>
      18             : #include <um_malloc.h>
      19             : 
      20             : #define PGD_BOUND (4 * 1024 * 1024)
      21             : #define STACKSIZE (8 * 1024 * 1024)
      22             : #define THREAD_NAME_LEN (256)
      23             : 
      24             : long elf_aux_hwcap;
      25             : 
      26           5 : static void set_stklim(void)
      27             : {
      28             :         struct rlimit lim;
      29             : 
      30           5 :         if (getrlimit(RLIMIT_STACK, &lim) < 0) {
      31           0 :                 perror("getrlimit");
      32           0 :                 exit(1);
      33             :         }
      34           5 :         if ((lim.rlim_cur == RLIM_INFINITY) || (lim.rlim_cur > STACKSIZE)) {
      35           0 :                 lim.rlim_cur = STACKSIZE;
      36           0 :                 if (setrlimit(RLIMIT_STACK, &lim) < 0) {
      37           0 :                         perror("setrlimit");
      38           0 :                         exit(1);
      39             :                 }
      40             :         }
      41           5 : }
      42             : 
      43           0 : static void last_ditch_exit(int sig)
      44             : {
      45           0 :         uml_cleanup();
      46           0 :         exit(1);
      47             : }
      48             : 
      49          10 : static void install_fatal_handler(int sig)
      50             : {
      51             :         struct sigaction action;
      52             : 
      53             :         /* All signals are enabled in this handler ... */
      54          10 :         sigemptyset(&action.sa_mask);
      55             : 
      56             :         /*
      57             :          * ... including the signal being handled, plus we want the
      58             :          * handler reset to the default behavior, so that if an exit
      59             :          * handler is hanging for some reason, the UML will just die
      60             :          * after this signal is sent a second time.
      61             :          */
      62          10 :         action.sa_flags = SA_RESETHAND | SA_NODEFER;
      63          10 :         action.sa_restorer = NULL;
      64          10 :         action.sa_handler = last_ditch_exit;
      65          10 :         if (sigaction(sig, &action, NULL) < 0) {
      66           0 :                 os_warn("failed to install handler for signal %d "
      67           0 :                         "- errno = %d\n", sig, errno);
      68           0 :                 exit(1);
      69             :         }
      70          10 : }
      71             : 
      72             : #define UML_LIB_PATH    ":" OS_LIB_PATH "/uml"
      73             : 
      74           5 : static void setup_env_path(void)
      75             : {
      76           5 :         char *new_path = NULL;
      77           5 :         char *old_path = NULL;
      78           5 :         int path_len = 0;
      79             : 
      80           5 :         old_path = getenv("PATH");
      81             :         /*
      82             :          * if no PATH variable is set or it has an empty value
      83             :          * just use the default + /usr/lib/uml
      84             :          */
      85           5 :         if (!old_path || (path_len = strlen(old_path)) == 0) {
      86           0 :                 if (putenv("PATH=:/bin:/usr/bin/" UML_LIB_PATH))
      87           0 :                         perror("couldn't putenv");
      88             :                 return;
      89             :         }
      90             : 
      91             :         /* append /usr/lib/uml to the existing path */
      92           5 :         path_len += strlen("PATH=" UML_LIB_PATH) + 1;
      93           5 :         new_path = malloc(path_len);
      94           5 :         if (!new_path) {
      95           0 :                 perror("couldn't malloc to set a new PATH");
      96           0 :                 return;
      97             :         }
      98           5 :         snprintf(new_path, path_len, "PATH=%s" UML_LIB_PATH, old_path);
      99           5 :         if (putenv(new_path)) {
     100           0 :                 perror("couldn't putenv to set a new PATH");
     101           0 :                 free(new_path);
     102             :         }
     103             : }
     104             : 
     105             : extern void scan_elf_aux( char **envp);
     106             : 
     107           5 : int __init main(int argc, char **argv, char **envp)
     108             : {
     109             :         char **new_argv;
     110             :         int ret, i, err;
     111             : 
     112           5 :         set_stklim();
     113             : 
     114           5 :         setup_env_path();
     115             : 
     116           5 :         setsid();
     117             : 
     118           5 :         new_argv = malloc((argc + 1) * sizeof(char *));
     119           5 :         if (new_argv == NULL) {
     120           0 :                 perror("Mallocing argv");
     121           0 :                 exit(1);
     122             :         }
     123          25 :         for (i = 0; i < argc; i++) {
     124          25 :                 new_argv[i] = strdup(argv[i]);
     125          25 :                 if (new_argv[i] == NULL) {
     126           0 :                         perror("Mallocing an arg");
     127           0 :                         exit(1);
     128             :                 }
     129             :         }
     130           5 :         new_argv[argc] = NULL;
     131             : 
     132             :         /*
     133             :          * Allow these signals to bring down a UML if all other
     134             :          * methods of control fail.
     135             :          */
     136           5 :         install_fatal_handler(SIGINT);
     137           5 :         install_fatal_handler(SIGTERM);
     138             : 
     139             : #ifdef CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA
     140             :         scan_elf_aux(envp);
     141             : #endif
     142             : 
     143           5 :         change_sig(SIGPIPE, 0);
     144           5 :         ret = linux_main(argc, argv);
     145             : 
     146             :         /*
     147             :          * Disable SIGPROF - I have no idea why libc doesn't do this or turn
     148             :          * off the profiling time, but UML dies with a SIGPROF just before
     149             :          * exiting when profiling is active.
     150             :          */
     151           1 :         change_sig(SIGPROF, 0);
     152             : 
     153             :         /*
     154             :          * This signal stuff used to be in the reboot case.  However,
     155             :          * sometimes a timer signal can come in when we're halting (reproducably
     156             :          * when writing out gcov information, presumably because that takes
     157             :          * some time) and cause a segfault.
     158             :          */
     159             : 
     160             :         /* stop timers and set timer signal to be ignored */
     161           1 :         os_timer_disable();
     162             : 
     163             :         /* disable SIGIO for the fds and set SIGIO to be ignored */
     164           1 :         err = deactivate_all_fds();
     165           1 :         if (err)
     166           0 :                 os_warn("deactivate_all_fds failed, errno = %d\n", -err);
     167             : 
     168             :         /*
     169             :          * Let any pending signals fire now.  This ensures
     170             :          * that they won't be delivered after the exec, when
     171             :          * they are definitely not expected.
     172             :          */
     173           1 :         unblock_signals();
     174             : 
     175           1 :         os_info("\n");
     176             :         /* Reboot */
     177           1 :         if (ret) {
     178           0 :                 execvp(new_argv[0], new_argv);
     179           0 :                 perror("Failed to exec kernel");
     180           0 :                 ret = 1;
     181             :         }
     182           1 :         return uml_exitcode;
     183             : }
     184             : 
     185             : extern void *__real_malloc(int);
     186             : 
     187          19 : void *__wrap_malloc(int size)
     188             : {
     189             :         void *ret;
     190             : 
     191          19 :         if (!kmalloc_ok)
     192          17 :                 return __real_malloc(size);
     193           2 :         else if (size <= UM_KERN_PAGE_SIZE)
     194             :                 /* finding contiguous pages can be hard*/
     195           2 :                 ret = uml_kmalloc(size, UM_GFP_KERNEL);
     196           0 :         else ret = vmalloc(size);
     197             : 
     198             :         /*
     199             :          * glibc people insist that if malloc fails, errno should be
     200             :          * set by malloc as well. So we do.
     201             :          */
     202           2 :         if (ret == NULL)
     203           0 :                 errno = ENOMEM;
     204             : 
     205             :         return ret;
     206             : }
     207             : 
     208           0 : void *__wrap_calloc(int n, int size)
     209             : {
     210           0 :         void *ptr = __wrap_malloc(n * size);
     211             : 
     212           0 :         if (ptr == NULL)
     213             :                 return NULL;
     214           0 :         memset(ptr, 0, n * size);
     215           0 :         return ptr;
     216             : }
     217             : 
     218             : extern void __real_free(void *);
     219             : 
     220             : extern unsigned long high_physmem;
     221             : 
     222          24 : void __wrap_free(void *ptr)
     223             : {
     224          24 :         unsigned long addr = (unsigned long) ptr;
     225             : 
     226             :         /*
     227             :          * We need to know how the allocation happened, so it can be correctly
     228             :          * freed.  This is done by seeing what region of memory the pointer is
     229             :          * in -
     230             :          *      physical memory - kmalloc/kfree
     231             :          *      kernel virtual memory - vmalloc/vfree
     232             :          *      anywhere else - malloc/free
     233             :          * If kmalloc is not yet possible, then either high_physmem and/or
     234             :          * end_vm are still 0 (as at startup), in which case we call free, or
     235             :          * we have set them, but anyway addr has not been allocated from those
     236             :          * areas. So, in both cases __real_free is called.
     237             :          *
     238             :          * CAN_KMALLOC is checked because it would be bad to free a buffer
     239             :          * with kmalloc/vmalloc after they have been turned off during
     240             :          * shutdown.
     241             :          * XXX: However, we sometimes shutdown CAN_KMALLOC temporarily, so
     242             :          * there is a possibility for memory leaks.
     243             :          */
     244             : 
     245          24 :         if ((addr >= uml_physmem) && (addr < high_physmem)) {
     246           2 :                 if (kmalloc_ok)
     247           1 :                         kfree(ptr);
     248             :         }
     249          22 :         else if ((addr >= start_vm) && (addr < end_vm)) {
     250           0 :                 if (kmalloc_ok)
     251           0 :                         vfree(ptr);
     252             :         }
     253          22 :         else __real_free(ptr);
     254          24 : }

Generated by: LCOV version 1.14