Почему strncpy небезопасен? - PullRequest
60 голосов
/ 15 мая 2009

Я хочу выяснить, почему strncpy считается небезопасным. У кого-нибудь есть какая-либо документация по этому поводу или примеры использования эксплойта?

Ответы [ 5 ]

35 голосов
/ 15 мая 2009

Взгляните на этот сайт ; это довольно подробное объяснение. По сути, strncpy() не требует завершения NUL и поэтому подвержен различным уязвимостям.

11 голосов
/ 01 июня 2012

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

Но strncpy (3) имеет еще одну проблему, заключающуюся в том, что он не предоставляет нулевое завершение в каждом случае в месте назначения. (Представьте, что исходная строка длиннее, чем целевой буфер.) В будущих операциях может ожидаться соответствие строк с концевыми C nul между буферами одинакового размера и неисправностью в нисходящем направлении, когда результат копируется в еще один третий буфер.

Использование strncpy (3) лучше, чем strcpy (3), но такие вещи, как strlcpy (3), еще лучше.

7 голосов
/ 22 октября 2010

Чтобы безопасно использовать strncpy, нужно либо (1) вручную вставить нулевой символ в буфер результатов, (2) знать, что буфер заканчивается нулевым заранее, и передать (length-1) strncpy, или (3 ) знать, что буфер никогда не будет скопирован с использованием любого метода, который не будет привязывать его длину к длине буфера.

Важно отметить, что strncpy будет заполнять нулями все в буфере после скопированной строки, в то время как другие варианты strcpy с ограниченной длиной не будут. В некоторых случаях это может привести к снижению производительности, но в других случаях это может быть преимуществом безопасности. Например, если кто-то использует strlcpy для копирования «supercalifragilisticexpalidocious» в буфер и затем для копирования «it», буфер будет содержать «it ^ ercalifragilisticexpalidocious ^» (используя «^» для представления нулевого байта). Если буфер копируется в формат фиксированного размера, дополнительные данные могут помечаться вместе с ним.

4 голосов
/ 10 сентября 2014

Вопрос основан на «загруженной» предпосылке, которая делает сам вопрос недействительным.

Суть в том, что strncpy не считается небезопасным и никогда не считалось небезопасным. Единственные утверждения о «небезопасности», которые могут быть присоединены к этой функции, - это широкие требования общей небезопасности модели памяти C и самого языка C. (Но это, очевидно, совершенно другая тема).

В области языка Си ошибочное убеждение о некой «небезопасности», присущей strncpy, вытекает из широко распространенной сомнительной схемы использования strncpy для «безопасного копирования строк», то есть чего-то, чего эта функция не делает и никогда не был предназначен для. Такое использование действительно очень подвержено ошибкам. Но даже если вы поставите знак равенства между «очень подверженным ошибкам» и «небезопасным», это все равно проблема использования (то есть проблема отсутствия образования), а не проблема strncpy.

По сути, можно сказать, что единственная проблема с strncpy - неудачное именование, из-за которого начинающие программисты предполагают, что они понимают, что делает эта функция, вместо того, чтобы фактически читать спецификацию. Глядя на название функции, некомпетентный программист предполагает, что strncpy является «безопасной версией» strcpy, тогда как на самом деле эти две функции совершенно не связаны.

Точно такая же претензия может быть предъявлена ​​оператору деления, например. Как большинство из вас знает, один из наиболее часто задаваемых вопросов о языке Си звучит так: «Я предполагал, что 1/2 оценивается как 0.5, но вместо этого я получил 0. Почему?» Тем не менее, мы не утверждаем, что оператор деления небезопасен только потому, что начинающие языки склонны неверно истолковывать его поведение.

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

Именно так и работает с strncpy функцией. Точно так же, как начинающим программистам требуется время, чтобы понять, что на самом деле делают генераторы псевдослучайных чисел, так и им нужно время, чтобы узнать, что на самом деле делает strncpy. Требуется время, чтобы понять, что strncpy - это функция преобразования , предназначенная для преобразования строк с нулевым окончанием в строки фиксированной ширины . Требуется время, чтобы понять, что strncpy не имеет абсолютно никакого отношения к «безопасному копированию строк» ​​и не может быть осмысленно использовано для этой цели.

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

P.S. Документ CERT, ссылка на который содержится в принятом ответе, посвящен именно этому: продемонстрировать отсутствие безопасности типичного некомпетентного злоупотребления функцией strncpy как «безопасной» версией strcpy. Он никоим образом не претендует на то, что strncpy сам по себе небезопасен.

2 голосов
/ 19 августа 2018

Pathc из Git 2.19 (Q3 2018) обнаруживает, что слишком легко неправильно использовать функции системного API, такие как strcat(); strncpy(); ... и запрещает эти функции в этой кодовой базе.

См. commit e488b7a , commit cc8fdae , commit 1b11b64 (24 июля 2018 г.) и commit c8af66a (26 июля 2018 г.) Джефф Кинг (peff) .
(Объединено с Junio ​​C Hamano - gitster - в commit e28daf2 , 15 августа 2018)

banned.h: пометить strcat() как запрещенные

Функция strcat() имеет те же проблемы переполнения, что и strcpy().
И в качестве бонуса легко оказаться случайно квадратичным, поскольку каждый последующий вызов должен проходить через существующую строку.

Последний strcat() звонок исчез в f063d38 (демон: использовать cld-> env_array при повторном порождении, 2015-09-24, Git 2.7.0).
В общем случае strcat() можно заменить либо динамической строкой (strbuf или xstrfmt), или с xsnprintf, если вы знаете, что длина ограничена.

...