我们已在第一篇中学习了 QSEECOM 的通用架构和 API。本篇以 Android 系统中实际的 Gatekeeper 服务为例,展示 QSEECOM 在真实场景中的完整调用链路。

1. Gatekeeper 在系统中的位置

Android Gatekeeper 服务负责锁屏密码(PIN/密码/图案)的 enrollment(注册)verification(验证)。当用户在锁屏界面输入密码时,Android Framework 通过 Binder 调用到 gatekeeperd 守护进程,最终进入 TrustZone 中的 Gatekeeper TA。验证成功后,Gatekeeper TA 生成一个 AuthToken(HMAC 签名的认证令牌),该令牌随后被 Keymaster TA 用来授权密钥的使用(如磁盘加密、指纹认证等)。

graph LR
  subgraph "Android Framework"
    LockSettings["LockSettingsService"]
  end
  subgraph "HLOS Userspace"
    GKD["gatekeeperd<br/>(Binder 服务)"]
    HAL["Gatekeeper HAL<br/>(vendor .so)"]
    QSEEAPI["libQSEEComAPI.so"]
  end
  subgraph "HLOS Kernel"
    QSEEDrv["QSEECom Driver<br/>(/dev/qseecom)"]
  end
  subgraph "Secure World"
    GKTA["Gatekeeper TA"]
    KMTA["Keymaster TA"]
  end

  LockSettings -- "Binder" --> GKD
  GKD -- "HAL 接口" --> HAL
  HAL -- "dlsym" --> QSEEAPI
  QSEEAPI -- "ioctl" --> QSEEDrv
  QSEEDrv -- "SMC" --> GKTA
  GKTA -- "Auth Token<br/>(HMAC Key 共享)" --> KMTA

系统模块关系:

  • Android Framework:LockSettingsService
  • HLOS Userspace:gatekeeperd(Binder 服务)、Gatekeeper HAL(vendor.so)、libQSEEComAPI.so
  • HLOS Kernel:QSEECom Driver/dev/qseecom
  • Secure World:Gatekeeper TAKeymaster TA

Gatekeeper 端到端架构,参考 [6] AOSP gatekeeperd、[7] AOSP keymaster QSEECom 用法、[8] QSEECom 驱动源码

2. HLOS 侧完整调用链

2.1 gatekeeperd 守护进程

源码位置:system/core/gatekeeperd/
该进程注册 Binder 服务 android.service.gatekeeper.IGatekeeperService。Framework 发起 enrollverify 请求时,gatekeeperd 通过 HIDL 调用到 HAL 层。

2.2 Gatekeeper HAL(厂商实现)

高通提供的 Gatekeeper HAL 是一个 vendor 共享库(如 gatekeeper.msm8996.so)实现了 gatekeeper_device_t 结构体中的 enroll()verify() 函数指针。其内部动态加载 libQSEEComAPI.so

struct qcom_gatekeeper_handle {
    struct QSEECom_handle *qseecom;
    void *libhandle;
    int (*QSEECom_start_app)(struct QSEECom_handle **handle,
                             char *path, char *appname, uint32_t size);
    int (*QSEECom_send_cmd)(struct QSEECom_handle *handle,
                            void *cbuf, uint32_t clen,
                            void *rbuf, uint32_t rlen);
    int (*QSEECom_shutdown_app)(struct QSEECom_handle **handle);
};

// 动态加载
handle->libhandle = dlopen("libQSEEComAPI.so", RTLD_NOW);
*(void**)(&handle->QSEECom_start_app) = dlsym(handle->libhandle, "QSEECom_start_app");
*(void**)(&handle->QSEECom_send_cmd)   = dlsym(handle->libhandle, "QSEECom_send_cmd");
*(void**)(&handle->QSEECom_shutdown_app) = dlsym(handle->libhandle, "QSEECom_shutdown_app");

2.3 libQSEEComAPI.so 与 ioctl

libQSEEComAPI.so 将 API 调用转换为对 /dev/qseecomioctl 操作。例如 QSEECom_send_cmd 最终调用 ioctl(fd, QSEECOM_IOCTL_SEND_CMD_REQ, &req)

3. 完整密码验证流程时序图

sequenceDiagram
  participant FW as Android Framework<br/>(LockSettingsService)
  participant GK as gatekeeperd
  participant HAL as Gatekeeper HAL<br/>(vendor .so)
  participant LIB as libQSEEComAPI
  participant DRV as QSEECom Driver<br/>(kernel)
  participant TZ as Gatekeeper TA

  FW->>GK: verify(userId, enrolledPasswordHandle, enteredPassword)
  GK->>HAL: device->verify(...)

  Note over HAL,TZ: Step 1: 启动 Gatekeeper TA
  HAL->>LIB: QSEECom_start_app(&handle, "/vendor/firmware/gatekeeper", "gatekeeper64", sb_size)
  LIB->>DRV: ioctl(QSEECOM_IOCTL_LOAD_APP_REQ)<br/>img_name="gatekeeper64"
  DRV->>DRV: 检查 TA 是否已加载
  DRV->>TZ: SMC (TZ_OS_START_APP_SMC_ID)
  TZ-->>TZ: 验证签名、加载 TA 到 pIMEM
  TZ-->>DRV: 返回 app_id
  DRV-->>LIB: 返回 handle
  LIB-->>HAL: 返回 QSEECom_handle

  Note over HAL,TZ: Step 2: 构造并发送验证请求
  HAL->>HAL: 序列化 VerifyRequest<br/>cmd_id=VERIFY<br/>+ enrolled_password_handle<br/>+ entered_password
  HAL->>LIB: QSEECom_send_cmd(handle, send_buf, sbuf_len, rcv_buf, rbuf_len)
  LIB->>DRV: ioctl(QSEECOM_IOCTL_SEND_CMD_REQ)<br/>{cmd_req_buf, cmd_req_len, resp_buf, resp_len}
  DRV->>DRV: 将用户态虚拟地址转换为物理地址<br/>cache clean (DMA 同步)
  DRV->>TZ: SMC (TZ_OS_SEND_CMD_SMC_ID)<br/>args: app_id, req_phys, req_len, rsp_phys, rsp_len
  TZ-->>TZ: QTEE 将共享内存映射到 TA 地址空间
  TZ-->>TZ: Gatekeeper TA: tz_app_cmd_handler(req, reqlen, rsp, rsplen)
  TZ->>TZ: 反序列化请求 → scrypt 验证 → 生成 AuthToken
  TZ->>TZ: 序列化 VerifyResponse 写入响应缓冲区
  TZ-->>DRV: SMC return
  DRV->>DRV: cache invalidate (DMA 同步)
  DRV-->>LIB: ioctl 返回
  LIB-->>HAL: QSEECom_send_cmd 返回
  HAL->>HAL: 反序列化 VerifyResponse<br/>提取 AuthToken

  Note over HAL,TZ: Step 3: 关闭 TA(如果不再需要)
  HAL->>LIB: QSEECom_shutdown_app(&handle)
  LIB->>DRV: ioctl(QSEECOM_IOCTL_UNLOAD_APP_REQ)
  DRV->>TZ: SMC (TZ_OS_SHUTDOWN_APP_SMC_ID)
  TZ-->>TZ: Unload Gatekeeper TA
  TZ-->>DRV: return
  DRV-->>LIB: return

  HAL-->>GK: 返回验证结果 + AuthToken
  GK-->>FW: 验证成功,Auth Token 可用于 Keymaster

阶段一:启动 Gatekeeper TA

  • HAL 调用 QSEECom_start_app(handle, "/vendor/firmware/gatekeeper", "gatekeeper64", sb_size)
  • libQSEEComAPI 执行 ioctl(QSEECOM_IOCTL_LOAD_APP_REQ)
  • QSEECom Driver 检查 TA 是否已加载,构建 SMC 命令
  • Driver 发送 SMC(TZ_OS_START_APP_SMC_ID
  • QTEE 验证 TA 签名,将 TA 加载到 pIMEM(安全内存)
  • QTEE 返回 app_id 给 Driver
  • Driver 返回 handle 给 HAL

阶段二:发送验证请求

  • HAL 序列化 VerifyRequest,包含 cmd_id=VERIFYenrolled_password_handleentered_password
  • 调用 QSEECom_send_cmd(handle, send_buf, sbuf_len, rcv_buf, rbuf_len)
  • libQSEEComAPI 执行 ioctl(QSEECOM_IOCTL_SEND_CMD_REQ)
  • Driver 将用户态虚拟地址转换为物理地址,执行 cache clean(DMA 同步)
  • Driver 发送 SMC(TZ_OS_SEND_CMD_SMC_ID),参数含 app_idreq_physreq_lenrsp_physrsp_len
  • QTEE 将共享内存映射到 TA 地址空间
  • Gatekeeper TA 调用 tz_app_cmd_handler(req, reqlen, rsp, rsplen)
  • TA 反序列化请求,执行 scrypt 验证,生成 AuthToken
  • TA 序列化 VerifyResponse 写入响应缓冲区
  • SMC 返回,Driver 执行 cache invalidate
  • ioctl 返回,HAL 反序列化响应,提取 AuthToken

阶段三:关闭 TA(可选)

  • HAL 调用 QSEECom_shutdown_app(&handle)
  • Driver 发送 SMC(TZ_OS_SHUTDOWN_APP_SMC_ID
  • QTEE 卸载 Gatekeeper TA

Gatekeeper 密码验证全链路,参考 [8] qseecom.c ioctl 流程、[4] 80-NH537-4 §8.5-8.9

4. 请求/响应的线格式(TLV 示例)

Gatekeeper 协议定义(gatekeeper_messages.h):

struct serial_header_t {
    uint32_t error;      // 错误码
    uint32_t user_id;    // Android 用户 ID
};
// 后续为 SizedBuffer 字段: [uint32_t length][uint8_t data[length]]

const uint32_t ENROLL = 0;
const uint32_t VERIFY = 1;
const uint32_t DELETE_USER = 2;

特点:线格式由 Client 和 TA 各自手动序列化/反序列化。没有 IDL 约束,完全依赖双方一致性。这是 QSEECOM “自定义协议” 的典型体现,也是接口不一致的隐患来源。

5. QSEECOM 模式下的特征总结

通过 Gatekeeper 实例可以清晰归纳 QSEECOM 的几个特征:

  • TA 名称硬编码"gatekeeper64" 字符串定位 TA,无标准化服务发现
  • 共享内存协议自定义:序列化格式由 HAL 和 TA 各自实现,容易出错
  • TA 身份不可知:TA 的入口 tz_app_cmd_handler 只接收原始字节,无法获知调用者进程身份
  • 引用关系简单QSEECom_handle 是扁平句柄,不能传递引用计数,无法共享给其他 Client

这些特征在高安全要求场景(如 Keymaster、DRM)中逐渐成为瓶颈,推动高通设计新一代框架 SMCInvoke。

Gatekeeper 案例让我们看到了 QSEECOM 在实际使用中的诸多不便和安全隐患。**下一篇**我们将系统性地总结 QSEECOM 的设计局限,并分析高通文档中提及的真实安全攻击案例,解释为何高通必须设计新一代通信框架。

更多推荐