使用 %d 时 fscanf 缓冲区会溢出吗?

Sha*_*hop 3 c scanf buffer-overflow fortify ossec

我在ossec-hids存储库上运行了Fortify 静态代码分析器,它报告了src/analysisd/stats.c:415的以下发现:Buffer Overflow: Format String

stats.c 第 415 行的 fscanf() 的格式字符串参数没有正确限制函数可以写入的数据量,这允许程序在分配的内存范围之外写入。此行为可能会损坏数据、使程序崩溃或导致恶意代码的执行

有问题的代码行是这样的:

if (fscanf(fp, "%d", &_RWHour[i][j]) <= 0) {
Run Code Online (Sandbox Code Playgroud)

_RWHour被声明为

static int _RWHour[7][25];
Run Code Online (Sandbox Code Playgroud)

在同一文件的第 33 行。我相信第 33 行的声明和第 415 行的使用之间没有任何阴影_RWHour,因为当我选择第 33 行的声明时,我的 IDE (Visual Studio 2019)_RWHour在 415 中突出显示。

当我查看 的cppreference 文档时fscanf,它显示以下内容:

d匹配十进制整数。数字的格式与基本参数strtol值的预期相同10

我从上面引用的表格还显示,当没有使用长度修饰符时%d(如所讨论的调用的情况fscanf),参数类型应该是signed int*or unsigned int*

我的问题是这样的:

在这种情况下,Fortify 的发现有可能是误报吗?int或者,当您将 an 的地址传递给intto时,是否可以写入 an 外部的内存fscanf

如果使用withint时可以在 an 的内存之外进行写入,如何安全地避免这种情况?%dfscanf

chu*_*ica 5

防止转换溢出

\n

fscanf(fp, "%d", &_RWHour[i][j])如果数字文本尝试转换为范围之外的值,则为未定义行为(UB) *1int

\n

防止 UB 的快速解决方法是限制使用width读取的字符数:

\n
//fscanf(fp, "%d", &_RWHour[i][j])\nfscanf(fp, "%4d", &_RWHour[i][j])  // Limit [-999 ... 9999].\n
Run Code Online (Sandbox Code Playgroud)\n

更强大的解决方案读取文本并用于strtol()转换。

\n

我建议创建一个辅助函数来处理int.

\n

这种级别的检查有点糟糕,不是吗?

\n

i, j在范围内

\n

对OP引用的代码的审查看起来不错,但分析工具可能对此有所抱怨。

\n
\n

*1

\n
\n

...或者如果转换的结果\n无法在对象中表示,则行为未定义。C23dr \xc2\xa7 7.23.6.2 10

\n
\n

使用 UB,“可以写入 int 之外的内存”。

\n

  • 我想说,尽管有“你会得到鼻恶魔 Har har 口头禅”,但作为整数溢出的“直接”后果,破坏内存的可能性为 0%。OP 建议有一种方法可以防止“fscanf”格式字符串中数组溢出:但没有。正如所评论的,OP 是否从 `int n; 中标记了此错误?fscanf(fp, "%d", &amp;n);`? UB 指的是“值”未定义,而不是编译器将西红柿扔出婴儿车。否则,将不可能编写出能够在用户输入错误后幸存下来的代码。 (4认同)
  • 添加了@pmacfarlane 引用。 (3认同)