10f80bc85SJeff Dike #include <stdio.h> 20f80bc85SJeff Dike #include <stdlib.h> 30f80bc85SJeff Dike #include <stddef.h> 40f80bc85SJeff Dike #include <stdarg.h> 50f80bc85SJeff Dike #include <unistd.h> 60f80bc85SJeff Dike #include <errno.h> 70f80bc85SJeff Dike #include <string.h> 80f80bc85SJeff Dike #include <fcntl.h> 90f80bc85SJeff Dike #include <sys/types.h> 100f80bc85SJeff Dike #include <sys/mman.h> 11966a082fSRob Landley #include <sys/statfs.h> 120f80bc85SJeff Dike #include "kern_util.h" 130f80bc85SJeff Dike #include "user.h" 140f80bc85SJeff Dike #include "user_util.h" 150f80bc85SJeff Dike #include "mem_user.h" 160f80bc85SJeff Dike #include "init.h" 170f80bc85SJeff Dike #include "os.h" 180f80bc85SJeff Dike #include "tempfile.h" 190f80bc85SJeff Dike #include "kern_constants.h" 200f80bc85SJeff Dike 210f80bc85SJeff Dike #include <sys/param.h> 220f80bc85SJeff Dike 23966a082fSRob Landley static char *default_tmpdir = "/tmp"; 240f80bc85SJeff Dike static char *tempdir = NULL; 250f80bc85SJeff Dike 260f80bc85SJeff Dike static void __init find_tempdir(void) 270f80bc85SJeff Dike { 280f80bc85SJeff Dike char *dirs[] = { "TMP", "TEMP", "TMPDIR", NULL }; 290f80bc85SJeff Dike int i; 300f80bc85SJeff Dike char *dir = NULL; 310f80bc85SJeff Dike 320f80bc85SJeff Dike if(tempdir != NULL) return; /* We've already been called */ 330f80bc85SJeff Dike for(i = 0; dirs[i]; i++){ 340f80bc85SJeff Dike dir = getenv(dirs[i]); 350f80bc85SJeff Dike if((dir != NULL) && (*dir != '\0')) 360f80bc85SJeff Dike break; 370f80bc85SJeff Dike } 380f80bc85SJeff Dike if((dir == NULL) || (*dir == '\0')) 39966a082fSRob Landley dir = default_tmpdir; 400f80bc85SJeff Dike 410f80bc85SJeff Dike tempdir = malloc(strlen(dir) + 2); 420f80bc85SJeff Dike if(tempdir == NULL){ 430f80bc85SJeff Dike fprintf(stderr, "Failed to malloc tempdir, " 440f80bc85SJeff Dike "errno = %d\n", errno); 450f80bc85SJeff Dike return; 460f80bc85SJeff Dike } 470f80bc85SJeff Dike strcpy(tempdir, dir); 480f80bc85SJeff Dike strcat(tempdir, "/"); 490f80bc85SJeff Dike } 500f80bc85SJeff Dike 51966a082fSRob Landley /* This will return 1, with the first character in buf being the 52966a082fSRob Landley * character following the next instance of c in the file. This will 53966a082fSRob Landley * read the file as needed. If there's an error, -errno is returned; 54966a082fSRob Landley * if the end of the file is reached, 0 is returned. 55966a082fSRob Landley */ 56966a082fSRob Landley static int next(int fd, char *buf, int size, char c) 57966a082fSRob Landley { 58c2b7a4bbSJeff Dike int n, len; 59966a082fSRob Landley char *ptr; 60966a082fSRob Landley 61966a082fSRob Landley while((ptr = strchr(buf, c)) == NULL){ 62966a082fSRob Landley n = read(fd, buf, size - 1); 63966a082fSRob Landley if(n == 0) 64966a082fSRob Landley return 0; 65966a082fSRob Landley else if(n < 0) 66966a082fSRob Landley return -errno; 67966a082fSRob Landley 68966a082fSRob Landley buf[n] = '\0'; 69966a082fSRob Landley } 70966a082fSRob Landley 71966a082fSRob Landley ptr++; 72c2b7a4bbSJeff Dike len = strlen(ptr); 73c2b7a4bbSJeff Dike memmove(buf, ptr, len + 1); 74c2b7a4bbSJeff Dike 75c2b7a4bbSJeff Dike /* Refill the buffer so that if there's a partial string that we care 76c2b7a4bbSJeff Dike * about, it will be completed, and we can recognize it. 77c2b7a4bbSJeff Dike */ 78c2b7a4bbSJeff Dike n = read(fd, &buf[len], size - len - 1); 79c2b7a4bbSJeff Dike if(n < 0) 80c2b7a4bbSJeff Dike return -errno; 81c2b7a4bbSJeff Dike 82c2b7a4bbSJeff Dike buf[len + n] = '\0'; 83966a082fSRob Landley return 1; 84966a082fSRob Landley } 85966a082fSRob Landley 86966a082fSRob Landley static int checked_tmpdir = 0; 87966a082fSRob Landley 88966a082fSRob Landley /* Look for a tmpfs mounted at /dev/shm. I couldn't find a cleaner 89966a082fSRob Landley * way to do this than to parse /proc/mounts. statfs will return the 90966a082fSRob Landley * same filesystem magic number and fs id for both /dev and /dev/shm 91966a082fSRob Landley * when they are both tmpfs, so you can't tell if they are different 92966a082fSRob Landley * filesystems. Also, there seems to be no other way of finding the 93966a082fSRob Landley * mount point of a filesystem from within it. 94966a082fSRob Landley * 95966a082fSRob Landley * If a /dev/shm tmpfs entry is found, then we switch to using it. 96966a082fSRob Landley * Otherwise, we stay with the default /tmp. 97966a082fSRob Landley */ 98966a082fSRob Landley static void which_tmpdir(void) 99966a082fSRob Landley { 100966a082fSRob Landley int fd, found; 101966a082fSRob Landley char buf[128] = { '\0' }; 102966a082fSRob Landley 103966a082fSRob Landley if(checked_tmpdir) 104966a082fSRob Landley return; 105966a082fSRob Landley 106966a082fSRob Landley checked_tmpdir = 1; 107966a082fSRob Landley 108966a082fSRob Landley printf("Checking for tmpfs mount on /dev/shm..."); 109966a082fSRob Landley 110966a082fSRob Landley fd = open("/proc/mounts", O_RDONLY); 111966a082fSRob Landley if(fd < 0){ 112966a082fSRob Landley printf("failed to open /proc/mounts, errno = %d\n", errno); 113966a082fSRob Landley return; 114966a082fSRob Landley } 115966a082fSRob Landley 116966a082fSRob Landley while(1){ 117966a082fSRob Landley found = next(fd, buf, sizeof(buf) / sizeof(buf[0]), ' '); 118966a082fSRob Landley if(found != 1) 119966a082fSRob Landley break; 120966a082fSRob Landley 121966a082fSRob Landley if(!strncmp(buf, "/dev/shm", strlen("/dev/shm"))) 122966a082fSRob Landley goto found; 123966a082fSRob Landley 124966a082fSRob Landley found = next(fd, buf, sizeof(buf) / sizeof(buf[0]), '\n'); 125966a082fSRob Landley if(found != 1) 126966a082fSRob Landley break; 127966a082fSRob Landley } 128966a082fSRob Landley 129966a082fSRob Landley err: 130966a082fSRob Landley if(found == 0) 131966a082fSRob Landley printf("nothing mounted on /dev/shm\n"); 132966a082fSRob Landley else if(found < 0) 133966a082fSRob Landley printf("read returned errno %d\n", -found); 134966a082fSRob Landley 135966a082fSRob Landley return; 136966a082fSRob Landley 137966a082fSRob Landley found: 138966a082fSRob Landley found = next(fd, buf, sizeof(buf) / sizeof(buf[0]), ' '); 139966a082fSRob Landley if(found != 1) 140966a082fSRob Landley goto err; 141966a082fSRob Landley 142966a082fSRob Landley if(strncmp(buf, "tmpfs", strlen("tmpfs"))){ 143966a082fSRob Landley printf("not tmpfs\n"); 144966a082fSRob Landley return; 145966a082fSRob Landley } 146966a082fSRob Landley 147966a082fSRob Landley printf("OK\n"); 148966a082fSRob Landley default_tmpdir = "/dev/shm"; 149966a082fSRob Landley } 150966a082fSRob Landley 1510f80bc85SJeff Dike /* 1520f80bc85SJeff Dike * This proc still used in tt-mode 1530f80bc85SJeff Dike * (file: kernel/tt/ptproxy/proxy.c, proc: start_debugger). 1540f80bc85SJeff Dike * So it isn't 'static' yet. 1550f80bc85SJeff Dike */ 1560f80bc85SJeff Dike int make_tempfile(const char *template, char **out_tempname, int do_unlink) 1570f80bc85SJeff Dike { 15887276f72SPaolo 'Blaisorblade' Giarrusso char *tempname; 1590f80bc85SJeff Dike int fd; 1600f80bc85SJeff Dike 161966a082fSRob Landley which_tmpdir(); 16287276f72SPaolo 'Blaisorblade' Giarrusso tempname = malloc(MAXPATHLEN); 16387276f72SPaolo 'Blaisorblade' Giarrusso 1640f80bc85SJeff Dike find_tempdir(); 16587276f72SPaolo 'Blaisorblade' Giarrusso if (template[0] != '/') 1660f80bc85SJeff Dike strcpy(tempname, tempdir); 1670f80bc85SJeff Dike else 16887276f72SPaolo 'Blaisorblade' Giarrusso tempname[0] = '\0'; 1690f80bc85SJeff Dike strcat(tempname, template); 1700f80bc85SJeff Dike fd = mkstemp(tempname); 1710f80bc85SJeff Dike if(fd < 0){ 1720f80bc85SJeff Dike fprintf(stderr, "open - cannot create %s: %s\n", tempname, 1730f80bc85SJeff Dike strerror(errno)); 17487276f72SPaolo 'Blaisorblade' Giarrusso goto out; 1750f80bc85SJeff Dike } 1760f80bc85SJeff Dike if(do_unlink && (unlink(tempname) < 0)){ 1770f80bc85SJeff Dike perror("unlink"); 17887276f72SPaolo 'Blaisorblade' Giarrusso goto out; 1790f80bc85SJeff Dike } 1800f80bc85SJeff Dike if(out_tempname){ 18187276f72SPaolo 'Blaisorblade' Giarrusso *out_tempname = tempname; 18287276f72SPaolo 'Blaisorblade' Giarrusso } else { 18387276f72SPaolo 'Blaisorblade' Giarrusso free(tempname); 1840f80bc85SJeff Dike } 1850f80bc85SJeff Dike return(fd); 18687276f72SPaolo 'Blaisorblade' Giarrusso out: 18787276f72SPaolo 'Blaisorblade' Giarrusso free(tempname); 18887276f72SPaolo 'Blaisorblade' Giarrusso return -1; 1890f80bc85SJeff Dike } 1900f80bc85SJeff Dike 1910f80bc85SJeff Dike #define TEMPNAME_TEMPLATE "vm_file-XXXXXX" 1920f80bc85SJeff Dike 1930f80bc85SJeff Dike /* 1940f80bc85SJeff Dike * This proc is used in start_up.c 1950f80bc85SJeff Dike * So it isn't 'static'. 1960f80bc85SJeff Dike */ 197ae173816SJeff Dike int create_tmp_file(unsigned long long len) 1980f80bc85SJeff Dike { 1990f80bc85SJeff Dike int fd, err; 2000f80bc85SJeff Dike char zero; 2010f80bc85SJeff Dike 2020f80bc85SJeff Dike fd = make_tempfile(TEMPNAME_TEMPLATE, NULL, 1); 2030f80bc85SJeff Dike if(fd < 0) { 2040f80bc85SJeff Dike exit(1); 2050f80bc85SJeff Dike } 2060f80bc85SJeff Dike 2070f80bc85SJeff Dike err = fchmod(fd, 0777); 2080f80bc85SJeff Dike if(err < 0){ 2090f80bc85SJeff Dike perror("os_mode_fd"); 2100f80bc85SJeff Dike exit(1); 2110f80bc85SJeff Dike } 2120f80bc85SJeff Dike 213*190f4939SJeff Dike /* Seek to len - 1 because writing a character there will 214*190f4939SJeff Dike * increase the file size by one byte, to the desired length. 215*190f4939SJeff Dike */ 216*190f4939SJeff Dike if (lseek64(fd, len - 1, SEEK_SET) < 0) { 2170f80bc85SJeff Dike perror("os_seek_file"); 2180f80bc85SJeff Dike exit(1); 2190f80bc85SJeff Dike } 2200f80bc85SJeff Dike 2210f80bc85SJeff Dike zero = 0; 2220f80bc85SJeff Dike 2230f80bc85SJeff Dike err = os_write_file(fd, &zero, 1); 2240f80bc85SJeff Dike if(err != 1){ 2250f80bc85SJeff Dike errno = -err; 2260f80bc85SJeff Dike perror("os_write_file"); 2270f80bc85SJeff Dike exit(1); 2280f80bc85SJeff Dike } 2290f80bc85SJeff Dike 2300f80bc85SJeff Dike return(fd); 2310f80bc85SJeff Dike } 2320f80bc85SJeff Dike 233ae173816SJeff Dike int create_mem_file(unsigned long long len) 2340f80bc85SJeff Dike { 2350f80bc85SJeff Dike int err, fd; 2360f80bc85SJeff Dike 23702dea087SJeff Dike fd = create_tmp_file(len); 2380f80bc85SJeff Dike 2390f80bc85SJeff Dike err = os_set_exec_close(fd, 1); 2400f80bc85SJeff Dike if(err < 0){ 2410f80bc85SJeff Dike errno = -err; 2420f80bc85SJeff Dike perror("exec_close"); 2430f80bc85SJeff Dike } 2440f80bc85SJeff Dike return(fd); 2450f80bc85SJeff Dike } 246966a082fSRob Landley 247966a082fSRob Landley 248966a082fSRob Landley void check_tmpexec(void) 249966a082fSRob Landley { 250966a082fSRob Landley void *addr; 251966a082fSRob Landley int err, fd = create_tmp_file(UM_KERN_PAGE_SIZE); 252966a082fSRob Landley 253966a082fSRob Landley addr = mmap(NULL, UM_KERN_PAGE_SIZE, 254966a082fSRob Landley PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, fd, 0); 255966a082fSRob Landley printf("Checking PROT_EXEC mmap in %s...",tempdir); 256966a082fSRob Landley fflush(stdout); 257966a082fSRob Landley if(addr == MAP_FAILED){ 258966a082fSRob Landley err = errno; 259966a082fSRob Landley perror("failed"); 260966a082fSRob Landley if(err == EPERM) 261966a082fSRob Landley printf("%s must be not mounted noexec\n",tempdir); 262966a082fSRob Landley exit(1); 263966a082fSRob Landley } 264966a082fSRob Landley printf("OK\n"); 265966a082fSRob Landley munmap(addr, UM_KERN_PAGE_SIZE); 266966a082fSRob Landley 267966a082fSRob Landley close(fd); 268966a082fSRob Landley } 269