📄 exec.c
字号:
break; set = files->close_on_exec->fds_bits[j]; if (!set) continue; files->close_on_exec->fds_bits[j] = 0; write_unlock(&files->file_lock); for ( ; set ; i++,set >>= 1) { if (set & 1) { sys_close(i); } } write_lock(&files->file_lock); } write_unlock(&files->file_lock);}/* * An execve() will automatically "de-thread" the process. * Note: we don't have to hold the tasklist_lock to test * whether we migth need to do this. If we're not part of * a thread group, there is no way we can become one * dynamically. And if we are, we only need to protect the * unlink - even if we race with the last other thread exit, * at worst the list_del_init() might end up being a no-op. */static inline void de_thread(struct task_struct *tsk){ if (!list_empty(&tsk->thread_group)) { write_lock_irq(&tasklist_lock); list_del_init(&tsk->thread_group); write_unlock_irq(&tasklist_lock); } /* Minor oddity: this might stay the same. */ tsk->tgid = tsk->pid;}int flush_old_exec(struct linux_binprm * bprm){ char * name; int i, ch, retval; struct signal_struct * oldsig; /* * Make sure we have a private signal table */ oldsig = current->sig; retval = make_private_signals(); if (retval) goto flush_failed; /* * Release all of the old mmap stuff */ retval = exec_mmap(); if (retval) goto mmap_failed; /* This is the point of no return */ release_old_signals(oldsig); current->sas_ss_sp = current->sas_ss_size = 0; if (current->euid == current->uid && current->egid == current->gid) current->mm->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'; flush_thread(); de_thread(current); if (bprm->e_uid != current->euid || bprm->e_gid != current->egid || permission(bprm->file->f_dentry->d_inode,MAY_READ)) current->mm->dumpable = 0; /* An exec changes our domain. We are no longer part of the thread group */ current->self_exec_id++; flush_signal_handlers(current); flush_old_files(current->files); return 0;mmap_failed:flush_failed: spin_lock_irq(¤t->sigmask_lock); if (current->sig != oldsig) { kmem_cache_free(sigact_cachep, current->sig); current->sig = oldsig; } spin_unlock_irq(¤t->sigmask_lock); return retval;}/* * We mustn't allow tracing of suid binaries, unless * the tracer has the capability to trace anything.. */static inline int must_not_trace_exec(struct task_struct * p){ return (p->ptrace & PT_PTRACED) && !(p->ptrace & PT_PTRACE_CAP);}/* * Fill the binprm structure from the inode. * Check permissions, then read the first 128 (BINPRM_BUF_SIZE) bytes */int prepare_binprm(struct linux_binprm *bprm){ int mode; struct inode * inode = bprm->file->f_dentry->d_inode; mode = inode->i_mode; /* * Check execute perms again - if the caller has CAP_DAC_OVERRIDE, * vfs_permission lets a non-executable through */ if (!(mode & 0111)) /* with at least _one_ execute bit set */ return -EACCES; if (bprm->file->f_op == NULL) return -EACCES; bprm->e_uid = current->euid; bprm->e_gid = current->egid; if(!(bprm->file->f_vfsmnt->mnt_flags & MNT_NOSUID)) { /* Set-uid? */ if (mode & S_ISUID) bprm->e_uid = inode->i_uid; /* 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 = inode->i_gid; } /* We don't have VFS support for capabilities yet */ cap_clear(bprm->cap_inheritable); cap_clear(bprm->cap_permitted); cap_clear(bprm->cap_effective); /* To support inheritance of root-permissions and suid-root * executables under compatibility mode, we raise all three * capability sets for the file. * * If only the real uid is 0, we only raise the inheritable * and permitted sets of the executable file. */ if (!issecure(SECURE_NOROOT)) { if (bprm->e_uid == 0 || current->uid == 0) { cap_set_full(bprm->cap_inheritable); cap_set_full(bprm->cap_permitted); } if (bprm->e_uid == 0) cap_set_full(bprm->cap_effective); } memset(bprm->buf,0,BINPRM_BUF_SIZE); return kernel_read(bprm->file,0,bprm->buf,BINPRM_BUF_SIZE);}/* * This function is used to produce the new IDs and capabilities * from the old ones and the file's capabilities. * * The formula used for evolving capabilities is: * * pI' = pI * (***) pP' = (fP & X) | (fI & pI) * pE' = pP' & fE [NB. fE is 0 or ~0] * * I=Inheritable, P=Permitted, E=Effective // p=process, f=file * ' indicates post-exec(), and X is the global 'cap_bset'. * */void compute_creds(struct linux_binprm *bprm) { kernel_cap_t new_permitted, working; int do_unlock = 0; new_permitted = cap_intersect(bprm->cap_permitted, cap_bset); working = cap_intersect(bprm->cap_inheritable, current->cap_inheritable); new_permitted = cap_combine(new_permitted, working); if (bprm->e_uid != current->uid || bprm->e_gid != current->gid || !cap_issubset(new_permitted, current->cap_permitted)) { current->mm->dumpable = 0; lock_kernel(); if (must_not_trace_exec(current) || atomic_read(¤t->fs->count) > 1 || atomic_read(¤t->files->count) > 1 || atomic_read(¤t->sig->count) > 1) { if(!capable(CAP_SETUID)) { bprm->e_uid = current->uid; bprm->e_gid = current->gid; } if(!capable(CAP_SETPCAP)) { new_permitted = cap_intersect(new_permitted, current->cap_permitted); } } do_unlock = 1; } /* For init, we want to retain the capabilities set * in the init_task struct. Thus we skip the usual * capability rules */ if (current->pid != 1) { current->cap_permitted = new_permitted; current->cap_effective = cap_intersect(new_permitted, bprm->cap_effective); } /* AUD: Audit candidate if current->cap_effective is set */ current->suid = current->euid = current->fsuid = bprm->e_uid; current->sgid = current->egid = current->fsgid = bprm->e_gid; if(do_unlock) unlock_kernel(); current->keep_capabilities = 0;}void remove_arg_zero(struct linux_binprm *bprm){ if (bprm->argc) { unsigned long offset; char * kaddr; struct page *page; offset = bprm->p % PAGE_SIZE; goto inside; while (bprm->p++, *(kaddr+offset++)) { if (offset != PAGE_SIZE) continue; offset = 0; kunmap(page);inside: page = bprm->page[bprm->p/PAGE_SIZE]; kaddr = kmap(page); } kunmap(page); bprm->argc--; }}/* * 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) { struct file * file; unsigned long loader; allow_write_access(bprm->file); fput(bprm->file); bprm->file = NULL; loader = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *); file = open_exec("/sbin/loader"); retval = PTR_ERR(file); if (IS_ERR(file)) return retval; /* Remember if the application is TASO. */ bprm->sh_bang = eh->ah.entry < 0x100000000; bprm->file = file; bprm->loader = loader; retval = prepare_binprm(bprm); if (retval<0) return retval; /* should call search_binary_handler recursively here, but it does not matter */ } }#endif /* kernel module loader fixup */ /* so we don't try to load run modprobe in kernel space. */ set_fs(USER_DS); for (try=0; try<2; try++) { read_lock(&binfmt_lock); for (fmt = formats ; fmt ; fmt = fmt->next) { int (*fn)(struct linux_binprm *, struct pt_regs *) = fmt->load_binary; if (!fn) continue; if (!try_inc_mod_count(fmt->module)) continue; read_unlock(&binfmt_lock); retval = fn(bprm, regs); if (retval >= 0) { put_binfmt(fmt); allow_write_access(bprm->file); if (bprm->file) fput(bprm->file); bprm->file = NULL; current->did_exec = 1; return retval; } read_lock(&binfmt_lock); put_binfmt(fmt); if (retval != -ENOEXEC) break; if (!bprm->file) { read_unlock(&binfmt_lock); return retval; } } read_unlock(&binfmt_lock); if (retval != -ENOEXEC) { break;#ifdef CONFIG_KMOD }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-%04x", *(unsigned short *)(&bprm->buf[2])); 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; struct file *file; int retval; int i; file = open_exec(filename); retval = PTR_ERR(file); if (IS_ERR(file)) return retval; bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *); memset(bprm.page, 0, MAX_ARG_PAGES*sizeof(bprm.page[0])); bprm.file = file; bprm.filename = filename; bprm.sh_bang = 0; bprm.loader = 0; bprm.exec = 0; if ((bprm.argc = count(argv, bprm.p / sizeof(void *))) < 0) { allow_write_access(file); fput(file); return bprm.argc; } if ((bprm.envc = count(envp, bprm.p / sizeof(void *))) < 0) { allow_write_access(file); fput(file); return bprm.envc; } retval = prepare_binprm(&bprm); if (retval < 0) goto out; retval = copy_strings_kernel(1, &bprm.filename, &bprm); if (retval < 0) goto out; bprm.exec = bprm.p; retval = copy_strings(bprm.envc, envp, &bprm); if (retval < 0) goto out; retval = copy_strings(bprm.argc, argv, &bprm); if (retval < 0) goto out; retval = search_binary_handler(&bprm,regs); if (retval >= 0) /* execve success */ return retval;out: /* Something went wrong, return the inode and free the argument pages*/ allow_write_access(bprm.file); if (bprm.file) fput(bprm.file); for (i = 0 ; i < MAX_ARG_PAGES ; i++) { struct page * page = bprm.page[i]; if (page) __free_page(page); } return retval;}void set_binfmt(struct linux_binfmt *new){ struct linux_binfmt *old = current->binfmt; if (new && new->module) __MOD_INC_USE_COUNT(new->module); current->binfmt = new; if (old && old->module) __MOD_DEC_USE_COUNT(old->module);}int do_coredump(long signr, struct pt_regs * regs){ struct linux_binfmt * binfmt; char corename[6+sizeof(current->comm)+10]; struct file * file; struct inode * inode; int retval = 0; lock_kernel(); binfmt = current->binfmt; if (!binfmt || !binfmt->core_dump) goto fail; if (!current->mm->dumpable) goto fail; current->mm->dumpable = 0; if (current->rlim[RLIMIT_CORE].rlim_cur < binfmt->min_coredump) goto fail; memcpy(corename,"core.", 5); corename[4] = '\0'; if (core_uses_pid || atomic_read(¤t->mm->mm_users) != 1) sprintf(&corename[4], ".%d", current->pid); file = filp_open(corename, O_CREAT | 2 | O_NOFOLLOW, 0600); if (IS_ERR(file)) goto fail; inode = file->f_dentry->d_inode; if (inode->i_nlink > 1) goto close_fail; /* multiple links - don't dump */ if (d_unhashed(file->f_dentry)) goto close_fail; if (!S_ISREG(inode->i_mode)) goto close_fail; if (!file->f_op) goto close_fail; if (!file->f_op->write) goto close_fail; if (do_truncate(file->f_dentry, 0) != 0) goto close_fail; retval = binfmt->core_dump(signr, regs, file);close_fail: filp_close(file, NULL);fail: unlock_kernel(); return retval;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -