summaryrefslogtreecommitdiff
path: root/src/unistd
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2013-10-12 19:50:09 -0400
committerRich Felker <dalias@aerifal.cx>2013-10-12 19:50:09 -0400
commit516358561efbc5754d0ad43a52483e0a839d6bd3 (patch)
treec9928345e85311f571e921bda7b3be366969dbad /src/unistd
parent4fb7df12f52982412e60afeaf9c4463f78b396fc (diff)
downloadmusl-516358561efbc5754d0ad43a52483e0a839d6bd3.tar.gz
musl-516358561efbc5754d0ad43a52483e0a839d6bd3.tar.bz2
musl-516358561efbc5754d0ad43a52483e0a839d6bd3.tar.xz
musl-516358561efbc5754d0ad43a52483e0a839d6bd3.zip
fix uid/gid-setting error in faccessat with AT_EACCESS flag
this fixes an issue reported by Daniel Thau whereby faccessat with the AT_EACCESS flag did not work in cases where the process is running suid or sgid but without root privileges. per POSIX, when the process does not have "appropriate privileges", setuid changes the euid, not the real uid, and the target uid must be equal to the current real or saved uid; if this condition is not met, EPERM results. this caused the faccessat child process to fail. using the setreuid syscall rather than setuid works. POSIX leaves it unspecified whether setreuid can set the real user id to the effective user id on processes without "appropriate privileges", but Linux allows this; if it's not allowed, there would be no way for this function to work.
Diffstat (limited to 'src/unistd')
-rw-r--r--src/unistd/faccessat.c4
1 files changed, 2 insertions, 2 deletions
diff --git a/src/unistd/faccessat.c b/src/unistd/faccessat.c
index 5b2c5e30..1083467f 100644
--- a/src/unistd/faccessat.c
+++ b/src/unistd/faccessat.c
@@ -14,8 +14,8 @@ static int checker(void *p)
{
struct ctx *c = p;
int ret;
- if (__syscall(SYS_setgid, __syscall(SYS_getegid))
- || __syscall(SYS_setuid, __syscall(SYS_geteuid)))
+ if (__syscall(SYS_setregid, __syscall(SYS_getegid), -1)
+ || __syscall(SYS_setreuid, __syscall(SYS_geteuid), -1))
__syscall(SYS_exit, 1);
ret = __syscall(SYS_faccessat, c->fd, c->filename, c->amode, 0);
__syscall(SYS_write, c->p, &ret, sizeof ret);