【问题标题】:Are snprintf and friends safe to use?snprintf 和朋友可以安全使用吗?
【发布时间】:2009-08-13 06:41:47
【问题描述】:

最近在 SO (Why on earth would anyone use strncpy instead of strcpy?) 上有一个问题,答案是 (answer 1, answer 2),这让我不确定其他名称中带有“n”的字符串函数,例如 snprintf (我一直在广泛使用)。 snprintf 使用安全吗?一般来说,'n' 系列的安全功能是什么?

【问题讨论】:

  • 相关:注意snprintf/swprintf/snwprintf/etc和%ls和%s在不同平台上的不同行为。它们都是不同的。
  • 仅在损坏的、不合规的实现上。 C 标准非常清楚这些格式说明符应该做什么。

标签: c buffer-overflow printf


【解决方案1】:

strncpy() 是一个奇怪的函数,它的名字确实是错误的——它的最初目的是确保缓冲区完全用字符串的内容初始化(没有溢出目标)并用零提醒缓冲区。据我了解,最初的目的是处理文件系统目录条目——目标缓冲区实际上并不是一个与 C 库中的其他 strxxx() 函数相同的字符串。 strncpy() 的主要问题是如果源字符串大于目标缓冲区,则结果不会以空值终止。

大多数其他处理字符串的 'n' 函数都可以正确终止字符串,但也有例外,例如微软的混蛋_snprintf()。正确的 C99 snprintf() 将始终以空值终止目标字符串(只要目标缓冲区的大小大于 0)。

有一个“技术报告”,TR 24731,它为处理字符串和内存缓冲区的函数提出了一组边界检查替代方案。 TR 的目标之一是使函数的参数、结果和错误行为在函数之间更加相似。 TR 似乎有一些不同的接受度,我认为除了 Microsoft 的编译器(我认为 MS 是 TR 背后的主要驱动程序)之外,它没有被广泛实施。你可以在这里获得更多信息:

即使您不喜欢这些建议,我认为它们也有助于了解现有功能的问题。

【讨论】:

【解决方案2】:

虽然snprintf 不会超出缓冲区,但如果您为其提供正确的参数,请记住它与*printf 系列的其他成员共享所有格式字符串漏洞。例如,%n 说明符很讨厌,因为攻击者可以使用它将任意字节写入任意内存位置。请参阅 CERT C 编码标准 wiki 中的 FIO30-C. Exclude user input from format strings

【讨论】:

    【解决方案3】:

    只要您提供正确的缓冲区长度,它就是安全的。

    【讨论】:

    • 您提供的长度(以及您是否自己手动终止缓冲区的结尾)取决于您所在的平台。
    【解决方案4】:

    snprintf 确实保证缓冲区不会被覆盖,但不保证空终止。如果您愿意非标准,可以在 MSVC 上使用 sprintf_s

    http://msdn.microsoft.com/en-us/library/2ts7cx93(VS.71).aspx

    【讨论】:

    • 其实不然,snprintf 根本不保证缓冲区溢出。这取决于您提供的缓冲区大小,可能不正确
    • 不言而喻,没有 CRT 函数可以神奇地知道传入的缓冲区实际有多大。
    • 好吧,那么不用说没有 CRT 函数是“安全的”,而且人们到处假装在它们的名称后面加上 _s 都违反了这条规则,这并没有多大意义 ;-)跨度>
    • -1:您应该澄清一下,您说的是损坏的 Microsoft 实现,而不是 C 标准。
    【解决方案5】:

    注意:不同的平台对于传递给snprintf的字符串的空终止有不同的行为。

    【讨论】:

    • snprintf 在 ISO C99 中的规定保证为空终止。
    • 你能举一个在这方面不符合标准 C 的平台的例子吗?
    • 如果缓冲区不够大,Microsoft 的变体 _snprintf() 不会终止目标:msdn.microsoft.com/en-us/library/2ts7cx93.aspx
    • 为什么有人会担心名称开头带有下划线的非标准函数中的不一致性,而您可以用标准名称的函数包装它并修复缺少-同时终止错误?
    • 如果可以的话,我会投反对票。这是绝对错误的。如果您选择使用非标准的、不同名称的 _snprintf,那么它的行为可能会有所不同。然而,这不是提交者所要求的。看起来 snprintf 在 Windows 上不可用;但是,您可以轻松编写自己的代码。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-02-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-20
    相关资源
    最近更新 更多