containers / bubblewrap

Low-level unprivileged sandboxing tool used by Flatpak and similar projects
Other
3.97k stars 237 forks source link

user-id mapping, or running bwrap as a different user #181

Open agordon opened 7 years ago

agordon commented 7 years ago

Hello,

I'm interested in using bubblewrap to run a long-term daemon, as a separate user.

first, is this an intended use-case ? or is bubblwrap mainly intended to sandbox an application for an active user (e.g. logged-in interactive user running a sandbox unsafe application) ?

second, If it is supported, what would be a recommended way to run bwrap with user-id mapping ? The --uid/--gid map ID inside the container, but the real user is still the user which invoked bwrap.

I can use sudo -u www-data bwrap [...] , but that seems a bit ugly as it will be www-data who runs the bwrap binary (and if using sudo, then why does bwrap needs to be setuid in the first place?)

thanks in advance for any advice, -assaf

casipw commented 5 years ago

Hi, I had the same thoughts and found these sources:

There is the sysctl setting kernel.unprivileged_userns_clone which allows unprivileged users to create new user namespaces. It is disabled on some security-focused kernels, as linux-hardened in Arch, because it gets unprivileged users in touch with a lot of (potentially exploitable) kernel code that they couldn't access else.

So if there are multiple real users on your system, or if you run public available services without bubblewrap, then its probably a good idea to have kernel.unprivileged_userns_clone disabled.

However bubblewrap requires permission to create a new user namespace. Quoting man bwrap:

Optionally it also sets up new user, ipc, pid, network and uts namespaces (but note the user namespace is required if bwrap is not installed setuid root).

So we have two options left. We could run bwrap as root and try to run the daemon as a different user. Either with bwrap [...] runuser -u http -- [...], but that's clumsy and has difficulties like #329, or with bwrap [...] --uid $(id -u http) --gid $(id -g http), which has difficulties like #331 and is not elegant too.

Let's recall the bubblewrap Readme:

Bubblewrap could be viewed as setuid implementation of a subset of user namespaces. Emphasis on subset - specifically relevant to the above CVE, bubblewrap does not allow control over iptables. [...] The maintainers of this tool believe that it does not, even when used in combination with typical software installed on that distribution, allow privilege escalation. It may increase the ability of a logged in user to perform denial of service attacks, however.

So it's probably the best idea to have the setuid bit set on the bwrap binary and then run it as an unprivileged user. That requires least change in systemd service files. Arch Linux even has a bubblewrap-setuid package.

smcv commented 5 years ago

So if there are multiple real users on your system, or if you run public available services without bubblewrap, then its probably a good idea to have kernel.unprivileged_userns_clone disabled.

This is a security trade-off. Which do you prefer to rely on: the upstream kernel's implementation of user namespaces (to be successfully avoiding vulnerabilities like CVE-2016-3135 that are made exploitable by the larger attack surface), or the bubblewrap code (to be successfully avoiding vulnerabilities like CVE-2016-8659)?

If you prefer to rely on the upstream kernel's implementation of user namespaces, either use a kernel that does not have the kernel.unprivileged_userns_clone patch (like upstream kernels and Arch's linux package), or use the kernel.unprivileged_userns_clone patch (like Arch's linux-hardened and Debian's linux) but enable the sysctl. bwrap does not need to be setuid in this situation.

If you prefer to rely on bubblewrap's correctness, make bwrap setuid. You do not need to enable kernel.unprivileged_userns_clone in this situation.

If you think both are equally safe, you can do either or both of those.

If you think both are unsafe, then you cannot safely use user namespaces or bubblewrap.

smcv commented 5 years ago

We could run bwrap as root and try to run the daemon as a different user

This means you are trusting bwrap, even if it is not setuid on your system. (Of course, if it's setuid, you are trusting it anyway.)

and if using sudo, then why does bwrap needs to be setuid in the first place?

If you use sudo -u www-data to switch to a different uid (in this case www-data), then the program invoked by sudo (in your case bwrap) is unprivileged, and does not have any special privileges itself. It is no more or less privileged than if you logged in as www-data and ran programs that way.

The program invoked by sudo only gets special privileges if you tell sudo to run it as root (which is the default if you do not use -u).

then why does bwrap needs to be setuid in the first place?

If your kernel restricts creation of user namespaces, then bwrap needs to be privileged so that it can create user namespaces despite that restriction.

When it is setuid, it is designed to drop the privileges that it gained from being setuid before it runs user code, and also drop additional privileges so that it cannot be used to exploit vulnerabilities like CVE-2016-3135. The intention is that merely being able to run a setuid bwrap does not grant additional privileges.

In particular, if uid 1000 could switch to uid 1234, and gain uid 1234's privileges outside the container, by running the setuid bwrap, we would consider that to be a major security flaw.

If you are uid 1000 and you run bwrap --uid 1234, that does not actually switch the uid in the init-namespace to 1234. It only changes what programs inside the sandbox think the uid is to 1234. The uid that is visible outside the container is still 1000. (Think about what would happen if this was not true: you would be able to write to uid 1234's files, kill uid 1234's processes and so on, just by being able to run bwrap. That would completely break the privilege separation between users.)

If you have CAP_SETUID and you want to use that privilege to run a process as a different uid in the init-namespace, use runuser or sudo or something similar.

is this an intended use-case ? or is bubblwrap mainly intended to sandbox an application for an active user (e.g. logged-in interactive user running a sandbox unsafe application) ?

bubblewrap was originally designed to sandbox an application running as an unprivileged human user, as part of Flatpak (it was originally named xdg-app-helper, where xdg-app is the old name for Flatpak). Something like this:

Since the project started, bubblewrap's functionality has expanded. I cannot answer the rest of your question: I don't know how suitable the other maintainers consider it to be for use-cases in which it is used to "jail" a program run by a non-human user, and if they consider it to be suitable, I don't know which techniques they would recommend.

I can use sudo -u www-data bwrap [...] , but that seems a bit ugly as it will be www-data who runs the bwrap binary

If the sandboxed process is "really" (in the init-namespace) running as www-data, then it has all the privileges of www-data. For example, if a file is -rwx------ and owned by www-data, then the process can write to that file, but you (assuming your uid is different and you are not root) cannot. (If you are root, then you wouldn't need sudo and could use runuser instead.)

Because of the principle that running bwrap never gives you more privileges than you already had, it must not allow you to run a process that is really (in the init-namespace) uid www-data, unless you were already uid www-data when you ran bwrap.

crocket commented 4 years ago

Does bubblewrap always have to create a new user namespace? Anyway, as far as I know, if unprivileged user namespaces are available, iptables is in danger regardless of bubblewrap's existence.

smcv commented 4 years ago

Does bubblewrap always have to create a new user namespace?

Yes, that's how it gets the ability to do everything else it does.

crocket commented 4 years ago

Wouldn't setuid bubblewrap be safer than bubblewrap with unprivileged user namespace?

smcv commented 4 years ago

Wouldn't setuid bubblewrap be safer than bubblewrap with unprivileged user namespace?

See https://github.com/containers/bubblewrap/issues/181#issuecomment-541104617. It's a security trade-off, depending on which threats you consider to be more severe, and which ones you consider to be more likely.

Debian (with its default kernel), and Arch Linux's non-default linux-hardened kernel with the bubblewrap-suid (bubblewrap-setuid?) package, behave as you suggest. Most other distributions (Ubuntu, Fedora, Arch Linux default kernel, etc.) take the opposite route. There is no single correct answer.

axelfontaine commented 10 months ago

What is the concensus in 2024 on the best workaround to be able to run a process sandboxed by root or setuid bubblewrap as a specific uid?

I currently have su-exec 1234 bwrap --bind / / ls -l /home/myuser, however that shows all files as owned by nobody instead of root.

How can I mount a directory in the sandbox and have it be owned by my regular user? (like id-mapped mounts)

smcv commented 10 months ago

If you want multiple uids to be visible in your container, have you considered using a different containerization tool like Docker, Podman, Incus or systemd-nspawn?

bubblewrap is not intended to be the only containerization tool that anyone will ever need.

axelfontaine commented 10 months ago

If you want multiple uids to be visible in your container, have you considered using a different containerization tool like Docker, Podman, Incus or systemd-nspawn?

Oh absolutely! But none come close to Bubblewrap in terms of simple elegance. Whereas they all need tens of megabytes of space in an image, with just 67K Bubblewrap gives us

The only thing I miss when running Bubblewrap as root is to be able to launch the sandboxed process as a specific uid. I know this wasn't the original design goal of Bubblewrap.

Judging by these issues however, I'm definitely not the only one using it like this: