【缺陷周话】第17期:有符号整数溢出
字数 1594 2025-08-18 11:37:49

有符号整数溢出缺陷分析与防护指南

1. 有符号整数溢出概述

在C/C++编程语言中,整数类型分为有符号整数和无符号整数:

  • 有符号整数:最高位表示符号(正或负),其余位表示数值大小
  • 无符号整数:所有位都用于表示数值大小

有符号整数的取值范围为[-2n-1, 2n-1-1],当有符号整数的值超出这个范围时,就会发生有符号整数溢出

2. 有符号整数溢出的主要原因

导致有符号整数溢出的重要原因之一是运算操作不当,常见运算包括:

  • 加法
  • 减法
  • 乘法
  • 除法
  • 位移运算

如果没有对值的范围进行判断和限制,很容易导致有符号整数溢出问题。

3. 有符号整数溢出的危害

有符号整数溢出会产生数值错误,根据错误数值的使用位置不同,可能导致不同的安全问题:

  1. 拒绝服务攻击:错误的数值可能导致程序崩溃或无限循环
  2. 内存破坏:错误的数值用于内存操作可能导致缓冲区溢出
  3. 任意代码执行:在严重情况下可能被利用执行恶意代码

实际案例统计:仅2018年1月至12月,CVE中就有605条与有符号整数溢出相关的漏洞信息。

4. 典型漏洞案例

CVE编号 影响范围 危害 修复版本
CVE-2018-1000876 binutils 2.32及更早版本 任意代码执行 3a551c7a1b80fca579461774860574eabfd7f18f
CVE-2018-1000098 teluu pjsip 2.7.1及更低版本 崩溃 2.7.2
CVE-2018-1000524 miniSphere 5.2.9及更早版本 拒绝服务 5.0.3/5.1.5/5.2.10
CVE-2018-1000127 memcached 1.4.37以前版本 数据损坏和死锁 1.4.37

5. 示例代码分析

5.1 缺陷代码示例

// 示例来源于Samate Juliet Test Suite for C/C++ v1.3
// 源文件名: CWE190_Integer_Overflow__int64_t_max_multiply_01.c

void bad()
{
    int64_t data;
    /* 初始化data为最大值 */
    data = INT64_MAX;
    
    if(data > 0) /* 确保data不小于等于0 */
    {
        /* 潜在缺陷: 没有检查data的上限 */
        int64_t result = data * 2; // 这里会发生整数溢出
        printLongLongLine(result);
    }
}

问题分析

  • 虽然代码通过if(data > 0)确保了data的值不小于等于0
  • 但没有对data值的上限进行限制
  • 当执行data * 2运算时,结果超出了int64_t的最大值,导致有符号整数溢出

5.2 修复后的代码

void good()
{
    int64_t data;
    /* 初始化data为最大值 */
    data = INT64_MAX;
    
    if(data > 0) /* 确保data不小于等于0 */
    {
        /* 修复: 添加上限检查 */
        if (data < (INT64_MAX/2))
        {
            int64_t result = data * 2;
            printLongLongLine(result);
        }
        else
        {
            printLine("data value is too large to perform multiplication.");
        }
    }
}

修复要点

  1. 添加了对data最大值的限制检查data < (INT64_MAX/2)
  2. 当data过大时,提供错误处理路径
  3. 确保乘法运算不会导致整数溢出

6. 防护措施

要避免有符号整数溢出,需要注意以下几点:

  1. 范围检查

    • 在进行有符号整数操作前,必须检查操作数的取值范围
    • 特别注意乘法运算,应确保a * b不会超过最大值(检查a <= MAX/b
    • 对于加法,检查a <= MAX - b
  2. 输入验证

    • 对来自不可信源的有符号整数进行严格验证
    • 确保输入值在预期范围内
  3. 使用安全库

    • 考虑使用经过安全验证的数学运算库
    • 使用编译器内置的安全检查功能
  4. 静态代码分析

    • 使用源代码静态分析工具进行自动化检测
    • 将整数溢出检查纳入代码审查清单
  5. 防御性编程

    • 假设所有外部输入都可能包含恶意值
    • 为所有数值运算添加边界检查
    • 使用更大的数据类型存储中间结果(如用int64_t存储int32_t的运算结果)

7. 检测工具示例

使用360代码卫士等静态分析工具可以有效地检测有符号整数溢出问题:

  1. 缺陷检测:能够准确识别潜在的整数溢出点
  2. 风险评级:对整数溢出缺陷通常标记为高风险
  3. 修复验证:可以验证修复后的代码是否消除了缺陷

8. 总结

有符号整数溢出是C/C++程序中常见的安全隐患,可能导致严重后果。通过:

  1. 严格的输入验证
  2. 完善的边界检查
  3. 防御性编程实践
  4. 自动化工具辅助

可以有效地预防和消除这类安全问题,提高软件的安全性和可靠性。

有符号整数溢出缺陷分析与防护指南 1. 有符号整数溢出概述 在C/C++编程语言中,整数类型分为有符号整数和无符号整数: 有符号整数 :最高位表示符号(正或负),其余位表示数值大小 无符号整数 :所有位都用于表示数值大小 有符号整数的取值范围为[ -2 n-1 , 2 n-1 -1],当有符号整数的值超出这个范围时,就会发生 有符号整数溢出 。 2. 有符号整数溢出的主要原因 导致有符号整数溢出的重要原因之一是 运算操作不当 ,常见运算包括: 加法 减法 乘法 除法 位移运算 如果没有对值的范围进行判断和限制,很容易导致有符号整数溢出问题。 3. 有符号整数溢出的危害 有符号整数溢出会产生数值错误,根据错误数值的使用位置不同,可能导致不同的安全问题: 拒绝服务攻击 :错误的数值可能导致程序崩溃或无限循环 内存破坏 :错误的数值用于内存操作可能导致缓冲区溢出 任意代码执行 :在严重情况下可能被利用执行恶意代码 实际案例统计 :仅2018年1月至12月,CVE中就有605条与有符号整数溢出相关的漏洞信息。 4. 典型漏洞案例 | CVE编号 | 影响范围 | 危害 | 修复版本 | |---------|----------|------|----------| | CVE-2018-1000876 | binutils 2.32及更早版本 | 任意代码执行 | 3a551c7a1b80fca579461774860574eabfd7f18f | | CVE-2018-1000098 | teluu pjsip 2.7.1及更低版本 | 崩溃 | 2.7.2 | | CVE-2018-1000524 | miniSphere 5.2.9及更早版本 | 拒绝服务 | 5.0.3/5.1.5/5.2.10 | | CVE-2018-1000127 | memcached 1.4.37以前版本 | 数据损坏和死锁 | 1.4.37 | 5. 示例代码分析 5.1 缺陷代码示例 问题分析 : 虽然代码通过 if(data > 0) 确保了data的值不小于等于0 但没有对data值的上限进行限制 当执行 data * 2 运算时,结果超出了 int64_t 的最大值,导致有符号整数溢出 5.2 修复后的代码 修复要点 : 添加了对data最大值的限制检查 data < (INT64_MAX/2) 当data过大时,提供错误处理路径 确保乘法运算不会导致整数溢出 6. 防护措施 要避免有符号整数溢出,需要注意以下几点: 范围检查 : 在进行有符号整数操作前,必须检查操作数的取值范围 特别注意乘法运算,应确保 a * b 不会超过最大值(检查 a <= MAX/b ) 对于加法,检查 a <= MAX - b 输入验证 : 对来自不可信源的有符号整数进行严格验证 确保输入值在预期范围内 使用安全库 : 考虑使用经过安全验证的数学运算库 使用编译器内置的安全检查功能 静态代码分析 : 使用源代码静态分析工具进行自动化检测 将整数溢出检查纳入代码审查清单 防御性编程 : 假设所有外部输入都可能包含恶意值 为所有数值运算添加边界检查 使用更大的数据类型存储中间结果(如用 int64_t 存储 int32_t 的运算结果) 7. 检测工具示例 使用 360代码卫士 等静态分析工具可以有效地检测有符号整数溢出问题: 缺陷检测 :能够准确识别潜在的整数溢出点 风险评级 :对整数溢出缺陷通常标记为高风险 修复验证 :可以验证修复后的代码是否消除了缺陷 8. 总结 有符号整数溢出是C/C++程序中常见的安全隐患,可能导致严重后果。通过: 严格的输入验证 完善的边界检查 防御性编程实践 自动化工具辅助 可以有效地预防和消除这类安全问题,提高软件的安全性和可靠性。