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