C++ 为什么 strncpy 不安全?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/869883/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why is strncpy insecure?
提问by stimms
I am looking to find out why strncpy is considered insecure. Does anybody have any sort of documentation on this or examples of an exploit using it?
我想找出为什么 strncpy 被认为是不安全的。是否有人对此有任何类型的文档或使用它的漏洞利用示例?
回答by Tim
回答by DigitalRoss
The original problem is obviously that strcpy(3)was not a memory-safe operation, so an attacker could supply a string longer than the buffer which would overwrite code on the stack, and if carefully arranged, could execute arbitrary code from the attacker.
最初的问题显然是strcpy(3)不是内存安全操作,因此攻击者可以提供比缓冲区更长的字符串,这会覆盖堆栈上的代码,如果仔细安排,可以执行攻击者的任意代码。
But strncpy(3)has another problem in that it doesn't supply null termination in every case at the destination. (Imagine a source string longer than the destination buffer.) Future operations may expect conforming C nul-terminated strings between equally sized buffers and malfunction downstream when the result is copied to yet a third buffer.
但是strncpy(3)有另一个问题,它不会在目的地的每种情况下都提供空终止。(想象一个比目标缓冲区长的源字符串。)未来的操作可能会期望在相同大小的缓冲区之间符合 C 以 nul 结尾的字符串,并且当结果被复制到第三个缓冲区时,下游会出现故障。
Using strncpy(3) is better than strcpy(3) but things like strlcpy(3) are better still.
使用 strncpy(3) 比 strcpy(3) 更好,但 strlcpy(3) 之类的东西仍然更好。
回答by supercat
To safely use strncpy, one must either (1) manually stick a null character onto the result buffer, (2) know that the buffer ends with a null beforehand, and pass (length-1) to strncpy, or (3) know that the buffer will never be copied using any method that won't bound its length to the buffer length.
要安全地使用 strncpy,您必须 (1) 手动将空字符粘贴到结果缓冲区,(2) 事先知道缓冲区以空结尾,并将 (length-1) 传递给 strncpy,或 (3) 知道缓冲区永远不会使用任何不会将其长度绑定到缓冲区长度的方法进行复制。
It's important to note that strncpy will zero-fill everything in the buffer past the copied string, while other length-limited strcpy variants will not. This may at some cases be a performance drain, but in other cases be a security advantage. For example, if one used strlcpy to copy "supercalifragilisticexpalidocious" into a buffer and then to copy "it", the buffer would hold "it^ercalifragilisticexpalidocious^" (using "^" to represent a zero byte). If the buffer gets copied to a fixed-sized format, the extra data might tag along with it.
重要的是要注意 strncpy 会将缓冲区中复制的字符串之后的所有内容都填充为零,而其他长度受限的 strcpy 变体则不会。在某些情况下,这可能会降低性能,但在其他情况下可能会带来安全优势。例如,如果使用 strlcpy 将“supercalifragilisticexpalidocious”复制到缓冲区中,然后复制“it”,则缓冲区将保存“it^ercalifragilisticexpalidocious^”(使用“^”表示零字节)。如果缓冲区被复制为固定大小的格式,则额外的数据可能会随之标记。
回答by AnT
The question is based on a "loaded" premise, which makes the question itself invalid.
该问题基于“加载”前提,这使得问题本身无效。
The bottom line here is that strncpy
is not considered insecure and has never been considered insecure. The only claims of "insecurity" that can be attached to that function are the broad claims of general insecurity of C memory model and C language itself. (But that is obviously a completely different topic).
这里的底线strncpy
是不被认为是不安全的,也从未被认为是不安全的。可以附加到该函数的唯一“不安全性”声明是 C 内存模型和 C 语言本身的一般不安全性的广泛声明。(但这显然是一个完全不同的话题)。
Within the realm of C language the misguided belief of some kind of "insecurity" inherent in strncpy
is derived from the widespread dubious pattern of using strncpy
for "safe string copying", i.e. something this function does not do and has never been intended for. Such usage is indeed highly error prone. But even if you put an equality sign between "highly error prone" and "insecure", it is still a usage problem (i.e. a lack of education problem) not a strncpy
problem.
在 C 语言领域内,对某种固有的“不安全”的错误信念strncpy
源自广泛使用的strncpy
用于“安全字符串复制”的可疑模式,即该函数不做且从未打算用于的东西。这种用法确实很容易出错。但是即使你在“高度容易出错”和“不安全”之间加上一个等号,它仍然是一个使用问题(即缺乏教育问题)而不是strncpy
问题。
Basically, one can say that the only problem with strncpy
is a unfortunate naming, which makes newbie programmers assume that they understand what this function does instead of actually reading the specification. Looking at the function name an incompetent programmer assumes that strncpy
is a "safe version" of strcpy
, while in reality these two functions are completely unrelated.
基本上,可以说唯一的问题strncpy
是不幸的命名,这让新手程序员认为他们了解这个函数的作用,而不是实际阅读规范。查看函数名称,一个不称职的程序员假定它strncpy
是 的“安全版本” strcpy
,而实际上这两个函数完全无关。
Exactly the same claim can be made against the division operator, for one example. As most of you know, one of the most frequently-asked questions about C language goes as "I assumed that 1/2
will evaluate to 0.5
but I got 0
instead. Why?" Yet, we don't claim that the division operator is insecure just because language beginners tend to misinterpret its behavior.
例如,可以对除法运算符提出完全相同的要求。正如你们大多数人所知,关于 C 语言的最常见问题之一是“我认为这1/2
会评估为,0.5
但我得到了0
。为什么?” 然而,我们不会仅仅因为语言初学者倾向于误解其行为而声称除法运算符是不安全的。
For another example, we don't call pseudo-random number generator functions "insecure" just because incompetent programmers are often unpleasantly surprised by the fact that their output is not truly random.
再举一个例子,我们不会仅仅因为不称职的程序员经常对他们的输出不是真正随机的事实而感到不愉快的惊讶,我们不会称伪随机数生成器函数为“不安全的”。
That is exactly how it is with strncpy
function. Just like it takes time for beginner programmers to learn what pseudo-random number generators actually do, it takes them time to learn what strncpy
actually does. It takes time to learn that strncpy
is a conversionfunction, intended for converting zero-terminatedstrings to fixed-widthstrings. It takes time to learn that strncpy
has absolutely nothing to do with "safe string copying" and can't be meaningfully used for that purpose.
这正是它的strncpy
功能。就像初学者程序员需要时间了解伪随机数生成器实际做什么一样,他们也需要时间来了解strncpy
实际做什么。需要花时间了解这strncpy
是一个转换函数,旨在将零终止字符串转换为固定宽度的字符串。需要时间来了解这strncpy
与“安全字符串复制”完全无关,并且不能有意义地用于该目的。
Granted, it usually takes much longer for a language student to learn the purpose of strncpy
than to sort things out with the division operator. However, this is a basis for any "insecurity" claims against strncpy
.
诚然,语言学生通常需要更长的时间来学习目的,而strncpy
不是使用除法运算符来解决问题。但是,这是针对strncpy
.
P.S. The CERT document linked in the accepted answer is dedicated to exactly that: to demonstrate the insecurities of the typical incompetent abuse of strncpy
function as a "safe" version of strcpy
. It is not in any way intended to claim that strncpy
itself is somehow insecure.
PS 在接受的答案中链接的 CERT 文件正是致力于:证明strncpy
作为“安全”版本的典型无能滥用功能的不安全性strcpy
。它绝不是要声称strncpy
自己在某种程度上是不安全的。
回答by VonC
A pathc of Git 2.19 (Q3 2018) finds that it is too easy to misuse system API functions such as strcat()
; strncpy()
; ... and forbids those functions in this codebase.
Git 2.19 (Q3 2018) 的一个路径发现,很容易滥用系统API函数,例如strcat()
; strncpy()
; ...并禁止此代码库中的这些功能。
See commit e488b7a, commit cc8fdae, commit 1b11b64(24 Jul 2018), and commit c8af66a(26 Jul 2018) by Jeff King (peff
).
(Merged by Junio C Hamano -- gitster
--in commit e28daf2, 15 Aug 2018)
请参阅Jeff King ( ) 的commit e488b7a、commit cc8fdae、commit 1b11b64(2018 年 7 月 24 日)和commit c8af66a(2018 年 7 月 26 日)。(由Junio C Hamano合并-- --在提交 e28daf2 中,2018 年 8 月 15 日)peff
gitster
banned.h
: markstrcat()
as bannedThe
strcat()
function has all of the same overflow problems asstrcpy()
.
And as a bonus, it's easy to end up accidentally quadratic, as each subsequent call has to walk through the existing string.The last
strcat()
call went away in f063d38(daemon: use cld->env_array when re-spawning, 2015-09-24, Git 2.7.0).
In general,strcat()
can be replaced either with a dynamic string (strbuf
orxstrfmt
), or withxsnprintf
if you know the length is bounded.
banned.h
: 标记strcat()
为禁止该
strcat()
函数具有与strcpy()
.
作为奖励,很容易意外地以二次方告终,因为每个后续调用都必须遍历现有字符串。最后一次
strcat()
调用在f063d38中消失了(守护进程:重新生成时使用 cld->env_array,2015-09-24,Git 2.7.0)。
通常,strcat()
可以用动态字符串(strbuf
或xstrfmt
)替换,或者xsnprintf
如果您知道长度是有界的,则可以替换。