【缺陷周话】第24期:在 scanf 函数中没有对 %s 格式符进行宽度限制

 

1、在 scanf 函数中没有对 %s 格式符进行宽度限制

scanf()是C语言中的一个输入函数,与printf函数一样,都被声明在头文件stdio.h中。函数原型:

int scanf(constchar*restrict format,…);

函数的第一个参数是格式字符串,它指定了输入的格式,并按照格式说明符解析输入对应位置的信息并存储于可变参数列表中对应的指针所指位置。

常见的格式说明符有 %c、%d、%s、%o、%p、%x、%X 等等,其中, %s 的功能是用来接收输入字符串并放入到一个字符数组中,在输入时以非空白字符串开始,以遇到第一个空白字符结束。scanf()函数在匹配非空字符时,使用字符指针指向数组,当没有对最大字段宽度进行限制时,可能会导致缓冲区溢出问题。

与 scanf() 函数存在相同问题的还有 vscanf()、 fscanf() 和 vsscanf()。

 

2、 “在 scanf 函数中没有对 %s 格式符进行宽度限制” 的危害

scanf()、 vscanf()、 fscanf() 和 vsscanf() 函数接收外部输入,如果输入的长度超出了目标缓冲区长度,就会覆盖其他数据区导致缓冲区溢出。

3、开源代码检测计划某项目示例

开源代码检测计划是一项免费的公益计划。通过使用360代码卫士对开源项目进行源代码检测和审计,找到源代码中存在的安全缺陷并及时与项目开发人员进行沟通和确认,使得开源项目的安全性得到提高。

以下示例代码地址:https://github.com/cisco/thor,存在该缺陷的分支为 y4m,文件名:enc/strings.c。

 

3.1缺陷代码

在缺陷代码中,第88行使用 fscanf() 函数从输入流 (stream) 中读入数据,使用%s格式说明符,但没有对宽度进行限制。当输入字符超过数组a的最大长度时,存在安全隐患。

使用360代码卫士对上述示例代码进行检测,可以检出“在scanf 函数中没有对%s格式符进行宽度限制”缺陷,显示等级为高。如图1所示:

图1:“在 scanf 函数中没有对 %s 格式符进行宽度限制”的检测示例

3.2 修复代码

针对该问题的提出,开发人员对相关代码进行了修复。在88行对 %s 格式符的宽度进行了限制,从而避免了“在 scanf 函数中没有对%s格式符进行宽度限制”问题。

使用360代码卫士对修复后的代码进行检测,可以看到已不存在“在scanf 函数中没有对%s格式符进行宽度限制”缺陷。如图2:

图2:修复后检测结果

 

4 、如何避免 “在 scanf 函数中未对 %s 格式符进行宽度限制”

(1)在使用 scanf()、 vscanf()、 fscanf() 和 vsscanf() 时,如果使用 %s 格式说明符,请对最大字段宽度进行限制;

(2)使用源代码静态分析工具进行自动化的检测,可以有效的发现源代码中的“在scanf函数中没有对%s格式符进行宽度限制”问题。

(完)