#include <linux/syscalls.h>
#include <linux/rmap.h>
#include <linux/acct.h>
+#include <linux/cn_proc.h>
#include <asm/uaccess.h>
#include <asm/mmu_context.h>
struct nameidata nd;
int error;
- error = __user_path_lookup_open(library, LOOKUP_FOLLOW, &nd, FMODE_READ);
+ error = __user_path_lookup_open(library, LOOKUP_FOLLOW, &nd, FMODE_READ|FMODE_EXEC);
if (error)
goto out;
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;
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;
goto out;
flush_dcache_page(page);
- pgd = pgd_offset(mm, address);
- pud = pud_alloc(mm, pgd, address);
- if (!pud)
- goto out;
- pmd = pmd_alloc(mm, pud, address);
- if (!pmd)
- goto out;
- pte = pte_alloc_map_lock(mm, pmd, address, &ptl);
+ pte = get_locked_pte(mm, address, &ptl);
if (!pte)
goto out;
if (!pte_none(*pte)) {
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);
+ page_add_new_anon_rmap(page, vma, address);
pte_unmap_unlock(pte, ptl);
/* no need for flush_tlb */
int err;
struct file *file;
- err = path_lookup_open(name, LOOKUP_FOLLOW, &nd, FMODE_READ);
+ err = path_lookup_open(AT_FDCWD, name, LOOKUP_FOLLOW, &nd, FMODE_READ|FMODE_EXEC);
file = ERR_PTR(err);
if (!err) {
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);
arch_pick_mmap_layout(mm);
if (old_mm) {
up_read(&old_mm->mmap_sem);
- if (active_mm != old_mm) BUG();
+ BUG_ON(active_mm != old_mm);
mmput(old_mm);
return 0;
}
* disturbing other processes. (Other processes might share the signal
* table via the CLONE_SIGHAND option to clone().)
*/
-static inline int de_thread(struct task_struct *tsk)
+static 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;
/*
kmem_cache_free(sighand_cachep, newsighand);
return -EAGAIN;
}
+
+ /*
+ * child_reaper ignores SIGKILL, change it now.
+ * Reparenting needs write_lock on tasklist_lock,
+ * so it is safe to do it under read_lock.
+ */
+ if (unlikely(current->group_leader == child_reaper))
+ child_reaper = current;
+
zap_other_threads(current);
read_unlock(&tasklist_lock);
* synchronize with any firing (by calling del_timer_sync)
* before we can safely let the old group leader die.
*/
- sig->real_timer.data = (unsigned long)current;
+ sig->tsk = current;
spin_unlock_irq(lock);
- if (del_timer_sync(&sig->real_timer))
- add_timer(&sig->real_timer);
+ if (hrtimer_cancel(&sig->real_timer))
+ hrtimer_restart(&sig->real_timer);
spin_lock_irq(lock);
}
while (atomic_read(&sig->count) > count) {
* and to assume its PID:
*/
if (!thread_group_leader(current)) {
- struct task_struct *leader = current->group_leader, *parent;
struct dentry *proc_dentry1, *proc_dentry2;
- unsigned long exit_state, 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();
+ /*
+ * The only record we have of the real-time age of a
+ * process, regardless of execs it's done, is start_time.
+ * All the past CPU time is accumulated in signal_struct
+ * from sister threads now dead. But in this non-leader
+ * exec, nothing survives from the original leader thread,
+ * whose birth marks the true age of this process now.
+ * When we take on its identity by switching to its PID, we
+ * also take its birthdate (always earlier than our own).
+ */
+ current->start_time = leader->start_time;
+
spin_lock(&leader->proc_lock);
spin_lock(¤t->proc_lock);
proc_dentry1 = proc_pid_unhash(current);
* two threads with a switched PID, and release
* the former thread group leader:
*/
- ptrace = leader->ptrace;
- parent = leader->parent;
- if (unlikely(ptrace) && unlikely(parent == current)) {
- /*
- * Joker was ptracing his own group leader,
- * and now he wants to be his own parent!
- * We can't have that.
- */
- ptrace = 0;
- }
- ptrace_unlink(current);
- ptrace_unlink(leader);
- remove_parent(current);
- remove_parent(leader);
-
- switch_exec_pids(leader, current);
+ /* Become a process group leader with the old leader's pid.
+ * Note: The old leader also uses thispid until release_task
+ * is called. Odd but simple and correct.
+ */
+ detach_pid(current, PIDTYPE_PID);
+ current->pid = leader->pid;
+ attach_pid(current, PIDTYPE_PID, current->pid);
+ attach_pid(current, PIDTYPE_PGID, current->signal->pgrp);
+ attach_pid(current, PIDTYPE_SID, current->signal->session);
+ list_add_tail_rcu(¤t->tasks, &init_task.tasks);
- current->parent = current->real_parent = leader->real_parent;
- leader->parent = leader->real_parent = child_reaper;
current->group_leader = current;
- leader->group_leader = leader;
+ leader->group_leader = current;
- add_parent(current, current->parent);
- add_parent(leader, leader->parent);
- if (ptrace) {
- current->ptrace = ptrace;
- __ptrace_link(current, parent);
- }
+ /* Reduce leader to a thread */
+ detach_pid(leader, PIDTYPE_PGID);
+ detach_pid(leader, PIDTYPE_SID);
+ list_del_init(&leader->tasks);
- 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);
}
/*
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) {
/*
/*
* Move our state over to newsighand and switch it in.
*/
- spin_lock_init(&newsighand->siglock);
atomic_set(&newsighand->count, 1);
memcpy(newsighand->action, oldsighand->action,
sizeof(newsighand->action));
spin_lock(&oldsighand->siglock);
spin_lock(&newsighand->siglock);
- current->sighand = newsighand;
+ rcu_assign_pointer(current->sighand, newsighand);
recalc_sigpending();
spin_unlock(&newsighand->siglock);
* so that a new one can be started
*/
-static inline void flush_old_files(struct files_struct * files)
+static void flush_old_files(struct files_struct * files)
{
long j = -1;
struct fdtable *fdt;
current->flags &= ~PF_RANDOMIZE;
flush_thread();
+ /* Set the new mm task size. We have to do that late because it may
+ * depend on TIF_32BIT which is only updated in flush_thread() on
+ * some architectures like powerpc
+ */
+ current->mm->task_size = TASK_SIZE;
+
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;
EXPORT_SYMBOL(prepare_binprm);
-static inline int unsafe_exec(struct task_struct *p)
+static int unsafe_exec(struct task_struct *p)
{
int unsafe = 0;
if (p->ptrace & PT_PTRACED) {
fput(bprm->file);
bprm->file = NULL;
current->did_exec = 1;
+ proc_exec_connector(current);
return retval;
}
read_lock(&binfmt_lock);
int i;
retval = -ENOMEM;
- bprm = kmalloc(sizeof(*bprm), GFP_KERNEL);
+ bprm = kzalloc(sizeof(*bprm), GFP_KERNEL);
if (!bprm)
goto out_ret;
- memset(bprm, 0, sizeof(*bprm));
file = open_exec(filename);
retval = PTR_ERR(file);
do_each_thread(g,p) {
if (mm == p->mm && p != tsk &&
p->ptrace && p->parent->mm == mm) {
- __ptrace_unlink(p);
+ __ptrace_detach(p, 0);
}
} while_each_thread(g,p);
write_unlock_irq(&tasklist_lock);
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)
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);