【发布时间】:2016-09-13 01:53:52
【问题描述】:
我无法理解为什么我的 setuid 程序看起来并没有真正提升权限,即使 id 看起来是正确的。这是在 2.6 内核上运行并失败,但在 Ubuntu 14.04 上完全按照预期工作,做同样的事情。我需要一个程序,在执行期间的某些时候需要提升权限,而最低权限是默认设置。
#include <stdio.h>
#include <stdint.h>
#include <arpa/inet.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
static uid_t _orig_euid;
void save_privilege(void){
_orig_euid = geteuid();
printf("saved privilege: %d\n", _orig_euid);
}
void drop_privileges(void){
if(seteuid(getuid()) == -1){
exit(0);
}
printf("dropped privileges %d %d\n", getuid(), geteuid());
}
void reacquire_privileges(void){
if(setuid(_orig_euid) == -1){
exit(0);
}
printf("reacquired privileges %d %d\n", getuid(), geteuid());
}
void do_privileged(int rw){
switch(rw){
case 0:
//read from driver
system("dd if=/dev/myrandom bs=10 count=1");
case 1:
//write to driver
system("dd if=/dev/zero of=/dev/myrandom");
case 2:
//change something in proc fs
system("echo 3 > /proc/sys/vm/drop_caches");
default:
break;
}
}
int main(int argc, char *argv[]){
int i;
if(argc != 2){
printf("usage: %s testno\n", argv[0]);
return 0;
}
i = atoi(argv[1]);
save_privilege();
do_privileged(i);
drop_privileges();
do_privileged(i);
reacquire_privileges();
do_privileged(i);
return 0;
}
我的程序权限设置为:
ls -l
-rwsr-xr-x 1 root root 6547 Sep 13 00:35 test
我当前的用户 ID 是:
id
uid=1000(user) gid=1000(user)
我要写入的 procfs 条目是:
ls -l /proc/sys/vm/drop_caches
-rw-r--r-- 1 root root 0 Sep 13 00:36 /proc/sys/vm/drop_caches
当我运行程序时,我得到:
./test 2
saved privilege: 0
sh: cannot create /proc/sys/vm/drop_caches: Permission denied
dropped privileges 1000 1000
sh: cannot create /proc/sys/vm/drop_caches: Permission denied
reacquired privileges 1000 0
sh: cannot create /proc/sys/vm/drop_caches: Permission denied
但是,在 Ubuntu 14.04 上运行相同的程序可以正常工作 - 只有当权限被删除时,它才无法修改 procfs 条目。
这是一个 strace(./test_perm 与 ./test 相同)。
$ strace ./test_perm 2
execve("./test_perm", ["./test_perm", "2"], [/* 8 vars */]) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|0x4000000, -1, 0) = 0x40005000
open("/lib/libc.so.0", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0755, st_size=310348, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|0x4000000, -1, 0) = 0x40006000
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0(\0\1\0\0\0\260\256\0\0004\0\0\0"..., 4096) = 4096
mmap2(NULL, 360448, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x4000e000
mmap2(0x4000e000, 303968, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED, 3, 0) = 0x4000e000
mmap2(0x40060000, 4972, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 3, 0x4a) = 0x40060000
mmap2(0x40062000, 15112, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x40062000
close(3) = 0
munmap(0x40006000, 4096) = 0
stat("/lib/ld-uClibc.so.0", {st_mode=S_IFREG|0755, st_size=21200, ...}) = 0
mprotect(0x40060000, 4096, PROT_READ) = 0
mprotect(0x4000c000, 4096, PROT_READ) = 0
ioctl(0, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(1, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
geteuid32() = 1000
write(1, "saved privilege: 1000\n", 22saved privilege: 1000
) = 22
rt_sigaction(SIGQUIT, {SIG_IGN, [QUIT], SA_RESTART|0x4000000}, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGINT, {SIG_IGN, [INT], SA_RESTART|0x4000000}, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGCHLD, {SIG_DFL, [CHLD], SA_RESTART|0x4000000}, {SIG_DFL, [], 0}, 8) = 0
vfork(sh: cannot create /proc/sys/vm/drop_caches: Permission denied
) = 1183
--- SIGCHLD (Child exited) @ 0 (0) ---
rt_sigaction(SIGQUIT, {SIG_IGN, [QUIT], SA_RESTART|0x4000000}, {SIG_IGN, [QUIT], SA_RESTART|0x4000000}, 8) = 0
rt_sigaction(SIGINT, {SIG_IGN, [INT], SA_RESTART|0x4000000}, {SIG_IGN, [INT], SA_RESTART|0x4000000}, 8) = 0
wait4(1183, [{WIFEXITED(s) && WEXITSTATUS(s) == 2}], 0, NULL) = 1183
rt_sigaction(SIGQUIT, {SIG_DFL, [QUIT], SA_RESTART|0x4000000}, {SIG_IGN, [QUIT], SA_RESTART|0x4000000}, 8) = 0
rt_sigaction(SIGINT, {SIG_DFL, [INT], SA_RESTART|0x4000000}, {SIG_IGN, [INT], SA_RESTART|0x4000000}, 8) = 0
rt_sigaction(SIGCHLD, {SIG_DFL, [CHLD], SA_RESTART|0x4000000}, {SIG_DFL, [CHLD], SA_RESTART|0x4000000}, 8) = 0
getuid32() = 1000
setresuid32(-1, 1000, -1) = 0
getuid32() = 1000
geteuid32() = 1000
write(1, "dropped privileges 1000 1000\n", 29dropped privileges 1000 1000
) = 29
rt_sigaction(SIGQUIT, {SIG_IGN, [QUIT], SA_RESTART|0x4000000}, {SIG_DFL, [QUIT], SA_RESTART|0x4000000}, 8) = 0
rt_sigaction(SIGINT, {SIG_IGN, [INT], SA_RESTART|0x4000000}, {SIG_DFL, [INT], SA_RESTART|0x4000000}, 8) = 0
rt_sigaction(SIGCHLD, {SIG_DFL, [CHLD], SA_RESTART|0x4000000}, {SIG_DFL, [CHLD], SA_RESTART|0x4000000}, 8) = 0
vfork(sh: cannot create /proc/sys/vm/drop_caches: Permission denied
) = 1184
--- SIGCHLD (Child exited) @ 0 (0) ---
rt_sigaction(SIGQUIT, {SIG_IGN, [QUIT], SA_RESTART|0x4000000}, {SIG_IGN, [QUIT], SA_RESTART|0x4000000}, 8) = 0
rt_sigaction(SIGINT, {SIG_IGN, [INT], SA_RESTART|0x4000000}, {SIG_IGN, [INT], SA_RESTART|0x4000000}, 8) = 0
wait4(1184, [{WIFEXITED(s) && WEXITSTATUS(s) == 2}], 0, NULL) = 1184
rt_sigaction(SIGQUIT, {SIG_DFL, [QUIT], SA_RESTART|0x4000000}, {SIG_IGN, [QUIT], SA_RESTART|0x4000000}, 8) = 0
rt_sigaction(SIGINT, {SIG_DFL, [INT], SA_RESTART|0x4000000}, {SIG_IGN, [INT], SA_RESTART|0x4000000}, 8) = 0
rt_sigaction(SIGCHLD, {SIG_DFL, [CHLD], SA_RESTART|0x4000000}, {SIG_DFL, [CHLD], SA_RESTART|0x4000000}, 8) = 0
setuid32(1000) = 0
getuid32() = 1000
geteuid32() = 1000
write(1, "reacquired privileges 1000 1000\n", 32reacquired privileges 1000 1000
) = 32
rt_sigaction(SIGQUIT, {SIG_IGN, [QUIT], SA_RESTART|0x4000000}, {SIG_DFL, [QUIT], SA_RESTART|0x4000000}, 8) = 0
rt_sigaction(SIGINT, {SIG_IGN, [INT], SA_RESTART|0x4000000}, {SIG_DFL, [INT], SA_RESTART|0x4000000}, 8) = 0
rt_sigaction(SIGCHLD, {SIG_DFL, [CHLD], SA_RESTART|0x4000000}, {SIG_DFL, [CHLD], SA_RESTART|0x4000000}, 8) = 0
vfork(sh: cannot create /proc/sys/vm/drop_caches: Permission denied
) = 1185
--- SIGCHLD (Child exited) @ 0 (0) ---
rt_sigaction(SIGQUIT, {SIG_IGN, [QUIT], SA_RESTART|0x4000000}, {SIG_IGN, [QUIT], SA_RESTART|0x4000000}, 8) = 0
rt_sigaction(SIGINT, {SIG_IGN, [INT], SA_RESTART|0x4000000}, {SIG_IGN, [INT], SA_RESTART|0x4000000}, 8) = 0
wait4(1185, [{WIFEXITED(s) && WEXITSTATUS(s) == 2}], 0, NULL) = 1185
rt_sigaction(SIGQUIT, {SIG_DFL, [QUIT], SA_RESTART|0x4000000}, {SIG_IGN, [QUIT], SA_RESTART|0x4000000}, 8) = 0
rt_sigaction(SIGINT, {SIG_DFL, [INT], SA_RESTART|0x4000000}, {SIG_IGN, [INT], SA_RESTART|0x4000000}, 8) = 0
rt_sigaction(SIGCHLD, {SIG_DFL, [CHLD], SA_RESTART|0x4000000}, {SIG_DFL, [CHLD], SA_RESTART|0x4000000}, 8) = 0
exit(0) = ?
【问题讨论】:
-
2.6 版中的下一个数字是多少?与 3.x 和 4.x 内核系列不同,它有一种感觉。无论如何,2.6.x内核系列都比较老了,你确定要支持吗?此外,在现代发行版下编译旧内核可能会导致内核内核和 libc 之间不兼容。你可以在没有你的程序(使用
su或sudo /bin/sh -c <command>)的情况下执行相同的操作(echo 3 > /proc/sys/vm/drop_caches)吗? -
@Tsyvarev,即使是 y 在 2.6.x.y 版本控制中也有意义。
-
输出重定向 '>' 可能通过 system() 函数导致问题。 'echo 3 > ...' 是唯一不起作用的命令吗?如果是这样,请尝试进入特权模式,实际通过 open(2) 和 write(2) 打开 proc 文件。
-
@Tsyvarev 内核是 2.6.28.9,这是用于具有自定义发行版的嵌入式平台。绝对计划在未来迁移到更新的内核,但现在,必须让它适用于现有项目。执行相同命令的 sudo 效果很好,我不明白。为了解决 kaiwan 的问题,这不是唯一不起作用的命令,它只是一个示例,我也无法使用系统调用 system("insmod testdriver.ko") 加载驱动程序,基本上我能做的任何事情作为root,我不能使用上面的程序。
-
一般来说,此语句:
exit(0);不适合在出现错误情况后退出。那是因为 0 表示成功。建议使用(来自 stdlib.h)exit( EXIT_FAILURE );
标签: c permissions linux-kernel setuid