_musl libc
_を使用すると、setuid(1000)
でアクセス許可を削除した後でも、uid
をroot
に変更できます。 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
_
私は実行しています Void Linux カーネルバージョン_4.18_1
_およびmuslバージョン_1.1.20_2
_、glibcバージョン_2.28_3
_
この問題はどこから来るのですか?それは私のカーネル、musl libcですか、それとも私のテストコードは間違っていますか?この問題は他の人にも再現可能ですか?
_$ 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 ./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 ./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 ./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のいずれかではなく、機能に起因していました。私の2つのテストシステム(glibc
とmusl
)には違いがあり、それらと関係があるように見えました。
この問題は、実際にはpam_rundir.so
セキュアビットを設定する SECBIT_NO_SETUID_FIXUP
module によって引き起こされました。これにより、カーネルはsetuid
の後にプログラムの機能を保持します(したがって、私をsetuid
に戻しroot
に戻します)。