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> 11*966a082fSRob 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 23*966a082fSRob 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')) 39*966a082fSRob 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 51*966a082fSRob Landley /* This will return 1, with the first character in buf being the 52*966a082fSRob Landley * character following the next instance of c in the file. This will 53*966a082fSRob Landley * read the file as needed. If there's an error, -errno is returned; 54*966a082fSRob Landley * if the end of the file is reached, 0 is returned. 55*966a082fSRob Landley */ 56*966a082fSRob Landley static int next(int fd, char *buf, int size, char c) 57*966a082fSRob Landley { 58*966a082fSRob Landley int n; 59*966a082fSRob Landley char *ptr; 60*966a082fSRob Landley 61*966a082fSRob Landley while((ptr = strchr(buf, c)) == NULL){ 62*966a082fSRob Landley n = read(fd, buf, size - 1); 63*966a082fSRob Landley if(n == 0) 64*966a082fSRob Landley return 0; 65*966a082fSRob Landley else if(n < 0) 66*966a082fSRob Landley return -errno; 67*966a082fSRob Landley 68*966a082fSRob Landley buf[n] = '\0'; 69*966a082fSRob Landley } 70*966a082fSRob Landley 71*966a082fSRob Landley ptr++; 72*966a082fSRob Landley memmove(buf, ptr, strlen(ptr) + 1); 73*966a082fSRob Landley return 1; 74*966a082fSRob Landley } 75*966a082fSRob Landley 76*966a082fSRob Landley static int checked_tmpdir = 0; 77*966a082fSRob Landley 78*966a082fSRob Landley /* Look for a tmpfs mounted at /dev/shm. I couldn't find a cleaner 79*966a082fSRob Landley * way to do this than to parse /proc/mounts. statfs will return the 80*966a082fSRob Landley * same filesystem magic number and fs id for both /dev and /dev/shm 81*966a082fSRob Landley * when they are both tmpfs, so you can't tell if they are different 82*966a082fSRob Landley * filesystems. Also, there seems to be no other way of finding the 83*966a082fSRob Landley * mount point of a filesystem from within it. 84*966a082fSRob Landley * 85*966a082fSRob Landley * If a /dev/shm tmpfs entry is found, then we switch to using it. 86*966a082fSRob Landley * Otherwise, we stay with the default /tmp. 87*966a082fSRob Landley */ 88*966a082fSRob Landley static void which_tmpdir(void) 89*966a082fSRob Landley { 90*966a082fSRob Landley int fd, found; 91*966a082fSRob Landley char buf[128] = { '\0' }; 92*966a082fSRob Landley 93*966a082fSRob Landley if(checked_tmpdir) 94*966a082fSRob Landley return; 95*966a082fSRob Landley 96*966a082fSRob Landley checked_tmpdir = 1; 97*966a082fSRob Landley 98*966a082fSRob Landley printf("Checking for tmpfs mount on /dev/shm..."); 99*966a082fSRob Landley 100*966a082fSRob Landley fd = open("/proc/mounts", O_RDONLY); 101*966a082fSRob Landley if(fd < 0){ 102*966a082fSRob Landley printf("failed to open /proc/mounts, errno = %d\n", errno); 103*966a082fSRob Landley return; 104*966a082fSRob Landley } 105*966a082fSRob Landley 106*966a082fSRob Landley while(1){ 107*966a082fSRob Landley found = next(fd, buf, sizeof(buf) / sizeof(buf[0]), ' '); 108*966a082fSRob Landley if(found != 1) 109*966a082fSRob Landley break; 110*966a082fSRob Landley 111*966a082fSRob Landley if(!strncmp(buf, "/dev/shm", strlen("/dev/shm"))) 112*966a082fSRob Landley goto found; 113*966a082fSRob Landley 114*966a082fSRob Landley found = next(fd, buf, sizeof(buf) / sizeof(buf[0]), '\n'); 115*966a082fSRob Landley if(found != 1) 116*966a082fSRob Landley break; 117*966a082fSRob Landley } 118*966a082fSRob Landley 119*966a082fSRob Landley err: 120*966a082fSRob Landley if(found == 0) 121*966a082fSRob Landley printf("nothing mounted on /dev/shm\n"); 122*966a082fSRob Landley else if(found < 0) 123*966a082fSRob Landley printf("read returned errno %d\n", -found); 124*966a082fSRob Landley 125*966a082fSRob Landley return; 126*966a082fSRob Landley 127*966a082fSRob Landley found: 128*966a082fSRob Landley found = next(fd, buf, sizeof(buf) / sizeof(buf[0]), ' '); 129*966a082fSRob Landley if(found != 1) 130*966a082fSRob Landley goto err; 131*966a082fSRob Landley 132*966a082fSRob Landley if(strncmp(buf, "tmpfs", strlen("tmpfs"))){ 133*966a082fSRob Landley printf("not tmpfs\n"); 134*966a082fSRob Landley return; 135*966a082fSRob Landley } 136*966a082fSRob Landley 137*966a082fSRob Landley printf("OK\n"); 138*966a082fSRob Landley default_tmpdir = "/dev/shm"; 139*966a082fSRob Landley } 140*966a082fSRob Landley 1410f80bc85SJeff Dike /* 1420f80bc85SJeff Dike * This proc still used in tt-mode 1430f80bc85SJeff Dike * (file: kernel/tt/ptproxy/proxy.c, proc: start_debugger). 1440f80bc85SJeff Dike * So it isn't 'static' yet. 1450f80bc85SJeff Dike */ 1460f80bc85SJeff Dike int make_tempfile(const char *template, char **out_tempname, int do_unlink) 1470f80bc85SJeff Dike { 14887276f72SPaolo 'Blaisorblade' Giarrusso char *tempname; 1490f80bc85SJeff Dike int fd; 1500f80bc85SJeff Dike 151*966a082fSRob Landley which_tmpdir(); 15287276f72SPaolo 'Blaisorblade' Giarrusso tempname = malloc(MAXPATHLEN); 15387276f72SPaolo 'Blaisorblade' Giarrusso 1540f80bc85SJeff Dike find_tempdir(); 15587276f72SPaolo 'Blaisorblade' Giarrusso if (template[0] != '/') 1560f80bc85SJeff Dike strcpy(tempname, tempdir); 1570f80bc85SJeff Dike else 15887276f72SPaolo 'Blaisorblade' Giarrusso tempname[0] = '\0'; 1590f80bc85SJeff Dike strcat(tempname, template); 1600f80bc85SJeff Dike fd = mkstemp(tempname); 1610f80bc85SJeff Dike if(fd < 0){ 1620f80bc85SJeff Dike fprintf(stderr, "open - cannot create %s: %s\n", tempname, 1630f80bc85SJeff Dike strerror(errno)); 16487276f72SPaolo 'Blaisorblade' Giarrusso goto out; 1650f80bc85SJeff Dike } 1660f80bc85SJeff Dike if(do_unlink && (unlink(tempname) < 0)){ 1670f80bc85SJeff Dike perror("unlink"); 16887276f72SPaolo 'Blaisorblade' Giarrusso goto out; 1690f80bc85SJeff Dike } 1700f80bc85SJeff Dike if(out_tempname){ 17187276f72SPaolo 'Blaisorblade' Giarrusso *out_tempname = tempname; 17287276f72SPaolo 'Blaisorblade' Giarrusso } else { 17387276f72SPaolo 'Blaisorblade' Giarrusso free(tempname); 1740f80bc85SJeff Dike } 1750f80bc85SJeff Dike return(fd); 17687276f72SPaolo 'Blaisorblade' Giarrusso out: 17787276f72SPaolo 'Blaisorblade' Giarrusso free(tempname); 17887276f72SPaolo 'Blaisorblade' Giarrusso return -1; 1790f80bc85SJeff Dike } 1800f80bc85SJeff Dike 1810f80bc85SJeff Dike #define TEMPNAME_TEMPLATE "vm_file-XXXXXX" 1820f80bc85SJeff Dike 1830f80bc85SJeff Dike /* 1840f80bc85SJeff Dike * This proc is used in start_up.c 1850f80bc85SJeff Dike * So it isn't 'static'. 1860f80bc85SJeff Dike */ 187ae173816SJeff Dike int create_tmp_file(unsigned long long len) 1880f80bc85SJeff Dike { 1890f80bc85SJeff Dike int fd, err; 1900f80bc85SJeff Dike char zero; 1910f80bc85SJeff Dike 1920f80bc85SJeff Dike fd = make_tempfile(TEMPNAME_TEMPLATE, NULL, 1); 1930f80bc85SJeff Dike if(fd < 0) { 1940f80bc85SJeff Dike exit(1); 1950f80bc85SJeff Dike } 1960f80bc85SJeff Dike 1970f80bc85SJeff Dike err = fchmod(fd, 0777); 1980f80bc85SJeff Dike if(err < 0){ 1990f80bc85SJeff Dike perror("os_mode_fd"); 2000f80bc85SJeff Dike exit(1); 2010f80bc85SJeff Dike } 2020f80bc85SJeff Dike 2030f80bc85SJeff Dike if (lseek64(fd, len, SEEK_SET) < 0) { 2040f80bc85SJeff Dike perror("os_seek_file"); 2050f80bc85SJeff Dike exit(1); 2060f80bc85SJeff Dike } 2070f80bc85SJeff Dike 2080f80bc85SJeff Dike zero = 0; 2090f80bc85SJeff Dike 2100f80bc85SJeff Dike err = os_write_file(fd, &zero, 1); 2110f80bc85SJeff Dike if(err != 1){ 2120f80bc85SJeff Dike errno = -err; 2130f80bc85SJeff Dike perror("os_write_file"); 2140f80bc85SJeff Dike exit(1); 2150f80bc85SJeff Dike } 2160f80bc85SJeff Dike 2170f80bc85SJeff Dike return(fd); 2180f80bc85SJeff Dike } 2190f80bc85SJeff Dike 220ae173816SJeff Dike int create_mem_file(unsigned long long len) 2210f80bc85SJeff Dike { 2220f80bc85SJeff Dike int err, fd; 2230f80bc85SJeff Dike 22402dea087SJeff Dike fd = create_tmp_file(len); 2250f80bc85SJeff Dike 2260f80bc85SJeff Dike err = os_set_exec_close(fd, 1); 2270f80bc85SJeff Dike if(err < 0){ 2280f80bc85SJeff Dike errno = -err; 2290f80bc85SJeff Dike perror("exec_close"); 2300f80bc85SJeff Dike } 2310f80bc85SJeff Dike return(fd); 2320f80bc85SJeff Dike } 233*966a082fSRob Landley 234*966a082fSRob Landley 235*966a082fSRob Landley void check_tmpexec(void) 236*966a082fSRob Landley { 237*966a082fSRob Landley void *addr; 238*966a082fSRob Landley int err, fd = create_tmp_file(UM_KERN_PAGE_SIZE); 239*966a082fSRob Landley 240*966a082fSRob Landley addr = mmap(NULL, UM_KERN_PAGE_SIZE, 241*966a082fSRob Landley PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, fd, 0); 242*966a082fSRob Landley printf("Checking PROT_EXEC mmap in %s...",tempdir); 243*966a082fSRob Landley fflush(stdout); 244*966a082fSRob Landley if(addr == MAP_FAILED){ 245*966a082fSRob Landley err = errno; 246*966a082fSRob Landley perror("failed"); 247*966a082fSRob Landley if(err == EPERM) 248*966a082fSRob Landley printf("%s must be not mounted noexec\n",tempdir); 249*966a082fSRob Landley exit(1); 250*966a082fSRob Landley } 251*966a082fSRob Landley printf("OK\n"); 252*966a082fSRob Landley munmap(addr, UM_KERN_PAGE_SIZE); 253*966a082fSRob Landley 254*966a082fSRob Landley close(fd); 255*966a082fSRob Landley } 256