Почему strncpy небезопасен?
Я ищу, чтобы выяснить, почему strncpy считается небезопасным. У кого-нибудь есть какая-либо документация по этому поводу или примеры использования эксплойта?
5 ответов
Взгляните на этот сайт; это довольно подробное объяснение. В принципе, strncpy()
не требует завершения NUL, и поэтому подвержен множеству эксплойтов.
Первоначальная проблема, очевидно, заключается в том, что strcpy(3) не была безопасной операцией с памятью, поэтому злоумышленник может предоставить строку длиннее буфера, который перезапишет код в стеке, и, если он тщательно спланирован, может выполнить произвольный код от злоумышленника.
Но у strncpy(3) есть другая проблема в том, что он не предоставляет нулевое завершение в каждом случае в месте назначения. (Представьте, что исходная строка длиннее, чем целевой буфер.) В будущих операциях может ожидаться соответствие строк с концевыми C-nul между буферами одинакового размера и неисправностью в нисходящем направлении, когда результат копируется в еще один третий буфер.
Использование strncpy(3) лучше, чем strcpy(3), но такие вещи, как strlcpy(3), еще лучше.
Чтобы безопасно использовать strncpy, нужно либо (1) вручную вставить нулевой символ в буфер результатов, (2) знать, что буфер заканчивается нулевым заранее, и передать (length-1) strncpy, либо (3) знать, что буфер никогда не будет скопирован с использованием любого метода, который не будет привязывать его длину к длине буфера.
Важно отметить, что strncpy будет заполнять нулями все в буфере после скопированной строки, в то время как другие варианты strcpy с ограниченной длиной не будут. В некоторых случаях это может привести к снижению производительности, но в других случаях может быть преимуществом безопасности. Например, если кто-то использует strlcpy для копирования "supercalifragilisticexpalidocious" в буфер, а затем для копирования "it", буфер будет содержать "it^ercalifragilisticexpalidocious^" (используя "^" для представления нулевого байта). Если буфер копируется в формат фиксированного размера, дополнительные данные могут помечаться вместе с ним.
Вопрос основан на "загруженной" предпосылке, которая делает сам вопрос недействительным.
Суть здесь в том, что strncpy
не считается небезопасным и никогда не считалось небезопасным. Единственными утверждениями о "небезопасности", которые могут быть связаны с этой функцией, являются широкие требования общей небезопасности модели памяти C и самого языка C. (Но это, очевидно, совершенно другая тема).
В области языка C ошибочное убеждение о некой "неуверенности", присущей strncpy
вытекает из широко распространенной сомнительной схемы использования strncpy
для "безопасного копирования строк", то есть чего-то, для чего эта функция не предназначена и никогда не предназначалась. Такое использование действительно очень подвержено ошибкам. Но даже если вы поставите знак равенства между "очень подверженным ошибкам" и "небезопасным", это все равно проблема использования (то есть проблема отсутствия образования), а не strncpy
проблема.
В принципе, можно сказать, что единственная проблема с strncpy
это неудачное именование, которое заставляет программистов-новичков предполагать, что они понимают, что делает эта функция, вместо того, чтобы фактически читать спецификацию. Глядя на имя функции, некомпетентный программист предполагает, что strncpy
является "безопасной версией" strcpy
в то время как на самом деле эти две функции совершенно не связаны.
Точно такая же претензия может быть подана против оператора деления, например. Как многие из вас знают, один из наиболее часто задаваемых вопросов о языке Си звучит так: "Я предположил, что 1/2
будет оценивать 0.5
но я получил 0
вместо. Почему? "Тем не менее, мы не утверждаем, что оператор деления небезопасен только потому, что начинающие языки склонны неверно истолковывать его поведение.
В другом примере мы не называем функции генератора псевдослучайных чисел "небезопасными" только потому, что некомпетентных программистов часто неприятно удивляет тот факт, что их выходные данные не являются действительно случайными.
Именно так и происходит с strncpy
функция. Так же, как начинающим программистам требуется время, чтобы понять, что на самом деле делают генераторы псевдослучайных чисел, им нужно время, чтобы узнать, что strncpy
на самом деле Требуется время, чтобы понять, что strncpy
является функцией преобразования, предназначенной для преобразования строк с нулевым окончанием в строки фиксированной ширины. Требуется время, чтобы понять, что strncpy
не имеет абсолютно никакого отношения к "безопасному копированию строк" и не может быть использовано для этой цели.
Конечно, студенту, изучающему язык, обычно требуется гораздо больше времени, чтобы strncpy
чем разобраться с оператором деления. Тем не менее, это является основанием для любых "небезопасных" претензий к strncpy
,
PS Документ CERT, указанный в принятом ответе, посвящен именно этому: чтобы продемонстрировать отсутствие безопасности типичного некомпетентного злоупотребления strncpy
функционировать как "безопасная" версия strcpy
, Он никоим образом не претендует на то, чтобы strncpy
само по себе как-то небезопасно.
Pathc из Git 2.19 (Q3 2018) обнаруживает, что слишком легко неправильно использовать функции системного API, такие как strcat()
; strncpy()
;... и запрещает эти функции в этой кодовой базе.
См. Коммит e488b7a, коммит cc8fdae, коммит 1b11b64 (24 июля 2018 г.) и коммит c8af66a (26 июля 2018 г.) Джеффом Кингом ( peff
)
(Объединено Юнио С Хамано - gitster
- в комитете e28daf2, 15 августа 2018 г.)
banned.h
: отметкаstrcat()
как запрещено
strcat()
Функция имеет все те же проблемы переполнения, что иstrcpy()
,
И в качестве бонуса легко оказаться случайно квадратичным, поскольку каждый последующий вызов должен проходить через существующую строку.Последний
strcat()
вызов исчез в f063d38 (демон: используйте cld->env_array при повторном порождении, 2015-09-24, Git 2.7.0).
В общем,strcat()
можно заменить либо динамической строкой (strbuf
или жеxstrfmt
) или сxsnprintf
если вы знаете, длина ограничена.
Опасности strncpy, _snprintf и wcsncpy должны быть одинаково хорошо известны, но, очевидно, это не так. Эти функции позволяют вам указать размер буфера, но - и это действительно важно - они не гарантируют нулевое завершение. Если вы попросите эти функции написать больше символов, чем заполнит буфер, они остановятся - таким образом, избегая переполнения буфера, - но не завершат буфер нулем. Для того, чтобы правильно использовать эти функции, вы должны делать такую ерунду.
Пожалуйста, используйте следующую ссылку для вашей ссылки!!!
https://randomascii.wordpress.com/2013/04/03/stop-using-strncpy-already/
Наихудшая ситуация возникает, когда исходная и целевая буферная память перекрываются друг с другом. Поэтому избегайте использования strncpy, когда вы чувствуете, что в вашей программе может возникать дублирующаяся ситуация. Вместо strncpy вы можете использовать функцию memmove в перекрывающемся сценарии.
Ниже я описываю простой пример, который описывает strncpy в перекрывающемся сценарии.
#include <stdio.h>
#include <string.h>
int main() {
char aszMessage[10] ="12345"; //Source Buffer
short siLen=4; // Length of byte you want to copy
strncpy(aszMessage + 2,aszMessage+1,siLen);//Here memory overlap
printf("\n\n\tMessage = %s\n",aszMessage);
return 0;
}
Здесь я принимаю, выходные данные должны быть 122345, но здесь выходные данные 122222, что является самым большим резервным сценарием strncpy.
Эта проблема может быть решена с помощью функции memove.
#include <stdio.h>
#include <string.h>
int main() {
char aszMessage[10] ="12345"; //Source Buffer
short siLen=4; // Length of byte you want to copy
memmove(aszMessage + 2,aszMessage+1,siLen);//Here memory overlap
printf("\n\n\tMessage = %s\n",aszMessage);
return 0;
}
Теперь я получаю желание вывода 122345.
Для более подробной информации вы можете увидеть эту ссылку http://aticleworld.com/how-to-use-strncpy-and-how-to-write-your-own-strncpy/