我看过这个question以及这些PDF' 1和2,page,我非常了解如果我这样做会发生什么printf(SOME_TEST_STRING)
。但我不明白为什么确切地说缓冲区vsnprintf
的大小与vsprintf
相比变得安全?
答案 0 :(得分:7)
这两种情况会发生什么?
案例1
char buf[3];
vsprint(buf, "%s", args);
案例2
char buf[3];
vsnprint(buf, sizeof buf, "%s", args);
在第1种情况下,如果您要格式化的字符串长度为3或更大,则缓冲区溢出,vsprintf可能会写入内存超过buf数组的存储,这是未定义的行为,可能导致havoc /安全问题/崩溃/等。
在第2种情况下.vsnprintf知道包含结果的缓冲区有多大,并且确保不会超过该值(而是将结果截断为适合buf
)。
答案 1 :(得分:3)
这是因为vsnprintf
有一个额外的size_t count
参数vsprintf
(和其他非n * sprintf方法)没有。该实现使用它来确保它写入缓冲区的数据不会在最后运行。
从缓冲区末端运行的数据可能导致数据损坏,或者恶意利用的数据可能会被用作buffer overrun攻击。
答案 2 :(得分:2)
vsnprintf()
中的“n”表示它采用输出字符串的最大大小来避免缓冲区溢出。这样可以避免缓冲区溢出,但如果格式字符串来自未经过验证的用户输入,则不会使其安全。如果你的用户给你一个巨大的格式字符串,你将避免溢出目标字符串,但如果用户给你%s
并且你没有在编译时在参数列表中传递一个C字符串,你仍然留下未定义的行为。
答案 3 :(得分:1)
我不确定问题是什么,因为你的问题基本上已经包含了答案。
通过将缓冲区大小传递给vsnprintf
,您可以为该函数提供有关缓冲区大小的信息。该函数现在知道缓冲区的结束位置,并确保它不会写入缓冲区的末尾。
vsprintf
没有关于缓冲区大小的信息,这就是为什么它不知道缓冲区的结束位置并且无法阻止缓冲区溢出的原因。