Skip to contentSkip to conversation

Requirements for CAP_SYS_ADMIN on setns() ?

DISCUSSION Daniel P. Berrange 5 participants 9 messages Jun 6, 2013 – Jun 9, 2013 5 messages not in the archive

lore
Share & tools
lore
#0 lore raw

IIUC, currently, in order to be able to invoke setns() the calling process is required to have CAP_SYS_ADMIN capability. Alternatively with user namespaces, access is allowed if the process' effective uid matches the uid of the owner of the namespace.

I have a scenario though that isn't dealt with by those rules. I have a container that was spawned by uid == 0, and I have an unprivileged process uid != 0 in the initial namespace that I wish to allow to enter the namespaces associated with the container.

With the CAP_SYS_ADMIN rule on setns(), it seems that the unprivileged process will need to execute some setuid binary in order to gain the CAP_SYS_ADMIN capability required to call setns().

Of course you can't call setns() without first obtaining a file descriptor corresponding to the /proc/$CONTAINERPID/ns/XXXX namespace you wish to join. This appears to require elevated privileges too.

Is it not sufficient to rely on the permissions on the /proc/$PID/ns/XXX file to control access to a namespace, and thus allow setns() without
a CAP_SYS_ADMIN check ? ie setns() is basically useless unless you
already have sufficient privileges to get a file descriptor for the namespace, so why does setns need an additional privilege check beyond that done at time of open() on the proc file.

In my scenario this would allow for a privileged daemon to open the /proc/$PID/ns/XXX file, and then pass the file descriptor back to the unprivileged process using SCM_RIGHTS, which could then invoke setns(). This kind of privilege separation is perferrable to requiring the unprivileged process to run some kind of setuid program to gain the CAP_SYS_ADMIN capability.

Regards,
Daniel

Signature · 4 lines
|: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org              -o-             http://virt-manager.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org       -o-       http://live.gnome.org/gtk-vnc :|

A message that is not in the archive (sent off-list or not yet received): [email protected]

#2 lore raw
Quoted 32 lines · Daniel P. Berrange

IIUC, currently, in order to be able to invoke setns() the calling process is required to have CAP_SYS_ADMIN capability. Alternatively with user namespaces, access is allowed if the process' effective uid matches the uid of the owner of the namespace.

I have a scenario though that isn't dealt with by those rules. I have a container that was spawned by uid == 0, and I have an unprivileged process uid != 0 in the initial namespace that I wish to allow to enter the namespaces associated with the container.

With the CAP_SYS_ADMIN rule on setns(), it seems that the unprivileged process will need to execute some setuid binary in order to gain the CAP_SYS_ADMIN capability required to call setns().

Of course you can't call setns() without first obtaining a file descriptor corresponding to the /proc/$CONTAINERPID/ns/XXXX namespace you wish to join. This appears to require elevated privileges too.

Is it not sufficient to rely on the permissions on the /proc/$PID/ns/XXX file to control access to a namespace, and thus allow setns() without
a CAP_SYS_ADMIN check ? ie setns() is basically useless unless you
already have sufficient privileges to get a file descriptor for the namespace, so why does setns need an additional privilege check beyond that done at time of open() on the proc file.

In my scenario this would allow for a privileged daemon to open the /proc/$PID/ns/XXX file, and then pass the file descriptor back to the unprivileged process using SCM_RIGHTS, which could then invoke setns(). This kind of privilege separation is perferrable to requiring the unprivileged process to run some kind of setuid program to gain the CAP_SYS_ADMIN capability.

Quoted 2 lines

Regards,
Daniel

Hey Daniel,

it's possible that as things settle down we can find ways to relax this, but note that this behavior was very specifically added by the commit below. Very unfortunate that this is a feature regression over the CONFIG_USER_NS=n case :(

5e4a08476b50fa39210fca82e03325cc46b9c235

Author: Eric W. Biederman <ebiederm-aS9lmoZGLiVWk0Htik3J/[email protected]>
Date:   Fri Dec 14 07:55:36 2012 -0800
    userns: Require CAP_SYS_ADMIN for most uses of setns.
    
    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.
#3 lore raw
Quoted 36 lines · Serge Hallyn
Quoted 32 lines · Daniel P. Berrange

IIUC, currently, in order to be able to invoke setns() the calling process is required to have CAP_SYS_ADMIN capability. Alternatively with user namespaces, access is allowed if the process' effective uid matches the uid of the owner of the namespace.

I have a scenario though that isn't dealt with by those rules. I have a container that was spawned by uid == 0, and I have an unprivileged process uid != 0 in the initial namespace that I wish to allow to enter the namespaces associated with the container.

With the CAP_SYS_ADMIN rule on setns(), it seems that the unprivileged process will need to execute some setuid binary in order to gain the CAP_SYS_ADMIN capability required to call setns().

Of course you can't call setns() without first obtaining a file descriptor corresponding to the /proc/$CONTAINERPID/ns/XXXX namespace you wish to join. This appears to require elevated privileges too.

Is it not sufficient to rely on the permissions on the /proc/$PID/ns/XXX file to control access to a namespace, and thus allow setns() without
a CAP_SYS_ADMIN check ? ie setns() is basically useless unless you
already have sufficient privileges to get a file descriptor for the namespace, so why does setns need an additional privilege check beyond that done at time of open() on the proc file.

In my scenario this would allow for a privileged daemon to open the /proc/$PID/ns/XXX file, and then pass the file descriptor back to the unprivileged process using SCM_RIGHTS, which could then invoke setns(). This kind of privilege separation is perferrable to requiring the unprivileged process to run some kind of setuid program to gain the CAP_SYS_ADMIN capability.

Quoted 2 lines

Regards,
Daniel

Quoted 6 lines

Hey Daniel,

it's possible that as things settle down we can find ways to relax this, but note that this behavior was very specifically added by the commit below. Very unfortunate that this is a feature regression over the CONFIG_USER_NS=n case :(

No this is not a feature regression over the CONFIG_USER_NS=n case. The patch was a setns bug fix. The situation Daniel wants to use is exploitable.

Allowing an unprivileged user to call setns allows confusing suid root processes.

It is completely possible for Daniels situation to work of the unprivileged user calls setns first. That is allowed.

Eric

A message that is not in the archive (sent off-list or not yet received): 87txlb8atb.fsf-aS9lmoZGLiVWk0Htik3J/[email protected]

#5 lore raw
Quoted 49 lines · Eric W. Biederman
Quoted 36 lines · Serge Hallyn
Quoted 32 lines · Daniel P. Berrange

IIUC, currently, in order to be able to invoke setns() the calling process is required to have CAP_SYS_ADMIN capability. Alternatively with user namespaces, access is allowed if the process' effective uid matches the uid of the owner of the namespace.

I have a scenario though that isn't dealt with by those rules. I have a container that was spawned by uid == 0, and I have an unprivileged process uid != 0 in the initial namespace that I wish to allow to enter the namespaces associated with the container.

With the CAP_SYS_ADMIN rule on setns(), it seems that the unprivileged process will need to execute some setuid binary in order to gain the CAP_SYS_ADMIN capability required to call setns().

Of course you can't call setns() without first obtaining a file descriptor corresponding to the /proc/$CONTAINERPID/ns/XXXX namespace you wish to join. This appears to require elevated privileges too.

Is it not sufficient to rely on the permissions on the /proc/$PID/ns/XXX file to control access to a namespace, and thus allow setns() without
a CAP_SYS_ADMIN check ? ie setns() is basically useless unless you
already have sufficient privileges to get a file descriptor for the namespace, so why does setns need an additional privilege check beyond that done at time of open() on the proc file.

In my scenario this would allow for a privileged daemon to open the /proc/$PID/ns/XXX file, and then pass the file descriptor back to the unprivileged process using SCM_RIGHTS, which could then invoke setns(). This kind of privilege separation is perferrable to requiring the unprivileged process to run some kind of setuid program to gain the CAP_SYS_ADMIN capability.

Quoted 2 lines

Regards,
Daniel

Quoted 6 lines

Hey Daniel,

it's possible that as things settle down we can find ways to relax this, but note that this behavior was very specifically added by the commit below. Very unfortunate that this is a feature regression over the CONFIG_USER_NS=n case :(

No this is not a feature regression over the CONFIG_USER_NS=n case. The patch was a setns bug fix. The situation Daniel wants to use is exploitable.

Quoted 5 lines

Allowing an unprivileged user to call setns allows confusing suid root processes.

It is completely possible for Daniels situation to work of the unprivileged user calls setns first. That is allowed.

Oh, hm. I thought that in the thread leading up to this email, the original reporter said that in a kernel with CONFIG_USER_NS=n, an unprivileged user could setns(fd) to an fd sent by a privileged process, whereas the same situation with CONFIG_USER_NS=y was not allowed. I probably misunderstood.

-serge

A message that is not in the archive (sent off-list or not yet received): 20130606164428.GA4687-anj0Drq5vpzx6HRWoRZK3AC/[email protected]

#7 lore raw
Quoted 7 lines · Serge E. Hallyn
Quoted 6 lines · Eric W. Biederman
Quoted 4 lines · Serge Hallyn
Quoted 3 lines · Daniel P. Berrange

Is it not sufficient to rely on the permissions on the /proc/$PID/ns/XXX file to control access to a namespace, and thus allow setns() without a CAP_SYS_ADMIN check ?

The permissions on /proc/$PID/ns/XXX are sufficient to control access but they are not ok to allow use.

Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines

ie setns() is basically useless unless you
already have sufficient privileges to get a file descriptor for the namespace, so why does setns need an additional privilege check beyond that done at time of open() on the proc file.

To be very clear.

setns requires CAP_SYS_ADMIN because changing the namespaces for your children can result in tricking a suid root application and thus lead to privilege escalation.

If you run setns inside a user namespace that you control the privilege escalation is not possible and so setns is allowed.

Eric

A message that is not in the archive (sent off-list or not yet received): 87bo7j6r80.fsf-aS9lmoZGLiVWk0Htik3J/[email protected]

#9 lore raw
Quoted 18 lines · Eric W. Biederman
Quoted 7 lines · Serge E. Hallyn
Quoted 6 lines · Eric W. Biederman
Quoted 4 lines · Serge Hallyn
Quoted 3 lines · Daniel P. Berrange

Is it not sufficient to rely on the permissions on the /proc/$PID/ns/XXX file to control access to a namespace, and thus allow setns() without a CAP_SYS_ADMIN check ?

The permissions on /proc/$PID/ns/XXX are sufficient to control access but they are not ok to allow use.

Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines

ie setns() is basically useless unless you
already have sufficient privileges to get a file descriptor for the namespace, so why does setns need an additional privilege check beyond that done at time of open() on the proc file.

Quoted 5 lines

To be very clear.

setns requires CAP_SYS_ADMIN because changing the namespaces for your children can result in tricking a suid root application and thus lead to privilege escalation.

Yep, ok I see that from the example shown earlier in the thread.

Quoted 2 lines

If you run setns inside a user namespace that you control the privilege escalation is not possible and so setns is allowed.

What are the privilege requirements for being able to call setns() on a user namespace FD ?

Thinking some more, if there was a setpidns(pid_t containerpid) syscall which unconditionally joined the caller to all namespaces associated with the target pid, then you'd not have the security risk described, right ?

Daniel

Signature · 4 lines
|: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org              -o-             http://virt-manager.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org       -o-       http://live.gnome.org/gtk-vnc :|

A message that is not in the archive (sent off-list or not yet received): [email protected]

#11 lore raw
Quoted 25 lines · Daniel P. Berrange
Quoted 18 lines · Eric W. Biederman
Quoted 7 lines · Serge E. Hallyn
Quoted 6 lines · Eric W. Biederman
Quoted 4 lines · Serge Hallyn
Quoted 3 lines · Daniel P. Berrange

Is it not sufficient to rely on the permissions on the /proc/$PID/ns/XXX file to control access to a namespace, and thus allow setns() without a CAP_SYS_ADMIN check ?

The permissions on /proc/$PID/ns/XXX are sufficient to control access but they are not ok to allow use.

Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines

ie setns() is basically useless unless you
already have sufficient privileges to get a file descriptor for the namespace, so why does setns need an additional privilege check beyond that done at time of open() on the proc file.

Quoted 5 lines

To be very clear.

setns requires CAP_SYS_ADMIN because changing the namespaces for your children can result in tricking a suid root application and thus lead to privilege escalation.

Quoted 7 lines

Yep, ok I see that from the example shown earlier in the thread.

Quoted 2 lines

If you run setns inside a user namespace that you control the privilege escalation is not possible and so setns is allowed.

What are the privilege requirements for being able to call setns() on a user namespace FD ?

That you are not threaded and the user namespace is a child of the current user namespace that you have CAP_SYS_ADMIN rights over.

Essentially the requirement is that it is a user namespace that your uid created.

Quoted 3 lines

Thinking some more, if there was a setpidns(pid_t containerpid) syscall which unconditionally joined the caller to all namespaces associated with the target pid, then you'd not have the security risk described, right ?

The security risk is present unless you join the user namespace, as namespaces can be a bit leaky (fd passing etc). At the same time the user namespace is sufficient to remove the security risk, as privilege escalation is not possible in the user namespace so even if you fool a suid application it does not matter.

Eric

#12 lore raw
In reply to a message not in the archive

Waaaay behind on my email...

Quoted 12 lines · Daniel P. Berrange
Quoted 2 lines · Eric W. Biederman

"Serge E. Hallyn" <[email protected]> writes:
setns requires CAP_SYS_ADMIN because changing the namespaces for

your

Quoted 1 line

children can result in tricking a suid root application and thus

lead

Quoted 1 line

to privilege escalation.

Yep, ok I see that from the example shown earlier in the thread.

Quoted 1 line

If you run setns inside a user namespace that you control the

privilege

Quoted 8 lines
Quoted 1 line

escalation is not possible and so setns is allowed.

What are the privilege requirements for being able to call setns() on a user namespace FD ?

Thinking some more, if there was a setpidns(pid_t containerpid) syscall which unconditionally joined the caller to all namespaces associated with the target pid, then you'd not have the security risk described, right ?

Sounds like you want a reparent_to_init() that works for a container's init.

Rob

#13 lore raw
Quoted 27 lines · Rob Landley

Waaaay behind on my email...

Quoted 17 lines · Daniel P. Berrange
Quoted 2 lines · Eric W. Biederman

"Serge E. Hallyn" <[email protected]> writes:
setns requires CAP_SYS_ADMIN because changing the namespaces for

your

Quoted 1 line

children can result in tricking a suid root application and thus

lead

Quoted 1 line

to privilege escalation.

Yep, ok I see that from the example shown earlier in the thread.

Quoted 1 line

If you run setns inside a user namespace that you control the

privilege

Quoted 1 line

escalation is not possible and so setns is allowed.

What are the privilege requirements for being able to call setns() on a user namespace FD ?

Quoted 6 lines

Thinking some more, if there was a setpidns(pid_t containerpid) syscall
which unconditionally joined the caller to all namespaces associated with
the target pid, then you'd not have the security risk described, right ?

Quoted 2 lines

Sounds like you want a reparent_to_init() that works for a container's init.

setns on all of the namespaces effectively gives you that ability. You probably want to play with cgroups and a few other similar things. And there is a utility in util-linux that automates at least the namespace portion of this called nsenter.

Eric