Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5e4a0847 authored by Eric W. Biederman's avatar Eric W. Biederman
Browse files

userns: Require CAP_SYS_ADMIN for most uses of setns.



Andy Lutomirski <luto@amacapital.net> 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: default avatarSerge Hallyn <serge.hallyn@canonical.com>
Signed-off-by: default avatar"Eric W. Biederman" <ebiederm@xmission.com>
parent 520d9eab
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -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)
+2 −1
Original line number Diff line number Diff line
@@ -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 */
+2 −1
Original line number Diff line number Diff line
@@ -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;

	/*
+2 −1
Original line number Diff line number Diff line
@@ -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);
+2 −1
Original line number Diff line number Diff line
@@ -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);