New issue
Advanced search Search tips
Note: Color blocks (like or ) mean that a user may not be available. Tooltip shows the reason.

Issue 786659 link

Starred by 8 users

Issue metadata

Status: Fixed
Owner:
User never visited
Closed: May 2018
Components:
EstimatedDays: ----
NextAction: ----
OS: Chrome
Pri: 1
Type: Bug



Sign in to add a comment

Enforce that LXD can't start privileged containers

Project Member Reported by dgreid@chromium.org, Nov 18 2017

Issue description

Explicitly disallow privileged containers.

Maybe an LXD command line option.
 
Components: OS>Systems>Containers

Comment 2 by jkwang@google.com, Apr 17 2018

I am trying to fix this. Here is some updates:
1. Went through lxd documents, could not found solution out there.
2. Explored the possibility of making this a server config (https://github.com/lxc/lxd/blob/master/doc/server.md). Looks like anyone in lxd group can change the config.

Working on a prototype with command line option.

Comment 3 by dgreid@chromium.org, Apr 17 2018

Owner: jkwang@chromium.org
Thanks jkwang. A command line options seems like a reasonable path to me.
Hm, I was just discussing this with Stéphane. We will have multi-user + ACL on our roadmap until then this doesn't make a lot of sense. But what would make sense is to have an env variable to control that behavior. This env variable would need to block:
- prevent setting the raw.idmap config value
- prevent setting security.privileged
- hook into raw.lxc to ban setting lxc.idmap, lxc.include and ensuring that users can't write to /usr/share/lxc/config/common.conf.d

Comment 5 by jkwang@google.com, Apr 17 2018

Thanks, Christian.
Can you explain "hook into raw.lxc to ban setting lxc.idmap, lxc.include"? How is this done? 
Oh sure. :) It sounds more complicated than it is. Basically you need to add a check to lxd/lxd/container_lxc.go:lxcValidConfig() [1] that checks whether lxc.idmap, lxc.id_map or lxc.include are present and if so ignore them or report an error that they are not allowed. So something like:

If HAS_ENV_TO_BLOCK_PRIV_CONTAINERS {
        if key == "lxc.idmap" || key == "lxc.id_map" {
                return fmt.Errorf("Setting lxc.idmap is not allowed")
        }

        if key == "lxc.include" {
                return fmt.Errorf("Setting lxc.include is not allowed")
        }
}

[1]: https://github.com/lxc/lxd/blob/5a7c2f21e91b14dd1b47c7763c60869921b172f0/lxd/container_lxc.go#L199
If I may give a few more general pointers.

#### Isolated idmaps

If you insanely care about security you should look into

security.idmap.isolated

which gives each container its own idmap that it doesn't share with any other container. Be aware though that depending on how many mappings you make available this will restrict the total numbers of containers that you can run.

#### Punching holes into idmaps
In order for a container to be able to write to files that the user owns on the host it it might be useful to map the users own uid through. Meaning that e.g. my_host_uid(1000) == my_container_id(1000). This can be done by using raw.idmap=both 1000 1000. This means that after you restarted the container and you attach e.g. your home volume you can actually write to it.
To make this feature more useful I pushed a kernel patch a while back for 4.15 that bumps the maximum number of idmaps a container can have from 5 to 340 [1].

[1]: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=6397fac4915ab3002dc15aae751455da1a852f25

Comment 8 by jkwang@google.com, Apr 18 2018

Thanks for your help. I will focus on isolation between container and host.  
I am doing this for raw.idmap and security.privileged.
+       if os.Getenv("LXD_UNPRIVILEGED_ONLY") == "true" {
+               if config["raw.idmap"] != "" {
+                       return fmt.Errorf("LXD_UNPRIVILEGED_ONLY is set, Setting raw.idmap is not allowed.")
+               }
+
+               if config["security.privileged"] == "true" || shared.IsTrue(config["security.privileged"]) {
+                       return fmt.Errorf("LXD_UNPRIVILEGED_ONLY is set, only unprivileged containers are allowed.")
+               }
+       }

I understand raw.idmap, but how is lxc.idmap different? I don't see it in container configuration table.

Comment 9 by jkwang@google.com, Apr 18 2018

shared.IsTrue(config["security.privileged"] is good enough. Please ignore == "true" part.
re #8
So raw.idmap is the LXD knob and lxc.idmap is the underlying config key of the LXC shared library. So when you set raw.idmap then LXD will calculate the correct lxc.idmap values to be set.
For example, raw.idmap=both 1000 1000 will cause LXD to punch a hole into the uidmap at uid 1000 and will translate to (assuming for simplicity that 1000000000 ids are allocated per container):

lxc.idmap = u    0 100000      1000
lxc.idmap = g    0 100000      1000
lxc.idmap = u 1000   1000         1
lxc.idmap = g 1000   1000         1
lxc.idmap = u 1001 101001 999998999
lxc.idmap = g 1001 101001 999998999

We have always adhered to the notion that users which understand what they are doing can turn basically every knob they want to turn. So we have an option called "raw.lxc" and this option let's you basically - with a few restrictions - access any configuration key that LXC itself exposes. In essence, users could bypass the raw.idmap key and use lxc.idmap directly. That's why you need to block it too. :)
s/users which/users who/
Project Member

Comment 12 by bugdroid1@chromium.org, Apr 21 2018

The following revision refers to this bug:
  https://chromium.googlesource.com/chromiumos/overlays/chromiumos-overlay/+/4c3dd2dd037b6720e4254b47355bd974080d993a

commit 4c3dd2dd037b6720e4254b47355bd974080d993a
Author: Jingkui Wang <jkwang@google.com>
Date: Sat Apr 21 06:01:32 2018

lxd: add unprivileged patch to lxd

This patch add unprivileged mode. When LXD_UNPRIVILEGED_ONLY is set,
user in lxd group won't be able to start a privileged container or mess
with idmap.

BUG= chromium:786659 
TEST=local build lxd and test.
Change-Id: Ic9097359c2deda7f22abfb7457ee50a0852c5036
Reviewed-on: https://chromium-review.googlesource.com/1017311
Commit-Ready: Jingkui Wang <jkwang@google.com>
Tested-by: Jingkui Wang <jkwang@google.com>
Reviewed-by: Jingkui Wang <jkwang@google.com>

[modify] https://crrev.com/4c3dd2dd037b6720e4254b47355bd974080d993a/app-emulation/lxd/lxd-2.21.ebuild
[add] https://crrev.com/4c3dd2dd037b6720e4254b47355bd974080d993a/app-emulation/lxd/files/2.21-unprivileged-only.patch
[add] https://crrev.com/4c3dd2dd037b6720e4254b47355bd974080d993a/app-emulation/lxd/lxd-2.21-r1.ebuild

Project Member

Comment 13 by bugdroid1@chromium.org, Apr 27 2018

The following revision refers to this bug:
  https://chromium.googlesource.com/chromiumos/platform2/+/7f64ec04b83a25714201c51a7b178a937ada7961

commit 7f64ec04b83a25714201c51a7b178a937ada7961
Author: Jingkui Wang <jkwang@google.com>
Date: Fri Apr 27 04:10:13 2018

vm_tools: use lxd_unprivileged_only when start lxd

Use the env to stop lxc from starting privileged container.

BUG= chromium:786659 
TEST=manual

Change-Id: I2cd1ddad8d86bb8e65a7285576cb49da10dd53f5
Reviewed-on: https://chromium-review.googlesource.com/1026943
Commit-Ready: Jingkui Wang <jkwang@google.com>
Tested-by: Jingkui Wang <jkwang@google.com>
Reviewed-by: Jingkui Wang <jkwang@google.com>
Reviewed-by: Chirantan Ekbote <chirantan@chromium.org>

[modify] https://crrev.com/7f64ec04b83a25714201c51a7b178a937ada7961/vm_tools/concierge/service.cc

Labels: Hotlist-Crostini-Platform
Fixed?

Comment 16 by jkwang@google.com, May 21 2018

Status: Fixed (was: Assigned)

Sign in to add a comment