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] 7978b567d315 ("signals: add from_ancestor_ns parameter to send_signal()") Cc: stable@vger.kernel.org Fixes: 6588c1e3ff01 ("signals: SI_USER: Masquerade si_pid when crossing pid ns boundary") Fixes: 6b550f949594 ("user namespace: make signal.c respect user namespaces") Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
This commit is contained in:
parent
70f1b0d34b
commit
7a0cf09494
@ -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
|
|||||||
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
|
|||||||
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 @@ ret:
|
|||||||
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
|
|||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user