10458df24Sths /* Code for loading Linux executables. Mostly linux kernel code. */ 2e5fe0c52Spbrook 3d39594e9SPeter Maydell #include "qemu/osdep.h" 4e5fe0c52Spbrook #include "qemu.h" 53b249d26SPeter Maydell #include "user-internals.h" 67d2c5526SRichard Henderson #include "user-mmap.h" 73ad0a769SPeter Maydell #include "loader.h" 87d2c5526SRichard Henderson #include "qapi/error.h" 9e5fe0c52Spbrook 10e5fe0c52Spbrook #define NGROUPS 32 11e5fe0c52Spbrook 12e5fe0c52Spbrook /* ??? This should really be somewhere else. */ 13a46955ffSRichard Henderson abi_long memcpy_to_target(abi_ulong dest, const void *src, unsigned long len) 14e5fe0c52Spbrook { 15e5fe0c52Spbrook void *host_ptr; 16e5fe0c52Spbrook 17579a97f7Sbellard host_ptr = lock_user(VERIFY_WRITE, dest, len, 0); 18a46955ffSRichard Henderson if (!host_ptr) { 19579a97f7Sbellard return -TARGET_EFAULT; 20a46955ffSRichard Henderson } 21e5fe0c52Spbrook memcpy(host_ptr, src, len); 22e5fe0c52Spbrook unlock_user(host_ptr, dest, 1); 23579a97f7Sbellard return 0; 24e5fe0c52Spbrook } 25e5fe0c52Spbrook 26e5fe0c52Spbrook static int count(char **vec) 27e5fe0c52Spbrook { 28e5fe0c52Spbrook int i; 29e5fe0c52Spbrook 30e5fe0c52Spbrook for (i = 0; *vec; i++) { 31e5fe0c52Spbrook vec++; 32e5fe0c52Spbrook } 33a46955ffSRichard Henderson return i; 34e5fe0c52Spbrook } 35e5fe0c52Spbrook 36e5fe0c52Spbrook static int prepare_binprm(struct linux_binprm *bprm) 37e5fe0c52Spbrook { 38e5fe0c52Spbrook struct stat st; 39e5fe0c52Spbrook int mode; 40331c23b5SJuan Quintela int retval; 41e5fe0c52Spbrook 42*d0b6b793SRichard Henderson if (fstat(bprm->src.fd, &st) < 0) { 43a46955ffSRichard Henderson return -errno; 44e5fe0c52Spbrook } 45e5fe0c52Spbrook 46e5fe0c52Spbrook mode = st.st_mode; 47e5fe0c52Spbrook if (!S_ISREG(mode)) { /* Must be regular file */ 48a46955ffSRichard Henderson return -EACCES; 49e5fe0c52Spbrook } 50e5fe0c52Spbrook if (!(mode & 0111)) { /* Must have at least one execute bit set */ 51a46955ffSRichard Henderson return -EACCES; 52e5fe0c52Spbrook } 53e5fe0c52Spbrook 54e5fe0c52Spbrook bprm->e_uid = geteuid(); 55e5fe0c52Spbrook bprm->e_gid = getegid(); 56e5fe0c52Spbrook 57e5fe0c52Spbrook /* Set-uid? */ 58e5fe0c52Spbrook if (mode & S_ISUID) { 59e5fe0c52Spbrook bprm->e_uid = st.st_uid; 60e5fe0c52Spbrook } 61e5fe0c52Spbrook 62e5fe0c52Spbrook /* Set-gid? */ 63e5fe0c52Spbrook /* 64e5fe0c52Spbrook * If setgid is set but no group execute bit then this 65e5fe0c52Spbrook * is a candidate for mandatory locking, not a setgid 66e5fe0c52Spbrook * executable. 67e5fe0c52Spbrook */ 68e5fe0c52Spbrook if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { 69e5fe0c52Spbrook bprm->e_gid = st.st_gid; 70e5fe0c52Spbrook } 71e5fe0c52Spbrook 72*d0b6b793SRichard Henderson retval = read(bprm->src.fd, bprm->buf, BPRM_BUF_SIZE); 73e5fe0c52Spbrook if (retval < 0) { 74e5fe0c52Spbrook perror("prepare_binprm"); 75e5fe0c52Spbrook exit(-1); 76e5fe0c52Spbrook } 779955ffacSRichard Henderson if (retval < BPRM_BUF_SIZE) { 789955ffacSRichard Henderson /* Make sure the rest of the loader won't read garbage. */ 799955ffacSRichard Henderson memset(bprm->buf + retval, 0, BPRM_BUF_SIZE - retval); 80e5fe0c52Spbrook } 817d2c5526SRichard Henderson 827d2c5526SRichard Henderson bprm->src.cache = bprm->buf; 837d2c5526SRichard Henderson bprm->src.cache_size = retval; 847d2c5526SRichard Henderson 859955ffacSRichard Henderson return retval; 86e5fe0c52Spbrook } 87e5fe0c52Spbrook 88e5fe0c52Spbrook /* Construct the envp and argv tables on the target stack. */ 89992f48a0Sblueswir1 abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp, 90992f48a0Sblueswir1 abi_ulong stringp, int push_ptr) 91e5fe0c52Spbrook { 920429a971SAndreas Färber TaskState *ts = (TaskState *)thread_cpu->opaque; 93992f48a0Sblueswir1 int n = sizeof(abi_ulong); 94992f48a0Sblueswir1 abi_ulong envp; 95992f48a0Sblueswir1 abi_ulong argv; 96e5fe0c52Spbrook 97e5fe0c52Spbrook sp -= (envc + 1) * n; 98e5fe0c52Spbrook envp = sp; 99e5fe0c52Spbrook sp -= (argc + 1) * n; 100e5fe0c52Spbrook argv = sp; 10160f1c801SRichard Henderson ts->info->envp = envp; 10260f1c801SRichard Henderson ts->info->envc = envc; 10360f1c801SRichard Henderson ts->info->argv = argv; 10460f1c801SRichard Henderson ts->info->argc = argc; 10560f1c801SRichard Henderson 106e5fe0c52Spbrook if (push_ptr) { 1072f619698Sbellard /* FIXME - handle put_user() failures */ 1082f619698Sbellard sp -= n; 1092f619698Sbellard put_user_ual(envp, sp); 1102f619698Sbellard sp -= n; 1112f619698Sbellard put_user_ual(argv, sp); 112e5fe0c52Spbrook } 11360f1c801SRichard Henderson 1142f619698Sbellard sp -= n; 1152f619698Sbellard /* FIXME - handle put_user() failures */ 1162f619698Sbellard put_user_ual(argc, sp); 11760f1c801SRichard Henderson 11860f1c801SRichard Henderson ts->info->arg_strings = stringp; 119e5fe0c52Spbrook while (argc-- > 0) { 1202f619698Sbellard /* FIXME - handle put_user() failures */ 1212f619698Sbellard put_user_ual(stringp, argv); 1222f619698Sbellard argv += n; 123e5fe0c52Spbrook stringp += target_strlen(stringp) + 1; 124e5fe0c52Spbrook } 1252f619698Sbellard /* FIXME - handle put_user() failures */ 1262f619698Sbellard put_user_ual(0, argv); 12760f1c801SRichard Henderson 12860f1c801SRichard Henderson ts->info->env_strings = stringp; 129e5fe0c52Spbrook while (envc-- > 0) { 1302f619698Sbellard /* FIXME - handle put_user() failures */ 1312f619698Sbellard put_user_ual(stringp, envp); 1322f619698Sbellard envp += n; 133e5fe0c52Spbrook stringp += target_strlen(stringp) + 1; 134e5fe0c52Spbrook } 1352f619698Sbellard /* FIXME - handle put_user() failures */ 1362f619698Sbellard put_user_ual(0, envp); 137e5fe0c52Spbrook 138e5fe0c52Spbrook return sp; 139e5fe0c52Spbrook } 140e5fe0c52Spbrook 14103cfd8faSLaurent Vivier int loader_exec(int fdexec, const char *filename, char **argv, char **envp, 142edf8e2afSMika Westerberg struct target_pt_regs *regs, struct image_info *infop, 143edf8e2afSMika Westerberg struct linux_binprm *bprm) 144e5fe0c52Spbrook { 145e5fe0c52Spbrook int retval; 146e5fe0c52Spbrook 1477d2c5526SRichard Henderson bprm->src.fd = fdexec; 148edf8e2afSMika Westerberg bprm->filename = (char *)filename; 149edf8e2afSMika Westerberg bprm->argc = count(argv); 150edf8e2afSMika Westerberg bprm->argv = argv; 151edf8e2afSMika Westerberg bprm->envc = count(envp); 152edf8e2afSMika Westerberg bprm->envp = envp; 153e5fe0c52Spbrook 154edf8e2afSMika Westerberg retval = prepare_binprm(bprm); 155e5fe0c52Spbrook 156f485be72SRichard Henderson if (retval < 4) { 157f485be72SRichard Henderson return -ENOEXEC; 158f485be72SRichard Henderson } 159edf8e2afSMika Westerberg if (bprm->buf[0] == 0x7f 160edf8e2afSMika Westerberg && bprm->buf[1] == 'E' 161edf8e2afSMika Westerberg && bprm->buf[2] == 'L' 162edf8e2afSMika Westerberg && bprm->buf[3] == 'F') { 163f0116c54SWill Newton retval = load_elf_binary(bprm, infop); 164e5fe0c52Spbrook #if defined(TARGET_HAS_BFLT) 165edf8e2afSMika Westerberg } else if (bprm->buf[0] == 'b' 166edf8e2afSMika Westerberg && bprm->buf[1] == 'F' 167edf8e2afSMika Westerberg && bprm->buf[2] == 'L' 168edf8e2afSMika Westerberg && bprm->buf[3] == 'T') { 169f0116c54SWill Newton retval = load_flt_binary(bprm, infop); 170e5fe0c52Spbrook #endif 171e5fe0c52Spbrook } else { 172885c1d10SPeter Maydell return -ENOEXEC; 173e5fe0c52Spbrook } 174f485be72SRichard Henderson if (retval < 0) { 175f485be72SRichard Henderson return retval; 176e5fe0c52Spbrook } 177e5fe0c52Spbrook 178f485be72SRichard Henderson /* Success. Initialize important registers. */ 179e5fe0c52Spbrook do_init_thread(regs, infop); 180f485be72SRichard Henderson return 0; 181e5fe0c52Spbrook } 1827d2c5526SRichard Henderson 1837d2c5526SRichard Henderson bool imgsrc_read(void *dst, off_t offset, size_t len, 1847d2c5526SRichard Henderson const ImageSource *img, Error **errp) 1857d2c5526SRichard Henderson { 1867d2c5526SRichard Henderson ssize_t ret; 1877d2c5526SRichard Henderson 1887d2c5526SRichard Henderson if (offset + len <= img->cache_size) { 1897d2c5526SRichard Henderson memcpy(dst, img->cache + offset, len); 1907d2c5526SRichard Henderson return true; 1917d2c5526SRichard Henderson } 1927d2c5526SRichard Henderson 1937d2c5526SRichard Henderson if (img->fd < 0) { 1947d2c5526SRichard Henderson error_setg(errp, "read past end of buffer"); 1957d2c5526SRichard Henderson return false; 1967d2c5526SRichard Henderson } 1977d2c5526SRichard Henderson 1987d2c5526SRichard Henderson ret = pread(img->fd, dst, len, offset); 1997d2c5526SRichard Henderson if (ret == len) { 2007d2c5526SRichard Henderson return true; 2017d2c5526SRichard Henderson } 2027d2c5526SRichard Henderson if (ret < 0) { 2037d2c5526SRichard Henderson error_setg_errno(errp, errno, "Error reading file header"); 2047d2c5526SRichard Henderson } else { 2057d2c5526SRichard Henderson error_setg(errp, "Incomplete read of file header"); 2067d2c5526SRichard Henderson } 2077d2c5526SRichard Henderson return false; 2087d2c5526SRichard Henderson } 2097d2c5526SRichard Henderson 2107d2c5526SRichard Henderson void *imgsrc_read_alloc(off_t offset, size_t len, 2117d2c5526SRichard Henderson const ImageSource *img, Error **errp) 2127d2c5526SRichard Henderson { 2137d2c5526SRichard Henderson void *alloc = g_malloc(len); 2147d2c5526SRichard Henderson bool ok = imgsrc_read(alloc, offset, len, img, errp); 2157d2c5526SRichard Henderson 2167d2c5526SRichard Henderson if (!ok) { 2177d2c5526SRichard Henderson g_free(alloc); 2187d2c5526SRichard Henderson alloc = NULL; 2197d2c5526SRichard Henderson } 2207d2c5526SRichard Henderson return alloc; 2217d2c5526SRichard Henderson } 2227d2c5526SRichard Henderson 2237d2c5526SRichard Henderson abi_long imgsrc_mmap(abi_ulong start, abi_ulong len, int prot, 2247d2c5526SRichard Henderson int flags, const ImageSource *src, abi_ulong offset) 2257d2c5526SRichard Henderson { 2267d2c5526SRichard Henderson const int prot_write = PROT_READ | PROT_WRITE; 2277d2c5526SRichard Henderson abi_long ret; 2287d2c5526SRichard Henderson void *haddr; 2297d2c5526SRichard Henderson 2307d2c5526SRichard Henderson assert(flags == (MAP_PRIVATE | MAP_FIXED)); 2317d2c5526SRichard Henderson 2327d2c5526SRichard Henderson if (src->fd >= 0) { 2337d2c5526SRichard Henderson return target_mmap(start, len, prot, flags, src->fd, offset); 2347d2c5526SRichard Henderson } 2357d2c5526SRichard Henderson 2367d2c5526SRichard Henderson /* 2377d2c5526SRichard Henderson * This case is for the vdso; we don't expect bad images. 2387d2c5526SRichard Henderson * The mmap may extend beyond the end of the image, especially 2397d2c5526SRichard Henderson * to the end of the page. Zero fill. 2407d2c5526SRichard Henderson */ 2417d2c5526SRichard Henderson assert(offset < src->cache_size); 2427d2c5526SRichard Henderson 2437d2c5526SRichard Henderson ret = target_mmap(start, len, prot_write, flags | MAP_ANON, -1, 0); 2447d2c5526SRichard Henderson if (ret == -1) { 2457d2c5526SRichard Henderson return ret; 2467d2c5526SRichard Henderson } 2477d2c5526SRichard Henderson 2487d2c5526SRichard Henderson haddr = lock_user(VERIFY_WRITE, start, len, 0); 2497d2c5526SRichard Henderson assert(haddr != NULL); 2507d2c5526SRichard Henderson if (offset + len <= src->cache_size) { 2517d2c5526SRichard Henderson memcpy(haddr, src->cache + offset, len); 2527d2c5526SRichard Henderson } else { 2537d2c5526SRichard Henderson size_t rest = src->cache_size - offset; 2547d2c5526SRichard Henderson memcpy(haddr, src->cache + offset, rest); 2557d2c5526SRichard Henderson memset(haddr + rest, 0, len - rest); 2567d2c5526SRichard Henderson } 2577d2c5526SRichard Henderson unlock_user(haddr, start, len); 2587d2c5526SRichard Henderson 2597d2c5526SRichard Henderson if (prot != prot_write) { 2607d2c5526SRichard Henderson target_mprotect(start, len, prot); 2617d2c5526SRichard Henderson } 2627d2c5526SRichard Henderson 2637d2c5526SRichard Henderson return ret; 2647d2c5526SRichard Henderson } 265