Linux
在musl libc中setuid(1000)後可以恢復root權限
musl libc
即使uid
在root
使用setuid(1000)
. 我無法重現該問題glibc
。程式碼:
#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; }
使用 編譯後
gcc -o setuidtest setuidtest.c
,以 root 身份執行時會產生以下輸出0 0 0 setuid(1000) succeded 1000 1000 1000 setuid(0) succeded 0 0 0
我正在執行核心版本和 musl 版本、glibc 版本的Void Linux
4.18_1``1.1.20_2``2.28_3
這個問題從何而來?是我的核心、musl libc 還是我的測試程式碼不正確?這個問題可以被其他人重現嗎?
strace 輸出(musl 無特權)
$ 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 輸出(musl 作為根)
# 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 輸出(glibc 非特權)
$ 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 輸出(glibc 作為根)
# 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 +++
這個問題確實不是來自核心或musl,而是來自功能。事實證明,我的兩個測試系統之間存在差異 -
glibc
並且musl
- 這似乎與它們有關。問題實際上是由設置安全位的
pam_rundir.so
模組SECBIT_NO_SETUID_FIXUP
引起的,這使得核心在之後保留程序的功能setuid
(因此允許我setuid
返回root
)。