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" 63ad0a769SPeter Maydell #include "loader.h" 7e5fe0c52Spbrook 8e5fe0c52Spbrook #define NGROUPS 32 9e5fe0c52Spbrook 10e5fe0c52Spbrook /* ??? This should really be somewhere else. */ 11a46955ffSRichard Henderson abi_long memcpy_to_target(abi_ulong dest, const void *src, unsigned long len) 12e5fe0c52Spbrook { 13e5fe0c52Spbrook void *host_ptr; 14e5fe0c52Spbrook 15579a97f7Sbellard host_ptr = lock_user(VERIFY_WRITE, dest, len, 0); 16a46955ffSRichard Henderson if (!host_ptr) { 17579a97f7Sbellard return -TARGET_EFAULT; 18a46955ffSRichard Henderson } 19e5fe0c52Spbrook memcpy(host_ptr, src, len); 20e5fe0c52Spbrook unlock_user(host_ptr, dest, 1); 21579a97f7Sbellard return 0; 22e5fe0c52Spbrook } 23e5fe0c52Spbrook 24e5fe0c52Spbrook static int count(char **vec) 25e5fe0c52Spbrook { 26e5fe0c52Spbrook int i; 27e5fe0c52Spbrook 28e5fe0c52Spbrook for (i = 0; *vec; i++) { 29e5fe0c52Spbrook vec++; 30e5fe0c52Spbrook } 31a46955ffSRichard Henderson return i; 32e5fe0c52Spbrook } 33e5fe0c52Spbrook 34e5fe0c52Spbrook static int prepare_binprm(struct linux_binprm *bprm) 35e5fe0c52Spbrook { 36e5fe0c52Spbrook struct stat st; 37e5fe0c52Spbrook int mode; 38331c23b5SJuan Quintela int retval; 39e5fe0c52Spbrook 40e5fe0c52Spbrook if (fstat(bprm->fd, &st) < 0) { 41a46955ffSRichard Henderson return -errno; 42e5fe0c52Spbrook } 43e5fe0c52Spbrook 44e5fe0c52Spbrook mode = st.st_mode; 45e5fe0c52Spbrook if (!S_ISREG(mode)) { /* Must be regular file */ 46a46955ffSRichard Henderson return -EACCES; 47e5fe0c52Spbrook } 48e5fe0c52Spbrook if (!(mode & 0111)) { /* Must have at least one execute bit set */ 49a46955ffSRichard Henderson return -EACCES; 50e5fe0c52Spbrook } 51e5fe0c52Spbrook 52e5fe0c52Spbrook bprm->e_uid = geteuid(); 53e5fe0c52Spbrook bprm->e_gid = getegid(); 54e5fe0c52Spbrook 55e5fe0c52Spbrook /* Set-uid? */ 56e5fe0c52Spbrook if (mode & S_ISUID) { 57e5fe0c52Spbrook bprm->e_uid = st.st_uid; 58e5fe0c52Spbrook } 59e5fe0c52Spbrook 60e5fe0c52Spbrook /* Set-gid? */ 61e5fe0c52Spbrook /* 62e5fe0c52Spbrook * If setgid is set but no group execute bit then this 63e5fe0c52Spbrook * is a candidate for mandatory locking, not a setgid 64e5fe0c52Spbrook * executable. 65e5fe0c52Spbrook */ 66e5fe0c52Spbrook if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { 67e5fe0c52Spbrook bprm->e_gid = st.st_gid; 68e5fe0c52Spbrook } 69e5fe0c52Spbrook 709955ffacSRichard Henderson retval = read(bprm->fd, bprm->buf, BPRM_BUF_SIZE); 71e5fe0c52Spbrook if (retval < 0) { 72e5fe0c52Spbrook perror("prepare_binprm"); 73e5fe0c52Spbrook exit(-1); 74e5fe0c52Spbrook } 759955ffacSRichard Henderson if (retval < BPRM_BUF_SIZE) { 769955ffacSRichard Henderson /* Make sure the rest of the loader won't read garbage. */ 779955ffacSRichard Henderson memset(bprm->buf + retval, 0, BPRM_BUF_SIZE - retval); 78e5fe0c52Spbrook } 799955ffacSRichard Henderson return retval; 80e5fe0c52Spbrook } 81e5fe0c52Spbrook 82e5fe0c52Spbrook /* Construct the envp and argv tables on the target stack. */ 83992f48a0Sblueswir1 abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp, 84992f48a0Sblueswir1 abi_ulong stringp, int push_ptr) 85e5fe0c52Spbrook { 860429a971SAndreas Färber TaskState *ts = (TaskState *)thread_cpu->opaque; 87992f48a0Sblueswir1 int n = sizeof(abi_ulong); 88992f48a0Sblueswir1 abi_ulong envp; 89992f48a0Sblueswir1 abi_ulong argv; 90e5fe0c52Spbrook 91e5fe0c52Spbrook sp -= (envc + 1) * n; 92e5fe0c52Spbrook envp = sp; 93e5fe0c52Spbrook sp -= (argc + 1) * n; 94e5fe0c52Spbrook argv = sp; 9560f1c801SRichard Henderson ts->info->envp = envp; 9660f1c801SRichard Henderson ts->info->envc = envc; 9760f1c801SRichard Henderson ts->info->argv = argv; 9860f1c801SRichard Henderson ts->info->argc = argc; 9960f1c801SRichard Henderson 100e5fe0c52Spbrook if (push_ptr) { 1012f619698Sbellard /* FIXME - handle put_user() failures */ 1022f619698Sbellard sp -= n; 1032f619698Sbellard put_user_ual(envp, sp); 1042f619698Sbellard sp -= n; 1052f619698Sbellard put_user_ual(argv, sp); 106e5fe0c52Spbrook } 10760f1c801SRichard Henderson 1082f619698Sbellard sp -= n; 1092f619698Sbellard /* FIXME - handle put_user() failures */ 1102f619698Sbellard put_user_ual(argc, sp); 11160f1c801SRichard Henderson 11260f1c801SRichard Henderson ts->info->arg_strings = stringp; 113e5fe0c52Spbrook while (argc-- > 0) { 1142f619698Sbellard /* FIXME - handle put_user() failures */ 1152f619698Sbellard put_user_ual(stringp, argv); 1162f619698Sbellard argv += n; 117e5fe0c52Spbrook stringp += target_strlen(stringp) + 1; 118e5fe0c52Spbrook } 1192f619698Sbellard /* FIXME - handle put_user() failures */ 1202f619698Sbellard put_user_ual(0, argv); 12160f1c801SRichard Henderson 12260f1c801SRichard Henderson ts->info->env_strings = stringp; 123e5fe0c52Spbrook while (envc-- > 0) { 1242f619698Sbellard /* FIXME - handle put_user() failures */ 1252f619698Sbellard put_user_ual(stringp, envp); 1262f619698Sbellard envp += n; 127e5fe0c52Spbrook stringp += target_strlen(stringp) + 1; 128e5fe0c52Spbrook } 1292f619698Sbellard /* FIXME - handle put_user() failures */ 1302f619698Sbellard put_user_ual(0, envp); 131e5fe0c52Spbrook 132e5fe0c52Spbrook return sp; 133e5fe0c52Spbrook } 134e5fe0c52Spbrook 13503cfd8faSLaurent Vivier int loader_exec(int fdexec, const char *filename, char **argv, char **envp, 136edf8e2afSMika Westerberg struct target_pt_regs *regs, struct image_info *infop, 137edf8e2afSMika Westerberg struct linux_binprm *bprm) 138e5fe0c52Spbrook { 139e5fe0c52Spbrook int retval; 140e5fe0c52Spbrook 14103cfd8faSLaurent Vivier bprm->fd = fdexec; 142edf8e2afSMika Westerberg bprm->filename = (char *)filename; 143edf8e2afSMika Westerberg bprm->argc = count(argv); 144edf8e2afSMika Westerberg bprm->argv = argv; 145edf8e2afSMika Westerberg bprm->envc = count(envp); 146edf8e2afSMika Westerberg bprm->envp = envp; 147e5fe0c52Spbrook 148edf8e2afSMika Westerberg retval = prepare_binprm(bprm); 149e5fe0c52Spbrook 150e5fe0c52Spbrook if (retval >= 0) { 151edf8e2afSMika Westerberg if (bprm->buf[0] == 0x7f 152edf8e2afSMika Westerberg && bprm->buf[1] == 'E' 153edf8e2afSMika Westerberg && bprm->buf[2] == 'L' 154edf8e2afSMika Westerberg && bprm->buf[3] == 'F') { 155f0116c54SWill Newton retval = load_elf_binary(bprm, infop); 156e5fe0c52Spbrook #if defined(TARGET_HAS_BFLT) 157edf8e2afSMika Westerberg } else if (bprm->buf[0] == 'b' 158edf8e2afSMika Westerberg && bprm->buf[1] == 'F' 159edf8e2afSMika Westerberg && bprm->buf[2] == 'L' 160edf8e2afSMika Westerberg && bprm->buf[3] == 'T') { 161f0116c54SWill Newton retval = load_flt_binary(bprm, infop); 162e5fe0c52Spbrook #endif 163e5fe0c52Spbrook } else { 164885c1d10SPeter Maydell return -ENOEXEC; 165e5fe0c52Spbrook } 166e5fe0c52Spbrook } 167e5fe0c52Spbrook 168e5fe0c52Spbrook if (retval >= 0) { 169e5fe0c52Spbrook /* success. Initialize important registers */ 170e5fe0c52Spbrook do_init_thread(regs, infop); 171e5fe0c52Spbrook return retval; 172e5fe0c52Spbrook } 173e5fe0c52Spbrook 174a46955ffSRichard Henderson return retval; 175e5fe0c52Spbrook } 176