📄 exec.c
字号:
/* * This function flushes out all traces of the currently running executable so * that a new one can be started */void flush_old_exec(struct linux_binprm * bprm){ int i; int ch; char * name; struct vm_area_struct * mpnt, *mpnt1; current->dumpable = 1; name = bprm->filename; for (i=0; (ch = *(name++)) != '\0';) { if (ch == '/') i = 0; else if (i < 15) current->comm[i++] = ch; } current->comm[i] = '\0'; if (current->shm) shm_exit(); if (current->executable) { iput(current->executable); current->executable = NULL; } /* Release all of the old mmap stuff. */ mpnt = current->mmap; current->mmap = NULL; current->stk_vma = NULL; while (mpnt) { mpnt1 = mpnt->vm_next; if (mpnt->vm_ops && mpnt->vm_ops->close) mpnt->vm_ops->close(mpnt); kfree(mpnt); mpnt = mpnt1; } /* Flush the old ldt stuff... */ if (current->ldt) { free_page((unsigned long) current->ldt); current->ldt = NULL; for (i=1 ; i<NR_TASKS ; i++) { if (task[i] == current) { set_ldt_desc(gdt+(i<<1)+ FIRST_LDT_ENTRY,&default_ldt, 1); load_ldt(i); } } } for (i=0 ; i<8 ; i++) current->debugreg[i] = 0; if (bprm->e_uid != current->euid || bprm->e_gid != current->egid || !permission(bprm->inode,MAY_READ)) current->dumpable = 0; current->signal = 0; for (i=0 ; i<32 ; i++) { current->sigaction[i].sa_mask = 0; current->sigaction[i].sa_flags = 0; if (current->sigaction[i].sa_handler != SIG_IGN) current->sigaction[i].sa_handler = NULL; } for (i=0 ; i<NR_OPEN ; i++) if (FD_ISSET(i,¤t->close_on_exec)) sys_close(i); FD_ZERO(¤t->close_on_exec); clear_page_tables(current); if (last_task_used_math == current) last_task_used_math = NULL; current->used_math = 0; current->elf_executable = 0;}/* * sys_execve() executes a new program. */static int do_execve(char * filename, char ** argv, char ** envp, struct pt_regs * regs){ struct linux_binprm bprm; struct linux_binfmt * fmt; unsigned long old_fs; int i; int retval; int sh_bang = 0; if (regs->cs != USER_CS) return -EINVAL; bprm.p = PAGE_SIZE*MAX_ARG_PAGES-4; for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */ bprm.page[i] = 0; retval = open_namei(filename, 0, 0, &bprm.inode, NULL); if (retval) return retval; bprm.filename = filename; bprm.argc = count(argv); bprm.envc = count(envp); restart_interp: if (!S_ISREG(bprm.inode->i_mode)) { /* must be regular file */ retval = -EACCES; goto exec_error2; } if (IS_NOEXEC(bprm.inode)) { /* FS mustn't be mounted noexec */ retval = -EPERM; goto exec_error2; } if (!bprm.inode->i_sb) { retval = -EACCES; goto exec_error2; } i = bprm.inode->i_mode; if (IS_NOSUID(bprm.inode) && (((i & S_ISUID) && bprm.inode->i_uid != current-> euid) || ((i & S_ISGID) && !in_group_p(bprm.inode->i_gid))) && !suser()) { retval = -EPERM; goto exec_error2; } /* make sure we don't let suid, sgid files be ptraced. */ if (current->flags & PF_PTRACED) { bprm.e_uid = current->euid; bprm.e_gid = current->egid; } else { bprm.e_uid = (i & S_ISUID) ? bprm.inode->i_uid : current->euid; bprm.e_gid = (i & S_ISGID) ? bprm.inode->i_gid : current->egid; } if (current->euid == bprm.inode->i_uid) i >>= 6; else if (in_group_p(bprm.inode->i_gid)) i >>= 3; if (!(i & 1) && !((bprm.inode->i_mode & 0111) && suser())) { retval = -EACCES; goto exec_error2; } memset(bprm.buf,0,sizeof(bprm.buf)); old_fs = get_fs(); set_fs(get_ds()); retval = read_exec(bprm.inode,0,bprm.buf,128); set_fs(old_fs); if (retval < 0) goto exec_error2; if ((bprm.buf[0] == '#') && (bprm.buf[1] == '!') && (!sh_bang)) { /* * This section does the #! interpretation. * Sorta complicated, but hopefully it will work. -TYT */ char *cp, *interp, *i_name, *i_arg; iput(bprm.inode); bprm.buf[127] = '\0'; if ((cp = strchr(bprm.buf, '\n')) == NULL) cp = bprm.buf+127; *cp = '\0'; while (cp > bprm.buf) { cp--; if ((*cp == ' ') || (*cp == '\t')) *cp = '\0'; else break; } for (cp = bprm.buf+2; (*cp == ' ') || (*cp == '\t'); cp++); if (!cp || *cp == '\0') { retval = -ENOEXEC; /* No interpreter name found */ goto exec_error1; } interp = i_name = cp; i_arg = 0; for ( ; *cp && (*cp != ' ') && (*cp != '\t'); cp++) { if (*cp == '/') i_name = cp+1; } while ((*cp == ' ') || (*cp == '\t')) *cp++ = '\0'; if (*cp) i_arg = cp; /* * OK, we've parsed out the interpreter name and * (optional) argument. */ if (sh_bang++ == 0) { bprm.p = copy_strings(bprm.envc, envp, bprm.page, bprm.p, 0); bprm.p = copy_strings(--bprm.argc, argv+1, bprm.page, bprm.p, 0); } /* * Splice in (1) the interpreter's name for argv[0] * (2) (optional) argument to interpreter * (3) filename of shell script * * This is done in reverse order, because of how the * user environment and arguments are stored. */ bprm.p = copy_strings(1, &bprm.filename, bprm.page, bprm.p, 2); bprm.argc++; if (i_arg) { bprm.p = copy_strings(1, &i_arg, bprm.page, bprm.p, 2); bprm.argc++; } bprm.p = copy_strings(1, &i_name, bprm.page, bprm.p, 2); bprm.argc++; if (!bprm.p) { retval = -E2BIG; goto exec_error1; } /* * OK, now restart the process with the interpreter's inode. * Note that we use open_namei() as the name is now in kernel * space, and we don't need to copy it. */ retval = open_namei(interp, 0, 0, &bprm.inode, NULL); if (retval) goto exec_error1; goto restart_interp; } if (!sh_bang) { bprm.p = copy_strings(bprm.envc,envp,bprm.page,bprm.p,0); bprm.p = copy_strings(bprm.argc,argv,bprm.page,bprm.p,0); if (!bprm.p) { retval = -E2BIG; goto exec_error2; } } bprm.sh_bang = sh_bang; fmt = formats; do { int (*fn)(struct linux_binprm *, struct pt_regs *) = fmt->load_binary; if (!fn) break; retval = fn(&bprm, regs); if (retval == 0) { iput(bprm.inode); current->did_exec = 1; return 0; } fmt++; } while (retval == -ENOEXEC);exec_error2: iput(bprm.inode);exec_error1: for (i=0 ; i<MAX_ARG_PAGES ; i++) free_page(bprm.page[i]); return(retval);}/* * sys_execve() executes a new program. */asmlinkage int sys_execve(struct pt_regs regs){ int error; char * filename; error = getname((char *) regs.ebx, &filename); if (error) return error; error = do_execve(filename, (char **) regs.ecx, (char **) regs.edx, ®s); putname(filename); return error;}/* * These are the prototypes for the functions in the dispatch table, as * well as the dispatch table itself. */extern int load_aout_binary(struct linux_binprm *, struct pt_regs * regs);extern int load_aout_library(int fd);#ifdef CONFIG_BINFMT_ELFextern int load_elf_binary(struct linux_binprm *, struct pt_regs * regs);extern int load_elf_library(int fd);#endif#ifdef CONFIG_BINFMT_COFFextern int load_coff_binary(struct linux_binprm *, struct pt_regs * regs);extern int load_coff_library(int fd);#endif/* Here are the actual binaries that will be accepted */struct linux_binfmt formats[] = { {load_aout_binary, load_aout_library},#ifdef CONFIG_BINFMT_ELF {load_elf_binary, load_elf_library},#endif#ifdef CONFIG_BINFMT_COFF {load_coff_binary, load_coff_library},#endif {NULL, NULL}};/* * These are the functions used to load a.out style executables and shared * libraries. There is no binary dependent code anywhere else. */int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs){ struct exec ex; struct file * file; int fd, error; unsigned long p = bprm->p; ex = *((struct exec *) bprm->buf); /* exec-header */ if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC && N_MAGIC(ex) != QMAGIC) || ex.a_trsize || ex.a_drsize || bprm->inode->i_size < ex.a_text+ex.a_data+ex.a_syms+N_TXTOFF(ex)) { return -ENOEXEC; } if (N_MAGIC(ex) == ZMAGIC && (N_TXTOFF(ex) < bprm->inode->i_sb->s_blocksize)) { printk("N_TXTOFF < BLOCK_SIZE. Please convert binary."); return -ENOEXEC; } if (N_TXTOFF(ex) != BLOCK_SIZE && N_MAGIC(ex) == ZMAGIC) { printk("N_TXTOFF != BLOCK_SIZE. See a.out.h."); return -ENOEXEC; } /* OK, This is the point of no return */ flush_old_exec(bprm); current->end_code = N_TXTADDR(ex) + ex.a_text; current->end_data = ex.a_data + current->end_code; current->start_brk = current->brk = current->end_data; current->start_code += N_TXTADDR(ex); current->rss = 0; current->suid = current->euid = bprm->e_uid; current->mmap = NULL; current->executable = NULL; /* for OMAGIC files */ current->sgid = current->egid = bprm->e_gid; if (N_MAGIC(ex) == OMAGIC) { do_mmap(NULL, 0, ex.a_text+ex.a_data, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_FIXED|MAP_PRIVATE, 0); read_exec(bprm->inode, 32, (char *) 0, ex.a_text+ex.a_data); } else { if (ex.a_text & 0xfff || ex.a_data & 0xfff) printk("%s: executable not page aligned\n", current->comm); fd = open_inode(bprm->inode, O_RDONLY); if (fd < 0) return fd; file = current->filp[fd]; if (!file->f_op || !file->f_op->mmap) { sys_close(fd); do_mmap(NULL, 0, ex.a_text+ex.a_data, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_FIXED|MAP_PRIVATE, 0); read_exec(bprm->inode, N_TXTOFF(ex), (char *) N_TXTADDR(ex), ex.a_text+ex.a_data); goto beyond_if; } error = do_mmap(file, N_TXTADDR(ex), ex.a_text, PROT_READ | PROT_EXEC, MAP_FIXED | MAP_SHARED, N_TXTOFF(ex)); if (error != N_TXTADDR(ex)) { sys_close(fd); send_sig(SIGSEGV, current, 0); return 0; }; error = do_mmap(file, N_TXTADDR(ex) + ex.a_text, ex.a_data, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE, N_TXTOFF(ex) + ex.a_text); sys_close(fd); if (error != N_TXTADDR(ex) + ex.a_text) { send_sig(SIGSEGV, current, 0); return 0; }; current->executable = bprm->inode; bprm->inode->i_count++; }beyond_if: sys_brk(current->brk+ex.a_bss); p += change_ldt(ex.a_text,bprm->page); p -= MAX_ARG_PAGES*PAGE_SIZE; p = (unsigned long) create_tables((char *)p,bprm->argc,bprm->envc,0); current->start_stack = p; regs->eip = ex.a_entry; /* eip, magic happens :-) */ regs->esp = p; /* stack pointer */ if (current->flags & PF_PTRACED) send_sig(SIGTRAP, current, 0); return 0;}int load_aout_library(int fd){ struct file * file; struct exec ex; struct inode * inode; unsigned int len; unsigned int bss; unsigned int start_addr; int error; file = current->filp[fd]; inode = file->f_inode; set_fs(KERNEL_DS); if (file->f_op->read(inode, file, (char *) &ex, sizeof(ex)) != sizeof(ex)) { return -EACCES; } set_fs(USER_DS); /* We come in here for the regular a.out style of shared libraries */ if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != QMAGIC) || ex.a_trsize || ex.a_drsize || ((ex.a_entry & 0xfff) && N_MAGIC(ex) == ZMAGIC) || inode->i_size < ex.a_text+ex.a_data+ex.a_syms+N_TXTOFF(ex)) { return -ENOEXEC; } if (N_MAGIC(ex) == ZMAGIC && N_TXTOFF(ex) && (N_TXTOFF(ex) < inode->i_sb->s_blocksize)) { printk("N_TXTOFF < BLOCK_SIZE. Please convert library\n"); return -ENOEXEC; } if (N_FLAGS(ex)) return -ENOEXEC; /* For QMAGIC, the starting address is 0x20 into the page. We mask this off to get the starting address for the page */ start_addr = ex.a_entry & 0xfffff000; /* Now use mmap to map the library into memory. */ error = do_mmap(file, start_addr, ex.a_text + ex.a_data, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE, N_TXTOFF(ex)); if (error != start_addr) return error; len = PAGE_ALIGN(ex.a_text + ex.a_data); bss = ex.a_text + ex.a_data + ex.a_bss; if (bss > len) do_mmap(NULL, start_addr + len, bss-len, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_FIXED, 0); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -