【发布时间】:2018-04-11 15:00:19
【问题描述】:
程序在嵌入式 Linux(内核版本:3.4.0)上执行。在调用execve()之前,还调用setgid()和setuid()切换到另一个用户(tstuser)。用户存在,必要的条目在/etc/[passwd && group && shadow] 中找到。命令su tstuser(由root)也简单地报告“Killed”。之前已经用getrlimit() 检查过资源限制,似乎一切正常。在dmesg && /var/log/messages 中找不到错误日志(不是一行)。
可能是什么原因?我怎样才能让内核更详细?有什么想法或进一步调查的地方吗?
完整代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <pwd.h>
int main( int argc, char *argv[] ) {
char *newargv[] = { NULL, NULL };
char *newenviron[] = { NULL };
if ( argc != 2 ) {
fprintf( stderr, "Usage: %s <file-to-exec>\n", argv[0] );
exit( EXIT_FAILURE );
}
newargv[0] = argv[1];
struct passwd * pw;
if ( ( pw = getpwnam( "tstuser" ) ) == NULL ) {
fprintf( stderr, "ERROR: the specified user '%s' does not exist\n", "tstuser" );
exit( EXIT_FAILURE );
}
else {
if ( setgid( pw->pw_gid ) != 0 ) {
fprintf( stderr, "ERROR: setgid() to %d failed\n", pw->pw_gid );
exit( EXIT_FAILURE );
}
else if ( setuid( pw->pw_uid ) != 0 ) {
fprintf( stderr, "ERROR: setuid() to %d failed\n", pw->pw_uid );
exit( EXIT_FAILURE );
}
}
execve( argv[1], newargv, newenviron );
perror( "execve" );
exit( EXIT_FAILURE );
}
完整的 strace 输出:
~# strace ./execve /bin/ls
execve("./execve", ["./execve", "/bin/ls"], [/* 13 vars */]) = 0
brk(0) = 0x145d000
uname({sys="Linux", node="sagVED_A", ...}) = 0
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=4666, ...}) = 0
mmap2(NULL, 4666, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb6fb5000
close(3) = 0
open("/lib/tls/v5l/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat64("/lib/tls/v5l", 0xbee6b468) = -1 ENOENT (No such file or directory)
open("/lib/tls/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat64("/lib/tls", 0xbee6b468) = -1 ENOENT (No such file or directory)
open("/lib/v5l/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat64("/lib/v5l", 0xbee6b468) = -1 ENOENT (No such file or directory)
open("/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0(\0\1\0\0\0\354\225\262F4\0\0\0"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=1245200, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb6fb4000
mmap2(0x46b10000, 1284496, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x46b10000
mprotect(0x46c3c000, 32768, PROT_NONE) = 0
mmap2(0x46c44000, 16384, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x12c) = 0x46c44000
mmap2(0x46c48000, 6544, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x46c48000
close(3) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb6fb3000
set_tls(0xb6fb34c0, 0xb6fb3b98, 0x46b07058, 0xb6fb34c0, 0x46b07058) = 0
mprotect(0x46c44000, 8192, PROT_READ) = 0
mprotect(0x46b06000, 4096, PROT_READ) = 0
munmap(0xb6fb5000, 4666) = 0
brk(0) = 0x145d000
brk(0x147e000) = 0x147e000
socket(PF_FILE, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0) = 3
connect(3, {sa_family=AF_FILE, sun_path="/var/run/nscd/socket"}, 110) = -1 ENOENT (No such file or directory)
close(3) = 0
socket(PF_FILE, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0) = 3
connect(3, {sa_family=AF_FILE, sun_path="/var/run/nscd/socket"}, 110) = -1 ENOENT (No such file or directory)
close(3) = 0
open("/etc/nsswitch.conf", O_RDONLY|O_CLOEXEC) = 3
fcntl64(3, F_GETFD) = 0x1 (flags FD_CLOEXEC)
fstat64(3, {st_mode=S_IFREG|0644, st_size=465, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb6fb6000
read(3, "# /etc/nsswitch.conf\n#\n# Example"..., 4096) = 465
read(3, "", 4096) = 0
close(3) = 0
munmap(0xb6fb6000, 4096) = 0
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=4666, ...}) = 0
mmap2(NULL, 4666, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb6fb5000
close(3) = 0
open("/lib/libnss_compat.so.2", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0(\0\1\0\0\0\340\r\0\0004\0\0\0"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=30524, ...}) = 0
mmap2(NULL, 62060, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb6fa3000
mprotect(0xb6fa9000, 32768, PROT_NONE) = 0
mmap2(0xb6fb1000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x6) = 0xb6fb1000
close(3) = 0
open("/lib/libnsl.so.1", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0(\0\1\0\0\0p/\361F4\0\0\0"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=73264, ...}) = 0
mmap2(0x46f10000, 112464, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x46f10000
mprotect(0x46f21000, 28672, PROT_NONE) = 0
mmap2(0x46f28000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x10) = 0x46f28000
mmap2(0x46f2a000, 5968, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x46f2a000
close(3) = 0
mprotect(0x46f28000, 4096, PROT_READ) = 0
mprotect(0xb6fb1000, 4096, PROT_READ) = 0
munmap(0xb6fb5000, 4666) = 0
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=4666, ...}) = 0
mmap2(NULL, 4666, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb6fb5000
close(3) = 0
open("/lib/libnss_nis.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/usr/lib/tls/v5l/libnss_nis.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat64("/usr/lib/tls/v5l", 0xbee6b340) = -1 ENOENT (No such file or directory)
open("/usr/lib/tls/libnss_nis.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat64("/usr/lib/tls", 0xbee6b340) = -1 ENOENT (No such file or directory)
open("/usr/lib/v5l/libnss_nis.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat64("/usr/lib/v5l", 0xbee6b340) = -1 ENOENT (No such file or directory)
open("/usr/lib/libnss_nis.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat64("/usr/lib", {st_mode=S_IFDIR|0755, st_size=8456, ...}) = 0
munmap(0xb6fb5000, 4666) = 0
open("/etc/passwd", O_RDONLY|O_CLOEXEC) = 3
fcntl64(3, F_GETFD) = 0x1 (flags FD_CLOEXEC)
_llseek(3, 0, [0], SEEK_CUR) = 0
fstat64(3, {st_mode=S_IFREG|0644, st_size=848, ...}) = 0
mmap2(NULL, 848, PROT_READ, MAP_SHARED, 3, 0) = 0xb6fb6000
_llseek(3, 848, [848], SEEK_SET) = 0
munmap(0xb6fb6000, 848) = 0
close(3) = 0
setgid32(1001) = 0
setuid32(1001) = 0
execve("/bin/ls", ["/bin/ls"], [/* 0 vars */] <unfinished ...>
+++ killed by SIGKILL +++
Killed
【问题讨论】:
-
尝试不使用 setuid/setgid。问题可能是一些模糊的权限,而不是 execve 本身。此外,可能会尝试至少将 argv[0] 传递给新进程。
-
在这里工作。 (使用
sudo ./a.out /bin/ls)也许涉及到selinux?系统日志说什么? -
没有 setuid/setgid 就可以了。没有 setuid 也可以。发布的原始应用程序适用于周围可用的任何其他平台。它仅不适用于这个特定的嵌入式平台(KaRo TX28 SOC、Poky (Yocto) 发行版、3.4.0 内核。
-
不使用 SELinux。最令人不安的是,syslog 或 dmesg 中没有一条日志行。当 OOM 发生并且内核在同一个平台上杀死一个进程时,dmesg 会显示发生了什么。目前有 70 / 128 MB 内存可用。
-
用printk()消息修饰内核源码后,现在可以看出SIGKILL来自fs/binfmt_elf.c:elixir.bootlin.com/linux/v3.4/source/fs/binfmt_elf.c#L812可能是什么原因?
标签: linux embedded-linux su execve