Commit 7a0cf094 authored by Eric W. Biederman's avatar Eric W. Biederman

signal: Correct namespace fixups of si_pid and si_uid

The function send_signal was split from __send_signal so that it would
be possible to bypass the namespace logic based upon current[1].  As it
turns out the si_pid and the si_uid fixup are both inappropriate in
the case of kill_pid_usb_asyncio so move that logic into send_signal.

It is difficult to arrange but possible for a signal with an si_code
of SI_TIMER or SI_SIGIO to be sent across namespace boundaries.  In
which case tests for when it is ok to change si_pid and si_uid based
on SI_FROMUSER are incorrect.  Replace the use of SI_FROMUSER with a
new test has_si_pid_and_used based on siginfo_layout.

Now that the uid fixup is no longer present after expanding
SEND_SIG_NOINFO properly calculate the si_uid that the target
task needs to read.

[1] 7978b567 ("signals: add from_ancestor_ns parameter to send_signal()")
Cc: stable@vger.kernel.org
Fixes: 6588c1e3 ("signals: SI_USER: Masquerade si_pid when crossing pid ns boundary")
Fixes: 6b550f94 ("user namespace: make signal.c respect user namespaces")
Signed-off-by: default avatar"Eric W. Biederman" <ebiederm@xmission.com>
parent 70f1b0d3
...@@ -1056,27 +1056,6 @@ static inline bool legacy_queue(struct sigpending *signals, int sig) ...@@ -1056,27 +1056,6 @@ static inline bool legacy_queue(struct sigpending *signals, int sig)
return (sig < SIGRTMIN) && sigismember(&signals->signal, sig); return (sig < SIGRTMIN) && sigismember(&signals->signal, sig);
} }
#ifdef CONFIG_USER_NS
static inline void userns_fixup_signal_uid(struct kernel_siginfo *info, struct task_struct *t)
{
if (current_user_ns() == task_cred_xxx(t, user_ns))
return;
if (SI_FROMKERNEL(info))
return;
rcu_read_lock();
info->si_uid = from_kuid_munged(task_cred_xxx(t, user_ns),
make_kuid(current_user_ns(), info->si_uid));
rcu_read_unlock();
}
#else
static inline void userns_fixup_signal_uid(struct kernel_siginfo *info, struct task_struct *t)
{
return;
}
#endif
static int __send_signal(int sig, struct kernel_siginfo *info, struct task_struct *t, static int __send_signal(int sig, struct kernel_siginfo *info, struct task_struct *t,
enum pid_type type, int from_ancestor_ns) enum pid_type type, int from_ancestor_ns)
{ {
...@@ -1134,7 +1113,11 @@ static int __send_signal(int sig, struct kernel_siginfo *info, struct task_struc ...@@ -1134,7 +1113,11 @@ static int __send_signal(int sig, struct kernel_siginfo *info, struct task_struc
q->info.si_code = SI_USER; q->info.si_code = SI_USER;
q->info.si_pid = task_tgid_nr_ns(current, q->info.si_pid = task_tgid_nr_ns(current,
task_active_pid_ns(t)); task_active_pid_ns(t));
q->info.si_uid = from_kuid_munged(current_user_ns(), current_uid()); rcu_read_lock();
q->info.si_uid =
from_kuid_munged(task_cred_xxx(t, user_ns),
current_uid());
rcu_read_unlock();
break; break;
case (unsigned long) SEND_SIG_PRIV: case (unsigned long) SEND_SIG_PRIV:
clear_siginfo(&q->info); clear_siginfo(&q->info);
...@@ -1146,13 +1129,8 @@ static int __send_signal(int sig, struct kernel_siginfo *info, struct task_struc ...@@ -1146,13 +1129,8 @@ static int __send_signal(int sig, struct kernel_siginfo *info, struct task_struc
break; break;
default: default:
copy_siginfo(&q->info, info); copy_siginfo(&q->info, info);
if (from_ancestor_ns)
q->info.si_pid = 0;
break; break;
} }
userns_fixup_signal_uid(&q->info, t);
} else if (!is_si_special(info)) { } else if (!is_si_special(info)) {
if (sig >= SIGRTMIN && info->si_code != SI_USER) { if (sig >= SIGRTMIN && info->si_code != SI_USER) {
/* /*
...@@ -1196,6 +1174,28 @@ static int __send_signal(int sig, struct kernel_siginfo *info, struct task_struc ...@@ -1196,6 +1174,28 @@ static int __send_signal(int sig, struct kernel_siginfo *info, struct task_struc
return ret; return ret;
} }
static inline bool has_si_pid_and_uid(struct kernel_siginfo *info)
{
bool ret = false;
switch (siginfo_layout(info->si_signo, info->si_code)) {
case SIL_KILL:
case SIL_CHLD:
case SIL_RT:
ret = true;
break;
case SIL_TIMER:
case SIL_POLL:
case SIL_FAULT:
case SIL_FAULT_MCEERR:
case SIL_FAULT_BNDERR:
case SIL_FAULT_PKUERR:
case SIL_SYS:
ret = false;
break;
}
return ret;
}
static int send_signal(int sig, struct kernel_siginfo *info, struct task_struct *t, static int send_signal(int sig, struct kernel_siginfo *info, struct task_struct *t,
enum pid_type type) enum pid_type type)
{ {
...@@ -1205,7 +1205,20 @@ static int send_signal(int sig, struct kernel_siginfo *info, struct task_struct ...@@ -1205,7 +1205,20 @@ static int send_signal(int sig, struct kernel_siginfo *info, struct task_struct
from_ancestor_ns = si_fromuser(info) && from_ancestor_ns = si_fromuser(info) &&
!task_pid_nr_ns(current, task_active_pid_ns(t)); !task_pid_nr_ns(current, task_active_pid_ns(t));
#endif #endif
if (!is_si_special(info) && has_si_pid_and_uid(info)) {
struct user_namespace *t_user_ns;
rcu_read_lock();
t_user_ns = task_cred_xxx(t, user_ns);
if (current_user_ns() != t_user_ns) {
kuid_t uid = make_kuid(current_user_ns(), info->si_uid);
info->si_uid = from_kuid_munged(t_user_ns, uid);
}
rcu_read_unlock();
if (!task_pid_nr_ns(current, task_active_pid_ns(t)))
info->si_pid = 0;
}
return __send_signal(sig, info, t, type, from_ancestor_ns); return __send_signal(sig, info, t, type, from_ancestor_ns);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment