【发布时间】:2014-09-24 07:44:55
【问题描述】:
我看过这个question 以及这些PDF 的1 和2,这个page 并且非常了解如果我这样做printf(SOME_TEST_STRING) 会发生什么。但是我不明白为什么要确保缓冲区的大小vsnprintf 与vsprintf 相比变得安全?
【问题讨论】:
标签: c++ c security memory printf
我看过这个question 以及这些PDF 的1 和2,这个page 并且非常了解如果我这样做printf(SOME_TEST_STRING) 会发生什么。但是我不明白为什么要确保缓冲区的大小vsnprintf 与vsprintf 相比变得安全?
【问题讨论】:
标签: c++ c security memory printf
这两种情况会发生什么?
案例一
char buf[3];
vsprint(buf, "%s", args);
案例 2
char buf[3];
vsnprint(buf, sizeof buf, "%s", args);
在情况 1 中,如果您要格式化的字符串的长度为 3 或更大,则表示缓冲区溢出,vsprintf 可能会写入内存超出 buf 数组的存储空间,这是未定义的行为,可能会造成破坏/安全问题/崩溃/等等。
在情况 2. vsnprintf 知道将包含结果的缓冲区有多大,并且它会确保不会超过该缓冲区(而是截断结果以适应 buf )。
【讨论】:
buf 参数。
这是因为vsnprintf 有一个额外的size_t count 参数,而vsprintf(和其他非n *sprintf 方法)没有。实现使用它来确保它写入缓冲区的数据不会跑完。
超出缓冲区末尾的数据可能会导致数据损坏,或者在被恶意利用时可用作buffer overrun 攻击。
【讨论】:
vsnprintf() 中的“n”表示需要输出字符串的最大大小以避免缓冲区溢出。这使其免受缓冲区溢出的影响,但如果格式字符串来自未经处理的用户输入,则不会使其安全。如果你的用户给你一个巨大的格式字符串,你会避免溢出目标字符串,但是如果用户给你%s并且你没有在编译时在参数列表中传递一个C字符串,你仍然会留下未定义的行为。
【讨论】:
我不确定问题是什么,因为您的问题基本上已经包含答案了。
通过将缓冲区大小传递给vsnprintf,您可以向该函数提供有关缓冲区大小的信息。该函数现在知道缓冲区在哪里结束,并且可以确保它不会写入超过缓冲区的末尾。
vsprintf 没有缓冲区大小的信息,所以它不知道缓冲区在哪里结束,也无法防止缓冲区溢出。
【讨论】: