This source file includes following definitions.
- sys_uselib
- create_tables
- count
- copy_strings
- change_ldt
- do_execve
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 #include <signal.h>
21 #include <errno.h>
22 #include <string.h>
23 #include <sys/stat.h>
24 #include <a.out.h>
25
26 #include <linux/fs.h>
27 #include <linux/sched.h>
28 #include <linux/kernel.h>
29 #include <linux/mm.h>
30 #include <asm/segment.h>
31
32 extern int sys_exit(int exit_code);
33 extern int sys_close(int fd);
34
35
36
37
38
39
40 #define MAX_ARG_PAGES 32
41
42 int sys_uselib(const char * library)
43 {
44 struct inode * inode;
45 unsigned long base;
46
47 if (get_limit(0x17) != TASK_SIZE)
48 return -EINVAL;
49 if (library) {
50 if (!(inode=namei(library)))
51 return -ENOENT;
52 } else
53 inode = NULL;
54
55 iput(current->library);
56 current->library = NULL;
57 base = get_base(current->ldt[2]);
58 base += LIBRARY_OFFSET;
59 free_page_tables(base,LIBRARY_SIZE);
60 current->library = inode;
61 return 0;
62 }
63
64
65
66
67
68
69 static unsigned long * create_tables(char * p,int argc,int envc)
70 {
71 unsigned long *argv,*envp;
72 unsigned long * sp;
73
74 sp = (unsigned long *) (0xfffffffc & (unsigned long) p);
75 sp -= envc+1;
76 envp = sp;
77 sp -= argc+1;
78 argv = sp;
79 put_fs_long((unsigned long)envp,--sp);
80 put_fs_long((unsigned long)argv,--sp);
81 put_fs_long((unsigned long)argc,--sp);
82 while (argc-->0) {
83 put_fs_long((unsigned long) p,argv++);
84 while (get_fs_byte(p++)) ;
85 }
86 put_fs_long(0,argv);
87 while (envc-->0) {
88 put_fs_long((unsigned long) p,envp++);
89 while (get_fs_byte(p++)) ;
90 }
91 put_fs_long(0,envp);
92 return sp;
93 }
94
95
96
97
98 static int count(char ** argv)
99 {
100 int i=0;
101 char ** tmp;
102
103 if (tmp = argv)
104 while (get_fs_long((unsigned long *) (tmp++)))
105 i++;
106
107 return i;
108 }
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127 static unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
128 unsigned long p, int from_kmem)
129 {
130 char *tmp, *pag;
131 int len, offset = 0;
132 unsigned long old_fs, new_fs;
133
134 if (!p)
135 return 0;
136 new_fs = get_ds();
137 old_fs = get_fs();
138 if (from_kmem==2)
139 set_fs(new_fs);
140 while (argc-- > 0) {
141 if (from_kmem == 1)
142 set_fs(new_fs);
143 if (!(tmp = (char *)get_fs_long(((unsigned long *)argv)+argc)))
144 panic("argc is wrong");
145 if (from_kmem == 1)
146 set_fs(old_fs);
147 len=0;
148 do {
149 len++;
150 } while (get_fs_byte(tmp++));
151 if (p < len) {
152 set_fs(old_fs);
153 return 0;
154 }
155 while (len) {
156 --p; --tmp; --len;
157 if (--offset < 0) {
158 offset = p % PAGE_SIZE;
159 if (from_kmem==2)
160 set_fs(old_fs);
161 if (!(pag = (char *) page[p/PAGE_SIZE]) &&
162 !(pag = (char *) page[p/PAGE_SIZE] =
163 (unsigned long *) get_free_page()))
164 return 0;
165 if (from_kmem==2)
166 set_fs(new_fs);
167
168 }
169 *(pag + offset) = get_fs_byte(tmp);
170 }
171 }
172 if (from_kmem==2)
173 set_fs(old_fs);
174 return p;
175 }
176
177 static unsigned long change_ldt(unsigned long text_size,unsigned long * page)
178 {
179 unsigned long code_limit,data_limit,code_base,data_base;
180 int i;
181
182 code_limit = TASK_SIZE;
183 data_limit = TASK_SIZE;
184 code_base = get_base(current->ldt[1]);
185 data_base = code_base;
186 set_base(current->ldt[1],code_base);
187 set_limit(current->ldt[1],code_limit);
188 set_base(current->ldt[2],data_base);
189 set_limit(current->ldt[2],data_limit);
190
191 __asm__("pushl $0x17\n\tpop %%fs"::);
192 data_base += data_limit - LIBRARY_SIZE;
193 for (i=MAX_ARG_PAGES-1 ; i>=0 ; i--) {
194 data_base -= PAGE_SIZE;
195 if (page[i])
196 put_dirty_page(page[i],data_base);
197 }
198 return data_limit;
199 }
200
201
202
203
204
205
206
207 int do_execve(unsigned long * eip,long tmp,char * filename,
208 char ** argv, char ** envp)
209 {
210 struct inode * inode;
211 struct buffer_head * bh;
212 struct exec ex;
213 unsigned long page[MAX_ARG_PAGES];
214 int i,argc,envc;
215 int e_uid, e_gid;
216 int retval;
217 int sh_bang = 0;
218 unsigned long p=PAGE_SIZE*MAX_ARG_PAGES-4;
219 int ch;
220
221 if ((0xffff & eip[1]) != 0x000f)
222 panic("execve called from supervisor mode");
223 for (i=0 ; i<MAX_ARG_PAGES ; i++)
224 page[i]=0;
225 if (!(inode=namei(filename)))
226 return -ENOENT;
227 argc = count(argv);
228 envc = count(envp);
229
230 restart_interp:
231 if (!S_ISREG(inode->i_mode)) {
232 retval = -EACCES;
233 goto exec_error2;
234 }
235 i = inode->i_mode;
236
237 if (current->flags & PF_PTRACED) {
238 e_uid = current->euid;
239 e_gid = current->egid;
240 } else {
241 e_uid = (i & S_ISUID) ? inode->i_uid : current->euid;
242 e_gid = (i & S_ISGID) ? inode->i_gid : current->egid;
243 }
244 if (current->euid == inode->i_uid)
245 i >>= 6;
246 else if (in_group_p(inode->i_gid))
247 i >>= 3;
248 if (!(i & 1) &&
249 !((inode->i_mode & 0111) && suser())) {
250 retval = -EACCES;
251 goto exec_error2;
252 }
253 if (!(bh = bread(inode->i_dev,inode->i_data[0]))) {
254 retval = -EACCES;
255 goto exec_error2;
256 }
257 ex = *((struct exec *) bh->b_data);
258 if ((bh->b_data[0] == '#') && (bh->b_data[1] == '!') && (!sh_bang)) {
259
260
261
262
263
264 char buf[128], *cp, *interp, *i_name, *i_arg;
265 unsigned long old_fs;
266
267 strncpy(buf, bh->b_data+2, 127);
268 brelse(bh);
269 iput(inode);
270 buf[127] = '\0';
271 if (cp = strchr(buf, '\n')) {
272 *cp = '\0';
273 for (cp = buf; (*cp == ' ') || (*cp == '\t'); cp++);
274 }
275 if (!cp || *cp == '\0') {
276 retval = -ENOEXEC;
277 goto exec_error1;
278 }
279 interp = i_name = cp;
280 i_arg = 0;
281 for ( ; *cp && (*cp != ' ') && (*cp != '\t'); cp++) {
282 if (*cp == '/')
283 i_name = cp+1;
284 }
285 if (*cp) {
286 *cp++ = '\0';
287 i_arg = cp;
288 }
289
290
291
292
293 if (sh_bang++ == 0) {
294 p = copy_strings(envc, envp, page, p, 0);
295 p = copy_strings(--argc, argv+1, page, p, 0);
296 }
297
298
299
300
301
302
303
304
305 p = copy_strings(1, &filename, page, p, 1);
306 argc++;
307 if (i_arg) {
308 p = copy_strings(1, &i_arg, page, p, 2);
309 argc++;
310 }
311 p = copy_strings(1, &i_name, page, p, 2);
312 argc++;
313 if (!p) {
314 retval = -ENOMEM;
315 goto exec_error1;
316 }
317
318
319
320 old_fs = get_fs();
321 set_fs(get_ds());
322 if (!(inode=namei(interp))) {
323 set_fs(old_fs);
324 retval = -ENOENT;
325 goto exec_error1;
326 }
327 set_fs(old_fs);
328 goto restart_interp;
329 }
330 brelse(bh);
331 if (N_MAGIC(ex) != ZMAGIC || ex.a_trsize || ex.a_drsize ||
332 ex.a_text+ex.a_data+ex.a_bss>0x3000000 ||
333 inode->i_size < ex.a_text+ex.a_data+ex.a_syms+N_TXTOFF(ex)) {
334 retval = -ENOEXEC;
335 goto exec_error2;
336 }
337 if (N_TXTOFF(ex) != BLOCK_SIZE) {
338 printk("%s: N_TXTOFF != BLOCK_SIZE. See a.out.h.", filename);
339 retval = -ENOEXEC;
340 goto exec_error2;
341 }
342 if (!sh_bang) {
343 p = copy_strings(envc,envp,page,p,0);
344 p = copy_strings(argc,argv,page,p,0);
345 if (!p) {
346 retval = -ENOMEM;
347 goto exec_error2;
348 }
349 }
350
351
352 for (i=0; (ch = get_fs_byte(filename++)) != '\0';)
353 if (ch == '/')
354 i = 0;
355 else
356 if (i < 8)
357 current->comm[i++] = ch;
358 if (i < 8)
359 current->comm[i] = '\0';
360
361 if (current->executable)
362 iput(current->executable);
363 current->executable = inode;
364 current->signal = 0;
365 for (i=0 ; i<32 ; i++) {
366 current->sigaction[i].sa_mask = 0;
367 current->sigaction[i].sa_flags = 0;
368 if (current->sigaction[i].sa_handler != SIG_IGN)
369 current->sigaction[i].sa_handler = NULL;
370 }
371 for (i=0 ; i<NR_OPEN ; i++)
372 if ((current->close_on_exec>>i)&1)
373 sys_close(i);
374 current->close_on_exec = 0;
375 free_page_tables(get_base(current->ldt[1]),get_limit(0x0f));
376 free_page_tables(get_base(current->ldt[2]),get_limit(0x17));
377 if (last_task_used_math == current)
378 last_task_used_math = NULL;
379 current->used_math = 0;
380 p += change_ldt(ex.a_text,page);
381 p -= LIBRARY_SIZE + MAX_ARG_PAGES*PAGE_SIZE;
382 p = (unsigned long) create_tables((char *)p,argc,envc);
383 current->brk = ex.a_bss +
384 (current->end_data = ex.a_data +
385 (current->end_code = ex.a_text));
386 current->start_stack = p;
387 current->rss = (LIBRARY_OFFSET - p + PAGE_SIZE-1) / PAGE_SIZE;
388 current->suid = current->euid = e_uid;
389 current->sgid = current->egid = e_gid;
390 eip[0] = ex.a_entry;
391 eip[3] = p;
392 if (current->flags & PF_PTRACED)
393 send_sig(SIGTRAP, current, 0);
394 return 0;
395 exec_error2:
396 iput(inode);
397 exec_error1:
398 for (i=0 ; i<MAX_ARG_PAGES ; i++)
399 free_page(page[i]);
400 return(retval);
401 }