Оба system()
и _ 2_ может использоваться для выполнения другой команды внутри программы. Почему в программах с установленным UID system()
опасно, а execve()
безопасно?
система () против execve ()
Ответы (3)
система вызовет оболочку (sh), чтобы выполнить команду, отправленную в качестве аргумента. Проблема с system
, потому что поведение оболочки зависит от пользователя, запустившего команду. Небольшой пример:
Создание файла test.c
:
#include <stdio.h>
int main(void) {
if (system ("ls") != 0)
printf("Error!");
return 0;
}
Потом:
$ gcc test.c -o test
$ sudo chown root:root test
$ sudo chmod +s test
$ ls -l test
-rwsr-sr-x 1 root root 6900 Dec 12 17:53 test
Создание скрипта с именем ls
в вашем текущем каталоге:
$ cat > ls
#!/bin/sh
/bin/sh
$ chmod +x ls
Теперь:
$ PATH=. ./test
# /usr/bin/id
uid=1000(cuonglm) gid=1000(cuonglm) euid=0(root) egid=0(root) groups=0(root),
24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),105(scanner),
110(bluetooth),111(netdev),999(docker),1000(cuonglm)
# /usr/bin/whoami
root
К сожалению, у вас есть оболочка с привилегиями root.
execve не вызывает оболочку. Он выполняет программу, переданную ему в качестве первого аргумента. Программа должна быть двоичным исполняемым файлом или сценарием, начинающимся со строки shebang.
system()
без проблем, но разве вышеупомянутое нельзя решить с помощью абсолютных путей в двоичном исполняемом файле?
- person Bratchley; 12.12.2014
ls
может делать необычные вещи со своим окружением, поэтому даже без system()
вам, вероятно, следует очистить среду. При использовании setuids вы хотите свести к минимуму то, что делается от имени root (обычно не выполнять команды).
- person Stephane Chazelas; 12.12.2014
/bin/ls
, пользователь может добавить /
к $IFS
, в результате чего оболочка разделится /bin/ls
на bin
и ls
. Теперь исполняемый файл с именем bin
в текущем каталоге может делать то же самое, что и ls
в моем ответе.
- person cuonglm; 12.12.2014
system()
и execve()
работают по-разному. system()
всегда будет вызывать оболочку, и эта оболочка будет выполнять команду как отдельный процесс (вот почему вы можете использовать подстановочные знаки и другие средства оболочки в командной строке при использовании system()
).
execve()
(и другие функции в семействе exec()
) заменяет текущий процесс тем, который создается напрямую (функция execve()
не возвращается, за исключением случая сбоя). Фактически реализация system()
должна использовать последовательность вызовов fork()
, execve()
и wait()
для выполнения своей функции.
Конечно, и то, и другое опасно в зависимости от того, что выполняется, когда у процесса есть привилегии root. system()
, однако, несет некоторые дополнительные опасности из-за дополнительного «слоя» оболочки, который он использует, который открывает бреши в безопасности комнаты, поскольку он вызывает корневую оболочку, как в случае вашего вопроса (т.е. процесс имеет бит suid).
Помимо отмеченных проблем безопасности с system()
, порожденный процесс наследует среду основной программы. Это может быть очень проблематичным при использовании suid
, например, когда вызывающий процесс устанавливает переменную LD_LIBRARY_PATH
-окружения.
С семейством exec()
вызывающая программа может установить среду в точности так, как это необходимо (и безопасно) для вызываемой программы, перед вызовом exec()
.
И, конечно же, оболочка, вызываемая system()
, сама может иметь проблемы с безопасностью.