xref: /qemu/linux-user/linuxload.c (revision f9734d5d)
1 /* Code for loading Linux executables.  Mostly linux kernel code.  */
2 
3 #include "qemu/osdep.h"
4 #include "qemu.h"
5 
6 #define NGROUPS 32
7 
8 /* ??? This should really be somewhere else.  */
9 abi_long memcpy_to_target(abi_ulong dest, const void *src, unsigned long len)
10 {
11     void *host_ptr;
12 
13     host_ptr = lock_user(VERIFY_WRITE, dest, len, 0);
14     if (!host_ptr) {
15         return -TARGET_EFAULT;
16     }
17     memcpy(host_ptr, src, len);
18     unlock_user(host_ptr, dest, 1);
19     return 0;
20 }
21 
22 static int count(char **vec)
23 {
24     int i;
25 
26     for (i = 0; *vec; i++) {
27         vec++;
28     }
29     return i;
30 }
31 
32 static int prepare_binprm(struct linux_binprm *bprm)
33 {
34     struct stat st;
35     int mode;
36     int retval;
37 
38     if (fstat(bprm->fd, &st) < 0) {
39         return -errno;
40     }
41 
42     mode = st.st_mode;
43     if (!S_ISREG(mode)) {   /* Must be regular file */
44         return -EACCES;
45     }
46     if (!(mode & 0111)) {   /* Must have at least one execute bit set */
47         return -EACCES;
48     }
49 
50     bprm->e_uid = geteuid();
51     bprm->e_gid = getegid();
52 
53     /* Set-uid? */
54     if (mode & S_ISUID) {
55         bprm->e_uid = st.st_uid;
56     }
57 
58     /* Set-gid? */
59     /*
60      * If setgid is set but no group execute bit then this
61      * is a candidate for mandatory locking, not a setgid
62      * executable.
63      */
64     if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
65         bprm->e_gid = st.st_gid;
66     }
67 
68     retval = read(bprm->fd, bprm->buf, BPRM_BUF_SIZE);
69     if (retval < 0) {
70         perror("prepare_binprm");
71         exit(-1);
72     }
73     if (retval < BPRM_BUF_SIZE) {
74         /* Make sure the rest of the loader won't read garbage.  */
75         memset(bprm->buf + retval, 0, BPRM_BUF_SIZE - retval);
76     }
77     return retval;
78 }
79 
80 /* Construct the envp and argv tables on the target stack.  */
81 abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp,
82                               abi_ulong stringp, int push_ptr)
83 {
84     TaskState *ts = (TaskState *)thread_cpu->opaque;
85     int n = sizeof(abi_ulong);
86     abi_ulong envp;
87     abi_ulong argv;
88 
89     sp -= (envc + 1) * n;
90     envp = sp;
91     sp -= (argc + 1) * n;
92     argv = sp;
93     if (push_ptr) {
94         /* FIXME - handle put_user() failures */
95         sp -= n;
96         put_user_ual(envp, sp);
97         sp -= n;
98         put_user_ual(argv, sp);
99     }
100     sp -= n;
101     /* FIXME - handle put_user() failures */
102     put_user_ual(argc, sp);
103     ts->info->arg_start = stringp;
104     while (argc-- > 0) {
105         /* FIXME - handle put_user() failures */
106         put_user_ual(stringp, argv);
107         argv += n;
108         stringp += target_strlen(stringp) + 1;
109     }
110     ts->info->arg_end = stringp;
111     /* FIXME - handle put_user() failures */
112     put_user_ual(0, argv);
113     while (envc-- > 0) {
114         /* FIXME - handle put_user() failures */
115         put_user_ual(stringp, envp);
116         envp += n;
117         stringp += target_strlen(stringp) + 1;
118     }
119     /* FIXME - handle put_user() failures */
120     put_user_ual(0, envp);
121 
122     return sp;
123 }
124 
125 int loader_exec(int fdexec, const char *filename, char **argv, char **envp,
126                 struct target_pt_regs *regs, struct image_info *infop,
127                 struct linux_binprm *bprm)
128 {
129     int retval;
130 
131     bprm->fd = fdexec;
132     bprm->filename = (char *)filename;
133     bprm->argc = count(argv);
134     bprm->argv = argv;
135     bprm->envc = count(envp);
136     bprm->envp = envp;
137 
138     retval = prepare_binprm(bprm);
139 
140     if (retval >= 0) {
141         if (bprm->buf[0] == 0x7f
142                 && bprm->buf[1] == 'E'
143                 && bprm->buf[2] == 'L'
144                 && bprm->buf[3] == 'F') {
145             retval = load_elf_binary(bprm, infop);
146 #if defined(TARGET_HAS_BFLT)
147         } else if (bprm->buf[0] == 'b'
148                 && bprm->buf[1] == 'F'
149                 && bprm->buf[2] == 'L'
150                 && bprm->buf[3] == 'T') {
151             retval = load_flt_binary(bprm, infop);
152 #endif
153         } else {
154             return -ENOEXEC;
155         }
156     }
157 
158     if (retval >= 0) {
159         /* success.  Initialize important registers */
160         do_init_thread(regs, infop);
161         return retval;
162     }
163 
164     return retval;
165 }
166