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