2

I want to build a small web application in Rust which should be able to read and write files on a users behalf. The user should authenticate with their UNIX credentials and then be able to read / write only the files they have access to.

My first idea, which would also seem the most secure to me, would be to switch the user-context of an application thread and do all the read/write-stuff there. Is this possible?

If this is possible, what would the performance look like? I would assume spawning an operating system thread every time a request comes in could have a very high overhead. Is there a better way to do this?

I really wouldn't like to run my entire application as root and check the permissions manually.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
lschuermann
  • 862
  • 1
  • 7
  • 17

2 Answers2

2

On GNU/Linux, it is not possible to switch UID and GID just for a single thread of a process. The Linux kernel maintains per-thread credentials, but POSIX requires a single set of credentials per process: POSIX setuid must change the UID of all threads or none. glibc goes to great lengths to emulate the POSIX behavior, although that is quite difficult.

You would have to create a completely new process for each request, not just a new thread. Process creation is quite cheap on Linux, but it could still be a performance problem. You could keep a pool of processes around to avoid the overhead of repeated process creation. On the other hand, many years ago, lots of web sites (including some fairly large ones) used CGI to generate web pages, and you can get relatively far with a simple design.

Florian Weimer
  • 32,022
  • 3
  • 48
  • 92
1

I think @Florian got this backwards in his original answer. man 2 setuid says

C library/kernel differences

At the kernel level, user IDs and group IDs are a per-thread attribute. However, POSIX requires that all threads in a process share the same credentials. The NPTL threading implementation handles the POSIX requirements by providing wrapper functions for the various system calls that change process UIDs and GIDs. These wrapper functions (including the one for setuid()) employ a signal-based technique to ensure that when one thread changes credentials, all of the other threads in the process also change their credentials. For details, see nptl(7).

Since libc does the signal dance to do it for the whole process you will have to do direct system calls to bypass that.

Note that this is linux-specific. Most other unix variants do seem to follow posix at the kernel level instead emulating it in libc.

the8472
  • 40,999
  • 5
  • 70
  • 122
  • 1
    I clarified my answer. With GNU/Linux, I meant the Linux kernel with a GNU (glibc) userland. Other libcs might behave differently. glibc may may not react well to UID/GID changes with direct system calls. – Florian Weimer Jul 30 '17 at 09:20