summaryrefslogtreecommitdiff
path: root/src/unistd/setegid.c
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2011-07-29 22:59:44 -0400
committerRich Felker <dalias@aerifal.cx>2011-07-29 22:59:44 -0400
commitacb04806628990ad2430e04261dd20f23babde5e (patch)
tree90e734333eee81878a920bfd32277bc96aa46402 /src/unistd/setegid.c
parentaed707f679cce80afd929f0efaf080f1e8481330 (diff)
downloadmusl-acb04806628990ad2430e04261dd20f23babde5e.tar.gz
new attempt at making set*id() safe and robust
changing credentials in a multi-threaded program is extremely difficult on linux because it requires synchronizing the change between all threads, which have their own thread-local credentials on the kernel side. this is further complicated by the fact that changing the real uid can fail due to exceeding RLIMIT_NPROC, making it possible that the syscall will succeed in some threads but fail in others. the old __rsyscall approach being replaced was robust in that it would report failure if any one thread failed, but in this case, the program would be left in an inconsistent state where individual threads might have different uid. (this was not as bad as glibc, which would sometimes even fail to report the failure entirely!) the new approach being committed refuses to change real user id when it cannot temporarily set the rlimit to infinity. this is completely POSIX conformant since POSIX does not require an implementation to allow real-user-id changes for non-privileged processes whatsoever. still, setting the real uid can fail due to memory allocation in the kernel, but this can only happen if there is not already a cached object for the target user. thus, we forcibly serialize the syscalls attempts, and fail the entire operation on the first failure. this *should* lead to an all-or-nothing success/failure result, but it's still fragile and highly dependent on kernel developers not breaking things worse than they're already broken. ideally linux will eventually add a CLONE_USERCRED flag that would give POSIX conformant credential changes without any hacks from userspace, and all of this code would become redundant and could be removed ~10 years down the line when everyone has abandoned the old broken kernels. i'm not holding my breath...
Diffstat (limited to 'src/unistd/setegid.c')
-rw-r--r--src/unistd/setegid.c4
1 files changed, 3 insertions, 1 deletions
diff --git a/src/unistd/setegid.c b/src/unistd/setegid.c
index 85348842..e6da2573 100644
--- a/src/unistd/setegid.c
+++ b/src/unistd/setegid.c
@@ -1,6 +1,8 @@
#include <unistd.h>
+#include "libc.h"
+#include "syscall.h"
int setegid(gid_t egid)
{
- return setregid(-1, egid);
+ return __setxid(SYS_setresgid, -1, egid, -1);
}