【NFC】CVE-2019-9358 ce_t3t_data_cback越界读写

这个漏洞因为不能直接触发,所以谷歌只在Android 10上面进行了修复而且没有公开补丁

漏洞原理总结:在函数ce_t3t_data_cback()中直接获取传入数据作为长度进行数组拷贝造成越界写,可EoP

CVE参考编号类型严重程度

CVE-2019-9358

A-120156401

EoP

这个漏洞暂时没有找到补丁,漏洞细节可以看注释

/*******************************************************************************
**
** Function         ce_t3t_data_cback
**
** Description      This callback function receives the data from NFCC.
**
** Returns          none
**
*******************************************************************************/
void ce_t3t_data_cback(tNFC_DATA_CEVT* p_data) {
    tCE_CB* p_ce_cb = &ce_cb;
    tCE_T3T_MEM* p_cb = &p_ce_cb->mem.t3t;
    NFC_HDR* p_msg = p_data->p_data;
    tCE_DATA ce_data;
    uint8_t cmd_id, bl0, entry_len, i;
    uint8_t* p_nfcid2 = nullptr;
    uint8_t* p = (uint8_t*)(p_msg + 1) + p_msg->offset;
    uint8_t cmd_nfcid2[NCI_RF_F_UID_LEN];
    uint16_t block_list_start_offset, remaining;
    bool msg_processed = false;
    bool block_list_ok;
    uint8_t sod;
    uint8_t cmd_type;

    /* If activate system code is not NDEF, or if no local NDEF contents was set,
     * then pass data up to the app */
    if ((p_cb->system_code != T3T_SYSTEM_CODE_NDEF) ||
        (!p_cb->ndef_info.initialized)) {
        ce_data.raw_frame.status = p_data->status;
        ce_data.raw_frame.p_data = p_msg;
        p_ce_cb->p_cback(CE_T3T_RAW_FRAME_EVT, &ce_data);
        return;
    }

    /* Verify that message contains at least Sod and cmd_id */
    if (p_msg->len < 2) {
        LOG(ERROR) << StringPrintf(
            "CE: received invalid T3t message (invalid length: %i)", p_msg->len);
    } else {
        /* Get and validate command opcode */
        STREAM_TO_UINT8(sod, p);
        STREAM_TO_UINT8(cmd_id, p);

        /* Valid command and message length */
        cmd_type = ce_t3t_is_valid_opcode(cmd_id);
        if (cmd_type == CE_T3T_COMMAND_INVALID) {
            LOG(ERROR) << StringPrintf(
                "CE: received invalid T3t message (invalid command: 0x%02X)", cmd_id);
        } else if (cmd_type == CE_T3T_COMMAND_FELICA) {
            ce_t3t_handle_non_nfc_forum_cmd(p_ce_cb, cmd_id, p_msg);
            msg_processed = true;
        } else {
            /* Verify that message contains at least NFCID2 and NUM services */
            if (p_msg->len < T3T_MSG_CMD_COMMON_HDR_LEN) {
                LOG(ERROR) << StringPrintf(
                    "CE: received invalid T3t message (invalid length: %i)",
                    p_msg->len);
            } else {
                /* Handle NFC_FORUM command (UPDATE or CHECK) */
                STREAM_TO_ARRAY(cmd_nfcid2, p, NCI_RF_F_UID_LEN);
                STREAM_TO_UINT8(p_cb->cur_cmd.num_services, p); // 取值

                // ############################################################
                // 新增补丁判断,不能大于T3T_MSG_SERVICE_LIST_MAX
                // #define T3T_MSG_SERVICE_LIST_MAX 16
                /* Validate num_services */
                if (p_cb->cur_cmd.num_services > T3T_MSG_SERVICE_LIST_MAX) {
                    LOG(ERROR) << StringPrintf(
                    "CE: recieved num_services (%i) exceeds maximum (%i)",
                    p_cb->cur_cmd.num_services, T3T_MSG_SERVICE_LIST_MAX);
                } else {
                // ############################################################
                    /* Calculate offset of block-list-start */
                    block_list_start_offset =
                        T3T_MSG_CMD_COMMON_HDR_LEN + 2 * p_cb->cur_cmd.num_services + 1;

                    if (p_cb->state == CE_T3T_STATE_NOT_ACTIVATED) {
                        LOG(ERROR) << StringPrintf("CE: received command 0x%02X while in bad state (%i))", cmd_id, p_cb->state);
                    } else if (memcmp(cmd_nfcid2, p_cb->local_nfcid2, NCI_RF_F_UID_LEN) != 0) {
                        LOG(ERROR) << StringPrintf("CE: received invalid T3t message (invalid NFCID2)");
                        p_nfcid2 = cmd_nfcid2; /* respond with ERROR using the NFCID2 from the command message */
                    } else if (p_msg->len < block_list_start_offset) {
                        /* Does not have minimum (including number_of_blocks field) */
                        LOG(ERROR) << StringPrintf("CE: incomplete message");
                    } else {
                        // 由于未对p_cb->cur_cmd.num_services进行长度判断,导致越界写
                        /* Parse service code list */
                        for (i = 0; i < p_cb->cur_cmd.num_services; i++) {
                            STREAM_TO_UINT16(p_cb->cur_cmd.service_code_list[i], p);
                        }
                        
                        ...
                    }
                }
            }
        }
    }

    if (!msg_processed) {
        ce_t3t_send_rsp(p_ce_cb, p_nfcid2, T3T_MSG_OPC_CHECK_RSP,
                        T3T_MSG_RSP_STATUS_ERROR,
                        T3T_MSG_RSP_STATUS2_ERROR_PROCESSING);
        GKI_freebuf(p_msg);
    }
}

Last updated