setuid () перед вызовом execv () в vfork () / clone ()

Мне нужно разблокировать exec с сервера. Поскольку мой размер памяти для печати на сервере большой, я намерен использовать vfork() / linux clone() . Мне также нужно открыть трубы для stdin / stdout / stderr . Разрешено ли это с помощью clone() / vfork() ?

Из стандарта:

[..] поведение не определено, если процесс, созданный vfork() либо изменяет любые данные, отличные от переменной типа pid_t используемые для хранения возвращаемого значения из vfork() , либо возвращает из функции, в которой был вызван vfork() , или вызывает любую другую функцию перед успешным вызовом функции _exit() или одного из семейств функций exec .

Проблема с вызывающими функциями, такими как setuid или pipe заключается в том, что они могут влиять на память в адресном пространстве, разделяемом между родительским и дочерним процессами. Если вам нужно что-то сделать до exec , лучший способ – написать небольшой процесс прокладки, который сделает все, что вам нужно, а затем exec s для последующего дочернего процесса (возможно, аргументы, предоставленные через argv ).

 shim.c ====== enum { /* initial arguments */ ARGV_FILE = 5, ARGV_ARGS }; int main(int argc, char *argv[]) { /* consume instructions from argv */ /* setuid, pipe() etc. */ return execvp(argv[ARGV_FILE], argv + ARGV_ARGS); } 

Вместо этого я использовал бы clone() , используя CLONE_VFORK|CLONE_VM ; см. man 2 clone для деталей.

Поскольку CLONE_FILES не установлен, дочерний процесс имеет свои собственные файловые дескрипторы и может закрывать и открывать стандартные дескрипторы, не затрагивая вообще родителя.

Поскольку клонированный процесс представляет собой отдельный процесс, он имеет свои собственные идентификаторы пользователей и групп, поэтому устанавливая их через setresgid() и setresuid() (возможно, setgroups() или initgroups() чтобы установить дополнительные группы – см. Man 2 setresuid , man 2 setgroups и man 3 initgroups для деталей) никак не повлияет на родителя.

CLONE_VFORK|CLONE_VM означают, что clone() должен вести себя как vfork() , при этом дочерний процесс работает в том же пространстве памяти, что и родительский процесс, до вызова execve() .

Такой подход позволяет избежать задержек при использовании промежуточного исполняемого файла – это довольно важно – но подход полностью зависит от Linux.