Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (C) 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
0004  */
0005 
0006 #include <stdio.h>
0007 #include <stddef.h>
0008 #include <stdlib.h>
0009 #include <unistd.h>
0010 #include <errno.h>
0011 #include <fcntl.h>
0012 #include <string.h>
0013 #include <sys/stat.h>
0014 #include <sys/mman.h>
0015 #include <sys/vfs.h>
0016 #include <linux/magic.h>
0017 #include <init.h>
0018 #include <os.h>
0019 
0020 /*
0021  * kasan_map_memory - maps memory from @start with a size of @len.
0022  * The allocated memory is filled with zeroes upon success.
0023  * @start: the start address of the memory to be mapped
0024  * @len: the length of the memory to be mapped
0025  *
0026  * This function is used to map shadow memory for KASAN in uml
0027  */
0028 void kasan_map_memory(void *start, size_t len)
0029 {
0030     if (mmap(start,
0031          len,
0032          PROT_READ|PROT_WRITE,
0033          MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE|MAP_NORESERVE,
0034          -1,
0035          0) == MAP_FAILED) {
0036         os_info("Couldn't allocate shadow memory: %s\n.",
0037             strerror(errno));
0038         exit(1);
0039     }
0040 }
0041 
0042 /* Set by make_tempfile() during early boot. */
0043 static char *tempdir = NULL;
0044 
0045 /* Check if dir is on tmpfs. Return 0 if yes, -1 if no or error. */
0046 static int __init check_tmpfs(const char *dir)
0047 {
0048     struct statfs st;
0049 
0050     os_info("Checking if %s is on tmpfs...", dir);
0051     if (statfs(dir, &st) < 0) {
0052         os_info("%s\n", strerror(errno));
0053     } else if (st.f_type != TMPFS_MAGIC) {
0054         os_info("no\n");
0055     } else {
0056         os_info("OK\n");
0057         return 0;
0058     }
0059     return -1;
0060 }
0061 
0062 /*
0063  * Choose the tempdir to use. We want something on tmpfs so that our memory is
0064  * not subject to the host's vm.dirty_ratio. If a tempdir is specified in the
0065  * environment, we use that even if it's not on tmpfs, but we warn the user.
0066  * Otherwise, we try common tmpfs locations, and if no tmpfs directory is found
0067  * then we fall back to /tmp.
0068  */
0069 static char * __init choose_tempdir(void)
0070 {
0071     static const char * const vars[] = {
0072         "TMPDIR",
0073         "TMP",
0074         "TEMP",
0075         NULL
0076     };
0077     static const char fallback_dir[] = "/tmp";
0078     static const char * const tmpfs_dirs[] = {
0079         "/dev/shm",
0080         fallback_dir,
0081         NULL
0082     };
0083     int i;
0084     const char *dir;
0085 
0086     os_info("Checking environment variables for a tempdir...");
0087     for (i = 0; vars[i]; i++) {
0088         dir = getenv(vars[i]);
0089         if ((dir != NULL) && (*dir != '\0')) {
0090             os_info("%s\n", dir);
0091             if (check_tmpfs(dir) >= 0)
0092                 goto done;
0093             else
0094                 goto warn;
0095         }
0096     }
0097     os_info("none found\n");
0098 
0099     for (i = 0; tmpfs_dirs[i]; i++) {
0100         dir = tmpfs_dirs[i];
0101         if (check_tmpfs(dir) >= 0)
0102             goto done;
0103     }
0104 
0105     dir = fallback_dir;
0106 warn:
0107     os_warn("Warning: tempdir %s is not on tmpfs\n", dir);
0108 done:
0109     /* Make a copy since getenv results may not remain valid forever. */
0110     return strdup(dir);
0111 }
0112 
0113 /*
0114  * Create an unlinked tempfile in a suitable tempdir. template must be the
0115  * basename part of the template with a leading '/'.
0116  */
0117 static int __init make_tempfile(const char *template)
0118 {
0119     char *tempname;
0120     int fd;
0121 
0122     if (tempdir == NULL) {
0123         tempdir = choose_tempdir();
0124         if (tempdir == NULL) {
0125             os_warn("Failed to choose tempdir: %s\n",
0126                 strerror(errno));
0127             return -1;
0128         }
0129     }
0130 
0131 #ifdef O_TMPFILE
0132     fd = open(tempdir, O_CLOEXEC | O_RDWR | O_EXCL | O_TMPFILE, 0700);
0133     /*
0134      * If the running system does not support O_TMPFILE flag then retry
0135      * without it.
0136      */
0137     if (fd != -1 || (errno != EINVAL && errno != EISDIR &&
0138             errno != EOPNOTSUPP))
0139         return fd;
0140 #endif
0141 
0142     tempname = malloc(strlen(tempdir) + strlen(template) + 1);
0143     if (tempname == NULL)
0144         return -1;
0145 
0146     strcpy(tempname, tempdir);
0147     strcat(tempname, template);
0148     fd = mkstemp(tempname);
0149     if (fd < 0) {
0150         os_warn("open - cannot create %s: %s\n", tempname,
0151             strerror(errno));
0152         goto out;
0153     }
0154     if (unlink(tempname) < 0) {
0155         perror("unlink");
0156         goto close;
0157     }
0158     free(tempname);
0159     return fd;
0160 close:
0161     close(fd);
0162 out:
0163     free(tempname);
0164     return -1;
0165 }
0166 
0167 #define TEMPNAME_TEMPLATE "/vm_file-XXXXXX"
0168 
0169 static int __init create_tmp_file(unsigned long long len)
0170 {
0171     int fd, err;
0172     char zero;
0173 
0174     fd = make_tempfile(TEMPNAME_TEMPLATE);
0175     if (fd < 0)
0176         exit(1);
0177 
0178     /*
0179      * Seek to len - 1 because writing a character there will
0180      * increase the file size by one byte, to the desired length.
0181      */
0182     if (lseek64(fd, len - 1, SEEK_SET) < 0) {
0183         perror("lseek64");
0184         exit(1);
0185     }
0186 
0187     zero = 0;
0188 
0189     err = write(fd, &zero, 1);
0190     if (err != 1) {
0191         perror("write");
0192         exit(1);
0193     }
0194 
0195     return fd;
0196 }
0197 
0198 int __init create_mem_file(unsigned long long len)
0199 {
0200     int err, fd;
0201 
0202     fd = create_tmp_file(len);
0203 
0204     err = os_set_exec_close(fd);
0205     if (err < 0) {
0206         errno = -err;
0207         perror("exec_close");
0208     }
0209     return fd;
0210 }
0211 
0212 void __init check_tmpexec(void)
0213 {
0214     void *addr;
0215     int err, fd = create_tmp_file(UM_KERN_PAGE_SIZE);
0216 
0217     addr = mmap(NULL, UM_KERN_PAGE_SIZE,
0218             PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, fd, 0);
0219     os_info("Checking PROT_EXEC mmap in %s...", tempdir);
0220     if (addr == MAP_FAILED) {
0221         err = errno;
0222         os_warn("%s\n", strerror(err));
0223         close(fd);
0224         if (err == EPERM)
0225             os_warn("%s must be not mounted noexec\n", tempdir);
0226         exit(1);
0227     }
0228     os_info("OK\n");
0229     munmap(addr, UM_KERN_PAGE_SIZE);
0230 
0231     close(fd);
0232 }