我在ossec-hids repo上运行Fortify Static Code Analyzer,它报告了src/analysisd/stats.c:415的以下Buffer Overflow: Format String
结果:
stats.c第415行的fscanf()的格式字符串参数没有正确限制函数可以写入的数据量,这允许程序在分配的内存范围之外写入。此行为可能会损坏数据、使程序崩溃或导致执行恶意代码
有问题的代码行是这样的:
if (fscanf(fp, "%d", &_RWHour[i][j]) <= 0) {
_RWHour
声明为
static int _RWHour[7][25];
在同一文件的第33行。我相信在第33行的声明和第415行的使用之间没有_RWHour
的影子,因为当我选择第33行的声明时,我的IDE(Visual Studio 2019)在415中突出显示_RWHour
。
当我看cppreference documentation for fscanf
时,它说:
d匹配十进制整数。数字的格式与strtol
所期望的格式相同,其基本参数的值为10
上面引用的表格还显示,当%d
没有使用长度修饰符时(就像正在讨论的fscanf
调用一样),参数类型应该是signed int*
或unsigned int*
。
我的问题是:
在这种情况下,Fortify发现是否可能是假阳性?或者,当您将int
的地址传递给fscanf
时,是否可以写入int
外部的内存?
如果将%d
与fscanf
一起使用时,可能会在int
的内存之外写入,如何安全地避免这种情况?
3条答案
按热度按时间5uzkadbs1#
防止转换溢出
fscanf(fp, "%d", &_RWHour[i][j])
是 undefined behavior(UB)*1,如果数字文本试图转换为int
范围之外的值。防止UB的一个快速修复方法是使用 width 限制读取的字符数:
一个更健壮的解决方案是读入文本并使用
strtol()
进行转换。我建议创建一个helper函数来处理
int
中的阅读。这种程度的检查有点臭,不是吗?
i, j
在范围内对OP的引用代码的检查看起来没问题,但分析工具可能会抱怨。
...或者如果转换的结果无法在对象中表示,则行为未定义。C23dr § 7.23.6.2
有了UB,“可以在int之外写入内存”。
ua4mk5z42#
Fortify的发现是否可能是假阳性?
当然,一般来说,Fortify报告的是假阳性。尽管@chux关于可能的未定义行为的回答,我认为这确实是一个错误的肯定。至少,这是一个不准确的诊断。从形式上讲,一个执行未定义行为的程序可以做任何事情,但在实践中,在这种情况下,超出指定
int
对象的界限是极不可能的结果,并且诊断会忽略所有其他可能的结果。假设其他参数在格式方面正确匹配,
scanf
家族函数溢出目标对象的主要风险是没有宽度的%s
或%[
转换规范,或者宽度太大的%s
,%[
或%c
转换规范。我认为Fortify是不恰当的概括。或者,当你把int的地址传递给fscanf时,是否有可能在int之外写入内存?
如果不涉及未定义的行为,无论是输入过长还是来自
fscanf()
调用之外的其他源,都是如此。如果在fscanf中使用%d时,可能会在int的内存之外写入,那么如何安全地避免这种情况?
实际上,我不认为这是值得关注的事情。
尽管如此,您可能可以通过向转换说明符添加适当的字段宽度来满足Fortify的要求,尽管在这种情况下确定“适当”的含义可能很棘手。这也将排除任何可能的UB所产生的呼吁,这是一个有价值的目标。
或者,您可以通过
fscanf()
以外的其他方式解析数字。py49o6xq3#
代码似乎不保证该工具报告的问题。
此外,在同一个文件中还有另一个对
fscanf
的调用,它应该报告相同的问题,除了目标int
是1D数组而不是2D数组中的条目:但在这两种情况下,很明显,工具应该推断出索引变量保持在适当的边界内。
您可以尝试使用以下代码更改第404..426行中的循环,以调查是否是工具造成的: