diff options
Diffstat (limited to 'ipc/mqueue.c')
| -rw-r--r-- | ipc/mqueue.c | 34 | 
1 files changed, 26 insertions, 8 deletions
| diff --git a/ipc/mqueue.c b/ipc/mqueue.c index dc8307bf2d74..beff0cfcd1e8 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -142,6 +142,7 @@ struct mqueue_inode_info {  	struct sigevent notify;  	struct pid *notify_owner; +	u32 notify_self_exec_id;  	struct user_namespace *notify_user_ns;  	struct user_struct *user;	/* user who created, for accounting */  	struct sock *notify_sock; @@ -773,28 +774,44 @@ static void __do_notify(struct mqueue_inode_info *info)  	 * synchronously. */  	if (info->notify_owner &&  	    info->attr.mq_curmsgs == 1) { -		struct kernel_siginfo sig_i;  		switch (info->notify.sigev_notify) {  		case SIGEV_NONE:  			break; -		case SIGEV_SIGNAL: -			/* sends signal */ +		case SIGEV_SIGNAL: { +			struct kernel_siginfo sig_i; +			struct task_struct *task; + +			/* do_mq_notify() accepts sigev_signo == 0, why?? */ +			if (!info->notify.sigev_signo) +				break;  			clear_siginfo(&sig_i);  			sig_i.si_signo = info->notify.sigev_signo;  			sig_i.si_errno = 0;  			sig_i.si_code = SI_MESGQ;  			sig_i.si_value = info->notify.sigev_value; -			/* map current pid/uid into info->owner's namespaces */  			rcu_read_lock(); +			/* map current pid/uid into info->owner's namespaces */  			sig_i.si_pid = task_tgid_nr_ns(current,  						ns_of_pid(info->notify_owner)); -			sig_i.si_uid = from_kuid_munged(info->notify_user_ns, current_uid()); +			sig_i.si_uid = from_kuid_munged(info->notify_user_ns, +						current_uid()); +			/* +			 * We can't use kill_pid_info(), this signal should +			 * bypass check_kill_permission(). It is from kernel +			 * but si_fromuser() can't know this. +			 * We do check the self_exec_id, to avoid sending +			 * signals to programs that don't expect them. +			 */ +			task = pid_task(info->notify_owner, PIDTYPE_TGID); +			if (task && task->self_exec_id == +						info->notify_self_exec_id) { +				do_send_sig_info(info->notify.sigev_signo, +						&sig_i, task, PIDTYPE_TGID); +			}  			rcu_read_unlock(); - -			kill_pid_info(info->notify.sigev_signo, -				      &sig_i, info->notify_owner);  			break; +		}  		case SIGEV_THREAD:  			set_cookie(info->notify_cookie, NOTIFY_WOKENUP);  			netlink_sendskb(info->notify_sock, info->notify_cookie); @@ -1383,6 +1400,7 @@ retry:  			info->notify.sigev_signo = notification->sigev_signo;  			info->notify.sigev_value = notification->sigev_value;  			info->notify.sigev_notify = SIGEV_SIGNAL; +			info->notify_self_exec_id = current->self_exec_id;  			break;  		} |