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. */
memcpy_to_target(abi_ulong dest,const void * src,unsigned long len)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
count(char ** vec)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
prepare_binprm(struct linux_binprm * bprm)36e5fe0c52Spbrook static int prepare_binprm(struct linux_binprm *bprm)
37e5fe0c52Spbrook {
38e5fe0c52Spbrook struct stat st;
39e5fe0c52Spbrook int mode;
40331c23b5SJuan Quintela int retval;
41e5fe0c52Spbrook
42d0b6b793SRichard 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
72d0b6b793SRichard 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. */
loader_build_argptr(int envc,int argc,abi_ulong sp,abi_ulong stringp,int push_ptr)89992f48a0Sblueswir1 abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp,
90992f48a0Sblueswir1 abi_ulong stringp, int push_ptr)
91e5fe0c52Spbrook {
92*e4e5cb4aSIlya Leoshkevich TaskState *ts = get_task_state(thread_cpu);
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
loader_exec(int fdexec,const char * filename,char ** argv,char ** envp,struct target_pt_regs * regs,struct image_info * infop,struct linux_binprm * bprm)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
imgsrc_read(void * dst,off_t offset,size_t len,const ImageSource * img,Error ** errp)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
imgsrc_read_alloc(off_t offset,size_t len,const ImageSource * img,Error ** errp)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
imgsrc_mmap(abi_ulong start,abi_ulong len,int prot,int flags,const ImageSource * src,abi_ulong offset)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