mirror of
https://github.com/torvalds/linux.git
synced 2024-11-22 12:11:40 +00:00
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: Serge Hallyn <serge.hallyn@canonical.com> Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
This commit is contained in:
parent
520d9eabce
commit
5e4a08476b
@ -2781,7 +2781,8 @@ static int mntns_install(struct nsproxy *nsproxy, void *ns)
|
|||||||
struct path root;
|
struct path root;
|
||||||
|
|
||||||
if (!ns_capable(mnt_ns->user_ns, CAP_SYS_ADMIN) ||
|
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;
|
return -EPERM;
|
||||||
|
|
||||||
if (fs->users != 1)
|
if (fs->users != 1)
|
||||||
|
@ -170,7 +170,8 @@ static void ipcns_put(void *ns)
|
|||||||
static int ipcns_install(struct nsproxy *nsproxy, void *new)
|
static int ipcns_install(struct nsproxy *nsproxy, void *new)
|
||||||
{
|
{
|
||||||
struct ipc_namespace *ns = 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;
|
return -EPERM;
|
||||||
|
|
||||||
/* Ditch state from the old ipc namespace */
|
/* Ditch state from the old ipc namespace */
|
||||||
|
@ -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 *active = task_active_pid_ns(current);
|
||||||
struct pid_namespace *ancestor, *new = ns;
|
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;
|
return -EPERM;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -113,7 +113,8 @@ static int utsns_install(struct nsproxy *nsproxy, void *new)
|
|||||||
{
|
{
|
||||||
struct uts_namespace *ns = 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;
|
return -EPERM;
|
||||||
|
|
||||||
get_uts_ns(ns);
|
get_uts_ns(ns);
|
||||||
|
@ -649,7 +649,8 @@ static int netns_install(struct nsproxy *nsproxy, void *ns)
|
|||||||
{
|
{
|
||||||
struct net *net = 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;
|
return -EPERM;
|
||||||
|
|
||||||
put_net(nsproxy->net_ns);
|
put_net(nsproxy->net_ns);
|
||||||
|
Loading…
Reference in New Issue
Block a user