views:

851

answers:

2

Is there a way to change UID/GID only of one thread in a multithreaded process?

The reason for this is writing a file-serving application - the ACL's and quota are not enforced unless the uid/gid of the caller is set to the correct user, new files/directories are not created with correct uid/gid etc.

The network applications can usually fork() themselves at the beginning and process each user request in separate process. If there is a need for shared data, it must go through some kind of shared memory. However, e.g. the FUSE (linux user filesystem) by default uses multithreading and in conjuction with python bindings it wouldn't be practical to try to use a forking model.

The 'consistent' UID for a whole process seems to be according to the POSIX standard, however old Linuxes didn't follow the POSIX and allowed different uids for different threads. The new kernels seem to follow POSIX, is there some way to allow the old 'broken' behaviour?

+3  A: 

No. A thread is part of the same process which has the same UID/GID.

All the file descriptors are owned by the process and setting the UID/GID in a thread would set it to each one.

Daniel A. White
And I might add that any alternative would be pretty scary - considering that threads have unrestricted access to each other's memory space.
Avdi
It would not - the program is trusted, therefore there is no problem with parts running under differnt UID's. The parent must have been run as root anyway, there is no added security by disabling this feature. The alternative is often fork()ing the program with shared memory, doing setuid() in the fork()ed processes - however the forked process can do some damage through the shared memory.
ondra
What's the point of dropping a thread's privileges if it still has all the power of the superuser? You might as well just leave all the threads running as root in that case.Comparing shared memory communication to having total access to a program's entire address space is a bit of a stretch.
Avdi
The point is that the filesystem routines in kernel behave depending on your UID/GID. If you are writing a fileserver, you have 2 options: either setuid()/setgid() (and you CAN setuid() back to root using saved uid's) or doing ALL the work yourself - which e.g. in case of quota's can be pretty hard.If you are writing Fuse server, you cannot fork() - the whole thing is designed to use multithreading (at least I think so). Setuid() thread is the only thing that would make writing a multiuser overlay FS reasonably simple.
ondra
+1  A: 

Have you checked if setfsuid() / setfsgid() are per-thread or per-process? They're designed specifically for this use case (file server).

caf
This is better - I have checked and surprisingly found out that they are really per-thread. This would probably be the preferred way.However - the reason I did not test it is, that quota() and access() do not work. Other things do work - so this is probably Linux bug.
ondra
Yes, that does sound like a bug, since the comments in the kernel code for sys_setfsuid() specifically mention access()...
caf
@Ondrej, please post code (or a link to it), demonstrating that `fsuid` is, unlike other UID/GID constructs, per-thread and not per-process. Please also specify your kernel and glibc versions, as well as your threading implementation (NPTL, LinuxThreads, OndrejThreads, etc.).
pilcrow
pilcrow, I did some really simple tests using python and threads. However: the quota() works, but one must drop some capability (CAP_RESOURCE, I think) before checking. access() does not work, and 'should not' work according to the POSIX. To me it seems to be a bug in POSIX (second I have found) and it doesn't seem that anyone in Linux would be interested in changing it :(
ondra