Гарантировано ли, что аргументы программы C завершаются '\0'?

Об аргументах main() стандарт C 2011 года говорит (5.1.2.2.1:2):

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

Должно ли слово «строка» в этом контексте интерпретироваться как «строка, заканчивающаяся 0», то есть последовательность символов, отличных от 0, за которой следует конечная «\0», или могут ли некоторые реализации передавать аргументы программам по-другому?

На платформе POSIX аргументы одной из функций семейства exec* проверяются функцией exec* как указатели на правильно сформированные строки (и как?), или программа setuid должна воздерживаться от предположения, что она была передана правильно сформированной строки с 0-завершением в качестве аргументов?


person Pascal Cuoq    schedule 05.05.2014    source источник
comment
Встречный вопрос: без завершения \0 как можно было бы разумно ожидать возможности чтения строк?   -  person Robert Harvey    schedule 05.05.2014
comment
Ну практически, как бы вы узнали, как долго они в противном случае?   -  person Shafik Yaghmour    schedule 05.05.2014
comment
@RobertHarvey Что ж, если бы не определение, которое выкопал Оли Чарльзуорт, аргумент программы на какой-то платформе мог бы всегда содержать не более 16 символов.   -  person Pascal Cuoq    schedule 05.05.2014
comment
Вопрос, по сути, заключается в том, может ли злонамеренная (или даже просто ошибочная) программа заставить exec() передать искаженный массив аргументов - то, что это не будет осмысленно интерпретироваться, не имеет значения, поскольку вопрос касается риск, а не функция.   -  person Chris Stratton    schedule 06.05.2014
comment
В C строка всегда означает строку с завершающим нулем.   -  person M.M    schedule 06.05.2014


Ответы (1)


Должно ли слово «строка» в этом контексте интерпретироваться как «строка, заканчивающаяся 0», то есть последовательность символов, отличных от 0, за которой следует конечная «\0», или могут ли некоторые реализации передавать аргументы программам по-другому?

7.1.1 определяет строку:

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


Проверяются ли аргументы одной из функций семейства exec* функцией exec* как указатели на правильно сформированные строки (и как?).

В спецификации POSIX указано, что аргументы для семейства exec являются строками, заканчивающимися нулем. , и не указывает, что произойдет, если это не так. Предположительно, это неопределенное поведение. Это кажется разумным, потому что у функций exec нет разумного способа проверить правильность завершения каждого аргумента нулем. (Хотя имейте в виду, что exec* должен скопировать свои аргументы, так как адресное пространство будет выгружено.)

person Oliver Charlesworth    schedule 05.05.2014
comment
Хорошо, первая часть вопроса глупа ввиду определения «строки». Как насчет второй части: на платформе POSIX может ли вызывающая сторона exec* передать указатель на что-то отличное от правильно сформированной строки для использования аргумента программы, и как exec* проверяет его, если да? - person Pascal Cuoq; 05.05.2014
comment
Без этой гарантии это не настоящий C, поскольку он не соответствует стандарту C. - person Robert Harvey; 05.05.2014
comment
@PascalCuoq: спецификация POSIX гласит, что аргументы для семейства exec являются строки, оканчивающиеся нулем, и не указывает, что произойдет, если это не так. Предположительно, это неопределенное поведение (потому что нет разумного способа проверить это). - person Oliver Charlesworth; 05.05.2014
comment
@OliCharlesworth Я удивлен, что такая угроза безопасности была бы оставлена ​​​​как «неопределенное поведение» (но я согласен, что это не для стандарта C и, возможно, даже для POSIX). - person Pascal Cuoq; 05.05.2014
comment
@PascalCuoq: я не думаю, что это может быть что-то кроме UB (как можно проверить, правильно ли строка завершается нулем?). Можно возразить, что каждый аргумент должен сопровождаться аргументом length, конечно. - person Oliver Charlesworth; 05.05.2014
comment
@OliCharlesworth Хорошо, подумав об этом, если бы это было для МОЕЙ операционной системы, я бы определил максимальную длину аргумента (4 КБ или что-то разумное для того времени) и прочитал до этой длины из процесса, вызывающего execv*, и если бы я не нашел '\0' в пределах этого предела, что было бы ошибкой (и/или я бы добавил завершающий 0 к копии). - person Pascal Cuoq; 06.05.2014
comment
@OliCharlesworth О, есть такое ограничение, оно называется ARG_MAX. Спасибо за ссылку на соответствующий стандарт. - person Pascal Cuoq; 06.05.2014
comment
Я должен уточнить сейчас, если это еще не ясно из моей одержимости точки зрения программы execed, что «неопределенное поведение в программе, вызывающей exec*» и «неопределенное поведение, вызванное любым двоичным файлом setuid, на который я могу положить лапы». не одно и то же, и что мой вопрос был о самой разнице между ними. - person Pascal Cuoq; 06.05.2014
comment
@PascalCuoq: Вы говорите, что, поскольку злонамеренный родитель может вводить строки без завершения в программу exec, требование стандарта C неверно? Думаю, да, в некотором смысле. Но, конечно же, вредоносная ОС может делать всевозможные вещи, которые делают недействительными положения стандарта C! - person Oliver Charlesworth; 06.05.2014
comment
@OliCharlesworth Меня интересует вредоносный процесс, вызывающий функцию exec в доброжелательной ОС с доброжелательными двоичными файлами setuid, что не так теоретично. - person Pascal Cuoq; 06.05.2014
comment
@OliCharlesworth & @PascalCuoq, независимо от того, что говорит или не говорит спецификация, на практике вызов exec действительно проверяет нулевое завершение. Exec должен скопировать аргументы в новый процесс. При запуске аргументы дочернего процесса не указывают на память, выделенную в родительском. Это было бы невозможно для любого pgm, который хотел бы сослаться на свои параметры argv после того, как родитель умер. В процессе копирования этих аргументов exec должен проверять наличие правильно сформированных строк, в противном случае, не обнаружив нулевого завершения, произойдет сбой с E2BIG. - person Duck; 06.05.2014
comment
@OliCharlesworth Не могли бы вы упомянуть в своем ответе, что строки, переданные в качестве аргумента через argv в execve(), копируются до того, как управление будет передано новой программе, и, таким образом, если какая-либо из них неправильно сформирована, выполнение либо не происходит, либо имеет место с аргументом-мусором, который по-прежнему является правильно сформированной строкой? Я боюсь, что эта информация в настоящее время теряется в море комментариев. PS: мой вопрос был в том же контексте, что и сообщение в блоге по адресу trust-in-soft.com/ - person Pascal Cuoq; 07.06.2014