Можно ли изменить argv во время выполнения (не самим приложением) - PullRequest
7 голосов
/ 30 января 2020

Интересно, могут ли параметры ввода main() быть изменены во время выполнения. Другими словами, должны ли мы защищать приложение от возможных атак TOCTTOU при обработке данных в argv? В настоящее время я не знаю способа изменить данные, которые были переданы в argv, но я не уверен, что таких способов не существует.

UPD: я забыл указать, что я ' Мне любопытно изменить argv извне программы, так как argv принимается извне программы.

Ответы [ 2 ]

11 голосов
/ 30 января 2020

Я бы сказал, что есть две основные опции, основанные на вашей модели угрозы здесь:

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

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

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

В обоих вышеупомянутых случаях ответ: нет , вы не должны защищать приложение от возможной атаки TOCTTOU при обработке данных в argv.

TOCTTOU Как правило, проблемы возникают из-за внешних ненадежных данных , которые могут быть изменены кем-то другим, и по определению им нельзя доверять. Простым примером является наличие файла: вы не можете полагаться на него, так как другие пользователи или программы на компьютере могут удалить или переместить его, единственный способ убедиться, что файл можно использовать, - это попытаться открыть его. В случае argv данные не являются внешними и принадлежат самому процессу, поэтому проблема действительно не применима.

4 голосов
/ 31 января 2020

Как правило, набор строк, которые передаются в main() в массиве argv, устанавливается внутри пользовательского пространства программы, в основном в фиксированном месте вверху стека программы.

Причиной такого фиксированного места является то, что некоторые программы изменяют эту область, чтобы позволить привилегированной программе (например, команда ps) собирать и показывать вам различные аргументы команды по мере развития программы во время выполнения. Это используется в таких программах, как sendmail(8) или в потоках пользовательских программ, чтобы показать вам, какой поток выполняет какую-либо работу в вашей программе.

Эта функция не является стандартной, она по-разному используется разными операционные системы (я описал вам путь BSD). Насколько я знаю, linux также демонстрирует такое поведение и в Solaris.

В общем, это приводит к аргументам для включения чего-то, принадлежащего пользовательскому процессу. пространство, должно быть изменено с осторожностью (используя некоторую операционную систему, специфицированную c контрактом), так как это обычно подчиняется жестким соглашениям. Команда ps(1) копает в пользовательском пространстве процесса, который она собирается показать, чтобы показать длинный список, показывающий параметры команды. Документ о различных операционных системах (возможно, вы можете получить это из стандартного сценария компоновщика, используемого в вашей системе, точного формата или того, как стек инициализируется семейством вызовов exec(2) - страница справки exec(2) также должна помочь )

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

Кстати, страница руководства FreeBSD для системного вызова execlp(2) показывает следующую выдержку:

Тип параметров argv и envp для execle(), exect(), execv(), execvp() и execvP() является историческим несчастным случаем, и никакая вменяемая реализация не должна изменять предоставленные строки. Поддельные типы параметров запускают ложные срабатывания из const анализаторов корректности. В FreeBSD макрос __DECONST() может использоваться для обхода этого ограничения.

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

EDIT

Если вы посмотрите на /usr/include/sys/exec.h (строка 43) во FreeBSD, вы обнаружите, что в верхней части пользовательского стека находится struct ps_strings, который используется * Команда 1041 * для поиска и определения местоположения среды процесса и строк argv. Хотя вы можете изменить это, чтобы изменить информацию, которую программа выдает на ps(1), у вас есть setproctitle(3) функция библиотеки (опять же, все это FreeBSDi sh, вам придется копать, чтобы получить способ linux или другой, решает эту проблему)

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

...