SubmittedCWE-20 — Improper Input Validation
dbinder UnFlattenDBinderData 跨设备通信中未验证指针导致内存读取异常
View Upstream Issuegitcode.com/openharmony/communication_ipc/issues/1916背景
binder_buffer_object 是 binder 框架中用于传递数据缓冲区的标准结构体。在本地 IPC 中,binder 驱动会识别 BINDER_TYPE_PTR 类型的 buffer object,自动完成跨进程的指针翻译和数据拷贝。但在 dbinder(分布式 binder,跨设备通信) 场景下,数据通过软总线传输,没有 binder 驱动参与指针翻译。
问题分析
序列化端(发送方)
// ipc/native/src/core/framework/source/process_skeleton.cpp
bool ProcessSkeleton::FlattenDBinderData(Parcel &parcel, const dbinder_negotiation_data *&dbinderData)
{
binder_buffer_object obj;
obj.hdr.type = BINDER_TYPE_PTR;
obj.flags = BINDER_BUFFER_FLAG_HAS_DBINDER;
obj.buffer = reinterpret_cast<binder_uintptr_t>(dbinderData); // 将本地指针地址存入结构体
obj.length = sizeof(dbinder_negotiation_data);
parcel.WriteBuffer(&obj, sizeof(binder_buffer_object)); // 作为原始字节写入 Parcel
return true;
}
发送方将 dbinderData 的原始指针地址存入 obj.buffer,然后通过 WriteBuffer 将整个结构体作为原始字节写入 Parcel。
反序列化端(接收方)
bool ProcessSkeleton::UnFlattenDBinderData(Parcel &parcel, dbinder_negotiation_data *&dbinderData)
{
auto *buf = parcel.ReadBuffer(sizeof(binder_buffer_object), false);
if (buf == nullptr) { return false; }
auto obj = reinterpret_cast<const binder_buffer_object *>(buf);
auto ret = memcpy_s(dbinderData, sizeof(dbinder_negotiation_data),
reinterpret_cast<const void *>(obj->buffer), // 直接将 buffer 字段用作源地址
obj->length); // 直接将 length 字段用作拷贝长度
return (ret == EOK);
}
接收方从 Parcel 读出 binder_buffer_object 结构体后,直接将 obj->buffer 字段解释为本地内存地址,用作 memcpy_s 的源指针。
问题所在
在跨设备通信中,Parcel 数据经软总线传输到对端设备后:
obj->buffer的值是发送方设备上的地址,在接收方设备上无意义- 该值被直接用作
memcpy_s的源地址,实际读取的是接收方进程中同一数值对应的地址空间 obj->length也未经校验,若其值超过sizeof(dbinder_negotiation_data),虽然memcpy_s会因目标缓冲区保护而返回错误,但源地址的读取行为已不可逆
如果攻击者控制了通信中的远程设备,可以构造恶意的 binder_buffer_object,将 buffer 设为任意值、length 设为期望的大小,使接收方从指定地址读取数据。
触发路径
远程设备构造恶意 Parcel
→ 软总线传输到目标设备
→ 目标设备反序列化 Parcel
→ UnFlattenDBinderData 被调用
→ ReadBuffer 返回 Parcel 内部缓冲区(本地有效)
→ obj->buffer 为攻击者指定的地址值
→ memcpy_s 从该地址读取 sizeof(dbinder_negotiation_data) 字节到本地变量
影响范围
- 信息泄露风险: 若攻击者能猜测接收方进程中已映射的地址,可读取该地址处的内存内容(单次最多
sizeof(dbinder_negotiation_data)字节) - 进程崩溃(DoS): 若
obj->buffer指向未映射的地址,将触发 SIGSEGV 导致进程崩溃 - 攻击前提: 攻击者需控制一台与目标设备建立 dbinder 通信的远程设备
建议修复
问题的根源在于跨设备传输时不应使用 binder_buffer_object.buffer 作为绝对指针。建议将实际的协商数据内联写入 Parcel,而非传递指针值:
// 发送方:直接写入实际数据
bool ProcessSkeleton::FlattenDBinderData(Parcel &parcel, const dbinder_negotiation_data *&dbinderData)
{
if (!parcel.WriteBuffer(dbinderData, sizeof(dbinder_negotiation_data))) {
return false;
}
return true;
}
// 接收方:直接从 Parcel 读取数据
bool ProcessSkeleton::UnFlattenDBinderData(Parcel &parcel, dbinder_negotiation_data *&dbinderData)
{
auto *buf = parcel.ReadBuffer(sizeof(dbinder_negotiation_data));
if (buf == nullptr) { return false; }
auto ret = memcpy_s(dbinderData, sizeof(dbinder_negotiation_data), buf, sizeof(dbinder_negotiation_data));
return (ret == EOK);
}
如果出于兼容性需要保留 binder_buffer_object 结构,则应在反序列化时验证 obj->buffer 指向 Parcel 内部数据区域,且 obj->length <= sizeof(dbinder_negotiation_data)。
涉及文件
ipc/native/src/core/framework/source/process_skeleton.cpp