xref: /qemu/linux-user/linuxload.c (revision 60f1c801)
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