Home > database >  How to implement runas in Linux?
How to implement runas in Linux?

Time:10-05

I’ve tried fork, setresgid, setresuid and execvpe — doesn’t work.

Specifically, no errors are returned anywhere, the child process starts OK, I have confirmed all 6 magic numbers returned by getresuid and getresgid match, yet the child process doesn’t have the required permissions.

The files in question are in the /dev/input/ folder. Here’s the permissions:

drwxr-xr-x    3 root     root           180 Sep 23 19:47 .
drwxr-xr-x   17 root     root          4120 Sep 23 19:47 ..
drwxr-xr-x    2 root     root           160 Sep 23 19:47 by-path
crw-rw----    1 root     input      13,  64 Sep 23 19:47 event0
crw-rw----    1 root     input      13,  65 Sep 23 19:47 event1
crw-rw----    1 root     input      13,  66 Sep 23 19:47 event2
crw-rw----    1 root     input      13,  67 Sep 23 19:47 event3
crw-rw----    1 root     input      13,  68 Sep 23 19:47 event4
crw-rw----    1 root     input      13,  69 Sep 23 19:47 event5

The user is a member of the input group, that’s why under normal circumstances it can access these files. However, the process launched with fork/setresgid/setresuid/execvpe can’t access these files.

Here’s relevant lines from the strace log, the log was made with -ff option i.e. only includes a single process:

setresgid(10000, 10000, 10000)          = 0
setresuid(10000, 10000, 10000)          = 0
execve("/usr/local/bin/dotnet", ["/usr/local/bin/dotnet", "/home/user/launcher/Debug/Desktop.dll"], 0xffffea463f50 /* 1 var */) = 0
.. much later
openat(AT_FDCWD, "/dev/input/event0", O_RDONLY|O_LARGEFILE|O_CLOEXEC) = -1 EACCES (Permission denied)

CodePudding user response:

The problem was indeed extra groups. Contrary to my expectation, setresuid does not refresh the list of additional groups.

To set them up, the launcher process first needs to call getgrouplist to query the list of additional groups for the target user, then after the fork call setgroups to apply these values.

The complete sequence of kernel calls to implement a Linux equivalent of CreateProcessAsUser is following:

getgrouplist, fork, chdir, setresgid, setgroups, setresuid, execvpe

Note how setresuid needs to be the very last step before the execvpe. The reason for that, after that call the forked process no longer has permissions to modify these security-related things.

P.S. I wonder how many security bugs in Linux software were caused by the developers forgetting to update that list of extra groups when switching user accounts in their programs?

  • Related