|
1 /* Code for loading BSD executables. Mostly linux kernel code. */ |
|
2 |
|
3 #include <sys/types.h> |
|
4 #include <sys/stat.h> |
|
5 #include <fcntl.h> |
|
6 #include <errno.h> |
|
7 #include <unistd.h> |
|
8 #include <stdio.h> |
|
9 #include <stdlib.h> |
|
10 |
|
11 #include "qemu.h" |
|
12 |
|
13 #define NGROUPS 32 |
|
14 |
|
15 /* ??? This should really be somewhere else. */ |
|
16 abi_long memcpy_to_target(abi_ulong dest, const void *src, |
|
17 unsigned long len) |
|
18 { |
|
19 void *host_ptr; |
|
20 |
|
21 host_ptr = lock_user(VERIFY_WRITE, dest, len, 0); |
|
22 if (!host_ptr) |
|
23 return -TARGET_EFAULT; |
|
24 memcpy(host_ptr, src, len); |
|
25 unlock_user(host_ptr, dest, 1); |
|
26 return 0; |
|
27 } |
|
28 |
|
29 static int in_group_p(gid_t g) |
|
30 { |
|
31 /* return TRUE if we're in the specified group, FALSE otherwise */ |
|
32 int ngroup; |
|
33 int i; |
|
34 gid_t grouplist[NGROUPS]; |
|
35 |
|
36 ngroup = getgroups(NGROUPS, grouplist); |
|
37 for(i = 0; i < ngroup; i++) { |
|
38 if(grouplist[i] == g) { |
|
39 return 1; |
|
40 } |
|
41 } |
|
42 return 0; |
|
43 } |
|
44 |
|
45 static int count(char ** vec) |
|
46 { |
|
47 int i; |
|
48 |
|
49 for(i = 0; *vec; i++) { |
|
50 vec++; |
|
51 } |
|
52 |
|
53 return(i); |
|
54 } |
|
55 |
|
56 static int prepare_binprm(struct linux_binprm *bprm) |
|
57 { |
|
58 struct stat st; |
|
59 int mode; |
|
60 int retval, id_change; |
|
61 |
|
62 if(fstat(bprm->fd, &st) < 0) { |
|
63 return(-errno); |
|
64 } |
|
65 |
|
66 mode = st.st_mode; |
|
67 if(!S_ISREG(mode)) { /* Must be regular file */ |
|
68 return(-EACCES); |
|
69 } |
|
70 if(!(mode & 0111)) { /* Must have at least one execute bit set */ |
|
71 return(-EACCES); |
|
72 } |
|
73 |
|
74 bprm->e_uid = geteuid(); |
|
75 bprm->e_gid = getegid(); |
|
76 id_change = 0; |
|
77 |
|
78 /* Set-uid? */ |
|
79 if(mode & S_ISUID) { |
|
80 bprm->e_uid = st.st_uid; |
|
81 if(bprm->e_uid != geteuid()) { |
|
82 id_change = 1; |
|
83 } |
|
84 } |
|
85 |
|
86 /* Set-gid? */ |
|
87 /* |
|
88 * If setgid is set but no group execute bit then this |
|
89 * is a candidate for mandatory locking, not a setgid |
|
90 * executable. |
|
91 */ |
|
92 if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { |
|
93 bprm->e_gid = st.st_gid; |
|
94 if (!in_group_p(bprm->e_gid)) { |
|
95 id_change = 1; |
|
96 } |
|
97 } |
|
98 |
|
99 memset(bprm->buf, 0, sizeof(bprm->buf)); |
|
100 retval = lseek(bprm->fd, 0L, SEEK_SET); |
|
101 if(retval >= 0) { |
|
102 retval = read(bprm->fd, bprm->buf, 128); |
|
103 } |
|
104 if(retval < 0) { |
|
105 perror("prepare_binprm"); |
|
106 exit(-1); |
|
107 /* return(-errno); */ |
|
108 } |
|
109 else { |
|
110 return(retval); |
|
111 } |
|
112 } |
|
113 |
|
114 /* Construct the envp and argv tables on the target stack. */ |
|
115 abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp, |
|
116 abi_ulong stringp, int push_ptr) |
|
117 { |
|
118 int n = sizeof(abi_ulong); |
|
119 abi_ulong envp; |
|
120 abi_ulong argv; |
|
121 |
|
122 sp -= (envc + 1) * n; |
|
123 envp = sp; |
|
124 sp -= (argc + 1) * n; |
|
125 argv = sp; |
|
126 if (push_ptr) { |
|
127 /* FIXME - handle put_user() failures */ |
|
128 sp -= n; |
|
129 put_user_ual(envp, sp); |
|
130 sp -= n; |
|
131 put_user_ual(argv, sp); |
|
132 } |
|
133 sp -= n; |
|
134 /* FIXME - handle put_user() failures */ |
|
135 put_user_ual(argc, sp); |
|
136 |
|
137 while (argc-- > 0) { |
|
138 /* FIXME - handle put_user() failures */ |
|
139 put_user_ual(stringp, argv); |
|
140 argv += n; |
|
141 stringp += target_strlen(stringp) + 1; |
|
142 } |
|
143 /* FIXME - handle put_user() failures */ |
|
144 put_user_ual(0, argv); |
|
145 while (envc-- > 0) { |
|
146 /* FIXME - handle put_user() failures */ |
|
147 put_user_ual(stringp, envp); |
|
148 envp += n; |
|
149 stringp += target_strlen(stringp) + 1; |
|
150 } |
|
151 /* FIXME - handle put_user() failures */ |
|
152 put_user_ual(0, envp); |
|
153 |
|
154 return sp; |
|
155 } |
|
156 |
|
157 int loader_exec(const char * filename, char ** argv, char ** envp, |
|
158 struct target_pt_regs * regs, struct image_info *infop) |
|
159 { |
|
160 struct linux_binprm bprm; |
|
161 int retval; |
|
162 int i; |
|
163 |
|
164 bprm.p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int); |
|
165 for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */ |
|
166 bprm.page[i] = 0; |
|
167 retval = open(filename, O_RDONLY); |
|
168 if (retval < 0) |
|
169 return retval; |
|
170 bprm.fd = retval; |
|
171 bprm.filename = (char *)filename; |
|
172 bprm.argc = count(argv); |
|
173 bprm.argv = argv; |
|
174 bprm.envc = count(envp); |
|
175 bprm.envp = envp; |
|
176 |
|
177 retval = prepare_binprm(&bprm); |
|
178 |
|
179 infop->host_argv = argv; |
|
180 |
|
181 if(retval>=0) { |
|
182 if (bprm.buf[0] == 0x7f |
|
183 && bprm.buf[1] == 'E' |
|
184 && bprm.buf[2] == 'L' |
|
185 && bprm.buf[3] == 'F') { |
|
186 retval = load_elf_binary(&bprm,regs,infop); |
|
187 } else { |
|
188 fprintf(stderr, "Unknown binary format\n"); |
|
189 return -1; |
|
190 } |
|
191 } |
|
192 |
|
193 if(retval>=0) { |
|
194 /* success. Initialize important registers */ |
|
195 do_init_thread(regs, infop); |
|
196 return retval; |
|
197 } |
|
198 |
|
199 /* Something went wrong, return the inode and free the argument pages*/ |
|
200 for (i=0 ; i<MAX_ARG_PAGES ; i++) { |
|
201 free(bprm.page[i]); |
|
202 } |
|
203 return(retval); |
|
204 } |