Root-Rechte können nach setuid (1000) in musl libc wiederhergestellt werden

7

musl libckönnen Sie ändern , uidum rootmit selbst nach angeblich fallen Berechtigungen setuid(1000). Ich kann das Problem mit nicht reproduzieren glibc.

Code:

#define _GNU_SOURCE
#include <unistd.h>
#include <stdio.h>

int main(void) {
    uid_t r, e, s;

    getresuid(&r, &e, &s);
    printf("%d %d %d\n", r, e, s);

    if (setuid(1000) != 0)
        puts("setuid(1000) failed");
    else
        puts("setuid(1000) succeded");

    getresuid(&r, &e, &s);
    printf("%d %d %d\n", r, e, s);

    if (setuid(0) != 0)
        puts("setuid(0) failed");
    else
        puts("setuid(0) succeded");

    getresuid(&r, &e, &s);
    printf("%d %d %d\n", r, e, s);

    return 0;
}

Dies gcc -o setuidtest setuidtest.cerzeugt nach dem Kompilieren mit die folgende Ausgabe, wenn es als root ausgeführt wird

0 0 0
setuid(1000) succeded
1000 1000 1000
setuid(0) succeded
0 0 0

Ich verwende Void Linux mit Kernel-Version 4.18_1und Musl-Version 1.1.20_2, Glibc-Version2.28_3

Woher kommt dieses Problem? Ist es mein Kernel, musl libc oder ist mein Testcode einfach falsch? Ist dieses Problem für andere Personen reproduzierbar?

strace output (musl unpriviledged)

$ strace ./setuidtest (unpriviledged)
execve("./setuidtest", ["./setuidtest"], 0x7ffdd15f69e0 /* 24 vars */) = 0
arch_prctl(ARCH_SET_FS, 0x7f538925cb28) = 0
set_tid_address(0x7f538925cb68)         = 6299
mprotect(0x7f5389259000, 4096, PROT_READ) = 0
mprotect(0x55e9c5e75000, 4096, PROT_READ) = 0
getresuid([1000], [1000], [1000])       = 0
ioctl(1, TIOCGWINSZ, 0x7ffd2faf3160)    = -1 ENOTTY (Not a tty)
writev(1, [{iov_base="1000 1000 1000", iov_len=14}, {iov_base="\n", iov_len=1}], 21000 1000 1000
) = 15
rt_sigprocmask(SIG_BLOCK, ~[RTMIN RT_1 RT_2], [], 8) = 0
rt_sigprocmask(SIG_BLOCK, ~[], NULL, 8) = 0
setuid(1000)                            = 0
futex(0x7f538925cfd8, FUTEX_WAKE_PRIVATE, 2147483647) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
getresuid([1000], [1000], [1000])       = 0
rt_sigprocmask(SIG_BLOCK, ~[RTMIN RT_1 RT_2], [], 8) = 0
rt_sigprocmask(SIG_BLOCK, ~[], NULL, 8) = 0
setuid(0)                               = -1 EPERM (Operation not permitted)
futex(0x7f538925cfd8, FUTEX_WAKE_PRIVATE, 2147483647) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
getresuid([1000], [1000], [1000])       = 0
writev(1, [{iov_base="setuid(1000) succeded\n1000 1000 "..., iov_len=69}, {iov_base=NULL, iov_len=0}], 2setuid(1000) succeded
1000 1000 1000
setuid(0) failed
1000 1000 1000
) = 69
exit_group(0)                           = ?
+++ exited with 0 +++

strace output (musl als wurzel)

# strace ./setuidtest (as root)
execve("./setuidtest", ["./setuidtest"], 0x7ffe19286eb0 /* 18 vars */) = 0
arch_prctl(ARCH_SET_FS, 0x7f08b2619b28) = 0
set_tid_address(0x7f08b2619b68)         = 6409
mprotect(0x7f08b2616000, 4096, PROT_READ) = 0
mprotect(0x561507eb4000, 4096, PROT_READ) = 0
getresuid([0], [0], [0])                = 0
ioctl(1, TIOCGWINSZ, 0x7fffb222bff0)    = -1 ENOTTY (Not a tty)
writev(1, [{iov_base="0 0 0", iov_len=5}, {iov_base="\n", iov_len=1}], 20 0 0
) = 6
rt_sigprocmask(SIG_BLOCK, ~[RTMIN RT_1 RT_2], [], 8) = 0
rt_sigprocmask(SIG_BLOCK, ~[], NULL, 8) = 0
setuid(1000)                            = 0
futex(0x7f08b2619fd8, FUTEX_WAKE_PRIVATE, 2147483647) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
getresuid([1000], [1000], [1000])       = 0
rt_sigprocmask(SIG_BLOCK, ~[RTMIN RT_1 RT_2], [], 8) = 0
rt_sigprocmask(SIG_BLOCK, ~[], NULL, 8) = 0
setuid(0)                               = 0
futex(0x7f08b2619fd8, FUTEX_WAKE_PRIVATE, 2147483647) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
getresuid([0], [0], [0])                = 0
writev(1, [{iov_base="setuid(1000) succeded\n1000 1000 "..., iov_len=62}, {iov_base=NULL, iov_len=0}], 2setuid(1000) succeded
1000 1000 1000
setuid(0) succeded
0 0 0
) = 62
exit_group(0)                           = ?
+++ exited with 0 +++

strace output (glibc unprivilegiert)

$ strace ./setuidtest
execve("./setuidtest", ["./setuidtest"], 0x7fff673b2c20 /* 14 vars */) = 0
brk(NULL)                               = 0x558b5fbb1000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/tls/x86_64/x86_64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/tls/x86_64/x86_64", 0x7ffc25da1650) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/tls/x86_64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/tls/x86_64", 0x7ffc25da1650) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/tls/x86_64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/tls/x86_64", 0x7ffc25da1650) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/tls/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/tls", 0x7ffc25da1650)    = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/x86_64/x86_64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/x86_64/x86_64", 0x7ffc25da1650) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/x86_64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/x86_64", 0x7ffc25da1650) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/x86_64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/x86_64", 0x7ffc25da1650) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\3604\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=18248368, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fbcd7093000
mmap(NULL, 3921920, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fbcd6ab1000
mprotect(0x7fbcd6c65000, 2097152, PROT_NONE) = 0
mmap(0x7fbcd6e65000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1b4000) = 0x7fbcd6e65000
mmap(0x7fbcd6e6b000, 14336, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fbcd6e6b000
close(3)                                = 0
arch_prctl(ARCH_SET_FS, 0x7fbcd7094500) = 0
mprotect(0x7fbcd6e65000, 16384, PROT_READ) = 0
mprotect(0x558b5f5c0000, 4096, PROT_READ) = 0
mprotect(0x7fbcd7095000, 4096, PROT_READ) = 0
getresuid([1000], [1000], [1000])       = 0
fstat(1, {st_mode=S_IFIFO|0600, st_size=0, ...}) = 0
brk(NULL)                               = 0x558b5fbb1000
brk(0x558b5fbd2000)                     = 0x558b5fbd2000
setuid(1000)                            = 0
getresuid([1000], [1000], [1000])       = 0
setuid(0)                               = -1 EPERM (Operation not permitted)
getresuid([1000], [1000], [1000])       = 0
write(1, "1000 1000 1000\nsetuid(1000) succ"..., 841000 1000 1000
setuid(1000) succeded
1000 1000 1000
setuid(0) failed
1000 1000 1000
) = 84
exit_group(0)                           = ?
+++ exited with 0 +++

strace output (glibc als root)

# strace ./setuidtest
execve("./test", ["./test"], 0x7ffc9176d3f0 /* 15 vars */) = 0
brk(NULL)                               = 0x5653f4910000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/tls/x86_64/x86_64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/tls/x86_64/x86_64", 0x7ffe7d0c9550) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/tls/x86_64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/tls/x86_64", 0x7ffe7d0c9550) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/tls/x86_64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/tls/x86_64", 0x7ffe7d0c9550) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/tls/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/tls", 0x7ffe7d0c9550)    = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/x86_64/x86_64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/x86_64/x86_64", 0x7ffe7d0c9550) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/x86_64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/x86_64", 0x7ffe7d0c9550) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/x86_64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/x86_64", 0x7ffe7d0c9550) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\3604\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=18248368, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb18f5af000
mmap(NULL, 3921920, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb18efcd000
mprotect(0x7fb18f181000, 2097152, PROT_NONE) = 0
mmap(0x7fb18f381000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1b4000) = 0x7fb18f381000
mmap(0x7fb18f387000, 14336, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fb18f387000
close(3)                                = 0
arch_prctl(ARCH_SET_FS, 0x7fb18f5b0500) = 0
mprotect(0x7fb18f381000, 16384, PROT_READ) = 0
mprotect(0x5653f40df000, 4096, PROT_READ) = 0
mprotect(0x7fb18f5b1000, 4096, PROT_READ) = 0
getresuid([0], [0], [0])                = 0
fstat(1, {st_mode=S_IFIFO|0600, st_size=0, ...}) = 0
brk(NULL)                               = 0x5653f4910000
brk(0x5653f4931000)                     = 0x5653f4931000
setuid(1000)                            = 0
getresuid([1000], [1000], [1000])       = 0
setuid(0)                               = -1 EPERM (Operation not permitted)
getresuid([1000], [1000], [1000])       = 0
write(1, "0 0 0\nsetuid(1000) succeded\n1000"..., 750 0 0
setuid(1000) succeded
1000 1000 1000
setuid(0) failed
1000 1000 1000
) = 75
exit_group(0)                           = ?
+++ exited with 0 +++
apilat
quelle
1
Fragen Sie, ob dies beabsichtigt ist? Wenn Sie dies als Fehler melden möchten, ist diese Site nicht der richtige Ort. Wenden Sie sich lieber an die Entwickler von musl ( Mailingliste oder IRC finden Sie unter musl-libc.org/support.html). Wenn Sie einen webbasierten Bugtracker bevorzugen, ist es wahrscheinlich auch in Ordnung, ihn den Void-Entwicklern auf Github ( github.com/voidlinux/void-packages/issues ) zu melden .
crater2150
Es wäre interessant, die tatsächlichen Systemaufrufe und ihre Rückgabewerte zu sehen, um zu sehen, wo der Fehler liegt. Können Sie stracebeide Versionen Ihres Programms ausführen und der Frage die entsprechenden Zeilen (get | set * uid) hinzufügen?
Mark Plotnick
@ crater2150 Soweit ich weiß, ist dies nicht beabsichtigt. Ich suche nach Informationen darüber, ob dies von anderen Benutzern reproduzierbar ist, und nach der Ursache für dieses Problem - ist es der Kernel, der Muslim oder ist mein Programm falsch? Ich werde die Frage bearbeiten, um dies klarer zu machen.
Apilat
1
Ich kann es nicht sehen Ich frage mich also, ob Funktionen beteiligt sind: Wenn normalerweise die euid oder die letzte uid ungleich Null wird, werden alle Funktionen gelöscht. Wenn jedoch das SECBIT_KEEP_CAPS-Bit gesetzt ist, werden die Funktionen nicht gelöscht.
Strg-Alt-Delor
1
Ich würde `{int fd = open (" / proc / self / status ", O_RDONLY) einfügen; dup2 (fd, 0); System ("Katze"); schließen (fd); } `auch dort, um einen Blick auf die Funktionsmasken des Prozesses zu werfen. Ich wette, sie müssen involviert sein, da AFAIK pure POSIX befürchtet, dass Ihre Situation nicht möglich sein sollte.
PSkocik

Antworten:

4

Das Problem kam in der Tat weder vom Kernel noch vom Muslim, sondern von den Fähigkeiten. Es stellte sich heraus, dass es einen Unterschied zwischen meinen beiden Testsystemen gab - glibcund musl-, der den Anschein erweckte, als hätte es etwas mit ihnen zu tun.

Das Problem wurde tatsächlich durch das pam_rundir.soModul verursacht, das das SECBIT_NO_SETUID_FIXUPsichere Bit gesetzt hat, wodurch der Kernel die Funktionen für das Programm danach setuidbeibehält (wodurch ich setuidzurückkehren kann root).

apilat
quelle