为什么 execve 调用在启用 SELinux 的情况下失败?

Why is execve call failing with enabled SELinux?

我在 Linux 系统上,最近在许可和强制模式下启用了 SELinux。 使用正确的用户名和密码在 shell 中执行登录命令时,我在 execve() 系统调用上收到 "Permission denied" 错误消息。 使用 strace 调试所有系统调用会导致以下输出。

...
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x400a3000
set_tls(0x400a2d90)                     = 0
mprotect(0x40201000, 8192, PROT_READ)   = 0
mprotect(0x40364000, 4096, PROT_READ)   = 0
mprotect(0x402e4000, 4096, PROT_READ)   = 0
mprotect(0x402b8000, 4096, PROT_READ)   = 0
mprotect(0x4021d000, 4096, PROT_READ)   = 0
mprotect(0x400aa000, 4096, PROT_READ)   = 0
munmap(0x4009e000, 9811)                = 0
statfs("/sys/fs/selinux", {f_type=SELINUX_MAGIC, f_bsize=4096, f_blocks=0, f_bfree=0, f_bavail=0, f_files=0, f_ffree=0, f_fsid={val=[0, 0]}, f_namelen=255, f_frsize=4096, f_flags=ST_VALID|ST_RELATIME}) = 0
statfs("/sys/fs/selinux", {f_type=SELINUX_MAGIC, f_bsize=4096, f_blocks=0, f_bfree=0, f_bavail=0, f_files=0, f_ffree=0, f_fsid={val=[0, 0]}, f_namelen=255, f_frsize=4096, f_flags=ST_VALID|ST_RELATIME}) = 0
stat64("/sys/fs/selinux", {st_mode=S_IFDIR|0755, st_size=0, ...}) = 0
brk(NULL)                               = 0x907000
brk(0x928000)                           = 0x928000
access("/etc/selinux/config", F_OK)     = 0
getuid32()                              = 0
geteuid32()                             = 0
open("/dev/null", O_RDWR)               = 3
close(3)                                = 0
ioctl(0, TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(1, TCGETS, {B38400 opost isig icanon echo ...}) = 0
rt_sigaction(SIGALRM, {sa_handler=0x400b76ed, sa_mask=[ALRM], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x4013cae1}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
setitimer(ITIMER_REAL, {it_interval={tv_sec=0, tv_usec=0}, it_value={tv_sec=60, tv_usec=0}}, {it_interval={tv_sec=0, tv_usec=0}, it_value={tv_sec=0, tv_usec=0}}) = 0
ioctl(0, TCGETS, {B38400 opost isig icanon echo ...}) = 0
fstat64(0, {st_mode=S_IFCHR|0622, st_rdev=makedev(136, 1), ...}) = 0
readlink("/proc/self/fd/0", "/dev/pts/1", 126) = 10
stat64("/dev/pts/1", {st_mode=S_IFCHR|0622, st_rdev=makedev(136, 1), ...}) = 0
ioctl(0, TCFLSH, TCIFLUSH)              = 0
uname({sysname="Linux", nodename="node", ...}) = 0
fstat64(1, {st_mode=S_IFCHR|0622, st_rdev=makedev(136, 1), ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x4009e000
write(1, "node login: ", node login: )            = 12
fstat64(0, {st_mode=S_IFCHR|0622, st_rdev=makedev(136, 1), ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x4009f000
read(0, 
"\n", 1024)                 = 5
open("/etc/passwd", O_RDONLY)           = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=63, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x400a0000
read(3, ""..., 1024) = 63
close(3)                                = 0
munmap(0x400a0000, 4096)                = 0
open("/etc/securetty", O_RDONLY)        = -1 ENOENT (No such file or directory)
ioctl(0, TCFLSH, TCIFLUSH)              = 0
write(1, "Password: ", 10Password: )              = 10
ioctl(0, TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(0, SNDCTL_TMR_START or TCSETS, {B38400 opost isig icanon -echo ...}) = 0
rt_sigaction(SIGINT, {sa_handler=0x400f43b9, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x4013cae1}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
rt_sigaction(SIGINT, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x4013cae1}, NULL, 8) = 0
ioctl(0, SNDCTL_TMR_START or TCSETS, {B38400 opost isig icanon echo ...}) = 0
write(1, "\n", 1
)                       = 1
open("/proc/sys/crypto/fips_enabled", O_RDONLY) = -1 ENOENT (No such file or directory)
setitimer(ITIMER_REAL, {it_interval={tv_sec=0, tv_usec=0}, it_value={tv_sec=0, tv_usec=0}}, {it_interval={tv_sec=0, tv_usec=0}, it_value={tv_sec=57, tv_usec=707306}}) = 0
open("/etc/selinux/config", O_RDONLY|O_CLOEXEC) = 3
fcntl64(3, F_GETFD)                     = 0x1 (flags FD_CLOEXEC)
fstat64(3, {st_mode=S_IFREG|0644, st_size=586, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x400a0000
read(3, "# This file controls the state o"..., 1024) = 586
read(3, "", 1024)                       = 0
close(3)                                = 0
munmap(0x400a0000, 4096)                = 0
open("/proc/thread-self/attr/current", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
gettid()                                = 970
open("/proc/self/task/970/attr/current", O_RDONLY|O_CLOEXEC) = 3
read(3, "system_u:system_r:init_t[=10=]", 4095) = 25
close(3)                                = 0
access("/var/run/setrans/.setrans-unix", F_OK) = -1 ENOENT (No such file or directory)
open("/sys/fs/selinux/user", O_RDWR|O_CLOEXEC) = 3
write(3, "system_u:system_r:init_t root", 29) = 29
read(3, "5[=10=]root:staff_r:shutdown_t[=10=]root:s"..., 4095) = 127
close(3)                                = 0
open("/etc/selinux/refpolicy/contexts/users/root", O_RDONLY|O_CLOEXEC) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=630, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x400a0000
read(3, "system_r:crond_t\tunconfined_r:un"..., 1024) = 630
read(3, "", 1024)                       = 0
close(3)                                = 0
munmap(0x400a0000, 4096)                = 0
open("/etc/selinux/refpolicy/contexts/default_contexts", O_RDONLY|O_CLOEXEC) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=951, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x400a0000
read(3, "system_r:crond_t\tuser_r:user_t s"..., 1024) = 951
read(3, "", 1024)                       = 0
close(3)                                = 0
munmap(0x400a0000, 4096)                = 0
open("/etc/selinux/refpolicy/contexts/failsafe_context", O_RDONLY|O_CLOEXEC) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=18, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x400a0000
read(3, "sysadm_r:sysadm_t\n", 1024)    = 18
close(3)                                = 0
munmap(0x400a0000, 4096)                = 0
open("/sys/fs/selinux/context", O_RDWR|O_CLOEXEC) = 3
write(3, "root:sysadm_r:sysadm_t[=10=]", 23) = 23
close(3)                                = 0
getxattr("/dev/pts/1", "security.selinux", "system_u:object_r:devpts_t", 255) = 27
open("/sys/fs/selinux/relabel", O_RDWR|O_CLOEXEC) = 3
write(3, "root:sysadm_r:sysadm_t system_u:"..., 52) = 52
read(3, "root:object_r:devpts_t[=10=]", 4095) = 23
close(3)                                = 0
setxattr("/dev/pts/1", "security.selinux", "root:object_r:devpts_t", 23, 0) = 0
fchown32(0, 0, 0)                       = 0
fchmod(0, 0600)                         = 0
open("/etc/group", O_RDONLY)            = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=10, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x400a0000
read(3, "root:x:0:\n", 1024)            = 10
read(3, "", 1024)                       = 0
close(3)                                = 0
munmap(0x400a0000, 4096)                = 0
setgroups32(1, [0])                     = 0
setgid32(0)                             = 0
setuid32(0)                             = 0
chdir("/root")                          = 0
access(".hushlogin", F_OK)              = -1 ENOENT (No such file or directory)
open("/etc/motd", O_RDONLY)             = -1 ENOENT (No such file or directory)
gettimeofday({tv_sec=1542874616, tv_usec=399369}, NULL) = 0
open("/etc/localtime", O_RDONLY|O_CLOEXEC) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=2309, ...}) = 0
fstat64(3, {st_mode=S_IFREG|0644, st_size=2309, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x400a0000
read(3, "TZif2[=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=]"..., 1024) = 1024
_llseek(3, 1257, [2281], SEEK_CUR)      = 0
read(3, "\nCET-1CEST,M3.5.0,M10.5.0/3\n", 1024) = 28
close(3)                                = 0
munmap(0x400a0000, 4096)                = 0
getpid()                                = 970
socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0) = 3
connect(3, {sa_family=AF_UNIX, sun_path="/dev/log"}, 110) = -1 EPROTOTYPE (Protocol wrong type for socket)
close(3)                                = 0
socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0) = 3
connect(3, {sa_family=AF_UNIX, sun_path="/dev/log"}, 110) = 0
send(3, "<38>Nov 22 09:16:56 login[970]: "..., 54, MSG_NOSIGNAL) = 54
rt_sigaction(SIGINT, {sa_handler=SIG_DFL, sa_mask=[INT], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x4013cae1}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x4013cae1}, 8) = 0
open("/proc/thread-self/attr/exec", O_RDWR|O_CLOEXEC) = -1 ENOENT (No such file or directory)
gettid()                                = 970
open("/proc/self/task/970/attr/exec", O_RDWR|O_CLOEXEC) = 4
write(4, "root:sysadm_r:sysadm_t[=10=]", 23) = 23
close(4)                                = 0
execve("/bin/sh", ["-sh"], 0x907b30 /* 6 vars */) = -1 EACCES (Permission denied)
write(2, "login: can't execute '/bin/sh': "..., 50login: can't execute '/bin/sh': Permission denied
) = 50
exit_group(1)                           = ?
+++ exited with 1 +++

禁用 SE 后错误消息消失Linux,登录命令成功。请参阅下面的输出。

...
send(3, "<38>Nov 23 16:25:16 login[883]: "..., 54, MSG_NOSIGNAL) = 54
rt_sigaction(SIGINT, {sa_handler=SIG_DFL, sa_mask=[INT], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x400fcae1}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x400fcae1}, 8) = 0
execve("/bin/sh", ["-sh"], 0x32a3d0 /* 6 vars */) = 0
brk(NULL)                               = 0x1e14000
...

在特定上下文中尝试 运行 ssh 的另一项测试也会导致 "Permission denied" 消息。

~ # runcon system_u:system_r:sshd_t /usr/sbin/sshd 
runcon: can't execute '/usr/sbin/sshd': Permission denied
~ # strace runcon system_u:system_r:sshd_t /usr/sbin/sshd 
execve("/usr/bin/runcon", ["runcon", "system_u:system_r:sshd_t", "/usr/sbin/sshd"], 0xbea60de8 /* 12 vars */) = 0
brk(NULL)                               = 0x120b000
uname({sysname="Linux", nodename="node", ...}) = 0
mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x400cb000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=9811, ...}) = 0
mmap2(NULL, 9811, PROT_READ, MAP_PRIVATE, 3, 0) = 0x400cd000
close(3)                                = 0
...
various lib loading with no error
...
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x400d2000
set_tls(0x400d1d90)                     = 0
mprotect(0x40230000, 8192, PROT_READ)   = 0
mprotect(0x40393000, 4096, PROT_READ)   = 0
mprotect(0x40313000, 4096, PROT_READ)   = 0
mprotect(0x402e7000, 4096, PROT_READ)   = 0
mprotect(0x4024c000, 4096, PROT_READ)   = 0
mprotect(0x400d9000, 4096, PROT_READ)   = 0
munmap(0x400cd000, 9811)                = 0
statfs("/sys/fs/selinux", {f_type=SELINUX_MAGIC, f_bsize=4096, f_blocks=0, f_bfree=0, f_bavail=0, f_files=0, f_ffree=0, f_fsid={val=[0, 0]}, f_namelen=255, f_frsize=4096, f_flags=ST_VALID|ST_RELATIME}) = 0
statfs("/sys/fs/selinux", {f_type=SELINUX_MAGIC, f_bsize=4096, f_blocks=0, f_bfree=0, f_bavail=0, f_files=0, f_ffree=0, f_fsid={val=[0, 0]}, f_namelen=255, f_frsize=4096, f_flags=ST_VALID|ST_RELATIME}) = 0
stat64("/sys/fs/selinux", {st_mode=S_IFDIR|0755, st_size=0, ...}) = 0
brk(NULL)                               = 0x120b000
brk(0x122c000)                          = 0x122c000
access("/etc/selinux/config", F_OK)     = 0
access("/var/run/setrans/.setrans-unix", F_OK) = -1 ENOENT (No such file or directory)
open("/sys/fs/selinux/context", O_RDWR|O_CLOEXEC) = 3
write(3, "system_u:system_r:sshd_t[=12=]", 25) = 25
close(3)                                = 0
open("/proc/thread-self/attr/exec", O_RDWR|O_CLOEXEC) = -1 ENOENT (No such file or directory)
gettid()                                = 976
open("/proc/self/task/976/attr/exec", O_RDWR|O_CLOEXEC) = 3
write(3, "system_u:system_r:sshd_t[=12=]", 25) = 25
close(3)                                = 0
execve("/usr/sbin/sshd", ["/usr/sbin/sshd"], 0xbec8dde4 /* 12 vars */) = -1 EACCES (Permission denied)
write(2, "runcon: can't execute '/usr/sbin"..., 58runcon: can't execute '/usr/sbin/sshd': Permission denied
) = 58
exit_group(126)                         = ?
+++ exited with 126 +++

启用 SELinux 时如何解决此错误?

编辑: 在调查 sys_execve() 实现后,错误应该出现在函数 do_open_exec() (https://elixir.bootlin.com/linux/v3.18/source/fs/exec.c#L750) 中。 我不确定是哪个文件访问触发了错误。

已找到解决此问题的方法。 我的根分区挂载了 nosuid 标志。如本博客 post https://danwalsh.livejournal.com/68723.html 中所述,进程无法更改其域。 挂载没有nosuid的分区解决了这个问题。