diff options
author | Rich Felker <dalias@aerifal.cx> | 2011-07-29 23:10:07 -0400 |
---|---|---|
committer | Rich Felker <dalias@aerifal.cx> | 2011-07-29 23:10:07 -0400 |
commit | afade2356ea148e715307be8f7334b790282341e (patch) | |
tree | 35e0073557365949add14e9842b95ab335a44c85 /src/unistd | |
parent | acb04806628990ad2430e04261dd20f23babde5e (diff) | |
download | musl-afade2356ea148e715307be8f7334b790282341e.tar.gz musl-afade2356ea148e715307be8f7334b790282341e.tar.xz musl-afade2356ea148e715307be8f7334b790282341e.zip |
add setxid.c for new set*id() framework. missed in last commit.
Diffstat (limited to 'src/unistd')
-rw-r--r-- | src/unistd/setxid.c | 49 |
1 files changed, 49 insertions, 0 deletions
diff --git a/src/unistd/setxid.c b/src/unistd/setxid.c new file mode 100644 index 00000000..d3bfaf62 --- /dev/null +++ b/src/unistd/setxid.c @@ -0,0 +1,49 @@ +#include <unistd.h> +#include <errno.h> +#include <sys/resource.h> +#include "syscall.h" +#include "libc.h" + +struct ctx { + int id, eid, sid; + int nr, rlim, err; +}; + +/* We jump through hoops to eliminate the possibility of partial failures. */ + +static void do_setxid(void *p) +{ + struct ctx *c = p; + if (c->err) return; + if (c->rlim && c->id >= 0 && c->id != getuid()) { + struct rlimit inf = { RLIM_INFINITY, RLIM_INFINITY }, old; + getrlimit(RLIMIT_NPROC, &old); + if (setrlimit(RLIMIT_NPROC, &inf) && libc.threads_minus_1) { + c->err = errno; + return; + } + if (__syscall(c->nr, c->id, c->eid, c->sid)) + c->err = errno; + setrlimit(RLIMIT_NPROC, &old); + return; + } + if (__syscall(c->nr, c->id, c->eid, c->sid)) + c->err = errno; +} + +int __setxid(int nr, int id, int eid, int sid) +{ + struct ctx c = { .nr = nr, .id = id, .eid = eid, .sid = sid }; + switch (nr) { + case SYS_setuid: + case SYS_setreuid: + case SYS_setresuid: + c.rlim = 1; + } + __synccall(do_setxid, &c); + if (c.err) { + errno = c.err; + return -1; + } + return 0; +} |