Dashboard/Issues/OH-2026-IPC-004
SubmittedCWE-20 — Improper Input Validation

dbinder UnFlattenDBinderData 跨设备通信中未验证指针导致内存读取异常

View Upstream Issuegitcode.com/openharmony/communication_ipc/issues/1916
CWE:CWE-20 — Improper Input Validation
Date:2026-05-07
Reporter:Zirui

背景

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 数据经软总线传输到对端设备后:

  1. obj->buffer 的值是发送方设备上的地址,在接收方设备上无意义
  2. 该值被直接用作 memcpy_s 的源地址,实际读取的是接收方进程中同一数值对应的地址空间
  3. 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