diff options
Diffstat (limited to 'kernel/signal.c')
| -rw-r--r-- | kernel/signal.c | 37 | 
1 files changed, 28 insertions, 9 deletions
diff --git a/kernel/signal.c b/kernel/signal.c index c73c4284160e..e76001ccf5cd 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -1054,13 +1054,13 @@ static int __send_signal(int sig, struct siginfo *info, struct task_struct *t,  	struct sigpending *pending;  	struct sigqueue *q;  	int override_rlimit; - -	trace_signal_generate(sig, info, t); +	int ret = 0, result;  	assert_spin_locked(&t->sighand->siglock); +	result = TRACE_SIGNAL_IGNORED;  	if (!prepare_signal(sig, t, from_ancestor_ns)) -		return 0; +		goto ret;  	pending = group ? &t->signal->shared_pending : &t->pending;  	/* @@ -1068,8 +1068,11 @@ static int __send_signal(int sig, struct siginfo *info, struct task_struct *t,  	 * exactly one non-rt signal, so that we can get more  	 * detailed information about the cause of the signal.  	 */ +	result = TRACE_SIGNAL_ALREADY_PENDING;  	if (legacy_queue(pending, sig)) -		return 0; +		goto ret; + +	result = TRACE_SIGNAL_DELIVERED;  	/*  	 * fast-pathed signals for kernel-internal things like SIGSTOP  	 * or SIGKILL. @@ -1127,14 +1130,15 @@ static int __send_signal(int sig, struct siginfo *info, struct task_struct *t,  			 * signal was rt and sent by user using something  			 * other than kill().  			 */ -			trace_signal_overflow_fail(sig, group, info); -			return -EAGAIN; +			result = TRACE_SIGNAL_OVERFLOW_FAIL; +			ret = -EAGAIN; +			goto ret;  		} else {  			/*  			 * This is a silent loss of information.  We still  			 * send the signal, but the *info bits are lost.  			 */ -			trace_signal_lose_info(sig, group, info); +			result = TRACE_SIGNAL_LOSE_INFO;  		}  	} @@ -1142,7 +1146,9 @@ out_set:  	signalfd_notify(t, sig);  	sigaddset(&pending->signal, sig);  	complete_signal(sig, t, group); -	return 0; +ret: +	trace_signal_generate(sig, info, t, group, result); +	return ret;  }  static int send_signal(int sig, struct siginfo *info, struct task_struct *t, @@ -1585,7 +1591,7 @@ int send_sigqueue(struct sigqueue *q, struct task_struct *t, int group)  	int sig = q->info.si_signo;  	struct sigpending *pending;  	unsigned long flags; -	int ret; +	int ret, result;  	BUG_ON(!(q->flags & SIGQUEUE_PREALLOC)); @@ -1594,6 +1600,7 @@ int send_sigqueue(struct sigqueue *q, struct task_struct *t, int group)  		goto ret;  	ret = 1; /* the signal is ignored */ +	result = TRACE_SIGNAL_IGNORED;  	if (!prepare_signal(sig, t, 0))  		goto out; @@ -1605,6 +1612,7 @@ int send_sigqueue(struct sigqueue *q, struct task_struct *t, int group)  		 */  		BUG_ON(q->info.si_code != SI_TIMER);  		q->info.si_overrun++; +		result = TRACE_SIGNAL_ALREADY_PENDING;  		goto out;  	}  	q->info.si_overrun = 0; @@ -1614,7 +1622,9 @@ int send_sigqueue(struct sigqueue *q, struct task_struct *t, int group)  	list_add_tail(&q->list, &pending->list);  	sigaddset(&pending->signal, sig);  	complete_signal(sig, t, group); +	result = TRACE_SIGNAL_DELIVERED;  out: +	trace_signal_generate(sig, &q->info, t, group, result);  	unlock_task_sighand(t, &flags);  ret:  	return ret; @@ -1642,6 +1652,15 @@ bool do_notify_parent(struct task_struct *tsk, int sig)  	BUG_ON(!tsk->ptrace &&  	       (tsk->group_leader != tsk || !thread_group_empty(tsk))); +	if (sig != SIGCHLD) { +		/* +		 * This is only possible if parent == real_parent. +		 * Check if it has changed security domain. +		 */ +		if (tsk->parent_exec_id != tsk->parent->self_exec_id) +			sig = SIGCHLD; +	} +  	info.si_signo = sig;  	info.si_errno = 0;  	/*  | 
