lxc-user-nic does not ensure that target netns is caller-owned

Bug #1654676 reported by Jann Horn (corp account) on 2017-01-06
260
This bug affects 1 person
Affects Status Importance Assigned to Milestone
lxc (Ubuntu)
Undecided
Christian Brauner

Bug Description

The documentation for lxc-user-nic claims:

      It ensures that the calling
      user is privileged over the network namespace to which the interface
      will be attached.

Actually, the code only verifies that a process of the calling user is running in the network namespace to which the interface will be attached. To verify this:

 - As root, create a new bridge "lxcbr0".
 - As root, add an entry like "user veth lxcbr0 10" to
   /etc/lxc/lxc-usernet.
 - As the user specified in /etc/lxc/lxc-usernet, run the following
   command:
   /usr/lib/x86_64-linux-gnu/lxc/lxc-user-nic a b $$ veth lxcbr0 foobar
 - Run "ip link show foobar". The output shows that a network interface
   with the name "foobar" was created in the init namespace (in which the
   user is not privileged).

I suspect that it would also be possible to trick lxc-user-nic into operating on namespaces the caller can't access by reassigning the PID while lxc-user-nic is running, between the access check and the netlink calls - this is probably quite hard to fix, considering that the netlink interface just uses a PID to identify the target namespace.

I haven't found any way to actually exploit this; however, it seems interesting that this can e.g. be used to create network interfaces whose names contain special characters like dollar, semicolon and backtick. I'm not sure how dangerous that is - I'm reporting it as a security bug for now, but if you feel that this has no security impact, feel free to derestrict it.

One way to fix this might be to temporarily drop privileges (setresuid(ruid, ruid, 0)) in rename_in_ns() after the first setns() call. This way, the renaming could only succeed if the caller is actually privileged in the network namespace.

release: Ubuntu 16.10
version: lxc-common: 2.0.6-0ubuntu1~ubuntu16.10.1

CVE References

description: updated
Tyler Hicks (tyhicks) wrote :

Thanks for the report, Jann. I've subscribed the LXC security team to get their opinion.

Serge Hallyn (serge-hallyn) wrote :

Hi,

thanks for taking a close look at this. Indeed, this is one of the two pieces of unprivileged container startup which run with raised privilege, which we would much rather have running without. There may be better ways to structure this, and perhaps we should brainstorm and discuss them during the upcoming lxc hackfest before FOSDEM.

Going over lxc-user-nic as it stands now, the specific concern you raise *appears* to be addressed by the use of 'may_access_netns(pid)', which ensures that the caller is privileged over the network namespace being manipulated. If you see specific problems there, please let us know, but this should address exactly what is mentioned in this bug subject.

The other thing you mention is bad nic names. This *shouldn't* be an issue since the caller is privileged over his own network namespace (the target), so may confuse his tools however he likes; however outside administrators may end up trying to look inside the container and get confused, so perhaps some sanity checks on special characters would be worthwhile. The main counterpoint to that is that the container admin could always just re-add the special characters later, so we're not really adding any security by preventing it at container startup.

I'm going to keep this bug open for now as we have this conversation. Thanks again.

may_access_netns(pid) only checks whether the ruid has read access to /proc/$pid/ns/net. However, being able to open that special file does not imply any kind of privilege over the target namespace, it just implies privilege over the process that is inside the namespace. To test this, you can e.g. run the following command as a normal user:

    strace cat /proc/$$/ns/net 2>&1 | grep open.*ns/net

Have you tried running the commands from my bug report?

Stéphane Graber (stgraber) wrote :

Hey there,

Just wanted to update this issue to let you know that most of the LXC/LXD team is travelling this week and that we should be able to look into this much closer next week.

Serge Hallyn (serge-hallyn) wrote :

Hi,

> Have you tried running the commands from my bug report?

1 ✗ serge@sl ~ $ /usr/lib/x86_64-linux-gnu/lxc/lxc-user-nic a b $$ veth lxcbr0 foobar
Failed opening network namespace path for '28684'.Failed to rename the link
1 ✗ serge@sl ~ $ ip link show foobar
Device "foobar" does not exist.

I'm on Linux sl 4.4.0-59-generic #80-Ubuntu SMP Fri Jan 6 17:47:47 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux

Which kernel did you test under?

Download full text (4.0 KiB)

I'm testing on Ubuntu Server 16.10, with kernel 4.8.0-32-generic. In case it helps, here's an execution with bridge setup and various pieces of system information.

Script started on Fri 13 Jan 2017 11:37:55 AM CET
user@ubuntu:~$ sudo bash
[sudo] password for user:
root@ubuntu:~# ip link add name lxcbr0 type bridge
root@ubuntu:~# ip link set lxcbr0 up
root@ubuntu:~# exit
user@ubuntu:~$ /usr/lib/x86_64-linux-gnu/lxc/lxc-user-nic a b $$ veth lxcbr0 foobar
foobar:vethQ1C4AQ
user@ubuntu:~$ ip link show foobar
6: foobar@vethQ1C4AQ: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 8e:6e:3b:96:66:c6 brd ff:ff:ff:ff:ff:ff
user@ubuntu:~$ uname -a
Linux ubuntu 4.8.0-32-generic #34-Ubuntu SMP Tue Dec 13 14:30:43 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
user@ubuntu:~$ cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=16.10
DISTRIB_CODENAME=yakkety
DISTRIB_DESCRIPTION="Ubuntu 16.10"
user@ubuntu:~$ cat /etc/apt/sources.list
#

# deb cdrom:[Ubuntu-Server 16.10 _Yakkety Yak_ - Release amd64 (20161012.1)]/ yakkety main restricted

#deb cdrom:[Ubuntu-Server 16.10 _Yakkety Yak_ - Release amd64 (20161012.1)]/ yakkety main restricted

# See http://help.ubuntu.com/community/UpgradeNotes for how to upgrade to
# newer versions of the distribution.
deb http://ch.archive.ubuntu.com/ubuntu/ yakkety main restricted
# deb-src http://ch.archive.ubuntu.com/ubuntu/ yakkety main restricted

## Major bug fix updates produced after the final release of the
## distribution.
deb http://ch.archive.ubuntu.com/ubuntu/ yakkety-updates main restricted
# deb-src http://ch.archive.ubuntu.com/ubuntu/ yakkety-updates main restricted

## N.B. software from this repository is ENTIRELY UNSUPPORTED by the Ubuntu
## team. Also, please note that software in universe WILL NOT receive any
## review or updates from the Ubuntu security team.
deb http://ch.archive.ubuntu.com/ubuntu/ yakkety universe
# deb-src http://ch.archive.ubuntu.com/ubuntu/ yakkety universe
deb http://ch.archive.ubuntu.com/ubuntu/ yakkety-updates universe
# deb-src http://ch.archive.ubuntu.com/ubuntu/ yakkety-updates universe

## N.B. software from this repository is ENTIRELY UNSUPPORTED by the Ubuntu
## team, and may not be under a free licence. Please satisfy yourself as to
## your rights to use the software. Also, please note that software in
## multiverse WILL NOT receive any review or updates from the Ubuntu
## security team.
deb http://ch.archive.ubuntu.com/ubuntu/ yakkety multiverse
# deb-src http://ch.archive.ubuntu.com/ubuntu/ yakkety multiverse
deb http://ch.archive.ubuntu.com/ubuntu/ yakkety-updates multiverse
# deb-src http://ch.archive.ubuntu.com/ubuntu/ yakkety-updates multiverse

## N.B. software from this repository may not have been tested as
## extensively as that contained in the main release, although it includes
## newer versions of some applications which may provide useful features.
## Also, please note that software in backports WILL NOT receive any review
## or updates from the Ubuntu security team.
deb http://ch.archive.ubuntu.com/ubuntu/ yakkety-backports main restricted universe multiverse
# deb-src http://ch.archive.ubuntu.com/ubuntu...

Read more...

I just tested it in a Ubuntu Desktop 16.04.1 LTS install with kernel 4.4.0-59-generic #80-Ubuntu (same one you used), and it also worked there.

Maybe you could try debugging it like this to figure out what's going on? (Running strace as root ensures that setuid binaries still work properly because bprm->unsafe==LSM_UNSAFE_PTRACE_CAP instead of bprm->unsafe==LSM_UNSAFE_PTRACE.)

user@user-VirtualBox:~$ sudo strace -f sudo -u user /usr/lib/x86_64-linux-gnu/lxc/lxc-user-nic a b $$ veth lxcbr0 qux 2>&1 | grep /proc/
open("/proc/filesystems", O_RDONLY) = 3
open("/proc/sys/kernel/ngroups_max", O_RDONLY) = 3
open("/proc/2632/stat", O_RDONLY) = 3
open("/proc/sys/kernel/ngroups_max", O_RDONLY) = 8
readlink("/proc/self/fd/0", "/dev/pts/17", 31) = 11
readlink("/proc/self/exe", "/usr/bin/sudo", 4096) = 13
[pid 2633] open("/proc/self/fd", O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC) = 4
[pid 2633] open("/proc/filesystems", O_RDONLY) = 3
[pid 2633] open("/proc/1/cgroup", O_RDONLY) = 3
[pid 2633] open("/proc/self/mountinfo", O_RDONLY) = 3
[pid 2633] open("/proc/self/cgroup", O_RDONLY) = 4
[pid 2633] access("/proc/1739/ns/net", R_OK) = 0
[pid 2633] access("/proc/net", R_OK) = 0
[pid 2633] access("/proc/net/unix", R_OK) = 0
[pid 2633] open("/proc/2633/ns/net", O_RDONLY|O_CLOEXEC) = 3
[pid 2633] open("/proc/1739/ns/net", O_RDONLY|O_CLOEXEC) = 4

Hi Jann,

I managed to reproduce this following the steps you outlined. I will wait for
@Serge to figure out why he was not able to reproduce this.

Christian

On Fri, Jan 13, 2017 at 10:49:08AM -0000, Jann Horn (Google) wrote:
> I'm testing on Ubuntu Server 16.10, with kernel 4.8.0-32-generic. In
> case it helps, here's an execution with bridge setup and various pieces
> of system information.
>
> Script started on Fri 13 Jan 2017 11:37:55 AM CET
> user@ubuntu:~$ sudo bash
> [sudo] password for user:
> root@ubuntu:~# ip link add name lxcbr0 type bridge
> root@ubuntu:~# ip link set lxcbr0 up
> root@ubuntu:~# exit
> user@ubuntu:~$ /usr/lib/x86_64-linux-gnu/lxc/lxc-user-nic a b $$ veth lxcbr0 foobar
> foobar:vethQ1C4AQ
> user@ubuntu:~$ ip link show foobar
> 6: foobar@vethQ1C4AQ: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
> link/ether 8e:6e:3b:96:66:c6 brd ff:ff:ff:ff:ff:ff
> user@ubuntu:~$ uname -a
> Linux ubuntu 4.8.0-32-generic #34-Ubuntu SMP Tue Dec 13 14:30:43 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
> user@ubuntu:~$ cat /etc/lsb-release
> DISTRIB_ID=Ubuntu
> DISTRIB_RELEASE=16.10
> DISTRIB_CODENAME=yakkety
> DISTRIB_DESCRIPTION="Ubuntu 16.10"
> user@ubuntu:~$ cat /etc/apt/sources.list

<snip>

Serge Hallyn (serge-hallyn) wrote :

I can't explain why it doesn't work on my laptop. In a fresh xenial container, using the same ppa I use on my laptop and same kernel, I can reproduce it.

So while it's probably low priority as security issues go, I do think this is a security issue.

Christian, are you interested in floating a proposed fix for this here?

Christian Brauner (cbrauner) wrote :

So, yes, temporarily dropping privilege sounds fine. I'll come up with a proposed patch.

Christian Brauner (cbrauner) wrote :

@Jann, @Serge, please take a look at the proposed patch I attached here. :)

Nit: It would be a little bit more robust to explicitly specify CLONE_NEWNET in the setns() call.

Apart from that, I think it looks fine.

Christian Brauner (cbrauner) wrote :

@Jann, I'm going to do some more code-cleanup for lxc-user-nic and will likely add this as part of it.

Serge Hallyn (serge-hallyn) wrote :

Thanks! Looking.

On Sun, Jan 29, 2017 at 10:16 AM, Christian Brauner
<email address hidden> wrote:
> @Jann, I'm going to do some more code-cleanup for lxc-user-nic and will
> likely add this as part of it.
>
> --
> You received this bug notification because you are a member of Ubuntu
> Container Security team, which is subscribed to the bug report.
> https://bugs.launchpad.net/bugs/1654676
>
> Title:
> lxc-user-nic does not ensure that target netns is caller-owned
>
> Status in lxc package in Ubuntu:
> New
>
> Bug description:
> The documentation for lxc-user-nic claims:
>
> It ensures that the calling
> user is privileged over the network namespace to which the interface
> will be attached.
>
> Actually, the code only verifies that a process of the calling user is
> running in the network namespace to which the interface will be
> attached. To verify this:
>
> - As root, create a new bridge "lxcbr0".
> - As root, add an entry like "user veth lxcbr0 10" to
> /etc/lxc/lxc-usernet.
> - As the user specified in /etc/lxc/lxc-usernet, run the following
> command:
> /usr/lib/x86_64-linux-gnu/lxc/lxc-user-nic a b $$ veth lxcbr0 foobar
> - Run "ip link show foobar". The output shows that a network interface
> with the name "foobar" was created in the init namespace (in which the
> user is not privileged).
>
> I suspect that it would also be possible to trick lxc-user-nic into
> operating on namespaces the caller can't access by reassigning the PID
> while lxc-user-nic is running, between the access check and the
> netlink calls - this is probably quite hard to fix, considering that
> the netlink interface just uses a PID to identify the target
> namespace.
>
> I haven't found any way to actually exploit this; however, it seems
> interesting that this can e.g. be used to create network interfaces
> whose names contain special characters like dollar, semicolon and
> backtick. I'm not sure how dangerous that is - I'm reporting it as a
> security bug for now, but if you feel that this has no security
> impact, feel free to derestrict it.
>
> One way to fix this might be to temporarily drop privileges
> (setresuid(ruid, ruid, 0)) in rename_in_ns() after the first setns()
> call. This way, the renaming could only succeed if the caller is
> actually privileged in the network namespace.
>
> release: Ubuntu 16.10
> version: lxc-common: 2.0.6-0ubuntu1~ubuntu16.10.1
>
> To manage notifications about this bug go to:
> https://bugs.launchpad.net/ubuntu/+source/lxc/+bug/1654676/+subscriptions

Serge Hallyn (serge-hallyn) wrote :

Thanks, Christian. Is there a reason why you don't set fret to -1 if the final setns fails?

Christian Brauner (cbrauner) wrote :

On Sun, Jan 29, 2017 at 8:44 PM, Serge Hallyn
<email address hidden> wrote:
> Thanks, Christian. Is there a reason why you don't set fret to -1 if
> the final setns fails?

If the setns() back to the original namespace fails but everything
else succeeded I didn't take it to be a security issue. lxc-user-nic
is pretty short-lived and we don't perform any interesting operations
in the namespace after rename_in_ns() succeeded. We rather exit right
away:

/* Now rename the link. */
if (rename_in_ns(pid, cnic, &vethname) < 0) {
        usernic_error("%s", "Failed to rename the link.\n");
        exit(EXIT_FAILURE);
}

/* Write the name of the interface pair to the stdout - like
* eth0:veth9MT2L4.
*/
fprintf(stdout, "%s:%s\n", vethname, nicname);
exit(EXIT_SUCCESS);

Serge Hallyn (serge-hallyn) wrote :
Download full text (3.2 KiB)

I understand, but it's unexpected, therefore noteworthy.

Sent from my BlackBerry 10 smartphone.
  Original Message
From: Christian Brauner
Sent: Sunday, January 29, 2017 3:55 PM
To: <email address hidden>
Reply To: Bug 1654676
Subject: Re: [Bug 1654676] Re: lxc-user-nic does not ensure that target netns is caller-owned

On Sun, Jan 29, 2017 at 8:44 PM, Serge Hallyn
<email address hidden> wrote:
> Thanks, Christian. Is there a reason why you don't set fret to -1 if
> the final setns fails?

If the setns() back to the original namespace fails but everything
else succeeded I didn't take it to be a security issue. lxc-user-nic
is pretty short-lived and we don't perform any interesting operations
in the namespace after rename_in_ns() succeeded. We rather exit right
away:

/* Now rename the link. */
if (rename_in_ns(pid, cnic, &vethname) < 0) {
usernic_error("%s", "Failed to rename the link.\n");
exit(EXIT_FAILURE);
}

/* Write the name of the interface pair to the stdout - like
* eth0:veth9MT2L4.
*/
fprintf(stdout, "%s:%s\n", vethname, nicname);
exit(EXIT_SUCCESS);

--
You received this bug notification because you are a member of Ubuntu
Container Security team, which is subscribed to the bug report.
https://bugs.launchpad.net/bugs/1654676

Title:
lxc-user-nic does not ensure that target netns is caller-owned

Status in lxc package in Ubuntu:
New

Bug description:
The documentation for lxc-user-nic claims:

      It ensures that the calling
      user is privileged over the network namespace to which the interface
      will be attached.

Actually, the code only verifies that a process of the calling user is
running in the network namespace to which the interface will be
attached. To verify this:

 - As root, create a new bridge "lxcbr0".
 - As root, add an entry like "user veth lxcbr0 10" to
/etc/lxc/lxc-usernet.
 - As the user specified in /etc/lxc/lxc-usernet, run the following
command:
  /usr/lib/x86_64-linux-gnu/lxc/lxc-user-nic a b $$ veth lxcbr0 foobar
 - Run "ip link show foobar". The output shows that a network interface
with the name "foobar" was created in the init namespace (in which the
user is not privileged).

I suspect that it would also be possible to trick lxc-user-nic into
operating on namespaces the caller can't access by reassigning the PID
while lxc-user-nic is running, between the access check and the
netlink calls - this is probably quite hard to fix, considering that
the netlink interface just uses a PID to identify the target
namespace.

I haven't found any way to actually exploit this; however, it seems
interesting that this can e.g. be used to create network interfaces
whose names contain special characters like dollar, semicolon and
backtick. I'm not sure how dangerous that is - I'm reporting it as a
security bug for now, but if you feel that this has no security
impact, feel free to derestrict it.

One way to fix this might be to temporarily drop privileges
(setresuid(ruid, ruid, 0)) in rename_in_ns() after the first setns()
call. This way, the renaming could only succeed if the caller is
actually privileged in the network namespace.

release: Ubuntu 16.10
version: lxc-common: 2.0.6-0ubuntu1~ubuntu16.10.1
...

Read more...

Serge Hallyn (serge-hallyn) wrote :

On second thought, I've convinced myself on irc that there is a legitimate case where this would fail, which current lxc would not support. If I create a container in a new userns without a separate netns (sharing the parent netns), then want to create a unpriv container in there, then the setns back to original will (if i'm thinking right) fail.

Christian Brauner (cbrauner) wrote :

@Serge, I'm not entirely clear if by "would not support" you're trying to imply
that we should actually fail when setns() back fails.
To me it feels like we want is what is happening in the patch,
meaning we don't want to fail.
Given the premises in your argument, what I understand is:
1) You're in a new user namespace u1 but share the parent's network namespace n0.
2) You're cloning a new user namespace u2 and a new network namespace n1 in user namespace u1.
3) You're then using setns(n1_fd, CLONE_NEWNET) and rename a veth device.
4) You're using setns(n0_fd, CLONE_NEWNET) to attach back to network namespace n0.

1)-3) should succeed.
4) should fail.
But 4) failing is not sufficient reason to ban the user from being successful
in administering veth devices in a network namespace (here n1) where it has sufficient
privileges, right?
So I'd argue we should let the patch stand as it is, no?

Serge Hallyn (serge-hallyn) wrote :

As i said,

"I've convinced myself on irc that there is a legitimate case where this would fail, which current lxc would not support"

It's a tradeoff in my mind. Remembering that lxc-user-nic runs as setuid-root, ignoring any unexpected failure is dangerous. That was the real cause of the sendmail-capabilities bug.

Actually, now I've just convinced myself that the above case is *not* legitimate.

If root is not able to setns() back to the original netns, then it also would not have been able to create a network device in that namespace, or attach it to the bridge in that namespace.

So there is, AFAICS, no legitimate case where setns(oldfd, 0) would fail, but execution should continue as normal.

Christian Brauner (cbrauner) wrote :

On Mon, Jan 30, 2017 at 4:58 PM, Serge Hallyn
<email address hidden> wrote:
> As i said,
>
> "I've convinced myself on irc that there is a legitimate case where this
> would fail, which current lxc would not support"
>
> It's a tradeoff in my mind. Remembering that lxc-user-nic runs as
> setuid-root, ignoring any unexpected failure is dangerous. That was the
> real cause of the sendmail-capabilities bug.
>
> Actually, now I've just convinced myself that the above case is *not*
> legitimate.
>
> If root is not able to setns() back to the original netns, then it also
> would not have been able to create a network device in that namespace,
> or attach it to the bridge in that namespace.

That was my first conception but I was unable to console this with your first
argument. Of course, this also implies that we error out in any case
and the second setns(ofd, 0) still doesn't matter. But the point about
setuid is well
taken. I adjusted the patch accordingly and also inserted the CLONE_NEWNET
into the setns() calls like @Jann suggested. :)

Serge Hallyn (serge-hallyn) wrote :

Thanks, looks good.

Somewhat related - but not a blocker for this bug - is that if we fail at this point, we perhaps should try to clean up the nics we had created on the host. Maybe. On the other hand, if we try to clean up but do so in a buggy way, we could really mess with the host's network interfaces. So not something to rush into.

Stéphane Graber (stgraber) wrote :

Ok, so what we need from an upstream point of view is:
 - Patch for stable-1.0
 - Patch for stable-2.0
 - Patch for master

That will cover everything we care about and will let us prepare distribution uploads in the private security PPA.

Unless there is a rush on this, we'd like to delay the release of the security update by a couple of weeks to allow for the newly release LXD 2.0.7 to hit the various distributions and so we can then build the patched LXC on top of that rather than have to stop propagation of LXC 2.0.7 to push a patched 2.0.6.

Security team: Can we get a CVE for this?

Exploitation of this issue will allow an unprivileged LXC user with a valid lxc-usernet quota to create those interfaces in the host network namespace rather than inside a container.

In most cases this would merely pollute the host network namespace but be capped by the number of devices the user can create (lxc-usernet quota). The user won't be granted any kind of actual access to the create devices and the host side of the veth pair will still be connected to an authorized bridge. The user also will not be able to choose the name of the create device so can't use this to squat valid network device names on the host.

The one potential attack I can think of is if the host is somehow configured to auto-DHCP on any new network interface, in which case, the user would be able to create a normal LXC container, run a DHCP server there, trying to be faster than the one ran by LXC itself, and then create a veth in the host namespace, therefore allowing DHCP configuration of the host, potential attacks on the host DHCP client and routing host traffic through a container.

So as far as security issues go, I'd say this is a low priority one.

Stéphane Graber (stgraber) wrote :

So getting a CVE assigned to this may take a little while as the assignment process has changed in the past day or so and doesn't seem to cover the issuance of CVE numbers for embargoed issues.

Our security team is getting in touch with MITRE to sort this out and we'll get going with scheduling disclosure and preparing the various uploads once that's sorted out.

Christian Brauner (cbrauner) wrote :

Hi,

please find the necessary patches for all branches attached. Details
about branch-specific patches
can be found inline.

On Wed, Feb 1, 2017 at 11:53 AM, Stéphane Graber <email address hidden> wrote:
> Ok, so what we need from an upstream point of view is:
> - Patch for stable-1.0

There is a separate patch attached:
0001-security-ensure-target-netns-is-caller-owned_1point0.patch

@Serge, @Jann, please give the patches another look if in case
I messed something up.

Thanks again @Jann.
Thanks @Stéphane and the security team for sorting the MITRE stuff out!

Christian

Stéphane Graber (stgraber) wrote :

We got assigned CVE-2017-5985 for this issue.

Serge Hallyn (serge-hallyn) wrote :
Download full text (3.4 KiB)

Sorry for the delay. These look great, thanks!

  Original Message
From: Christian Brauner
Sent: Saturday, February 11, 2017 6:45 AM
To: <email address hidden>
Reply To: Bug 1654676
Subject: Re: [Bug 1654676] Re: lxc-user-nic does not ensure that target netns is caller-owned

Hi,

please find the necessary patches for all branches attached. Details
about branch-specific patches
can be found inline.

On Wed, Feb 1, 2017 at 11:53 AM, Stéphane Graber <email address hidden> wrote:
> Ok, so what we need from an upstream point of view is:
> - Patch for stable-1.0

There is a separate patch attached:
0001-security-ensure-target-netns-is-caller-owned_1point0.patch

@Serge, @Jann, please give the patches another look if in case
I messed something up.

Thanks again @Jann.
Thanks @Stéphane and the security team for sorting the MITRE stuff out!

Christian

** Patch added: "0001-security-ensure-target-netns-is-caller-owned_1point0.patch"
https://bugs.launchpad.net/bugs/1654676/+attachment/4816965/+files/0001-security-ensure-target-netns-is-caller-owned_1point0.patch

** Patch added: "0001-security-ensure-target-netns-is-caller-owned.patch"
https://bugs.launchpad.net/bugs/1654676/+attachment/4816966/+files/0001-security-ensure-target-netns-is-caller-owned.patch

--
You received this bug notification because you are a member of Ubuntu
Container Security team, which is subscribed to the bug report.
https://bugs.launchpad.net/bugs/1654676

Title:
lxc-user-nic does not ensure that target netns is caller-owned

Status in lxc package in Ubuntu:
New

Bug description:
The documentation for lxc-user-nic claims:

      It ensures that the calling
      user is privileged over the network namespace to which the interface
      will be attached.

Actually, the code only verifies that a process of the calling user is
running in the network namespace to which the interface will be
attached. To verify this:

 - As root, create a new bridge "lxcbr0".
 - As root, add an entry like "user veth lxcbr0 10" to
/etc/lxc/lxc-usernet.
 - As the user specified in /etc/lxc/lxc-usernet, run the following
command:
  /usr/lib/x86_64-linux-gnu/lxc/lxc-user-nic a b $$ veth lxcbr0 foobar
 - Run "ip link show foobar". The output shows that a network interface
with the name "foobar" was created in the init namespace (in which the
user is not privileged).

I suspect that it would also be possible to trick lxc-user-nic into
operating on namespaces the caller can't access by reassigning the PID
while lxc-user-nic is running, between the access check and the
netlink calls - this is probably quite hard to fix, considering that
the netlink interface just uses a PID to identify the target
namespace.

I haven't found any way to actually exploit this; however, it seems
interesting that this can e.g. be used to create network interfaces
whose names contain special characters like dollar, semicolon and
backtick. I'm not sure how dangerous that is - I'm reporting it as a
security bug for now, but if you feel that this has no security
impact, feel free to derestrict it.

One way to fix this might be to temporarily drop privileges
(setresuid(ruid, ruid, 0)) in rename_in_ns() after the first setns(...

Read more...

Stéphane Graber (stgraber) wrote :

Sorry for not following up on this before, we've been extremely busy fixing and pushing out a lot of LXD releases of the past couple of weeks.

So it looks like we all agree on the fix for this and I'll be uploading fixed Ubuntu packages to our security PPA early next week.

So now we need to figure out a release date for this. I'm going to be away on vacation between the 11th and the 17th, so would like to avoid releasing during that time.

It looks like our best bet would be either this Thursday, 9th of March or Tuesday the 21st of March. I'm fine with either date though I'm a bit worried that the 9th may be too short notice for other distributions.

Security team: What's your opinion on this? And once we agree on one of the two dates, can you take care of notifying the other distros?

Thanks

Tyler Hicks (tyhicks) wrote :

On 03/04/2017 02:01 PM, Stéphane Graber wrote:
> Sorry for not following up on this before, we've been extremely busy
> fixing and pushing out a lot of LXD releases of the past couple of
> weeks.
>
> So it looks like we all agree on the fix for this and I'll be uploading
> fixed Ubuntu packages to our security PPA early next week.
>
>
> So now we need to figure out a release date for this. I'm going to be away on vacation between the 11th and the 17th, so would like to avoid releasing during that time.
>
> It looks like our best bet would be either this Thursday, 9th of March
> or Tuesday the 21st of March. I'm fine with either date though I'm a bit
> worried that the 9th may be too short notice for other distributions.
>
> Security team: What's your opinion on this? And once we agree on one of
> the two dates, can you take care of notifying the other distros?

I'll suggest the 9th on the distros list. If it isn't enough time,
another distro can ask for a later date.

Tyler

Stéphane Graber (stgraber) wrote :

Packages for zesty, yakkety, xenial, vivid and trusty uploaded to the LXC security PPA:
https://launchpad.net/~ubuntu-lxc-security/+archive/ubuntu/devirt-security/+packages

Stéphane Graber (stgraber) wrote :

Reproducer for the issue and fix confirmation:
```
root@xen:~# vim /etc/lxc/lxc-usernet
root@xen:~# cat /etc/lxc/lxc-usernet
# USERNAME TYPE BRIDGE COUNT
ubuntu veth lxcbr0 10
root@xen:~# su ubuntu
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.

ubuntu@xen:/root$ /usr/lib/x86_64-linux-gnu/lxc/lxc-user-nic a b $$ veth lxcbr0 foobar
foobar:vethHLBXWW

ubuntu@xen:/root$ ifconfig foobar
foobar Link encap:Ethernet HWaddr 36:00:39:bb:a0:84
          BROADCAST MULTICAST MTU:1500 Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)

ubuntu@xen:/root$ sudo ip link del foobar

root@xen:~# dpkg -i *.deb
(Reading database ... 25966 files and directories currently installed.)
Preparing to unpack liblxc1_2.0.7-0ubuntu1-16.04.2_amd64.deb ...
Unpacking liblxc1 (2.0.7-0ubuntu1~16.04.2) over (2.0.7-0ubuntu1~16.04.1) ...
Preparing to unpack lxc-common_2.0.7-0ubuntu1-16.04.2_amd64.deb ...
Unpacking lxc-common (2.0.7-0ubuntu1~16.04.2) over (2.0.7-0ubuntu1~16.04.1) ...
Preparing to unpack lxc-templates_2.0.7-0ubuntu1-16.04.2_amd64.deb ...
Unpacking lxc-templates (2.0.7-0ubuntu1~16.04.2) over (2.0.7-0ubuntu1~16.04.1) ...
Preparing to unpack lxc1_2.0.7-0ubuntu1-16.04.2_amd64.deb ...
Unpacking lxc1 (2.0.7-0ubuntu1~16.04.2) over (2.0.7-0ubuntu1~16.04.1) ...
Preparing to unpack python3-lxc_2.0.7-0ubuntu1-16.04.2_amd64.deb ...
Unpacking python3-lxc (2.0.7-0ubuntu1~16.04.2) over (2.0.7-0ubuntu1~16.04.1) ...
Setting up liblxc1 (2.0.7-0ubuntu1~16.04.2) ...
Setting up lxc-common (2.0.7-0ubuntu1~16.04.2) ...
Setting up python3-lxc (2.0.7-0ubuntu1~16.04.2) ...
Setting up lxc1 (2.0.7-0ubuntu1~16.04.2) ...
Setting up lxc dnsmasq configuration.
Setting up lxc-templates (2.0.7-0ubuntu1~16.04.2) ...
Processing triggers for libc-bin (2.23-0ubuntu5) ...
Processing triggers for man-db (2.7.5-1) ...
Processing triggers for ureadahead (0.100.0-19) ...

ubuntu@xen:/root$ /usr/lib/x86_64-linux-gnu/lxc/lxc-user-nic a b $$ veth lxcbr0 foobar
lxc_user_nic.c: 743: rename_in_ns: Error -1 renaming netdev vethL7TJBTp to foobar in container.
Failed to rename the link

ubuntu@xen:/root$ ifconfig foobar
foobar: error fetching interface information: Device not found
```

Stéphane Graber (stgraber) wrote :

One bug we should resolve after this is released is that "lxc-user-nic" doesn't clean after itself on failure. It really ought to destroy any interface it created if it fails.

This means that even with this security fix, a trusted user will be able to create host veth device pairs but those devices will not be brought UP and the user will not be able to choose their name. The number of devices created will also be tracked and the quota enforced, so this can't be used for DoS.

Stéphane Graber (stgraber) wrote :

Note that for LXC 1.x, you should use "/usr/lib/x86_64-linux-gnu/lxc/lxc-user-nic $$ veth lxcbr0 foobar" instead as LXC 1.0.x and LXC 1.1.x doesn't take lxcpath and name as arguments.

Tyler Hicks (tyhicks) wrote :

I've finished my testing of the trusty, xenial, and yakkety packages on amd64 and i386. I'll be publishing the updates for those releases on 2017-03-09 16:00:00 UTC. Thanks again for preparing the packages!

Launchpad Janitor (janitor) wrote :

This bug was fixed in the package lxc - 2.0.7-0ubuntu1~16.10.2

---------------
lxc (2.0.7-0ubuntu1~16.10.2) yakkety-security; urgency=medium

  * SECURITY UPDATE: lxc-user-nic doesn't check netns ownership (LP: #1654676)
    - Ensure target netns is caller-owned
    - CVE-2017-5985

 -- Stéphane Graber <email address hidden> Tue, 07 Mar 2017 14:36:12 -0500

Changed in lxc (Ubuntu):
status: New → Fix Released
Launchpad Janitor (janitor) wrote :

This bug was fixed in the package lxc - 1.0.9-0ubuntu3

---------------
lxc (1.0.9-0ubuntu3) trusty-security; urgency=medium

  * SECURITY UPDATE: lxc-user-nic doesn't check netns ownership (LP: #1654676)
    - Ensure target netns is caller-owned
    - CVE-2017-5985

 -- Stéphane Graber <email address hidden> Tue, 07 Mar 2017 14:39:58 -0500

Changed in lxc (Ubuntu):
status: New → Fix Released
Launchpad Janitor (janitor) wrote :

This bug was fixed in the package lxc - 2.0.7-0ubuntu1~16.04.2

---------------
lxc (2.0.7-0ubuntu1~16.04.2) xenial-security; urgency=medium

  * SECURITY UPDATE: lxc-user-nic doesn't check netns ownership (LP: #1654676)
    - Ensure target netns is caller-owned
    - CVE-2017-5985

 -- Stéphane Graber <email address hidden> Tue, 07 Mar 2017 14:37:03 -0500

Changed in lxc (Ubuntu):
status: New → Fix Released
Tyler Hicks (tyhicks) on 2017-03-09
information type: Private Security → Public Security
Changed in lxc (Ubuntu):
assignee: nobody → Christian Brauner (cbrauner)
To post a comment you must log in.
This report contains Public Security information  Edit
Everyone can see this security related information.

Other bug subscribers