This source file includes following definitions.
- core_dump
- 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 <linux/fs.h>
21 #include <linux/sched.h>
22 #include <linux/kernel.h>
23 #include <linux/mm.h>
24 #include <linux/a.out.h>
25 #include <linux/errno.h>
26 #include <linux/signal.h>
27 #include <linux/string.h>
28 #include <linux/stat.h>
29 #include <linux/fcntl.h>
30 #include <linux/ptrace.h>
31 #include <linux/user.h>
32
33 #include <asm/segment.h>
34
35 extern int sys_exit(int exit_code);
36 extern int sys_close(int fd);
37
38
39
40
41
42
43 #define MAX_ARG_PAGES 32
44
45
46
47
48
49 #define DUMP_WRITE(addr,nr) \
50 while (file.f_op->write(inode,&file,(char *)(addr),(nr)) != (nr)) goto close_coredump
51
52 #define DUMP_SEEK(offset) \
53 if (file.f_op->lseek) { \
54 if (file.f_op->lseek(inode,&file,(offset),0) != (offset)) \
55 goto close_coredump; \
56 } else file.f_pos = (offset)
57
58
59
60
61
62
63
64
65
66
67 int core_dump(long signr, struct pt_regs * regs)
68 {
69 struct inode * inode = NULL;
70 struct file file;
71 unsigned short fs;
72 int has_dumped = 0;
73 register int dump_start, dump_size;
74 struct user dump;
75
76 if (!current->dumpable)
77 return 0;
78 current->dumpable = 0;
79
80 if(current->rlim[RLIMIT_CORE].rlim_cur < PAGE_SIZE/1024) return 0;
81 __asm__("mov %%fs,%0":"=r" (fs));
82 __asm__("mov %0,%%fs"::"r" ((unsigned short) 0x10));
83 if (open_namei("core",O_CREAT | O_WRONLY | O_TRUNC,0600,&inode))
84 goto end_coredump;
85 if (!S_ISREG(inode->i_mode))
86 goto end_coredump;
87 if (!inode->i_op || !inode->i_op->default_file_ops)
88 goto end_coredump;
89 file.f_mode = 3;
90 file.f_flags = 0;
91 file.f_count = 1;
92 file.f_inode = inode;
93 file.f_pos = 0;
94 file.f_reada = 0;
95 file.f_op = inode->i_op->default_file_ops;
96 if (file.f_op->open)
97 if (file.f_op->open(inode,&file))
98 goto end_coredump;
99 if (!file.f_op->write)
100 goto close_coredump;
101 has_dumped = 1;
102
103 __asm__("mov %0,%%fs"::"r" ((unsigned short) 0x10));
104 dump.magic = CMAGIC;
105 dump.u_tsize = current->end_code / PAGE_SIZE;
106 dump.u_dsize = (current->brk - current->end_code) / PAGE_SIZE;
107 dump.u_ssize =((current->start_stack +(PAGE_SIZE-1)) / PAGE_SIZE) -
108 (regs->esp/ PAGE_SIZE);
109
110
111 if ((dump.u_dsize+dump.u_ssize+1) * PAGE_SIZE/1024 >
112 current->rlim[RLIMIT_CORE].rlim_cur)
113 dump.u_dsize = 0;
114
115 if ((dump.u_ssize+1) * PAGE_SIZE / 1024 >
116 current->rlim[RLIMIT_CORE].rlim_cur)
117 dump.u_ssize = 0;
118 dump.u_comm = 0;
119 dump.u_ar0 = (struct pt_regs *)(((int)(&dump.regs)) -((int)(&dump)));
120 dump.signal = signr;
121 dump.regs = *regs;
122 dump.start_code = 0;
123 dump.start_stack = regs->esp & ~(PAGE_SIZE - 1);
124
125 if (dump.u_fpvalid = current->used_math) {
126 if (last_task_used_math == current)
127 __asm__("clts ; fnsave %0"::"m" (dump.i387));
128 else
129 memcpy(&dump.i387,¤t->tss.i387,sizeof(dump.i387));
130 };
131 DUMP_WRITE(&dump,sizeof(dump));
132 DUMP_SEEK(sizeof(dump));
133
134 DUMP_WRITE(current,sizeof(*current));
135
136 DUMP_SEEK(PAGE_SIZE);
137
138 __asm__("mov %0,%%fs"::"r" ((unsigned short) 0x17));
139
140 if (dump.u_dsize != 0) {
141 dump_start = current->end_code;
142 dump_size = current->brk - current->end_code;
143 DUMP_WRITE(dump_start,dump_size);
144 };
145
146 if (dump.u_ssize != 0) {
147 dump_start = regs->esp & ~(PAGE_SIZE - 1);
148 dump_size = dump.u_ssize * PAGE_SIZE;
149 DUMP_WRITE(dump_start,dump_size);
150 };
151 close_coredump:
152 if (file.f_op->release)
153 file.f_op->release(inode,&file);
154 end_coredump:
155 __asm__("mov %0,%%fs"::"r" (fs));
156 iput(inode);
157 return has_dumped;
158 }
159
160
161
162
163
164
165
166 int sys_uselib(const char * library)
167 {
168 #define libnum (current->numlibraries)
169 struct inode * inode;
170 struct buffer_head * bh;
171 struct exec ex;
172
173 if (get_limit(0x17) != TASK_SIZE)
174 return -EINVAL;
175 if ((libnum >= MAX_SHARED_LIBS) || (libnum < 0))
176 return -EINVAL;
177 if (library)
178 inode = namei(library);
179 else
180 inode = NULL;
181 if (!inode)
182 return -ENOENT;
183 if (!inode->i_sb || !S_ISREG(inode->i_mode) || !permission(inode,MAY_READ)) {
184 iput(inode);
185 return -EACCES;
186 }
187 if (!(bh = bread(inode->i_dev,bmap(inode,0),inode->i_sb->s_blocksize))) {
188 iput(inode);
189 return -EACCES;
190 }
191 if (!IS_RDONLY(inode)) {
192 inode->i_atime = CURRENT_TIME;
193 inode->i_dirt = 1;
194 }
195 ex = *(struct exec *) bh->b_data;
196 brelse(bh);
197 if (N_MAGIC(ex) != ZMAGIC || ex.a_trsize || ex.a_drsize ||
198 ex.a_text+ex.a_data+ex.a_bss>0x3000000 ||
199 inode->i_size < ex.a_text+ex.a_data+ex.a_syms+N_TXTOFF(ex)) {
200 iput(inode);
201 return -ENOEXEC;
202 }
203 current->libraries[libnum].library = inode;
204 current->libraries[libnum].start = ex.a_entry;
205 current->libraries[libnum].length = (ex.a_data+ex.a_text+0xfff) & 0xfffff000;
206 #if 0
207 printk("Loaded library %d at %08x, length %08x\n",
208 libnum,
209 current->libraries[libnum].start,
210 current->libraries[libnum].length);
211 #endif
212 libnum++;
213 return 0;
214 #undef libnum
215 }
216
217
218
219
220
221
222 static unsigned long * create_tables(char * p,int argc,int envc)
223 {
224 unsigned long *argv,*envp;
225 unsigned long * sp;
226
227 sp = (unsigned long *) (0xfffffffc & (unsigned long) p);
228 sp -= envc+1;
229 envp = sp;
230 sp -= argc+1;
231 argv = sp;
232 put_fs_long((unsigned long)envp,--sp);
233 put_fs_long((unsigned long)argv,--sp);
234 put_fs_long((unsigned long)argc,--sp);
235 while (argc-->0) {
236 put_fs_long((unsigned long) p,argv++);
237 while (get_fs_byte(p++)) ;
238 }
239 put_fs_long(0,argv);
240 while (envc-->0) {
241 put_fs_long((unsigned long) p,envp++);
242 while (get_fs_byte(p++)) ;
243 }
244 put_fs_long(0,envp);
245 return sp;
246 }
247
248
249
250
251 static int count(char ** argv)
252 {
253 int i=0;
254 char ** tmp;
255
256 if (tmp = argv)
257 while (get_fs_long((unsigned long *) (tmp++)))
258 i++;
259
260 return i;
261 }
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280 static unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
281 unsigned long p, int from_kmem)
282 {
283 char *tmp, *pag = NULL;
284 int len, offset = 0;
285 unsigned long old_fs, new_fs;
286
287 if (!p)
288 return 0;
289 new_fs = get_ds();
290 old_fs = get_fs();
291 if (from_kmem==2)
292 set_fs(new_fs);
293 while (argc-- > 0) {
294 if (from_kmem == 1)
295 set_fs(new_fs);
296 if (!(tmp = (char *)get_fs_long(((unsigned long *)argv)+argc)))
297 panic("argc is wrong");
298 if (from_kmem == 1)
299 set_fs(old_fs);
300 len=0;
301 do {
302 len++;
303 } while (get_fs_byte(tmp++));
304 if (p < len) {
305 set_fs(old_fs);
306 return 0;
307 }
308 while (len) {
309 --p; --tmp; --len;
310 if (--offset < 0) {
311 offset = p % PAGE_SIZE;
312 if (from_kmem==2)
313 set_fs(old_fs);
314 if (!(pag = (char *) page[p/PAGE_SIZE]) &&
315 !(pag = (char *) page[p/PAGE_SIZE] =
316 (unsigned long *) get_free_page(GFP_USER)))
317 return 0;
318 if (from_kmem==2)
319 set_fs(new_fs);
320
321 }
322 *(pag + offset) = get_fs_byte(tmp);
323 }
324 }
325 if (from_kmem==2)
326 set_fs(old_fs);
327 return p;
328 }
329
330 static unsigned long change_ldt(unsigned long text_size,unsigned long * page)
331 {
332 unsigned long code_limit,data_limit,code_base,data_base;
333 int i;
334
335 code_limit = TASK_SIZE;
336 data_limit = TASK_SIZE;
337 code_base = get_base(current->ldt[1]);
338 data_base = code_base;
339 set_base(current->ldt[1],code_base);
340 set_limit(current->ldt[1],code_limit);
341 set_base(current->ldt[2],data_base);
342 set_limit(current->ldt[2],data_limit);
343
344 __asm__("pushl $0x17\n\tpop %%fs"::);
345 data_base += data_limit - LIBRARY_SIZE;
346 for (i=MAX_ARG_PAGES-1 ; i>=0 ; i--) {
347 data_base -= PAGE_SIZE;
348 if (page[i])
349 put_dirty_page(page[i],data_base);
350 }
351 return data_limit;
352 }
353
354 static void read_omagic(struct inode *inode, int bytes)
355 {
356 struct buffer_head *bh;
357 int n, blkno, blk = 0;
358 char *dest = (char *) 0;
359 unsigned int block_size;
360
361 block_size = 1024;
362 if (inode->i_sb)
363 block_size = inode->i_sb->s_blocksize;
364 while (bytes > 0) {
365 if (!(blkno = bmap(inode, blk)))
366 sys_exit(-1);
367 if (!(bh = bread(inode->i_dev, blkno, block_size)))
368 sys_exit(-1);
369 n = (blk ? block_size : block_size - sizeof(struct exec));
370 if (bytes < n)
371 n = bytes;
372
373 memcpy_tofs(dest, (blk ? bh->b_data :
374 bh->b_data + sizeof(struct exec)), n);
375 brelse(bh);
376 ++blk;
377 dest += n;
378 bytes -= n;
379 }
380 iput(inode);
381 current->executable = NULL;
382 }
383
384
385
386
387
388
389
390 int do_execve(unsigned long * eip,long tmp,char * filename,
391 char ** argv, char ** envp)
392 {
393 struct inode * inode;
394 struct buffer_head * bh;
395 struct exec ex;
396 unsigned long page[MAX_ARG_PAGES];
397 int i,argc,envc;
398 int e_uid, e_gid;
399 int retval;
400 int sh_bang = 0;
401 unsigned long p=PAGE_SIZE*MAX_ARG_PAGES-4;
402 int ch;
403
404 if ((0xffff & eip[1]) != 0x000f)
405 panic("execve called from supervisor mode");
406 for (i=0 ; i<MAX_ARG_PAGES ; i++)
407 page[i]=0;
408 if (!(inode=namei(filename)))
409 return -ENOENT;
410 argc = count(argv);
411 envc = count(envp);
412
413 restart_interp:
414 if (!S_ISREG(inode->i_mode)) {
415 retval = -EACCES;
416 goto exec_error2;
417 }
418 if (IS_NOEXEC(inode)) {
419 retval = -EPERM;
420 goto exec_error2;
421 }
422 if (!inode->i_sb) {
423 retval = -EACCES;
424 goto exec_error2;
425 }
426 i = inode->i_mode;
427 if (IS_NOSUID(inode) && (((i & S_ISUID) && inode->i_uid != current->
428 euid) || ((i & S_ISGID) && inode->i_gid != current->egid)) &&
429 !suser()) {
430 retval = -EPERM;
431 goto exec_error2;
432 }
433
434 if (current->flags & PF_PTRACED) {
435 e_uid = current->euid;
436 e_gid = current->egid;
437 } else {
438 e_uid = (i & S_ISUID) ? inode->i_uid : current->euid;
439 e_gid = (i & S_ISGID) ? inode->i_gid : current->egid;
440 }
441 if (current->euid == inode->i_uid)
442 i >>= 6;
443 else if (in_group_p(inode->i_gid))
444 i >>= 3;
445 if (!(i & 1) &&
446 !((inode->i_mode & 0111) && suser())) {
447 retval = -EACCES;
448 goto exec_error2;
449 }
450 if (!(bh = bread(inode->i_dev,bmap(inode,0),inode->i_sb->s_blocksize))) {
451 retval = -EACCES;
452 goto exec_error2;
453 }
454 if (!IS_RDONLY(inode)) {
455 inode->i_atime = CURRENT_TIME;
456 inode->i_dirt = 1;
457 }
458 ex = *((struct exec *) bh->b_data);
459 if ((bh->b_data[0] == '#') && (bh->b_data[1] == '!') && (!sh_bang)) {
460
461
462
463
464
465 char buf[128], *cp, *interp, *i_name, *i_arg;
466 unsigned long old_fs;
467
468 strncpy(buf, bh->b_data+2, 127);
469 brelse(bh);
470 iput(inode);
471 buf[127] = '\0';
472 if (cp = strchr(buf, '\n')) {
473 *cp = '\0';
474 for (cp = buf; (*cp == ' ') || (*cp == '\t'); cp++);
475 }
476 if (!cp || *cp == '\0') {
477 retval = -ENOEXEC;
478 goto exec_error1;
479 }
480 interp = i_name = cp;
481 i_arg = 0;
482 for ( ; *cp && (*cp != ' ') && (*cp != '\t'); cp++) {
483 if (*cp == '/')
484 i_name = cp+1;
485 }
486 if (*cp) {
487 *cp++ = '\0';
488 i_arg = cp;
489 }
490
491
492
493
494 if (sh_bang++ == 0) {
495 p = copy_strings(envc, envp, page, p, 0);
496 p = copy_strings(--argc, argv+1, page, p, 0);
497 }
498
499
500
501
502
503
504
505
506 p = copy_strings(1, &filename, page, p, 1);
507 argc++;
508 if (i_arg) {
509 p = copy_strings(1, &i_arg, page, p, 2);
510 argc++;
511 }
512 p = copy_strings(1, &i_name, page, p, 2);
513 argc++;
514 if (!p) {
515 retval = -ENOMEM;
516 goto exec_error1;
517 }
518
519
520
521 old_fs = get_fs();
522 set_fs(get_ds());
523 if (!(inode=namei(interp))) {
524 set_fs(old_fs);
525 retval = -ENOENT;
526 goto exec_error1;
527 }
528 set_fs(old_fs);
529 goto restart_interp;
530 }
531 brelse(bh);
532 if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC) ||
533 ex.a_trsize || ex.a_drsize ||
534 ex.a_text+ex.a_data+ex.a_bss>0x3000000 ||
535 inode->i_size < ex.a_text+ex.a_data+ex.a_syms+N_TXTOFF(ex)) {
536 retval = -ENOEXEC;
537 goto exec_error2;
538 }
539 if (N_TXTOFF(ex) != BLOCK_SIZE && N_MAGIC(ex) != OMAGIC) {
540 printk("%s: N_TXTOFF != BLOCK_SIZE. See a.out.h.", filename);
541 retval = -ENOEXEC;
542 goto exec_error2;
543 }
544 if (!sh_bang) {
545 p = copy_strings(envc,envp,page,p,0);
546 p = copy_strings(argc,argv,page,p,0);
547 if (!p) {
548 retval = -ENOMEM;
549 goto exec_error2;
550 }
551 }
552
553 current->dumpable = 1;
554 for (i=0; (ch = get_fs_byte(filename++)) != '\0';)
555 if (ch == '/')
556 i = 0;
557 else
558 if (i < 8)
559 current->comm[i++] = ch;
560 if (i < 8)
561 current->comm[i] = '\0';
562 if (current->executable)
563 iput(current->executable);
564 i = current->numlibraries;
565 while (i-- > 0) {
566 iput(current->libraries[i].library);
567 current->libraries[i].library = NULL;
568 }
569 if (e_uid != current->euid || e_gid != current->egid ||
570 !permission(inode,MAY_READ))
571 current->dumpable = 0;
572 current->numlibraries = 0;
573 current->executable = inode;
574 current->signal = 0;
575 for (i=0 ; i<32 ; i++) {
576 current->sigaction[i].sa_mask = 0;
577 current->sigaction[i].sa_flags = 0;
578 if (current->sigaction[i].sa_handler != SIG_IGN)
579 current->sigaction[i].sa_handler = NULL;
580 }
581 for (i=0 ; i<NR_OPEN ; i++)
582 if ((current->close_on_exec>>i)&1)
583 sys_close(i);
584 current->close_on_exec = 0;
585 free_page_tables(get_base(current->ldt[1]),get_limit(0x0f));
586 free_page_tables(get_base(current->ldt[2]),get_limit(0x17));
587 if (last_task_used_math == current)
588 last_task_used_math = NULL;
589 current->used_math = 0;
590 p += change_ldt(ex.a_text,page);
591 p -= LIBRARY_SIZE + MAX_ARG_PAGES*PAGE_SIZE;
592 p = (unsigned long) create_tables((char *)p,argc,envc);
593 current->brk = ex.a_bss +
594 (current->end_data = ex.a_data +
595 (current->end_code = ex.a_text));
596 current->start_stack = p;
597 current->rss = (LIBRARY_OFFSET - p + PAGE_SIZE-1) / PAGE_SIZE;
598 current->suid = current->euid = e_uid;
599 current->sgid = current->egid = e_gid;
600 if (N_MAGIC(ex) == OMAGIC)
601 read_omagic(inode, ex.a_text+ex.a_data);
602 eip[0] = ex.a_entry;
603 eip[3] = p;
604 if (current->flags & PF_PTRACED)
605 send_sig(SIGTRAP, current, 0);
606 return 0;
607 exec_error2:
608 iput(inode);
609 exec_error1:
610 for (i=0 ; i<MAX_ARG_PAGES ; i++)
611 free_page(page[i]);
612 return(retval);
613 }