X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=fs%2Fexec.c;h=fd02ea4a81e96b8c1d748d7aed28980843cb2c2b;hb=54c762fe62d9ff0982f38e80cbec9c59104311e9;hp=6fae59a22b436bb1c2329d31387a18e33d68b54a;hpb=fb085cf1d4294824571815d487daccc0609543f0;p=safe%2Fjmp%2Flinux-2.6 diff --git a/fs/exec.c b/fs/exec.c index 6fae59a..fd02ea4a 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -48,6 +48,7 @@ #include #include #include +#include #include #include @@ -126,8 +127,7 @@ asmlinkage long sys_uselib(const char __user * library) struct nameidata nd; int error; - nd.intent.open.flags = FMODE_READ; - error = __user_walk(library, LOOKUP_FOLLOW|LOOKUP_OPEN, &nd); + error = __user_path_lookup_open(library, LOOKUP_FOLLOW, &nd, FMODE_READ); if (error) goto out; @@ -135,11 +135,11 @@ asmlinkage long sys_uselib(const char __user * library) if (!S_ISREG(nd.dentry->d_inode->i_mode)) goto exit; - error = permission(nd.dentry->d_inode, MAY_READ | MAY_EXEC, &nd); + error = vfs_permission(&nd, MAY_READ | MAY_EXEC); if (error) goto exit; - file = dentry_open(nd.dentry, nd.mnt, O_RDONLY); + file = nameidata_to_filp(&nd, O_RDONLY); error = PTR_ERR(file); if (IS_ERR(file)) goto out; @@ -167,6 +167,7 @@ asmlinkage long sys_uselib(const char __user * library) out: return error; exit: + release_open_intent(&nd); path_release(&nd); goto out; } @@ -305,44 +306,30 @@ void install_arg_page(struct vm_area_struct *vma, struct page *page, unsigned long address) { struct mm_struct *mm = vma->vm_mm; - pgd_t * pgd; - pud_t * pud; - pmd_t * pmd; pte_t * pte; + spinlock_t *ptl; if (unlikely(anon_vma_prepare(vma))) - goto out_sig; + goto out; flush_dcache_page(page); - pgd = pgd_offset(mm, address); - - spin_lock(&mm->page_table_lock); - pud = pud_alloc(mm, pgd, address); - if (!pud) - goto out; - pmd = pmd_alloc(mm, pud, address); - if (!pmd) - goto out; - pte = pte_alloc_map(mm, pmd, address); + pte = get_locked_pte(mm, address, &ptl); if (!pte) goto out; if (!pte_none(*pte)) { - pte_unmap(pte); + pte_unmap_unlock(pte, ptl); goto out; } - inc_mm_counter(mm, rss); + inc_mm_counter(mm, anon_rss); lru_cache_add_active(page); set_pte_at(mm, address, pte, pte_mkdirty(pte_mkwrite(mk_pte( page, vma->vm_page_prot)))); - page_add_anon_rmap(page, vma, address); - pte_unmap(pte); - spin_unlock(&mm->page_table_lock); + page_add_new_anon_rmap(page, vma, address); + pte_unmap_unlock(pte, ptl); /* no need for flush_tlb */ return; out: - spin_unlock(&mm->page_table_lock); -out_sig: __free_page(page); force_sig(SIGKILL, current); } @@ -421,11 +408,6 @@ int setup_arg_pages(struct linux_binprm *bprm, if (!mpnt) return -ENOMEM; - if (security_vm_enough_memory(arg_size >> PAGE_SHIFT)) { - kmem_cache_free(vm_area_cachep, mpnt); - return -ENOMEM; - } - memset(mpnt, 0, sizeof(*mpnt)); down_write(&mm->mmap_sem); @@ -495,8 +477,7 @@ struct file *open_exec(const char *name) int err; struct file *file; - nd.intent.open.flags = FMODE_READ; - err = path_lookup(name, LOOKUP_FOLLOW|LOOKUP_OPEN, &nd); + err = path_lookup_open(name, LOOKUP_FOLLOW, &nd, FMODE_READ); file = ERR_PTR(err); if (!err) { @@ -504,12 +485,12 @@ struct file *open_exec(const char *name) file = ERR_PTR(-EACCES); if (!(nd.mnt->mnt_flags & MNT_NOEXEC) && S_ISREG(inode->i_mode)) { - int err = permission(inode, MAY_EXEC, &nd); + int err = vfs_permission(&nd, MAY_EXEC); if (!err && !(inode->i_mode & 0111)) err = -EACCES; file = ERR_PTR(err); if (!err) { - file = dentry_open(nd.dentry, nd.mnt, O_RDONLY); + file = nameidata_to_filp(&nd, O_RDONLY); if (!IS_ERR(file)) { err = deny_write_access(file); if (err) { @@ -521,6 +502,7 @@ out: return file; } } + release_open_intent(&nd); path_release(&nd); } goto out; @@ -598,6 +580,7 @@ static inline int de_thread(struct task_struct *tsk) struct signal_struct *sig = tsk->signal; struct sighand_struct *newsighand, *oldsighand = tsk->sighand; spinlock_t *lock = &oldsighand->siglock; + struct task_struct *leader = NULL; int count; /* @@ -639,10 +622,9 @@ static inline int de_thread(struct task_struct *tsk) /* * Account for the thread group leader hanging around: */ - count = 2; - if (thread_group_leader(current)) - count = 1; - else { + count = 1; + if (!thread_group_leader(current)) { + count = 2; /* * The SIGALRM timer survives the exec, but needs to point * at us as the new group leader now. We have a race with @@ -651,8 +633,10 @@ static inline int de_thread(struct task_struct *tsk) * before we can safely let the old group leader die. */ sig->real_timer.data = (unsigned long)current; + spin_unlock_irq(lock); if (del_timer_sync(&sig->real_timer)) add_timer(&sig->real_timer); + spin_lock_irq(lock); } while (atomic_read(&sig->count) > count) { sig->group_exit_task = current; @@ -664,7 +648,6 @@ static inline int de_thread(struct task_struct *tsk) } sig->group_exit_task = NULL; sig->notify_count = 0; - sig->real_timer.data = (unsigned long)current; spin_unlock_irq(lock); /* @@ -673,15 +656,16 @@ static inline int de_thread(struct task_struct *tsk) * and to assume its PID: */ if (!thread_group_leader(current)) { - struct task_struct *leader = current->group_leader, *parent; + struct task_struct *parent; struct dentry *proc_dentry1, *proc_dentry2; - unsigned long exit_state, ptrace; + unsigned long ptrace; /* * Wait for the thread group leader to be a zombie. * It should already be zombie at this point, most * of the time. */ + leader = current->group_leader; while (leader->exit_state != EXIT_ZOMBIE) yield(); @@ -732,16 +716,15 @@ static inline int de_thread(struct task_struct *tsk) list_del(¤t->tasks); list_add_tail(¤t->tasks, &init_task.tasks); current->exit_signal = SIGCHLD; - exit_state = leader->exit_state; + + BUG_ON(leader->exit_state != EXIT_ZOMBIE); + leader->exit_state = EXIT_DEAD; write_unlock_irq(&tasklist_lock); spin_unlock(&leader->proc_lock); spin_unlock(¤t->proc_lock); proc_pid_flush(proc_dentry1); proc_pid_flush(proc_dentry2); - - BUG_ON(exit_state != EXIT_ZOMBIE); - release_task(leader); } /* @@ -751,8 +734,11 @@ static inline int de_thread(struct task_struct *tsk) sig->flags = 0; no_thread_group: - BUG_ON(atomic_read(&sig->count) != 1); exit_itimers(sig); + if (leader) + release_task(leader); + + BUG_ON(atomic_read(&sig->count) != 1); if (atomic_read(&oldsighand->count) == 1) { /* @@ -774,7 +760,7 @@ no_thread_group: spin_lock(&oldsighand->siglock); spin_lock(&newsighand->siglock); - current->sighand = newsighand; + rcu_assign_pointer(current->sighand, newsighand); recalc_sigpending(); spin_unlock(&newsighand->siglock); @@ -782,7 +768,7 @@ no_thread_group: write_unlock_irq(&tasklist_lock); if (atomic_dec_and_test(&oldsighand->count)) - kmem_cache_free(sighand_cachep, oldsighand); + sighand_free(oldsighand); } BUG_ON(!thread_group_leader(current)); @@ -900,7 +886,7 @@ int flush_old_exec(struct linux_binprm * bprm) flush_thread(); if (bprm->e_uid != current->euid || bprm->e_gid != current->egid || - permission(bprm->file->f_dentry->d_inode,MAY_READ, NULL) || + file_permission(bprm->file, MAY_READ) || (bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP)) { suid_keys(current); current->mm->dumpable = suid_dumpable; @@ -1105,6 +1091,7 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs) fput(bprm->file); bprm->file = NULL; current->did_exec = 1; + proc_exec_connector(current); return retval; } read_lock(&binfmt_lock); @@ -1212,7 +1199,6 @@ int do_execve(char * filename, /* execve success */ security_bprm_free(bprm); acct_update_integrals(current); - update_mem_hiwater(current); kfree(bprm); return retval; } @@ -1427,19 +1413,16 @@ static void zap_threads (struct mm_struct *mm) static void coredump_wait(struct mm_struct *mm) { DECLARE_COMPLETION(startup_done); + int core_waiters; - mm->core_waiters++; /* let other threads block */ mm->core_startup_done = &startup_done; - /* give other threads a chance to run: */ - yield(); - zap_threads(mm); - if (--mm->core_waiters) { - up_write(&mm->mmap_sem); + core_waiters = mm->core_waiters; + up_write(&mm->mmap_sem); + + if (core_waiters) wait_for_completion(&startup_done); - } else - up_write(&mm->mmap_sem); BUG_ON(mm->core_waiters); } @@ -1473,18 +1456,28 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs) current->fsuid = 0; /* Dump root private */ } mm->dumpable = 0; - init_completion(&mm->core_done); + + retval = -EAGAIN; spin_lock_irq(¤t->sighand->siglock); - current->signal->flags = SIGNAL_GROUP_EXIT; - current->signal->group_exit_code = exit_code; + if (!(current->signal->flags & SIGNAL_GROUP_EXIT)) { + current->signal->flags = SIGNAL_GROUP_EXIT; + current->signal->group_exit_code = exit_code; + current->signal->group_stop_count = 0; + retval = 0; + } spin_unlock_irq(¤t->sighand->siglock); + if (retval) { + up_write(&mm->mmap_sem); + goto fail; + } + + init_completion(&mm->core_done); coredump_wait(mm); /* * Clear any false indication of pending signals that might * be seen by the filesystem code called to write the core file. */ - current->signal->group_stop_count = 0; clear_thread_flag(TIF_SIGPENDING); if (current->signal->rlim[RLIMIT_CORE].rlim_cur < binfmt->min_coredump) @@ -1512,7 +1505,7 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs) goto close_fail; if (!file->f_op->write) goto close_fail; - if (do_truncate(file->f_dentry, 0) != 0) + if (do_truncate(file->f_dentry, 0, 0, file) != 0) goto close_fail; retval = binfmt->core_dump(signr, regs, file);