Dashboard/Issues/OH-2026-IPC-002
SubmittedCWE-789 — Memory Allocation with Excessive Size Value

ReadBoolVector 缺少数组大小上界检查导致 OOM 拒绝服务

View Upstream Issuegitcode.com/openharmony/communication_ipc/issues/1917
CWE:CWE-789 — Memory Allocation with Excessive Size Value
Date:2026-05-07
Reporter:Zirui

漏洞概述

在 OpenHarmony 的 IPC C 语言序列化器中,ReadBoolVector 函数从 IPC 消息中读取数组大小后,未进行任何上界验证即直接用于 malloc 分配内存。攻击者可以发送恶意 IPC 消息,将数组大小设为极大值,触发巨量内存分配导致 OOM 拒绝服务,或利用循环计数器的有符号/无符号类型不匹配触发无限循环。

漏洞详情

问题代码

文件: ipc/native/c/manager/src/serializer.c

// Lines 1126-1154
bool *ReadBoolVector(IpcIo *io, size_t *size)
{
    if (io == NULL || size == NULL) {
        RPC_LOG_ERROR("IPC io == NULL || size == NULL failed: %s:%d\n", __FUNCTION__, __LINE__);
        return NULL;
    }
    *size = 0;
    bool ret = ReadUint32(io, (uint32_t *)size);  // ← *size 来自不可信 IPC 数据
    if (!ret) {
        return NULL;
    }

    // ⚠️ 漏洞点 1:*size 无上界检查,直接用于 malloc
    bool *val = (bool *)malloc((*size) * sizeof(bool));
    if (val == NULL) {
        RPC_LOG_ERROR("IPC malloc failed: %s:%d\n", __FUNCTION__, __LINE__);
        return NULL;
    }

    int32_t *ptr = NULL;
    // ⚠️ 漏洞点 2:int32_t 循环计数器 vs size_t 比较
    for (int32_t i = 0; i != *size; i++) {
        ptr = (int32_t *)IoPop(io, sizeof(int32_t));
        if (ptr == NULL) {
            free(val);
            return NULL;
        }
        val[i] = (bool)(*ptr);
    }
    return val;
}

问题分析

问题 1:无上界的 malloc

*size 通过 ReadUint32 从 IPC 消息中读取,攻击者可设置为任意 32 位值。

攻击者设置的 *sizemalloc 分配大小结果
0x7FFFFFFF (2GB)2GB分配失败 → malloc 返回 NULL → 安全返回
0x10000000 (256MB)256MB可能成功 → 嵌入式设备 OOM
0x01000000 (16MB)16MB大概率成功 → 系统内存压力

在嵌入式 LiteOS/Small 设备上(通常 256MB~1GB 内存),即使 16MB 的分配也可能导致系统内存不足,影响其他进程的正常运行。

问题 2:有符号/无符号类型不匹配

for (int32_t i = 0; i != *size; i++) {
//   ^^^^^^^          ^^^^^^
//   int32_t (signed)  size_t (unsigned)

*size 值超过 INT32_MAX (0x7FFFFFFF) 时:

  • *size 作为 size_t 是一个正常的大正数
  • 循环变量 iint32_t,当 i 递增到 INT32_MAX 后再 +1 会导致有符号整数溢出(C 语言中是未定义行为)
  • 可能的后果i 绕回到负数,永远不等于 *size → 无限循环 → CPU 100% 拒绝服务

攻击场景

场景 1:OOM 攻击

攻击者进程                              目标服务进程 (小型系统)
    |                                         |
    | 1. 构造 IPC 消息                        |
    |    vector_size = 0x04000000 (64MB)       |
    |    后续数据为空                          |
    |                                         |
    | 2. 发送 IPC 消息                        |
    |---------------------------------------> |
    |                                         | 3. ReadBoolVector 被调用
    |                                         |    ReadUint32 → *size = 64MB
    |                                         |    malloc(64MB) → 
    |                                         |      a) 返回 NULL → 安全
    |                                         |      b) 成功 → 系统内存耗尽
    |                                         | 4. 如果 malloc 成功:
    |                                         |    IoPop 循环 64M 次
    |                                         |    → 第一次 IoPop 就返回 NULL
    |                                         |    → free(val) → 安全返回
    |                                         | 5. 但 64MB 的瞬时分配峰值
    |                                         |    已经触发 OOM killer

场景 2:无限循环攻击

攻击者进程                              目标服务进程
    |                                         |
    | 1. 构造 IPC 消息                        |
    |    vector_size = 0xFFFFFFFF              |
    |    后续数据 = 大量 int32 值              |
    |                                         |
    | 2. 发送 IPC 消息                        |
    |---------------------------------------> |
    |                                         | 3. ReadBoolVector 被调用
    |                                         |    ReadUint32 → *size = 0xFFFFFFFF
    |                                         |    malloc(0xFFFFFFFF) → 
    |                                         |      a) 返回 NULL → 安全返回
    |                                         |      b) 32位平台: sizeof(bool)=1
    |                                         |         malloc(4GB-1) → 几乎必定失败
    |                                         |
    |                                         | 注:如果某种情况 malloc 成功(如 mmap)
    |                                         | 则进入 for(int32_t i=0; i!=*size; i++)
    |                                         | i 永远不等于 0xFFFFFFFF → 无限循环

同族函数

同文件中的以下函数存在完全相同的问题模式:

函数行号类型
ReadBoolVector1126bool *
ReadInt8Vector1156int8_t *
ReadInt16Vector1186int16_t *
ReadInt32Vector1216int32_t *
ReadInt64Vector1246int64_t *
ReadUint8Vector1276uint8_t *
ReadUint16Vector1306uint16_t *
ReadUint32Vector1336uint32_t *

所有 Read*Vector 函数都从 IPC 消息读取 size 后直接 malloc,无上界检查。

触发条件

  1. 攻击者能够向使用 C 语言 IPC 序列化器的目标进程发送 IPC 消息
  2. 目标进程调用 ReadBoolVector(或同族函数)反序列化数据
  3. 目标运行在小型系统(LiteOS / Small 内核),内存有限

调用链

目标服务的 OnRemoteRequest
  → 反序列化 IPC 参数
    → ReadBoolVector(io, &size)  ← 漏洞触发点
      → ReadUint32(io, (uint32_t *)&size)  ← 读取攻击者控制的大小
      → malloc(size * sizeof(bool))  ← OOM

修复建议

// 定义合理的上界
#define MAX_VECTOR_SIZE (1024 * 1024)  // 1M 元素

bool *ReadBoolVector(IpcIo *io, size_t *size)
{
    if (io == NULL || size == NULL) {
        RPC_LOG_ERROR("IPC io == NULL || size == NULL failed: %s:%d\n", __FUNCTION__, __LINE__);
        return NULL;
    }
    *size = 0;
    
    uint32_t arraySize = 0;
    bool ret = ReadUint32(io, &arraySize);
    if (!ret) {
        return NULL;
    }
    
+   // 上界检查:防止 OOM
+   if (arraySize > MAX_VECTOR_SIZE) {
+       RPC_LOG_ERROR("ReadBoolVector size %u exceeds max %u", arraySize, MAX_VECTOR_SIZE);
+       return NULL;
+   }
    
    *size = (size_t)arraySize;
    bool *val = (bool *)malloc(arraySize * sizeof(bool));
    if (val == NULL) {
        RPC_LOG_ERROR("IPC malloc failed: %s:%d\n", __FUNCTION__, __LINE__);
        return NULL;
    }

    int32_t *ptr = NULL;
-   for (int32_t i = 0; i != *size; i++) {
+   for (uint32_t i = 0; i < arraySize; i++) {  // 统一无符号类型,使用 < 而非 !=
        ptr = (int32_t *)IoPop(io, sizeof(int32_t));
        if (ptr == NULL) {
            free(val);
            return NULL;
        }
        val[i] = (bool)(*ptr);
    }
    return val;
}

注意:应对所有 8 个 Read*Vector 函数统一修复。

涉及文件

  • ipc/native/c/manager/src/serializer.c (lines 1126-1350, 共 8 个函数)
  • interfaces/innerkits/c/ipc/include/serializer.h (函数声明)

参考

  • CWE-789: Memory Allocation with Excessive Size Value
  • CWE-190: Integer Overflow or Wraparound
  • CWE-835: Loop with Unreachable Exit Condition