为什么strncpy不安全?

时间:2009-05-15 17:16:42

标签: c++ c string strncpy

我希望找出为什么strncpy被认为是不安全的。有没有人有关于此的任何文档或使用它的漏洞利用示例?

5 个答案:

答案 0 :(得分:35)

看看this site;这是一个相当详细的解释。基本上,strncpy()不需要NUL终止,因此容易受到各种攻击。

答案 1 :(得分:11)

最初的问题显然是strcpy(3)不是memory-safe operation,因此攻击者可以提供比缓冲区更长的字符串,这将覆盖堆栈上的代码,如果仔细安排,可以执行任意操作来自攻击者的代码。

但是strncpy(3)还有一个问题,就是它不会在目的地的每种情况下都提供空终止。 (想象一下,源字符串比目标缓冲区长。)当结果被复制到第三个缓冲区时,未来的操作可能期望在大小相等的缓冲区之间符合C nul终止字符串,并在下游出现故障。

使用strncpy(3)比strcpy(3)更好,但strlcpy(3)之类的东西更好。

答案 2 :(得分:7)

要安全地使用strncpy,必须(1)手动将空字符粘贴到结果缓冲区上,(2)知道缓冲区事先以null结尾,并将(length-1)传递给strncpy或(3) )知道永远不会使用任何不会将其长度限制在缓冲区长度的方法来复制缓冲区。

重要的是要注意strncpy将填充缓冲区中的所有内容超过复制的字符串,而其他长度限制的strcpy变体则不会。在某些情况下,这可能会导致性能下降,但在其他情况下则具有安全优势。例如,如果使用strlcpy将“supercalifragilisticexpalidocious”复制到缓冲区然后复制“it”,则缓冲区将保持“it ^ ercalifragilisticexpalidocious ^”(使用“^”表示零字节)。如果缓冲区被复制到固定大小的格式,额外的数据可能会随之标记。

答案 3 :(得分:4)

问题是基于"加载"前提,这使得问题本身无效。

这里的底线是strncpy不被认为是不安全的,从未被认为是不安全的。唯一的不安全因素#34;可以附加到该函数的是C内存模型和C语言本身的一般不安全性的广泛主张。 (但这显然是一个完全不同的话题。)

在C语言领域,误导了某种“不安全”的错误信念。 strncpy中固有的内容来源于使用strncpy进行安全字符串复制"这一广泛的可疑模式,即这个函数不能做的事情,从来没有用过。这样的使用确实非常容易出错。但即使你在"高度容易出错"之间放置了一个平等的标志。并且"不安全",它仍然是一个使用问题(即缺乏教育问题)而不是strncpy问题。

基本上,可以说strncpy唯一的问题是一个不幸的命名,这使得新手程序员认为他们理解这个函数的作用而不是实际阅读规范。查看函数名称,一位不称职的程序员假定strncpy是一个"安全版本" strcpy的{​​{1}},而实际上这两个函数是完全无关的。

例如,对于除法运算符,可以提出完全相同的声明。正如大多数人所知,有关C语言的最常见问题之一是"我假设1/2将评估为0.5,但我得到了0。为什么&#34?;然而,我们并不是因为语言初学者倾向于误解其行为而声称除法运算符不安全。

另一个例子,我们不会调用伪随机数生成器函数"不安全"只是因为不称职的程序员经常会因为他们的输出并非真正随机而感到不愉快。

这就是strncpy函数的确切方式。就像初学者程序员花时间了解伪随机数生成器实际执行的操作一样,需要时间来了解strncpy实际执行的操作。需要时间来了解strncpy转换函数,用于将零终止字符串转换为固定宽度字符串。需要时间来了解strncpy绝对与"安全字符串复制"无关。并且无法有意义地用于此目的。

当然,语言学生通常需要花费更长的时间来学习strncpy的目的,而不是使用除法运算符来解决问题。但是,这是任何"不安全的基础。针对strncpy提出的索赔。

P.S。在接受的答案中链接的CERT文件专门用于:证明strncpy功能作为“安全”的典型无能滥用的不安全性。版本strcpy。它绝不意图声称strncpy本身不安全。

答案 4 :(得分:2)

Git 2.19(2018年第三季度)的路径发现,滥用strcat()之类的系统API函数太容易了; strncpy(); ...,并禁止在此代码库中使用这些功能。

请参见commit e488b7acommit cc8fdaecommit 1b11b64commit c8af66aJeff King (peff)(2018年7月26日)。
(由Junio C Hamano -- gitster --commit e28daf2中合并,2018年8月15日)

  

banned.h:将strcat()标记为禁止

     

strcat()函数具有与strcpy()相同的所有溢出问题。
  另外,由于每次后续调用都必须遍历现有字符串,因此很容易意外地以二次方结束。

     

最后一个strcat()呼叫在f063d38中消失了(守护进程:use   cld->重新生成时的env_array,2015-09-24,Git 2.7.0)。
  通常,strcat()可以用动态字符串替换   (strbufxstrfmt),或者如果知道长度是有界的,则使用xsnprintf