# Allowing non-root execution of a jailed application



## Holger (Jun 15, 2022)

*Allowing non-root execution of a jailed application*

Jailed programs can generally be executed by using `jexec(8)`. However, you have to be root in order to do that. In this short article I present an approach on how you can allow a specific set of non-privileged users to execute a particular jailed application.

*Motivation*

Suppose you have created a jail `jailedfoo` whose only purpose is to run exactly one specific program `foo`. You don't want it on your host system, either because it needs an emulation layer (like Linuxulator) or you just don't want to pollute your host-system with lots of dependecies.

Suppose this program is installed inside the jail under `/opt/bloatware.com/foo`. The executable in that directory is `foo-bin`.

On the host, you can simply execute it by doing:

```
jexec jailedfoo /opt/bloatware.com/foo/foo-bin
```

You have to be root, however, to do that.

I'll now explain how to make this application accessible by a non-privileged user. Let's call that hypothetical user `klaus`.

*Entering sudo*

If `klaus` is allowed to execute programs using `sudo(8)`, she could do

```
sudo jexec jailedfoo /opt/bloatware.com/foo/foo-bin
```

This is fine, but `sudo(8)` generally asks for a password. This is very inconvenient, especially if `foo` is a graphical application that is supposed to be run by a desktop launcher and not by a terminal.

Sure, you could prevent `sudo` from asking for a password for `klaus` in general, but you may not want to do that, because then she could also run _any_ privileged programs (even on the host) without ever being asked for a password. If an attacker gets somehow access to `klaus`' terminal, that would be hazardous.

*Command-based sudoer file*

The solution is to allow `klaus` the `sudo`ed execution of one specific command and to disable asking for a password for that specific command only.

What could that command be? Probably not `jexec` itself, because that would allow `klaus` to do that trick on _any_ jail, not just `jailedfoo`.

So, first we create a custom command in the form of a simple shell script. “By abuse of notation”, let's call this script `foo` and place it under `/usr/local/bin` on the host.

In our first approach, the script is just the one-liner from above:

```
#!/bin/sh

jexec jailedfoo /opt/bloatware.com/foo/foo-bin
```

Now here comes the trick: We create a `sudoer` file for that specific script. Call that `sudoer` file `foo` (like the command it is refering to) and place it in the directory `/usr/local/etc/sudoers.d`. Do this as `root` with the `visudo` command:

```
visudo -f /usr/local/etc/sudoers.d/foo
```
Let it have content of the following form:

```
<user> <host> = (root) NOPASSWD: <cmd>
```
where `<user>` is our non-privileged user, namely `klaus`, `<host>` is the host we're on (assume that host is called `mercury`), and `<cmd>` is the actual command we want to execute; using the full path is important here. So, in our example, the finally content will look like this:

```
klaus mercury = (root) NOPASSWD: /usr/local/bin/foo
```

Once you have saved the file, `klaus` will be able to do the following without being asked for a password:

```
sudo foo
```

*Non-privileged user inside the jail*

All fine and good. The only thing to worry about is that `foo` inside the jail is executed as `root`. It's still inside the jail, so there is probably no problem with that, but some applications just don't like being run as `root`.

We'll fix that now.

First, enter the jail (as root) and create a jailed user for `klaus`:

```
jexec jailedfoo /bin/sh
adduser klaus
```

Now we have to tell our wrapper script on the host, `/usr/local/bin/foo`, to execute the program as the jailed user `klaus`, who has to have the same name as the host-`klaus`. `jexec(8)` has a special option `-U` for that, but this won't work, if the jail is an Ubuntu running on Linuxulator, for example. So we will use a more portable solution using `su(1)`. The general syntax will be as follows:

```
su -c /opt/bloatware.com/foo/foo-bin - klaus
```

So we mingle that with our `jexec` invocation in `/usr/local/bin/foo`:

```
jexec jailedfoo "su -c /opt/bloatware.com/foo/foo-bin - klaus"
```

*The general solution*

Now `klaus` is fine. But what about other users, like `marie`, for exmple? He might want to run `foo` as well. Creating another entry in `/usr/local/etc/sudoers.d/foo` will be easy, but what about the non-privileged execution inside the jail? With our current solution, `marie` would run `foo` inside the jail as the user `klaus`, which is probably not what we want (unless you replace `klaus` inside the jail by a more general user like `foouser`, or something like that).

A first idea might be to replace `klaus` in `/usr/local/bin/foo` by a simple call to `whoami(1)`. The problem is, however, that the script `/usr/local/bin/foo` is executed by `sudo`, so the user returned by `whoami` will always be root.

Fortunately, `sudo` is wise enough to provide us with the user-ID of the caller in the form of an environment variable called `SUDO_UID`. The only thing we have to do is to convert that UID to the actual user name. The program `id(1)` is the right tool for that job:

```
id -n -u <UID>
```
will give us the user name belonging to `<UID>`, e.g. `klaus` or `marie`.

So, the final version of our wrapper-script `/usr/local/bin/foo` looks as follows:

```
#!/bin/sh

jexec jailedfoo "su -c /opt/bloatware.com/foo/foo-bin - $(id -n -u ${SUDO_UID})"
```

Now both `klaus` and `marie` both can launch `foo` from the host by doing a `sudo foo` without being asked for a password.


----------

