|
|
1.1.1.2 root 1: /*
2: * linux/fs/exec.c
3: *
1.1.1.10! root 4: * Copyright (C) 1991, 1992 Linus Torvalds
1.1.1.2 root 5: */
6:
1.1.1.3 root 7: /*
8: * #!-checking implemented by tytso.
9: */
10:
11: /*
12: * Demand-loading implemented 01.12.91 - no need to read anything but
13: * the header into memory. The inode of the executable is put into
14: * "current->executable", and page faults do the actual loading. Clean.
15: *
16: * Once more I can proudly say that linux stood up to being changed: it
17: * was less than 2 hours work to get demand-loading completely implemented.
18: */
19:
1.1 root 20: #include <linux/fs.h>
21: #include <linux/sched.h>
22: #include <linux/kernel.h>
23: #include <linux/mm.h>
1.1.1.10! root 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:
1.1 root 33: #include <asm/segment.h>
34:
35: extern int sys_exit(int exit_code);
36: extern int sys_close(int fd);
37:
38: /*
39: * MAX_ARG_PAGES defines the number of pages allocated for arguments
40: * and envelope for the new program. 32 should suffice, this gives
41: * a maximum env+arg of 128kB !
42: */
43: #define MAX_ARG_PAGES 32
44:
1.1.1.7 root 45: /*
1.1.1.8 root 46: * These are the only things you should do on a core-file: use only these
47: * macros to write out all the necessary info.
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: * Routine writes a core dump image in the current directory.
60: * Currently only a stub-function.
61: *
62: * Note that setuid/setgid files won't make a core-dump if the uid/gid
63: * changed due to the set[u|g]id. It's enforced by the "current->dumpable"
64: * field, which also makes sure the core-dumps won't be recursive if the
65: * dumping of the process results in another error..
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: /* See if we have enough room to write the upage. */
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: /* write and seek example: from kernel space */
103: __asm__("mov %0,%%fs"::"r" ((unsigned short) 0x10));
1.1.1.10! root 104: dump.magic = CMAGIC;
1.1.1.8 root 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: /* If the size of the dump file exceeds the rlimit, then see what would happen
110: if we wrote the stack, but not the data area. */
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: /* Make sure we have enough room to write the stack and data areas. */
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: /* Flag indicating the math stuff is valid. */
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: /* Dump the task struct. Not be used by gdb, but could be useful */
134: DUMP_WRITE(current,sizeof(*current));
135: /* Now dump all of the user data. Include malloced stuff as well */
136: DUMP_SEEK(PAGE_SIZE);
137: /* now we start writing out the user space info */
138: __asm__("mov %0,%%fs"::"r" ((unsigned short) 0x17));
139: /* Dump the data area */
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: /* Now prepare to dump the stack area */
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: /*
1.1.1.7 root 161: * Note that a shared library must be both readable and executable due to
162: * security reasons.
163: *
164: * Also note that we take the address to load from from the file itself.
165: */
1.1.1.4 root 166: int sys_uselib(const char * library)
167: {
1.1.1.7 root 168: #define libnum (current->numlibraries)
1.1.1.5 root 169: struct inode * inode;
1.1.1.7 root 170: struct buffer_head * bh;
171: struct exec ex;
1.1.1.4 root 172:
173: if (get_limit(0x17) != TASK_SIZE)
174: return -EINVAL;
1.1.1.7 root 175: if ((libnum >= MAX_SHARED_LIBS) || (libnum < 0))
176: return -EINVAL;
177: if (library)
178: inode = namei(library);
179: else
1.1.1.4 root 180: inode = NULL;
1.1.1.7 root 181: if (!inode)
182: return -ENOENT;
1.1.1.10! root 183: if (!inode->i_sb || !S_ISREG(inode->i_mode) || !permission(inode,MAY_READ)) {
1.1.1.7 root 184: iput(inode);
185: return -EACCES;
186: }
1.1.1.10! root 187: if (!(bh = bread(inode->i_dev,bmap(inode,0),inode->i_sb->s_blocksize))) {
1.1.1.7 root 188: iput(inode);
189: return -EACCES;
190: }
1.1.1.10! root 191: if (!IS_RDONLY(inode)) {
! 192: inode->i_atime = CURRENT_TIME;
! 193: inode->i_dirt = 1;
! 194: }
1.1.1.7 root 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++;
1.1.1.4 root 213: return 0;
1.1.1.7 root 214: #undef libnum
1.1.1.4 root 215: }
216:
1.1 root 217: /*
218: * create_tables() parses the env- and arg-strings in new user
219: * memory and creates the pointer tables from them, and puts their
220: * addresses on the "stack", returning the new stack pointer value.
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++)) /* nothing */ ;
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++)) /* nothing */ ;
243: }
244: put_fs_long(0,envp);
245: return sp;
246: }
247:
248: /*
249: * count() counts the number of arguments/envelopes
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: * 'copy_string()' copies argument/envelope strings from user
265: * memory to free pages in kernel mem. These are in a format ready
266: * to be put directly into the top of new user memory.
1.1.1.2 root 267: *
268: * Modified by TYT, 11/24/91 to add the from_kmem argument, which specifies
269: * whether the string and the string array are from user or kernel segments:
270: *
271: * from_kmem argv * argv **
272: * 0 user space user space
273: * 1 kernel space user space
274: * 2 kernel space kernel space
275: *
276: * We do this by playing games with the fs segment register. Since it
277: * it is expensive to load a segment register, we try to avoid calling
278: * set_fs() unless we absolutely have to.
1.1 root 279: */
280: static unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
1.1.1.2 root 281: unsigned long p, int from_kmem)
1.1 root 282: {
1.1.1.9 root 283: char *tmp, *pag = NULL;
1.1.1.2 root 284: int len, offset = 0;
285: unsigned long old_fs, new_fs;
286:
287: if (!p)
288: return 0; /* bullet-proofing */
289: new_fs = get_ds();
290: old_fs = get_fs();
291: if (from_kmem==2)
292: set_fs(new_fs);
1.1 root 293: while (argc-- > 0) {
1.1.1.2 root 294: if (from_kmem == 1)
295: set_fs(new_fs);
296: if (!(tmp = (char *)get_fs_long(((unsigned long *)argv)+argc)))
1.1 root 297: panic("argc is wrong");
1.1.1.2 root 298: if (from_kmem == 1)
299: set_fs(old_fs);
1.1 root 300: len=0; /* remember zero-padding */
301: do {
302: len++;
303: } while (get_fs_byte(tmp++));
1.1.1.5 root 304: if (p < len) { /* this shouldn't happen - 128kB */
1.1.1.2 root 305: set_fs(old_fs);
1.1 root 306: return 0;
307: }
1.1.1.2 root 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] =
1.1.1.10! root 316: (unsigned long *) get_free_page(GFP_USER)))
1.1.1.2 root 317: return 0;
318: if (from_kmem==2)
319: set_fs(new_fs);
320:
321: }
322: *(pag + offset) = get_fs_byte(tmp);
323: }
1.1 root 324: }
1.1.1.2 root 325: if (from_kmem==2)
326: set_fs(old_fs);
1.1 root 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:
1.1.1.4 root 335: code_limit = TASK_SIZE;
336: data_limit = TASK_SIZE;
1.1 root 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: /* make sure fs points to the NEW data segment */
344: __asm__("pushl $0x17\n\tpop %%fs"::);
1.1.1.4 root 345: data_base += data_limit - LIBRARY_SIZE;
1.1 root 346: for (i=MAX_ARG_PAGES-1 ; i>=0 ; i--) {
347: data_base -= PAGE_SIZE;
348: if (page[i])
1.1.1.4 root 349: put_dirty_page(page[i],data_base);
1.1 root 350: }
351: return data_limit;
352: }
353:
1.1.1.7 root 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;
1.1.1.10! root 359: unsigned int block_size;
1.1.1.7 root 360:
1.1.1.10! root 361: block_size = 1024;
! 362: if (inode->i_sb)
! 363: block_size = inode->i_sb->s_blocksize;
1.1.1.7 root 364: while (bytes > 0) {
365: if (!(blkno = bmap(inode, blk)))
366: sys_exit(-1);
1.1.1.10! root 367: if (!(bh = bread(inode->i_dev, blkno, block_size)))
1.1.1.7 root 368: sys_exit(-1);
1.1.1.10! root 369: n = (blk ? block_size : block_size - sizeof(struct exec));
1.1.1.7 root 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:
1.1 root 384: /*
385: * 'do_execve()' executes a new program.
1.1.1.4 root 386: *
387: * NOTE! We leave 4MB free at the top of the data-area for a loadable
388: * library.
1.1 root 389: */
390: int do_execve(unsigned long * eip,long tmp,char * filename,
391: char ** argv, char ** envp)
392: {
1.1.1.5 root 393: struct inode * inode;
1.1 root 394: struct buffer_head * bh;
395: struct exec ex;
396: unsigned long page[MAX_ARG_PAGES];
397: int i,argc,envc;
1.1.1.2 root 398: int e_uid, e_gid;
399: int retval;
400: int sh_bang = 0;
401: unsigned long p=PAGE_SIZE*MAX_ARG_PAGES-4;
1.1.1.6 root 402: int ch;
1.1 root 403:
404: if ((0xffff & eip[1]) != 0x000f)
405: panic("execve called from supervisor mode");
406: for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */
407: page[i]=0;
408: if (!(inode=namei(filename))) /* get executables inode */
409: return -ENOENT;
1.1.1.2 root 410: argc = count(argv);
411: envc = count(envp);
412:
413: restart_interp:
1.1 root 414: if (!S_ISREG(inode->i_mode)) { /* must be regular file */
1.1.1.2 root 415: retval = -EACCES;
416: goto exec_error2;
1.1 root 417: }
1.1.1.10! root 418: if (IS_NOEXEC(inode)) { /* FS mustn't be mounted noexec */
! 419: retval = -EPERM;
! 420: goto exec_error2;
! 421: }
! 422: if (!inode->i_sb) {
! 423: retval = -EACCES;
! 424: goto exec_error2;
! 425: }
1.1 root 426: i = inode->i_mode;
1.1.1.10! root 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: }
1.1.1.5 root 433: /* make sure we don't let suid, sgid files be ptraced. */
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: }
1.1.1.2 root 441: if (current->euid == inode->i_uid)
442: i >>= 6;
1.1.1.4 root 443: else if (in_group_p(inode->i_gid))
1.1.1.2 root 444: i >>= 3;
445: if (!(i & 1) &&
446: !((inode->i_mode & 0111) && suser())) {
1.1.1.5 root 447: retval = -EACCES;
1.1.1.2 root 448: goto exec_error2;
1.1 root 449: }
1.1.1.10! root 450: if (!(bh = bread(inode->i_dev,bmap(inode,0),inode->i_sb->s_blocksize))) {
1.1.1.2 root 451: retval = -EACCES;
452: goto exec_error2;
1.1 root 453: }
1.1.1.10! root 454: if (!IS_RDONLY(inode)) {
! 455: inode->i_atime = CURRENT_TIME;
! 456: inode->i_dirt = 1;
! 457: }
1.1 root 458: ex = *((struct exec *) bh->b_data); /* read exec-header */
1.1.1.2 root 459: if ((bh->b_data[0] == '#') && (bh->b_data[1] == '!') && (!sh_bang)) {
460: /*
461: * This section does the #! interpretation.
462: * Sorta complicated, but hopefully it will work. -TYT
463: */
464:
1.1.1.4 root 465: char buf[128], *cp, *interp, *i_name, *i_arg;
1.1.1.2 root 466: unsigned long old_fs;
467:
1.1.1.4 root 468: strncpy(buf, bh->b_data+2, 127);
1.1.1.2 root 469: brelse(bh);
470: iput(inode);
1.1.1.4 root 471: buf[127] = '\0';
1.1.1.2 root 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; /* No interpreter name found */
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: * OK, we've parsed out the interpreter name and
492: * (optional) argument.
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: * Splice in (1) the interpreter's name for argv[0]
500: * (2) (optional) argument to interpreter
501: * (3) filename of shell script
502: *
503: * This is done in reverse order, because of how the
504: * user environment and arguments are stored.
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: * OK, now restart the process with the interpreter's inode.
520: */
521: old_fs = get_fs();
522: set_fs(get_ds());
523: if (!(inode=namei(interp))) { /* get executables inode */
524: set_fs(old_fs);
525: retval = -ENOENT;
526: goto exec_error1;
527: }
528: set_fs(old_fs);
529: goto restart_interp;
530: }
1.1 root 531: brelse(bh);
1.1.1.7 root 532: if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC) ||
533: ex.a_trsize || ex.a_drsize ||
1.1 root 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)) {
1.1.1.2 root 536: retval = -ENOEXEC;
537: goto exec_error2;
1.1 root 538: }
1.1.1.7 root 539: if (N_TXTOFF(ex) != BLOCK_SIZE && N_MAGIC(ex) != OMAGIC) {
1.1.1.2 root 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: }
1.1 root 551: }
552: /* OK, This is the point of no return */
1.1.1.8 root 553: current->dumpable = 1;
1.1.1.6 root 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';
1.1.1.3 root 562: if (current->executable)
563: iput(current->executable);
1.1.1.7 root 564: i = current->numlibraries;
565: while (i-- > 0) {
566: iput(current->libraries[i].library);
567: current->libraries[i].library = NULL;
568: }
1.1.1.8 root 569: if (e_uid != current->euid || e_gid != current->egid ||
570: !permission(inode,MAY_READ))
571: current->dumpable = 0;
1.1.1.7 root 572: current->numlibraries = 0;
1.1.1.3 root 573: current->executable = inode;
1.1.1.4 root 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: }
1.1 root 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;
1.1.1.4 root 590: p += change_ldt(ex.a_text,page);
591: p -= LIBRARY_SIZE + MAX_ARG_PAGES*PAGE_SIZE;
1.1 root 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));
1.1.1.5 root 596: current->start_stack = p;
1.1.1.6 root 597: current->rss = (LIBRARY_OFFSET - p + PAGE_SIZE-1) / PAGE_SIZE;
1.1.1.4 root 598: current->suid = current->euid = e_uid;
599: current->sgid = current->egid = e_gid;
1.1.1.7 root 600: if (N_MAGIC(ex) == OMAGIC)
601: read_omagic(inode, ex.a_text+ex.a_data);
1.1 root 602: eip[0] = ex.a_entry; /* eip, magic happens :-) */
603: eip[3] = p; /* stack pointer */
1.1.1.5 root 604: if (current->flags & PF_PTRACED)
1.1.1.8 root 605: send_sig(SIGTRAP, current, 0);
1.1 root 606: return 0;
1.1.1.2 root 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);
1.1 root 613: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.