📄 exec.c
字号:
return -ENOMEM; printk("exec mmap count >1 new %p old %p\n", mm, current->mm); *mm = *current->mm; init_new_context(mm); mm->def_flags = 0; /* should future lockings be kept? */ mm->count = 1; mm->mmap = NULL; mm->mmap_avl = NULL; mm->total_vm = 0; mm->rss = 0; old_mm = current->mm; current->mm = mm; if (new_page_tables(current)) { current->mm = old_mm; exit_mmap(mm); destroy_context(mm); kfree(mm); return -ENOMEM; } if ((old_mm != &init_mm) && (!--old_mm->count)) { /* * all threads exited while we were sleeping, 'old_mm' is held * by us exclusively, lets get rid of it: */ exit_mmap(old_mm); free_page_tables(old_mm); destroy_context(old_mm); kfree(old_mm); } /* since we have switched to a new mm now, we need to make sure * it gets a new mmu context as well. init_new_context just marks * it as NO_CONTEXT (since we dont allocate contexts until the * processes actually are scheduled). */ get_mmu_context(current); return 0; } flush_cache_mm(current->mm); exit_mmap(current->mm); clear_page_tables(current); flush_tlb_mm(current->mm); return 0;}#else /* NO_MM */static int exec_mmap(void){ /* * The clear_page_tables done later on exec does the right thing * to the page directory when shared, except for graceful abort */#ifdef CONFIG_SHARE_SHLIB_CORE shlibmod_exit(¤t->shlib_deps);#endif if (current->mm->count > 1) { struct mm_struct *old_mm, *mm = kmalloc(sizeof(*mm), GFP_KERNEL); if (!mm) return -ENOMEM; *mm = *current->mm; mm->def_flags = 0; /* should future lockings be kept? */ mm->count = 1; mm->total_vm = 0; mm->rss = 0; old_mm = current->mm; current->mm = mm; if (new_page_tables(current)) { current->mm = old_mm; exit_mmap(mm); kfree(mm); return -ENOMEM; } if ((old_mm != &init_mm) && (!--old_mm->count)) { /* * all threads exited while we were sleeping, 'old_mm' is held * by us exclusively, lets get rid of it: */ exit_mmap(old_mm); free_page_tables(old_mm); kfree(old_mm); } return 0; } exit_mmap(current->mm); clear_page_tables(current); return 0;}#endif /* NO_MM *//* * These functions flushes out all traces of the currently running executable * so that a new one can be started */static inline void flush_old_signals(struct signal_struct *sig){ int i; struct sigaction * sa = sig->action; for (i=32 ; i != 0 ; i--) { sa->sa_mask = 0; sa->sa_flags = 0; if (sa->sa_handler != SIG_IGN) sa->sa_handler = NULL; sa++; }}static inline void flush_old_files(struct files_struct * files){ unsigned long j; j = 0; for (;;) { unsigned long set, i; i = j * __NFDBITS; if (i >= NR_OPEN) break; set = files->close_on_exec.fds_bits[j]; files->close_on_exec.fds_bits[j] = 0; j++; for ( ; set ; i++,set >>= 1) { if (set & 1) sys_close(i); } }}int flush_old_exec(struct linux_binprm * bprm){ int i; int ch; char * name; if (current->euid == current->uid && current->egid == current->gid) 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'; /* Release all of the old mmap stuff. */ if (exec_mmap()) return -ENOMEM; flush_thread(); if (bprm->e_uid != current->euid || bprm->e_gid != current->egid || permission(bprm->inode,MAY_READ)) current->dumpable = 0; flush_old_signals(current->sig); flush_old_files(current->files); return 0;}/* * Fill the binprm structure from the inode. * Check permissions, then read the first 512 bytes */int prepare_binprm(struct linux_binprm *bprm){ int mode; int retval,id_change; mode = bprm->inode->i_mode; if (!S_ISREG(mode)) /* must be regular file */ return -EACCES; if (!(mode & 0111)) /* with at least _one_ execute bit set */ return -EACCES; if (IS_NOEXEC(bprm->inode)) /* FS mustn't be mounted noexec */ return -EACCES; if (!bprm->inode->i_sb) return -EACCES; if ((retval = permission(bprm->inode, MAY_EXEC)) != 0) return retval; /* better not execute files which are being written to */ if (bprm->inode->i_writecount > 0) return -ETXTBSY; bprm->e_uid = current->euid; bprm->e_gid = current->egid; id_change = 0; /* Set-uid? */ if (mode & S_ISUID) { bprm->e_uid = bprm->inode->i_uid; if (bprm->e_uid != current->euid) id_change = 1; } /* Set-gid? */ /* * If setgid is set but no group execute bit then this * is a candidate for mandatory locking, not a setgid * executable. */ if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { bprm->e_gid = bprm->inode->i_gid; if (!in_group_p(bprm->e_gid)) id_change = 1; } if (id_change) { /* We can't suid-execute if we're sharing parts of the executable */ /* or if we're being traced (or if suid execs are not allowed) */ /* (current->mm->count > 1 is ok, as we'll get a new mm anyway) */ if (IS_NOSUID(bprm->inode) || (current->flags & PF_PTRACED) || (current->fs->count > 1) || (current->sig->count > 1) || (current->files->count > 1)) { if (!suser()) return -EPERM; } } memset(bprm->buf,0,sizeof(bprm->buf)); return read_exec(bprm->inode,0,bprm->buf,128,1);}#ifndef NO_MMvoid remove_arg_zero(struct linux_binprm *bprm){ if (bprm->argc) { unsigned long offset; char * page; offset = bprm->p % PAGE_SIZE; page = (char*)bprm->page[bprm->p/PAGE_SIZE]; while(bprm->p++,*(page+offset++)) if(offset==PAGE_SIZE){ offset=0; page = (char*)bprm->page[bprm->p/PAGE_SIZE]; } bprm->argc--; }}#endif/* * cycle the list of binary formats handler, until one recognizes the image */int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs){ int try,retval=0; struct linux_binfmt *fmt;#ifdef __alpha__ /* handle /sbin/loader.. */ { struct exec * eh = (struct exec *) bprm->buf; if (!bprm->loader && eh->fh.f_magic == 0x183 && (eh->fh.f_flags & 0x3000) == 0x3000) { char * dynloader[] = { "/sbin/loader" }; iput(bprm->inode); bprm->dont_iput = 1; remove_arg_zero(bprm); bprm->p = copy_strings(1, dynloader, bprm->page, bprm->p, 2); bprm->argc++; bprm->loader = bprm->p; retval = open_namei(dynloader[0], 0, 0, &bprm->inode, NULL); if (retval) return retval; bprm->dont_iput = 0; retval = prepare_binprm(bprm); if (retval<0) return retval; /* should call search_binary_handler recursively here, but it does not matter */ } }#endif for (try=0; try<2; try++) { for (fmt = formats ; fmt ; fmt = fmt->next) { int (*fn)(struct linux_binprm *, struct pt_regs *) = fmt->load_binary; if (!fn) continue; retval = fn(bprm, regs); if (retval >= 0) { if(!bprm->dont_iput) iput(bprm->inode); bprm->dont_iput=1; current->did_exec = 1; return retval; } if (retval != -ENOEXEC) break; if (bprm->dont_iput) /* We don't have the inode anymore*/ return retval; } if (retval != -ENOEXEC) { break;#ifdef CONFIG_KERNELD }else{#define printable(c) (((c)=='\t') || ((c)=='\n') || (0x20<=(c) && (c)<=0x7e)) char modname[20]; if (printable(bprm->buf[0]) && printable(bprm->buf[1]) && printable(bprm->buf[2]) && printable(bprm->buf[3])) break; /* -ENOEXEC */ sprintf(modname, "binfmt-%hd", *(short*)(&bprm->buf)); request_module(modname);#endif } } return retval;}/* * sys_execve() executes a new program. */int do_execve(char * filename, char ** argv, char ** envp, struct pt_regs * regs){ struct linux_binprm bprm; int retval;#ifndef NO_MM int i;#endif #ifdef DEBUG printk("dp_execve invoked with filename '%s', argv: %x, envp: %x\n", filename, (unsigned long)argv, (unsigned long)envp);#endif#ifndef NO_MM bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *); for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */ bprm.page[i] = 0;#endif retval = open_namei(filename, 0, 0, &bprm.inode, NULL); if (retval) return retval; bprm.filename = filename; bprm.sh_bang = 0; bprm.loader = 0; bprm.exec = 0; bprm.dont_iput = 0; if ((bprm.argc = count(argv)) < 0) return bprm.argc; if ((bprm.envc = count(envp)) < 0) return bprm.envc; retval = prepare_binprm(&bprm); #ifndef NO_MM if(retval>=0) { bprm.p = copy_strings(1, &bprm.filename, bprm.page, bprm.p, 2); bprm.exec = bprm.p; 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; }#else bprm.envp = envp; bprm.argv = argv;#endif if(retval>=0) retval = search_binary_handler(&bprm,regs); if(retval>=0) {#ifdef NO_MM /* If the parent to this process did a vfork, we need to wake it up because it's supposed to sleep until the child does an exec. */ wake_up(¤t->vforkwait);#endif /* execve success */ return retval; } /* Something went wrong, return the inode and free the argument pages*/ if(!bprm.dont_iput) iput(bprm.inode); #ifndef NO_MM for (i=0 ; i<MAX_ARG_PAGES ; i++) free_page(bprm.page[i]);#endif return(retval);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -