On Linux (Unix?) You Can Make Up a User ID On The Fly
Recently I’ve been working with Docker, launching non-root containers.
Mostly because I mounted files into the container I didn’t want every file to be owned by root.
I use commands like this:
docker run --user="$(id --user):$(id --group) -v $PWD:/mounted-directory <image> <comand>
.
This way the processes inside the container use the same user id as the current user,
so any file created inside the container on the mounted directory can easily be read and changed.
What happens if you pick a random user id, one which doesn’t exist? Try it:
docker run --detach --rm --user=42421:42421 busybox sleep 10
> 542d4de888751e6d067ddd84bf3b9f21698e2af4a0a90844b586c92a3d47d6d
ps aux | grep sleep
> 42421 88497 0.0 0.0 1308 4 ? Ss 14:28 0:00 sleep 10
> roman 88539 0.0 0.0 6404 2292 pts/11 S+ 14:28 0:00 grep --color=auto sleep
As you see, no error or warning. The process runs under user 42421. You didn’t have to create a user. The only odd thing is that you see the raw user-id instead of a name. So, is this Docker magic sauce? [1]
Outside Docker: Setreuid/Setregid
Let’s try this outside Docker. I’m using this small test file which prints the user id and sleeps for bit. Mark the file as executable.
#!/usr/bin/env bash
id
sleep 10
For sudo
, it doesn’t work. It wants to know the user:
chmod +x /tmp/test.sh
sudo -u 42421 /tmp/test.sh
sudo: unknown user: 42421
sudo: error initializing audit plugin sudoers_audit
Ok, lets go down to metal and use the Linux APIs (insert some GNU/Posix/Unix joke here yourself).
#include <stdio.h>
#include <unistd.h>
int main(int argc, char** argv) {
int err = setregid(42421, 42421);
if(err){
perror("Failed to switch to other group id");
return 1;
}
err = setreuid(42421, 42421);
if(err){
perror("Failed to switch to other user id");
return 1;
}
execv("/tmp/test.sh", argv);
perror("Failed to launch /tmp/test.sh");
return 1;
}
Then we compile, run our program and check the user id. We compile it and run it.
gcc launch-setuid.c -o launch-setuid ./launch-setuid > Failed to switch to other user id: Operation not permitted
We’ll get an error. That’s because we can’t just willy-nilly switch to another user. Otherwise, there would be no security boundary. We have to run the user switching as root: [2][3]
$ gcc launch-setuid.c -o launch-setuid $ sudo ./launch-setuid & > uid=42421 gid=42421 groups=42421,0(root) $ ps aux | grep test.sh > 42421 106250 0.0 0.0 7264 2824 pts/7 S 18:31 0:00 bash /tmp/test.sh > roman 106286 0.0 0.0 6408 2368 pts/7 S+ 18:31 0:00 grep --color=auto test.sh
Tada, we did it. That process runs as user 42421
.
Weirdness in 'made-up' User Land
Because the user lacks a proper setup, you’ll get some weirdness. Some utilities might not find the user name or complain. For example, bash in docker will show this:
$ docker run -it --rm --user 42000:42000 ubuntu:20.04 > groups: cannot find name for group ID 42000 > I have no name!@7dd968f5308a:/$
You may need to define some things in that environment for some programs to work.
Like, define the USER
and HOME
environment variables.
USER=virtuser HOME=/tmp/virtuser
Or in Docker you might go further and mount a /etc/passwd and /etc/group into the container. So you can generate some user name on the fly:
$ echo 'root:x:0:0::/root:/bin/bash' > ./virtual-passwd $ echo 'virtualuser:x:42000:42000::/home/virtualuser:/bin/bash' >> ./virtual-passwd $ echo 'root:x:0:root' > ./virtual-group $ echo 'virtualuser:x:42000:' >> ./virtual-group docker run -it --rm --user 42000:42000 \ -v $PWD/virtual-passwd:/etc/passwd \ -v $PWD/virtual-group:/etc/group \ ubuntu:20.04
There are probably more consequences and odd behaviors. However, many basic processes which do not have some user interaction will run happily.
Happy Adhoc User Creating ;)
That’s it. I’m not a Linux/Unix guru to tell you much more or give any insights on deeper consequences =)
I also don’t know if this applies to all Unix-ish operating systems. I tried it on Linux and FreeBSD and it worked. I didn’t test on other Unix systems like illumos or MacOS