fix uid/gid-setting error in faccessat with AT_EACCESS flag
authorRich Felker <dalias@aerifal.cx>
Sat, 12 Oct 2013 23:50:09 +0000 (19:50 -0400)
committerRich Felker <dalias@aerifal.cx>
Sat, 12 Oct 2013 23:50:09 +0000 (19:50 -0400)
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.

src/unistd/faccessat.c

index 5b2c5e307552085c34fe34a94a1c732c43a38c44..1083467f8e442b90dd38002d602cbb1ee7d73f2e 100644 (file)
@@ -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);