SubmittedCWE-789 — Memory Allocation with Excessive Size Value
ReadBoolVector 缺少数组大小上界检查导致 OOM 拒绝服务
View Upstream Issuegitcode.com/openharmony/communication_ipc/issues/1917CWE:CWE-789 — Memory Allocation with Excessive Size Value
Repository:communication_ipc
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 位值。
| 攻击者设置的 *size | malloc 分配大小 | 结果 |
|---|---|---|
| 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是一个正常的大正数- 循环变量
i是int32_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 → 无限循环
同族函数
同文件中的以下函数存在完全相同的问题模式:
| 函数 | 行号 | 类型 |
|---|---|---|
ReadBoolVector | 1126 | bool * |
ReadInt8Vector | 1156 | int8_t * |
ReadInt16Vector | 1186 | int16_t * |
ReadInt32Vector | 1216 | int32_t * |
ReadInt64Vector | 1246 | int64_t * |
ReadUint8Vector | 1276 | uint8_t * |
ReadUint16Vector | 1306 | uint16_t * |
ReadUint32Vector | 1336 | uint32_t * |
所有 Read*Vector 函数都从 IPC 消息读取 size 后直接 malloc,无上界检查。
触发条件
- 攻击者能够向使用 C 语言 IPC 序列化器的目标进程发送 IPC 消息
- 目标进程调用
ReadBoolVector(或同族函数)反序列化数据 - 目标运行在小型系统(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