【缺陷周话】第35期:除数为零
字数 1155 2025-08-18 11:38:37

除数为零缺陷分析与防范指南

1. 缺陷概述

除数为零(Divide By Zero)是C/C++编程中常见的安全缺陷,属于CWE-369分类。当程序执行除法或取模运算时,如果除数为零,会导致程序崩溃或产生未定义行为。

基本算数运算符

  • + 加法
  • - 减法
  • * 乘法
  • / 除法
  • % 取模

安全要求:除法(/)和取模(%)运算的第二个操作数绝对不能为零。

2. 危害分析

主要影响

  • 程序崩溃
  • 拒绝服务(DoS)漏洞
  • 可能导致程序进入未定义状态

实际漏洞案例

  1. ImageMagick (CVE-2019-11472)

    • 影响版本:7.0.8-41 Q16
    • 漏洞位置:XWD图像解析组件的ReadXWDImage函数
    • 攻击方式:特制XWD图像文件可导致除零漏洞
  2. Wireshark (CVE-2018-19628)

    • 影响版本:2.6.0-2.6.4, 2.4.0-2.4.10
    • 漏洞位置:ZigBee ZCL解析器
    • 攻击方式:畸形数据包导致崩溃
  3. elfutils (CVE-2018-18521)

    • 影响版本:0.174
    • 漏洞位置:arlibaddsymbols()函数
    • 问题原因:未正确处理shentsize为零的情况

3. 缺陷代码示例

#include <stdio.h>

void badSink(int data)
{
    /* POTENTIAL FLAW: Possibly divide by zero */
    int result = 100 / data;
    printf(result);
}

void main()
{
    int data;
    /* Initialize data */
    data = -1;
    /* POTENTIAL FLAW: Read data from the console using fscanf() */
    fscanf(stdin, "%d", &data);
    badSink(data);
}

问题分析

  1. 第28行使用fscanf()从标准输入读取数据到data
  2. 输入来自不可信源,可能为零
  3. 第30行进行除法运算时未检查除数是否为零

4. 修复方案

修复代码示例

#include <stdio.h>

void goodSink(int data)
{
    /* FIX: test for a zero denominator */
    if(data != 0)
    {
        int result = 100 / data;
        printf(result);
    }
    else
    {
        printf("Error: Attempt to divide by zero");
    }
}

void main()
{
    int data;
    /* Initialize data */
    data = -1;
    /* POTENTIAL FLAW: Read data from the console using fscanf() */
    fscanf(stdin, "%d", &data);
    goodSink(data);
}

修复要点

  1. 在执行除法前检查除数是否为零
  2. 为零时提供错误处理路径
  3. 使用明确的错误提示信息

5. 防范措施

最佳实践

  1. 输入验证:对所有外部输入进行验证,确保除数不为零
  2. 防御性编程:在除法运算前添加显式检查
  3. 异常处理:为零时提供适当的错误处理逻辑
  4. 代码审查:重点关注以下场景:
    • 除数为函数返回值
    • 除数为复杂表达式结果
    • 除数为外部输入数据
  5. 静态分析:使用代码卫士等工具进行自动化检测

高风险场景

  1. 除数为用户输入数据
  2. 除数为网络数据解析结果
  3. 除数为文件读取内容
  4. 除数为复杂计算表达式结果
  5. 除数为可能溢出的变量

6. 检测与验证

静态分析工具

  • 使用代码卫士等专业工具检测
  • 检测等级:高

测试用例设计

  1. 边界值测试:输入0值
  2. 异常输入测试:输入可能产生零的表达式
  3. 模糊测试:随机生成输入数据

7. 相关资源

  1. CWE-369: Divide By Zero (3.2)
  2. Samate Juliet Test Suite for C/C++ v1.3
  3. 代码卫士静态分析工具

8. 总结

除数为零是常见但严重的安全缺陷,可能导致程序崩溃和拒绝服务。通过输入验证、防御性编程和静态分析工具的综合应用,可以有效预防此类缺陷。开发人员应特别注意来自不可信源的除数,并在所有除法运算前添加显式检查。

除数为零缺陷分析与防范指南 1. 缺陷概述 除数为零(Divide By Zero)是C/C++编程中常见的安全缺陷,属于CWE-369分类。当程序执行除法或取模运算时,如果除数为零,会导致程序崩溃或产生未定义行为。 基本算数运算符 + 加法 - 减法 * 乘法 / 除法 % 取模 安全要求 :除法( / )和取模( % )运算的第二个操作数绝对不能为零。 2. 危害分析 主要影响 程序崩溃 拒绝服务(DoS)漏洞 可能导致程序进入未定义状态 实际漏洞案例 ImageMagick (CVE-2019-11472) 影响版本:7.0.8-41 Q16 漏洞位置:XWD图像解析组件的 ReadXWDImage 函数 攻击方式:特制XWD图像文件可导致除零漏洞 Wireshark (CVE-2018-19628) 影响版本:2.6.0-2.6.4, 2.4.0-2.4.10 漏洞位置:ZigBee ZCL解析器 攻击方式:畸形数据包导致崩溃 elfutils (CVE-2018-18521) 影响版本:0.174 漏洞位置: arlibaddsymbols() 函数 问题原因:未正确处理shentsize为零的情况 3. 缺陷代码示例 问题分析 第28行使用 fscanf() 从标准输入读取数据到 data 输入来自不可信源,可能为零 第30行进行除法运算时未检查除数是否为零 4. 修复方案 修复代码示例 修复要点 在执行除法前检查除数是否为零 为零时提供错误处理路径 使用明确的错误提示信息 5. 防范措施 最佳实践 输入验证 :对所有外部输入进行验证,确保除数不为零 防御性编程 :在除法运算前添加显式检查 异常处理 :为零时提供适当的错误处理逻辑 代码审查 :重点关注以下场景: 除数为函数返回值 除数为复杂表达式结果 除数为外部输入数据 静态分析 :使用代码卫士等工具进行自动化检测 高风险场景 除数为用户输入数据 除数为网络数据解析结果 除数为文件读取内容 除数为复杂计算表达式结果 除数为可能溢出的变量 6. 检测与验证 静态分析工具 使用代码卫士等专业工具检测 检测等级:高 测试用例设计 边界值测试:输入0值 异常输入测试:输入可能产生零的表达式 模糊测试:随机生成输入数据 7. 相关资源 CWE-369: Divide By Zero (3.2) Samate Juliet Test Suite for C/C++ v1.3 代码卫士静态分析工具 8. 总结 除数为零是常见但严重的安全缺陷,可能导致程序崩溃和拒绝服务。通过输入验证、防御性编程和静态分析工具的综合应用,可以有效预防此类缺陷。开发人员应特别注意来自不可信源的除数,并在所有除法运算前添加显式检查。