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