Skip to content

Commit

Permalink
user namespace: make signal.c respect user namespaces
Browse files Browse the repository at this point in the history
ipc/mqueue.c: for __SI_MESQ, convert the uid being sent to recipient's
user namespace. (new, thanks Oleg)

__send_signal: convert current's uid to the recipient's user namespace
for any siginfo which is not SI_FROMKERNEL (patch from Oleg, thanks
again :)

do_notify_parent and do_notify_parent_cldstop: map task's uid to parent's
user namespace

ptrace_signal maps parent's uid into current's user namespace before
including in signal to current.  IIUC Oleg has argued that this shouldn't
matter as the debugger will play with it, but it seems like not converting
the value currently being set is misleading.

Changelog:
Sep 20: Inspired by Oleg's suggestion, define map_cred_ns() helper to
	simplify callers and help make clear what we are translating
        (which uid into which namespace).  Passing the target task would
	make callers even easier to read, but we pass in user_ns because
	current_user_ns() != task_cred_xxx(current, user_ns).
Sep 20: As recommended by Oleg, also put task_pid_vnr() under rcu_read_lock
	in ptrace_signal().
Sep 23: In send_signal(), detect when (user) signal is coming from an
	ancestor or unrelated user namespace.  Pass that on to __send_signal,
	which sets si_uid to 0 or overflowuid if needed.
Oct 12: Base on Oleg's fixup_uid() patch.  On top of that, handle all
	SI_FROMKERNEL cases at callers, because we can't assume sender is
	current in those cases.
Nov 10: (mhelsley) rename fixup_uid to more meaningful usern_fixup_signal_uid
Nov 10: (akpm) make the !CONFIG_USER_NS case clearer

Signed-off-by: Serge Hallyn <[email protected]>
Cc: Oleg Nesterov <[email protected]>
Cc: Matt Helsley <[email protected]>
Cc: "Eric W. Biederman" <[email protected]>
From: Serge Hallyn <[email protected]>
Subject: __send_signal: pass q->info, not info, to userns_fixup_signal_uid (v2)

Eric Biederman pointed out that passing info is a bug and could lead to a
NULL pointer deref to boot.

A collection of signal, securebits, filecaps, cap_bounds, and a few other
ltp tests passed with this kernel.

Changelog:
    Nov 18: previous patch missed a leading '&'

Signed-off-by: Serge Hallyn <[email protected]>
Cc: "Eric W. Biederman" <[email protected]>
From: Dan Carpenter <[email protected]>
Subject: ipc/mqueue: lock() => unlock() typo

There was a double lock typo introduced in b085f4bd6b21 "user namespace:
make signal.c respect user namespaces"

Signed-off-by: Dan Carpenter <[email protected]>
Cc: Oleg Nesterov <[email protected]>
Cc: Matt Helsley <[email protected]>
Cc: "Eric W. Biederman" <[email protected]>
Acked-by: Serge Hallyn <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
hallyn authored and torvalds committed Jan 11, 2012
1 parent b196be8 commit 6b550f9
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 4 deletions.
7 changes: 6 additions & 1 deletion ipc/mqueue.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include <linux/nsproxy.h>
#include <linux/pid.h>
#include <linux/ipc_namespace.h>
#include <linux/user_namespace.h>
#include <linux/slab.h>

#include <net/sock.h>
Expand Down Expand Up @@ -542,9 +543,13 @@ static void __do_notify(struct mqueue_inode_info *info)
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();
sig_i.si_pid = task_tgid_nr_ns(current,
ns_of_pid(info->notify_owner));
sig_i.si_uid = current_uid();
sig_i.si_uid = user_ns_map_uid(info->user->user_ns,
current_cred(), current_uid());
rcu_read_unlock();

kill_pid_info(info->notify.sigev_signo,
&sig_i, info->notify_owner);
Expand Down
43 changes: 40 additions & 3 deletions kernel/signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include <linux/freezer.h>
#include <linux/pid_namespace.h>
#include <linux/nsproxy.h>
#include <linux/user_namespace.h>
#define CREATE_TRACE_POINTS
#include <trace/events/signal.h>

Expand Down Expand Up @@ -1019,6 +1020,34 @@ static inline int legacy_queue(struct sigpending *signals, int sig)
return (sig < SIGRTMIN) && sigismember(&signals->signal, sig);
}

/*
* map the uid in struct cred into user namespace *ns
*/
static inline uid_t map_cred_ns(const struct cred *cred,
struct user_namespace *ns)
{
return user_ns_map_uid(ns, cred, cred->uid);
}

#ifdef CONFIG_USER_NS
static inline void userns_fixup_signal_uid(struct siginfo *info, struct task_struct *t)
{
if (current_user_ns() == task_cred_xxx(t, user_ns))
return;

if (SI_FROMKERNEL(info))
return;

info->si_uid = user_ns_map_uid(task_cred_xxx(t, user_ns),
current_cred(), info->si_uid);
}
#else
static inline void userns_fixup_signal_uid(struct siginfo *info, struct task_struct *t)
{
return;
}
#endif

static int __send_signal(int sig, struct siginfo *info, struct task_struct *t,
int group, int from_ancestor_ns)
{
Expand Down Expand Up @@ -1088,6 +1117,9 @@ static int __send_signal(int sig, struct siginfo *info, struct task_struct *t,
q->info.si_pid = 0;
break;
}

userns_fixup_signal_uid(&q->info, t);

} else if (!is_si_special(info)) {
if (sig >= SIGRTMIN && info->si_code != SI_USER) {
/*
Expand Down Expand Up @@ -1626,7 +1658,8 @@ bool do_notify_parent(struct task_struct *tsk, int sig)
*/
rcu_read_lock();
info.si_pid = task_pid_nr_ns(tsk, tsk->parent->nsproxy->pid_ns);
info.si_uid = __task_cred(tsk)->uid;
info.si_uid = map_cred_ns(__task_cred(tsk),
task_cred_xxx(tsk->parent, user_ns));
rcu_read_unlock();

info.si_utime = cputime_to_clock_t(tsk->utime + tsk->signal->utime);
Expand Down Expand Up @@ -1709,7 +1742,8 @@ static void do_notify_parent_cldstop(struct task_struct *tsk,
*/
rcu_read_lock();
info.si_pid = task_pid_nr_ns(tsk, parent->nsproxy->pid_ns);
info.si_uid = __task_cred(tsk)->uid;
info.si_uid = map_cred_ns(__task_cred(tsk),
task_cred_xxx(parent, user_ns));
rcu_read_unlock();

info.si_utime = cputime_to_clock_t(tsk->utime);
Expand Down Expand Up @@ -2125,8 +2159,11 @@ static int ptrace_signal(int signr, siginfo_t *info,
info->si_signo = signr;
info->si_errno = 0;
info->si_code = SI_USER;
rcu_read_lock();
info->si_pid = task_pid_vnr(current->parent);
info->si_uid = task_uid(current->parent);
info->si_uid = map_cred_ns(__task_cred(current->parent),
current_user_ns());
rcu_read_unlock();
}

/* If the (new) signal is now blocked, requeue it. */
Expand Down

0 comments on commit 6b550f9

Please sign in to comment.