система () против execve ()

Оба system() и _ 2_ может использоваться для выполнения другой команды внутри программы. Почему в программах с установленным UID system() опасно, а execve() безопасно?


person Jake    schedule 12.12.2014    source источник


Ответы (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.

person cuonglm    schedule 12.12.2014
comment
Я не говорю, что system() без проблем, но разве вышеупомянутое нельзя решить с помощью абсолютных путей в двоичном исполняемом файле? - person Bratchley; 12.12.2014
comment
@JoelDavis, нет, вам нужно хотя бы очистить всю среду, дать нормальные значения по умолчанию для нескольких envvars (PATH, HOME ...), при необходимости сохранить некоторые env vars после дезинфекции (TERM, DISPLAY, LANG .. .) убедитесь, что fds 0, 1, 2 открыты ... В основном делайте то, что делает sudo. Даже тогда я бы туда не пошел. Не вызывайте оболочку в контексте повышения привилегий, если этого можно избежать. Обратите внимание, что ls может делать необычные вещи со своим окружением, поэтому даже без system() вам, вероятно, следует очистить среду. При использовании setuids вы хотите свести к минимуму то, что делается от имени root (обычно не выполнять команды). - person Stephane Chazelas; 12.12.2014
comment
@JoelDavis: Нет, у вас все еще есть проблема, даже если вы используете полный путь. Если вы используете /bin/ls, пользователь может добавить / к $IFS, в результате чего оболочка разделится /bin/ls на bin и ls. Теперь исполняемый файл с именем bin в текущем каталоге может делать то же самое, что и ls в моем ответе. - person cuonglm; 12.12.2014
comment
Спасибо вам обоим. На самом деле это был довольно интересный ответ. - person Bratchley; 12.12.2014

system() и execve() работают по-разному. system() всегда будет вызывать оболочку, и эта оболочка будет выполнять команду как отдельный процесс (вот почему вы можете использовать подстановочные знаки и другие средства оболочки в командной строке при использовании system()).

execve() (и другие функции в семействе exec()) заменяет текущий процесс тем, который создается напрямую (функция execve() не возвращается, за исключением случая сбоя). Фактически реализация system() должна использовать последовательность вызовов fork(), execve() и wait() для выполнения своей функции.

Конечно, и то, и другое опасно в зависимости от того, что выполняется, когда у процесса есть привилегии root. system(), однако, несет некоторые дополнительные опасности из-за дополнительного «слоя» оболочки, который он использует, который открывает бреши в безопасности комнаты, поскольку он вызывает корневую оболочку, как в случае вашего вопроса (т.е. процесс имеет бит suid).

person Marcelo    schedule 12.12.2014
comment
Итак, при использовании execve () ... вы упомянули, что он заменяет текущий процесс ... останется ли процесс setuid? - person Jake; 12.12.2014
comment
да. Новый процесс, инициированный execve, наследует ряд свойств заменяемого, таких как файловые дескрипторы, сокеты и т. Д., И эффективный uid является одним из них, но бывают ситуации, когда uid изменяется во время выполнения execve, например, если исполняемый файл, на который указывает параметр execve, имеет установленный бит suid. В этом случае uid изменяется на владельца файла, как он определен в файловой системе. - person Marcelo; 12.12.2014

Помимо отмеченных проблем безопасности с system(), порожденный процесс наследует среду основной программы. Это может быть очень проблематичным при использовании suid, например, когда вызывающий процесс устанавливает переменную LD_LIBRARY_PATH-окружения.

С семейством exec() вызывающая программа может установить среду в точности так, как это необходимо (и безопасно) для вызываемой программы, перед вызовом exec().

И, конечно же, оболочка, вызываемая system(), сама может иметь проблемы с безопасностью.

person TBrandt    schedule 12.12.2014
comment
Переменная среды LD_LIBRARY_PATH будет игнорироваться, если программа setuid запускается пользователем без полномочий root, за исключением случаев, когда реальный uid также равен 0. - person alam; 24.10.2018