1#define _GNU_SOURCE 2#include <unistd.h> 3#include <signal.h> 4#include "syscall.h" 5#include "libc.h" 6 7struct ctx { 8 size_t count; 9 const gid_t *list; 10 int ret; 11}; 12 13static void do_setgroups(void *p) 14{ 15 struct ctx *c = p; 16 if (c->ret<0) return; 17 int ret = __syscall(SYS_setgroups, c->count, c->list); 18 if (ret && !c->ret) { 19 /* If one thread fails to set groups after another has already 20 * succeeded, forcibly killing the process is the only safe 21 * thing to do. State is inconsistent and dangerous. Use 22 * SIGKILL because it is uncatchable. */ 23 __block_all_sigs(0); 24 __syscall(SYS_kill, __syscall(SYS_getpid), SIGKILL); 25 } 26 c->ret = ret; 27} 28 29int setgroups(size_t count, const gid_t list[]) 30{ 31 /* ret is initially nonzero so that failure of the first thread does not 32 * trigger the safety kill above. */ 33 struct ctx c = { .count = count, .list = list, .ret = 1 }; 34 __synccall(do_setgroups, &c); 35 return __syscall_ret(c.ret); 36} 37