【缺陷周话】第20期:无符号整数回绕
字数 1375 2025-08-18 11:37:53

无符号整数回绕安全缺陷详解

1. 无符号整数回绕概述

无符号整数回绕是C/C++编程中常见的安全缺陷,当无符号整数的数值超过其取值范围时会发生回绕现象,而不是产生溢出错误。

1.1 无符号整数取值范围

ANSI标准定义的无符号整数类型及范围:

类型 位数 取值范围
unsigned int 16/32 0~65535
unsigned short int 16 0~65535
unsigned long int 32 0~4294967295
unsigned long long int 64 0~2^64-1

1.2 回绕原理

根据C99标准第6.2.5节第9条规定:

  • 涉及无符号整数的计算不会产生溢出
  • 当数值超过无符号整数的取值范围时会发生回绕
    • 最大值加1会返回0
    • 最小值减1会返回该类型的最大值

可能导致回绕的操作符:+, -, *, ++, --, +=, -=, *=

2. 无符号整数回绕的危害

2.1 直接危害

  • 产生不符合预期的数值错误
  • 可能导致内存操作异常

2.2 典型利用场景

  1. 内存拷贝函数:如memcpy(),当回绕产生极大值时,可能导致:

    • 复制巨大数据量
    • 破坏堆栈结构
  2. 内存分配函数:如malloc(),当参数回绕时可能导致:

    • 分配0长度内存
    • 内存分配失败

2.3 实际漏洞案例

CVE编号 描述
CVE-2018-6323 BFD库(libbfd)中elf_object_p()函数存在无符号整数回绕,精心制作的ELF文件可导致拒绝服务
CVE-2018-5848 Android Qualcomm WIGIG组件因未正确处理无符号整数回绕导致缓冲区溢出,可执行任意代码或拒绝服务

3. 示例代码分析

3.1 缺陷代码示例

void badSink(unsigned int data)
{
    unsigned int result = data * 2; // 可能发生回绕
    printUnsignedLine(result);
}

void bad()
{
    unsigned int data;
    data = 0;
    fscanf(stdin, "%u", &data); // 从输入读取无符号整数
    badSink(data);
}

问题分析

  • 从输入流读取无符号整数data
  • 只对下限进行了限制(0),未限制上限
  • data*2超过UINT_MAX时会发生回绕

3.2 修复代码示例

void goodSink(unsigned int data)
{
    if(data > (UINT_MAX/2)) // 检查是否会导致回绕
    {
        printLine("Input value is too large to perform arithmetic safely.");
    }
    else
    {
        unsigned int result = data * 2;
        printUnsignedLine(result);
    }
}

void good()
{
    unsigned int data;
    data = 0;
    fscanf(stdin, "%u", &data);
    goodSink(data);
}

修复要点

  • 在执行乘法前检查data是否超过UINT_MAX/2
  • 如果可能回绕,则拒绝执行并提示错误

4. 防御措施

4.1 编码实践

  1. 参数验证

    • 对无符号整数参数进行上下界检查
    • 特别注意来自不可信源的输入数据
  2. 运算前检查

    • 在执行运算前检查是否会导致回绕
    • 例如乘法前检查a > MAX/b
  3. 使用安全库

    • 使用经过安全验证的数学运算库
    • SafeInt等安全整数运算库

4.2 检测方法

  1. 静态代码分析

    • 使用专业工具(如360代码卫士)进行自动化检测
    • 识别潜在的无符号整数回绕风险
  2. 代码审查

    • 重点关注无符号整数运算
    • 特别审查内存分配和拷贝相关代码

5. 总结

无符号整数回绕是C/C++开发中常见但容易被忽视的安全问题,可能导致严重的安全漏洞。开发者应当:

  1. 充分理解无符号整数的回绕特性
  2. 对所有无符号整数运算进行边界检查
  3. 对不可信输入进行严格验证
  4. 使用自动化工具辅助检测

通过规范的编码实践和严格的代码审查,可以有效避免无符号整数回绕导致的安全问题。

无符号整数回绕安全缺陷详解 1. 无符号整数回绕概述 无符号整数回绕是C/C++编程中常见的安全缺陷,当无符号整数的数值超过其取值范围时会发生回绕现象,而不是产生溢出错误。 1.1 无符号整数取值范围 ANSI标准定义的无符号整数类型及范围: | 类型 | 位数 | 取值范围 | |------|------|----------| | unsigned int | 16/32 | 0~65535 | | unsigned short int | 16 | 0~65535 | | unsigned long int | 32 | 0~4294967295 | | unsigned long long int | 64 | 0~2^64-1 | 1.2 回绕原理 根据C99标准第6.2.5节第9条规定: 涉及无符号整数的计算不会产生溢出 当数值超过无符号整数的取值范围时会发生回绕 最大值加1会返回0 最小值减1会返回该类型的最大值 可能导致回绕的操作符: + , - , * , ++ , -- , += , -= , *= 2. 无符号整数回绕的危害 2.1 直接危害 产生不符合预期的数值错误 可能导致内存操作异常 2.2 典型利用场景 内存拷贝函数 :如 memcpy() ,当回绕产生极大值时,可能导致: 复制巨大数据量 破坏堆栈结构 内存分配函数 :如 malloc() ,当参数回绕时可能导致: 分配0长度内存 内存分配失败 2.3 实际漏洞案例 | CVE编号 | 描述 | |---------|------| | CVE-2018-6323 | BFD库(libbfd)中elf_ object_ p()函数存在无符号整数回绕,精心制作的ELF文件可导致拒绝服务 | | CVE-2018-5848 | Android Qualcomm WIGIG组件因未正确处理无符号整数回绕导致缓冲区溢出,可执行任意代码或拒绝服务 | 3. 示例代码分析 3.1 缺陷代码示例 问题分析 : 从输入流读取无符号整数 data 只对下限进行了限制(0),未限制上限 当 data*2 超过 UINT_MAX 时会发生回绕 3.2 修复代码示例 修复要点 : 在执行乘法前检查 data 是否超过 UINT_MAX/2 如果可能回绕,则拒绝执行并提示错误 4. 防御措施 4.1 编码实践 参数验证 : 对无符号整数参数进行上下界检查 特别注意来自不可信源的输入数据 运算前检查 : 在执行运算前检查是否会导致回绕 例如乘法前检查 a > MAX/b 使用安全库 : 使用经过安全验证的数学运算库 如 SafeInt 等安全整数运算库 4.2 检测方法 静态代码分析 : 使用专业工具(如360代码卫士)进行自动化检测 识别潜在的无符号整数回绕风险 代码审查 : 重点关注无符号整数运算 特别审查内存分配和拷贝相关代码 5. 总结 无符号整数回绕是C/C++开发中常见但容易被忽视的安全问题,可能导致严重的安全漏洞。开发者应当: 充分理解无符号整数的回绕特性 对所有无符号整数运算进行边界检查 对不可信输入进行严格验证 使用自动化工具辅助检测 通过规范的编码实践和严格的代码审查,可以有效避免无符号整数回绕导致的安全问题。