diff --git a/kernel/exit.c b/kernel/exit.c index ef2dfa818bf..7838b4d6877 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -1097,6 +1097,7 @@ struct wait_opts { int __user *wo_stat; struct rusage __user *wo_rusage; + wait_queue_t child_wait; int notask_error; }; @@ -1570,20 +1571,35 @@ static int ptrace_do_wait(struct wait_opts *wo, struct task_struct *tsk) return 0; } +static int child_wait_callback(wait_queue_t *wait, unsigned mode, + int sync, void *key) +{ + struct wait_opts *wo = container_of(wait, struct wait_opts, + child_wait); + struct task_struct *p = key; + + if (!eligible_child(wo, p)) + return 0; + + return default_wake_function(wait, mode, sync, key); +} + void __wake_up_parent(struct task_struct *p, struct task_struct *parent) { - wake_up_interruptible_sync(&parent->signal->wait_chldexit); + __wake_up_sync_key(&parent->signal->wait_chldexit, + TASK_INTERRUPTIBLE, 1, p); } static long do_wait(struct wait_opts *wo) { - DECLARE_WAITQUEUE(wait, current); struct task_struct *tsk; int retval; trace_sched_process_wait(wo->wo_pid); - add_wait_queue(¤t->signal->wait_chldexit,&wait); + init_waitqueue_func_entry(&wo->child_wait, child_wait_callback); + wo->child_wait.private = current; + add_wait_queue(¤t->signal->wait_chldexit, &wo->child_wait); repeat: /* * If there is nothing that can match our critiera just get out. @@ -1624,7 +1640,8 @@ notask: } end: __set_current_state(TASK_RUNNING); - remove_wait_queue(¤t->signal->wait_chldexit,&wait); + remove_wait_queue(¤t->signal->wait_chldexit, &wo->child_wait); + if (wo->wo_info) { struct siginfo __user *infop = wo->wo_info; diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 417f7c99452..bb230d5d708 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -2411,7 +2411,7 @@ static void selinux_bprm_committed_creds(struct linux_binprm *bprm) /* Wake up the parent if it is waiting so that it can recheck * wait permission to the new task SID. */ read_lock(&tasklist_lock); - wake_up_interruptible(¤t->real_parent->signal->wait_chldexit); + __wake_up_parent(current, current->real_parent); read_unlock(&tasklist_lock); }