]>
Commit | Line | Data |
---|---|---|
320054e8 | 1 | #include <unistd.h> |
322bd4ff | 2 | #include <signal.h> |
320054e8 DG |
3 | #include "syscall.h" |
4 | #include "libc.h" | |
320054e8 DG |
5 | |
6 | struct ctx { | |
7 | int id, eid, sid; | |
322bd4ff | 8 | int nr, ret; |
320054e8 DG |
9 | }; |
10 | ||
11 | static void do_setxid(void *p) | |
12 | { | |
13 | struct ctx *c = p; | |
322bd4ff DG |
14 | if (c->ret<0) return; |
15 | int ret = __syscall(c->nr, c->id, c->eid, c->sid); | |
16 | if (ret && !c->ret) { | |
320054e8 DG |
17 | /* If one thread fails to set ids after another has already |
18 | * succeeded, forcibly killing the process is the only safe | |
19 | * thing to do. State is inconsistent and dangerous. Use | |
20 | * SIGKILL because it is uncatchable. */ | |
21 | __block_all_sigs(0); | |
22 | __syscall(SYS_kill, __syscall(SYS_getpid), SIGKILL); | |
23 | } | |
322bd4ff | 24 | c->ret = ret; |
320054e8 DG |
25 | } |
26 | ||
27 | int __setxid(int nr, int id, int eid, int sid) | |
28 | { | |
322bd4ff | 29 | /* ret is initially nonzero so that failure of the first thread does not |
320054e8 | 30 | * trigger the safety kill above. */ |
322bd4ff | 31 | struct ctx c = { .nr = nr, .id = id, .eid = eid, .sid = sid, .ret = 1 }; |
320054e8 | 32 | __synccall(do_setxid, &c); |
322bd4ff | 33 | return __syscall_ret(c.ret); |
320054e8 | 34 | } |