Overv / outrun

Execute a local command using the processing power of another Linux machine.
Apache License 2.0
3.12k stars 64 forks source link

Feature request: drop privileges after chroot #1

Open nickodell opened 4 years ago

nickodell commented 4 years ago

Example of current behavior:

$ outrun njodell@outrun-vm whoami
fuse: warning: library too old, some operations may not not work
root

I'd like the program I'm running to execute as the same user that I logged in as.

edbaunton commented 4 years ago

There are a number of tools that exist that could help with this including userchroot, which allows a system administrator to configure a system to allow unprivileged chrooting into a set of preconfigured locations.

Overv commented 4 years ago

I'm currently looking into alternatives that don't require root. The perfect approach for me meets these requirements:

nickodell commented 4 years ago

It strikes me that there are two feature requests being discussed here, and the second is much more ambitious than the first:

  1. Don't run the user's process as root. You still need root to set up the chroot, but not afterwards. This is helpful to prevent accidental damage, but not helpful against malicious attackers.

    Example: Imagine I use outrun to run a poorly-coded shell script. Running as a non-root user would limit the amount of damage it does.

  2. Don't require the user to be root (or have sudo privileges) at all. In order for this feature to be useful, it needs to be set up in a way where the user can't use the chroot mechanism to gain root. It's not clear to me how to do that. (If the user can supply /etc/sudoers from their own system, can't they just give themselves the power to be root? Not sure.)
Overv commented 4 years ago

You're right that (1) is a sensible first step towards (2). I think that it is possible to safely implement (2) through unshare, as described here.

haampie commented 3 years ago

You wan't to rely on user namespaces here. For instance:

$ docker export $(docker create alpine) | tar -xC rootfs
$ unshare -r chroot ./rootfs whoami
root

doesn't require you to be root to use chroot by mapping the current user to root inside the unshare process. However, you are only root in the context of that process, so you can't remove root-owned files or anything:

$ mkdir rootfs/test-permission
$ echo "hello" > rootfs/test-permission/file.txt
$ sudo chown -R root:root rootfs/test-permission

Can't remove the folder outside of unshare:

$ rm -rf rootfs/test-permission/
rm: cannot remove 'rootfs/test-permission/file.txt': Permission denied

And can't remove it inside of unshare being mapped to root:

$ unshare -r chroot rootfs rm -rf /test-permission
rm: can't remove '/test-permission/file.txt': Permission denied
nickodell commented 3 years ago

Thanks @haampie!

Looking around on the net, I found a Python implementation ​of bindings to the unshare(2) syscall. It's surprisingly simple, with only 50 lines of source code.

On a related note, I was discussing Outrun on LWN recently, in the context of unprivileged chroot. One of the commenters provided a detailed blueprint of how you might implement this:

That doesn't require an unprivileged chroot; you could do something like:

logfile = fopen("foo.log", "a");
sqlite3_open("foo.db", &db);
sprintf(rootdir, "/run/user/%d/my-jail", getuid());
chdir(rootdir);
unshare(CLONE_NEWUSER);
chroot(".");
caps = cap_get_proc();
cap_clear(caps);
cap_set_proc(caps);

(Credit to floppus on LWN.)

Edit: There is a potential complication here, though. Debian/Ubuntu carry a nonstandard patch which adds a the sysctl knob kernel.unprivileged_userns_clone. That controls whether an unprivileged process like outrun can create a user namespace.

haampie commented 3 years ago

Rootless docker has some overview of different systems: https://docs.docker.com/engine/security/rootless/#distribution-specific-hint they recommend

Add kernel.unprivileged_userns_clone=1 to /etc/sysctl.conf (or /etc/sysctl.d) and run sudo sysctl --system

only for Debian and Arch, but not for Ubuntu, openSUSE or CentOS

gnull commented 2 years ago
  1. Don't run the user's process as root. You still need root to set up the chroot, but not afterwards. This is helpful to prevent accidental damage, but not helpful against malicious attackers.

This is also required for some tools to work. For example, the Haskell build tool Stack refuses to proceed if it sees that ~/.stack is not owned by the user running Stack. (Which makes sense: you don't want root to create files owned by him in your home dir. As @nickodell notes, it prevents accidental damage as well.)