Мне трудно понять, почему моя программа setuid не выглядит так, как будто она на самом деле повышает разрешения, хотя идентификатор кажется правильным. Это работает на ядре 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
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) = ?
echo 3 > /proc/sys/vm/drop_caches
) без вашей программы (используяsu
илиsudo /bin/sh -c <command>
)? - person Tsyvarev   schedule 13.09.2016exit(0);
неверно для выхода после состояния ошибки. Это потому, что 0 является показателем успеха. Предложите использовать (из stdlib.h)exit( EXIT_FAILURE );
- person user3629249   schedule 15.09.2016switch()
написан неправильно. В конце каждого случая должен быть операторbreak;
. - person user3629249   schedule 15.09.2016/dev/myrandom
не является частью ОС, вы сами его создали? Какие разрешения/свойства у него есть? - person user3629249   schedule 15.09.2016system("dd if=/dev/zero of=/dev/myrandom");
/dev/zero
предоставит только запрошенное количество символов NUL. К сожалению, в командной строке отсутствует параметрcount=
, поэтому этот вызов может никогда не завершиться. - person user3629249   schedule 15.09.2016echo 3 > /proc/sys/vm/drop_caches
Этот файл не является средством управления ростом различных кэшей ядра (иноды, dentries, кэш страниц и т. д.). Эти объекты автоматически освобождаются ядром, когда память требуется в другом месте на система. Использование этого файла может вызвать проблемы с производительностью. Поскольку он отбрасывает кэшированные объекты, повторное создание отброшенных объектов может потребовать значительного объема операций ввода-вывода и ЦП, особенно если они интенсивно использовались. По этой причине не рекомендуется использовать его вне среды тестирования или отладки. - person user3629249   schedule 15.09.2016