Skip to content

Commit

Permalink
userns: Require CAP_SYS_ADMIN for most uses of setns.
Browse files Browse the repository at this point in the history
Andy Lutomirski <[email protected]> found a nasty little bug in
the permissions of setns.  With unprivileged user namespaces it
became possible to create new namespaces without privilege.

However the setns calls were relaxed to only require CAP_SYS_ADMIN in
the user nameapce of the targed namespace.

Which made the following nasty sequence possible.

pid = clone(CLONE_NEWUSER | CLONE_NEWNS);
if (pid == 0) { /* child */
	system("mount --bind /home/me/passwd /etc/passwd");
}
else if (pid != 0) { /* parent */
	char path[PATH_MAX];
	snprintf(path, sizeof(path), "/proc/%u/ns/mnt");
	fd = open(path, O_RDONLY);
	setns(fd, 0);
	system("su -");
}

Prevent this possibility by requiring CAP_SYS_ADMIN
in the current user namespace when joing all but the user namespace.

Acked-by: Serge Hallyn <[email protected]>
Signed-off-by: "Eric W. Biederman" <[email protected]>
  • Loading branch information
ebiederm committed Dec 15, 2012
1 parent 520d9ea commit 5e4a084
Show file tree
Hide file tree
Showing 5 changed files with 10 additions and 5 deletions.
3 changes: 2 additions & 1 deletion fs/namespace.c
Original file line number Diff line number Diff line change
Expand Up @@ -2781,7 +2781,8 @@ static int mntns_install(struct nsproxy *nsproxy, void *ns)
struct path root;

if (!ns_capable(mnt_ns->user_ns, CAP_SYS_ADMIN) ||
!nsown_capable(CAP_SYS_CHROOT))
!nsown_capable(CAP_SYS_CHROOT) ||
!nsown_capable(CAP_SYS_ADMIN))
return -EPERM;

if (fs->users != 1)
Expand Down
3 changes: 2 additions & 1 deletion ipc/namespace.c
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,8 @@ static void ipcns_put(void *ns)
static int ipcns_install(struct nsproxy *nsproxy, void *new)
{
struct ipc_namespace *ns = new;
if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN))
if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN) ||
!nsown_capable(CAP_SYS_ADMIN))
return -EPERM;

/* Ditch state from the old ipc namespace */
Expand Down
3 changes: 2 additions & 1 deletion kernel/pid_namespace.c
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,8 @@ static int pidns_install(struct nsproxy *nsproxy, void *ns)
struct pid_namespace *active = task_active_pid_ns(current);
struct pid_namespace *ancestor, *new = ns;

if (!ns_capable(new->user_ns, CAP_SYS_ADMIN))
if (!ns_capable(new->user_ns, CAP_SYS_ADMIN) ||
!nsown_capable(CAP_SYS_ADMIN))
return -EPERM;

/*
Expand Down
3 changes: 2 additions & 1 deletion kernel/utsname.c
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,8 @@ static int utsns_install(struct nsproxy *nsproxy, void *new)
{
struct uts_namespace *ns = new;

if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN))
if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN) ||
!nsown_capable(CAP_SYS_ADMIN))
return -EPERM;

get_uts_ns(ns);
Expand Down
3 changes: 2 additions & 1 deletion net/core/net_namespace.c
Original file line number Diff line number Diff line change
Expand Up @@ -649,7 +649,8 @@ static int netns_install(struct nsproxy *nsproxy, void *ns)
{
struct net *net = ns;

if (!ns_capable(net->user_ns, CAP_SYS_ADMIN))
if (!ns_capable(net->user_ns, CAP_SYS_ADMIN) ||
!nsown_capable(CAP_SYS_ADMIN))
return -EPERM;

put_net(nsproxy->net_ns);
Expand Down

0 comments on commit 5e4a084

Please sign in to comment.