Ядро Linux в комментариях

       

Do_execve


Тип, представляющий всю информацию, которая должна отслеживаться преобразуемым в exec процессом, является struct linux_binprm (см. строку ) — скорее всего, binprm является аббревиатурой слов «binary parameters» («двоичные параметры»). do_execve выполняет свою задачу и осуществляет обмен данными с другими функциями, которым она делегировала часть своей работы посредством переменной bprm. Обратите внимание, что переменная bprm освобождается, когда функция do_execve выполняет возврат — эта переменная требуется только во время создания exec, а не в течение всего времени существования процесса.

do_execve начинается с инициализации миниатюрной таблицы страниц (см. ), которая отслеживает страницы памяти, выделенные для аргументов и среды нового процесса. Для этого она выделяет MAX_ARG_PAGES страниц (в строке это значение определятся равным 32); на платформе х86 размер каждой страницы памяти равен 4 Кб, следовательно, общий доступный для аргументов и среды объем памяти составляет 32 х 4 Кб = 128 Кб. Лично я был весьма рад узнать об этом, поскольку иногда превышал этот предел — обычно, когда запускал команду типа cat * >/tmp/joined в каталоге, содержащем тысячи файлов; все эти имена файлов, будучи объединены, вполне могут занять более 128 Кб. Обычно я обхожу эту проблему, используя программу xargs, но, возможно, со временем я перекомпилирую ядро, установив более высокий предел для MAX_ARG_PAGES. По крайней мере, теперь я знаю как повысить этот предел, если он действительно начинает доставлять беспокойство. (Возможно некоторые решительные читатели решат вообще удалить этот жестко запрограммированный предел.) Всегда приятно иметь исходный код.

Следующий шаг — открытие выполняемого файла. Он еще не считывается — в настоящее время следует убедиться, что файл существует, чтобы функция do_execve знала, следует ли продолжать работу. В некоторых случаях функция do_execve была бы значительно более эффективной, если бы этот шаг был первым, вместо заполнения таблицы страниц bprm — если это не удается, время, затраченное на инициализацию таблицы страниц, оказывается потраченным зря. Однако это помогает, только если файл не существует — этот случай встречается слишком редко, чтобы для него стоило выполнять оптимизацию.


Продолжает заполнять bprm, в частности его члены argc и envc. Для заполнения этих членов функция do_execve использует функцию count (строка A HREF="part1_15.htm#l9480">9480), которая пошагово просматривает переданные массивы argv и envp, подсчитывая отличные от NULL указатели. Первый же указатель, имеющий значение NULL, прерывает список, в результате чего возвращается количество найденных до этого момента отличных от NULL указателей. Вначале это кажется еще одним возможным местом некоторого снижения эффективности: иногда программа, вызывающая функцию do_execve, уже знает длину массивов argv и envp. Следовательно, функцию do_execve можно было бы расширить для приема целочисленных аргументов argc и envc, которые, если не являются отрицательными, указывали бы длину соответствующих массивов. Но все не так просто: count также все время выполняет в сканируемом массиве проверку в поисках ошибок при доступе к памяти. Принуждение программы, вызывающей функцию do_execve (или точнее, доверие ей этого), выполнять такую проверку было ошибочным. Лучше оставить все так, как есть.

Копирует аргументы и среду в новый процесс, в основном посредством использования функции copy_strings (строка ). Эта функция кажется очень сложной, но ее задача достаточно проста: копировать строки в область памяти нового процесса, при необходимости выделяя страницы. Ее сложность проистекает из необходимости управлять таблицей страниц и пересекать границы областей ядра и пользователя, как подробнее освещено в .

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

Если достигнута эта точка, значит в одном из предшествующих шагов имела место ошибка. Любые страницы, выделенные для аргументов и среды программы, должны быть освобождены, после чего для сообщения об ошибке вызывающей программе должно быть возвращено отрицательное значение.


Содержание раздела