LCOV - code coverage report
Current view: top level - arch/um/os-Linux - mem.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 44 86 51.2 %
Date: 2023-04-06 08:38:28 Functions: 6 7 85.7 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0
       2             : /*
       3             :  * Copyright (C) 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
       4             :  */
       5             : 
       6             : #include <stdio.h>
       7             : #include <stddef.h>
       8             : #include <stdlib.h>
       9             : #include <unistd.h>
      10             : #include <errno.h>
      11             : #include <fcntl.h>
      12             : #include <string.h>
      13             : #include <sys/stat.h>
      14             : #include <sys/mman.h>
      15             : #include <sys/vfs.h>
      16             : #include <linux/magic.h>
      17             : #include <init.h>
      18             : #include <os.h>
      19             : 
      20             : /*
      21             :  * kasan_map_memory - maps memory from @start with a size of @len.
      22             :  * The allocated memory is filled with zeroes upon success.
      23             :  * @start: the start address of the memory to be mapped
      24             :  * @len: the length of the memory to be mapped
      25             :  *
      26             :  * This function is used to map shadow memory for KASAN in uml
      27             :  */
      28           0 : void kasan_map_memory(void *start, size_t len)
      29             : {
      30           0 :         if (mmap(start,
      31             :                  len,
      32             :                  PROT_READ|PROT_WRITE,
      33             :                  MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE|MAP_NORESERVE,
      34             :                  -1,
      35             :                  0) == MAP_FAILED) {
      36           0 :                 os_info("Couldn't allocate shadow memory: %s\n.",
      37           0 :                         strerror(errno));
      38           0 :                 exit(1);
      39             :         }
      40           0 : }
      41             : 
      42             : /* Set by make_tempfile() during early boot. */
      43             : static char *tempdir = NULL;
      44             : 
      45             : /* Check if dir is on tmpfs. Return 0 if yes, -1 if no or error. */
      46           2 : static int __init check_tmpfs(const char *dir)
      47             : {
      48             :         struct statfs st;
      49             : 
      50           2 :         os_info("Checking if %s is on tmpfs...", dir);
      51           2 :         if (statfs(dir, &st) < 0) {
      52           0 :                 os_info("%s\n", strerror(errno));
      53           2 :         } else if (st.f_type != TMPFS_MAGIC) {
      54           0 :                 os_info("no\n");
      55             :         } else {
      56           2 :                 os_info("OK\n");
      57           2 :                 return 0;
      58             :         }
      59             :         return -1;
      60             : }
      61             : 
      62             : /*
      63             :  * Choose the tempdir to use. We want something on tmpfs so that our memory is
      64             :  * not subject to the host's vm.dirty_ratio. If a tempdir is specified in the
      65             :  * environment, we use that even if it's not on tmpfs, but we warn the user.
      66             :  * Otherwise, we try common tmpfs locations, and if no tmpfs directory is found
      67             :  * then we fall back to /tmp.
      68             :  */
      69           2 : static char * __init choose_tempdir(void)
      70             : {
      71             :         static const char * const vars[] = {
      72             :                 "TMPDIR",
      73             :                 "TMP",
      74             :                 "TEMP",
      75             :                 NULL
      76             :         };
      77             :         static const char fallback_dir[] = "/tmp";
      78             :         static const char * const tmpfs_dirs[] = {
      79             :                 "/dev/shm",
      80             :                 fallback_dir,
      81             :                 NULL
      82             :         };
      83             :         int i;
      84             :         const char *dir;
      85             : 
      86           2 :         os_info("Checking environment variables for a tempdir...");
      87           8 :         for (i = 0; vars[i]; i++) {
      88           6 :                 dir = getenv(vars[i]);
      89           6 :                 if ((dir != NULL) && (*dir != '\0')) {
      90           0 :                         os_info("%s\n", dir);
      91           0 :                         if (check_tmpfs(dir) >= 0)
      92             :                                 goto done;
      93             :                         else
      94             :                                 goto warn;
      95             :                 }
      96             :         }
      97           2 :         os_info("none found\n");
      98             : 
      99           2 :         for (i = 0; tmpfs_dirs[i]; i++) {
     100           2 :                 dir = tmpfs_dirs[i];
     101           2 :                 if (check_tmpfs(dir) >= 0)
     102             :                         goto done;
     103             :         }
     104             : 
     105             :         dir = fallback_dir;
     106             : warn:
     107           0 :         os_warn("Warning: tempdir %s is not on tmpfs\n", dir);
     108             : done:
     109             :         /* Make a copy since getenv results may not remain valid forever. */
     110           2 :         return strdup(dir);
     111             : }
     112             : 
     113             : /*
     114             :  * Create an unlinked tempfile in a suitable tempdir. template must be the
     115             :  * basename part of the template with a leading '/'.
     116             :  */
     117           4 : static int __init make_tempfile(const char *template)
     118             : {
     119             :         char *tempname;
     120             :         int fd;
     121             : 
     122           4 :         if (tempdir == NULL) {
     123           2 :                 tempdir = choose_tempdir();
     124           2 :                 if (tempdir == NULL) {
     125           0 :                         os_warn("Failed to choose tempdir: %s\n",
     126           0 :                                 strerror(errno));
     127           0 :                         return -1;
     128             :                 }
     129             :         }
     130             : 
     131             : #ifdef O_TMPFILE
     132           4 :         fd = open(tempdir, O_CLOEXEC | O_RDWR | O_EXCL | O_TMPFILE, 0700);
     133             :         /*
     134             :          * If the running system does not support O_TMPFILE flag then retry
     135             :          * without it.
     136             :          */
     137           4 :         if (fd != -1 || (errno != EINVAL && errno != EISDIR &&
     138             :                         errno != EOPNOTSUPP))
     139             :                 return fd;
     140             : #endif
     141             : 
     142           0 :         tempname = malloc(strlen(tempdir) + strlen(template) + 1);
     143           0 :         if (tempname == NULL)
     144             :                 return -1;
     145             : 
     146           0 :         strcpy(tempname, tempdir);
     147           0 :         strcat(tempname, template);
     148           0 :         fd = mkstemp(tempname);
     149           0 :         if (fd < 0) {
     150           0 :                 os_warn("open - cannot create %s: %s\n", tempname,
     151             :                         strerror(errno));
     152           0 :                 goto out;
     153             :         }
     154           0 :         if (unlink(tempname) < 0) {
     155           0 :                 perror("unlink");
     156             :                 goto close;
     157             :         }
     158           0 :         free(tempname);
     159           0 :         return fd;
     160             : close:
     161           0 :         close(fd);
     162             : out:
     163           0 :         free(tempname);
     164           0 :         return -1;
     165             : }
     166             : 
     167             : #define TEMPNAME_TEMPLATE "/vm_file-XXXXXX"
     168             : 
     169           4 : static int __init create_tmp_file(unsigned long long len)
     170             : {
     171             :         int fd, err;
     172             :         char zero;
     173             : 
     174           4 :         fd = make_tempfile(TEMPNAME_TEMPLATE);
     175           4 :         if (fd < 0)
     176           0 :                 exit(1);
     177             : 
     178             :         /*
     179             :          * Seek to len - 1 because writing a character there will
     180             :          * increase the file size by one byte, to the desired length.
     181             :          */
     182           4 :         if (lseek64(fd, len - 1, SEEK_SET) < 0) {
     183           0 :                 perror("lseek64");
     184           0 :                 exit(1);
     185             :         }
     186             : 
     187           4 :         zero = 0;
     188             : 
     189           4 :         err = write(fd, &zero, 1);
     190           4 :         if (err != 1) {
     191           0 :                 perror("write");
     192           0 :                 exit(1);
     193             :         }
     194             : 
     195           4 :         return fd;
     196             : }
     197             : 
     198           2 : int __init create_mem_file(unsigned long long len)
     199             : {
     200             :         int err, fd;
     201             : 
     202           2 :         fd = create_tmp_file(len);
     203             : 
     204           2 :         err = os_set_exec_close(fd);
     205           2 :         if (err < 0) {
     206           0 :                 errno = -err;
     207           0 :                 perror("exec_close");
     208             :         }
     209           2 :         return fd;
     210             : }
     211             : 
     212           2 : void __init check_tmpexec(void)
     213             : {
     214             :         void *addr;
     215           2 :         int err, fd = create_tmp_file(UM_KERN_PAGE_SIZE);
     216             : 
     217           2 :         addr = mmap(NULL, UM_KERN_PAGE_SIZE,
     218             :                     PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, fd, 0);
     219           2 :         os_info("Checking PROT_EXEC mmap in %s...", tempdir);
     220           2 :         if (addr == MAP_FAILED) {
     221           0 :                 err = errno;
     222           0 :                 os_warn("%s\n", strerror(err));
     223           0 :                 close(fd);
     224           0 :                 if (err == EPERM)
     225           0 :                         os_warn("%s must be not mounted noexec\n", tempdir);
     226           0 :                 exit(1);
     227             :         }
     228           2 :         os_info("OK\n");
     229           2 :         munmap(addr, UM_KERN_PAGE_SIZE);
     230             : 
     231           2 :         close(fd);
     232           2 : }

Generated by: LCOV version 1.14