| #include "fuzz.h" |
| |
| #define MODULE_NAME "Type3 Read/Write" |
| |
| enum { |
| SUB_TYPE_CHECK_NDEF, |
| SUB_TYPE_UPDATE_NDEF, |
| SUB_TYPE_CHECK, |
| SUB_TYPE_UPDATE, |
| SUB_TYPE_SEND_RAW_FRAME, |
| |
| SUB_TYPE_NCI_CMD_FIRST, |
| SUB_TYPE_DETECT_NDEF = SUB_TYPE_NCI_CMD_FIRST, |
| SUB_TYPE_PRESENCE_CHECK, |
| SUB_TYPE_POLL, |
| SUB_TYPE_GET_SYSTEM_CODES, |
| SUB_TYPE_FORMAT_NDEF, |
| SUB_TYPE_SET_READ_ONLY_SOFT, |
| SUB_TYPE_SET_READ_ONLY_HARD, |
| |
| SUB_TYPE_MAX |
| }; |
| |
| // The following definition are copied from rw_t3t.cc |
| // ============================================================================ |
| |
| /* Default NDEF attribute information block (used when formatting Felica-Lite |
| * tags) */ |
| /* NBr (max block reads per cmd)*/ |
| #define RW_T3T_DEFAULT_FELICALITE_NBR 4 |
| /* NBw (max block write per cmd)*/ |
| #define RW_T3T_DEFAULT_FELICALITE_NBW 1 |
| #define RW_T3T_DEFAULT_FELICALITE_NMAXB (T3T_FELICALITE_NMAXB) |
| #define RW_T3T_DEFAULT_FELICALITE_ATTRIB_INFO_CHECKSUM \ |
| ((T3T_MSG_NDEF_VERSION + RW_T3T_DEFAULT_FELICALITE_NBR + \ |
| RW_T3T_DEFAULT_FELICALITE_NBW + (RW_T3T_DEFAULT_FELICALITE_NMAXB >> 8) + \ |
| (RW_T3T_DEFAULT_FELICALITE_NMAXB & 0xFF) + T3T_MSG_NDEF_WRITEF_OFF + \ |
| T3T_MSG_NDEF_RWFLAG_RW) & \ |
| 0xFFFF) |
| // ============================================================================ |
| |
| static void rw_cback(tRW_EVENT event, tRW_DATA* p_rw_data) { |
| FUZZLOG(MODULE_NAME ": rw_cback: event=0x%02x, p_rw_data=%p", event, |
| p_rw_data); |
| |
| if (event == RW_T3T_RAW_FRAME_EVT) { |
| if (p_rw_data->data.p_data) { |
| GKI_freebuf(p_rw_data->data.p_data); |
| p_rw_data->data.p_data = nullptr; |
| } |
| } |
| } |
| |
| #define TEST_NFCID_VALUE \ |
| { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 } |
| const uint8_t TEST_NFCID[] = TEST_NFCID_VALUE; |
| |
| static bool Init(Fuzz_Context& /*ctx*/) { |
| tNFC_ACTIVATE_DEVT activate_params = { |
| .protocol = NFC_PROTOCOL_T3T, |
| .rf_tech_param = {.mode = NFC_DISCOVERY_TYPE_POLL_F, |
| .param = {.pf = { |
| .nfcid2 = TEST_NFCID_VALUE, |
| .bit_rate = NFC_BIT_RATE_212, |
| .sensf_res_len = NFC_MAX_SENSF_RES_LEN, |
| .mrti_check = 1, |
| .mrti_update = 1, |
| }}}}; |
| |
| rw_init(); |
| if (NFC_STATUS_OK != RW_SetActivatedTagType(&activate_params, rw_cback)) { |
| FUZZLOG(MODULE_NAME ": RW_SetActivatedTagType failed"); |
| return false; |
| } |
| |
| // A workaround to initialize Type3 tag attribute |
| tRW_T3T_DETECT t3t_detect = { |
| NFC_STATUS_OK, // tNFC_STATUS status; |
| T3T_MSG_NDEF_VERSION, // uint8_t version; /* Ver: peer version */ |
| RW_T3T_DEFAULT_FELICALITE_NBR, // uint8_t |
| // nbr; /* NBr: number of blocks that can |
| // be read using one Check command */ |
| RW_T3T_DEFAULT_FELICALITE_NBW, // uint8_t nbw; /* Nbw: number of |
| // blocks that can be written using one |
| // Update command */ |
| RW_T3T_DEFAULT_FELICALITE_NMAXB, // uint16_t nmaxb; /* Nmaxb: maximum |
| // number of blocks available for NDEF |
| // data */ |
| T3T_MSG_NDEF_WRITEF_OFF, // uint8_t writef; /* WriteFlag: 00h if writing |
| // data finished; 0Fh if writing data in |
| // progress */ |
| T3T_MSG_NDEF_RWFLAG_RW, // uint8_t |
| // rwflag; /* RWFlag: 00h NDEF is read-only; 01h |
| // if read/write available */ |
| 0x100 * 16, // uint32_t ln; /* Ln: actual size of stored NDEF data (in |
| // bytes) */ |
| }; |
| |
| tRW_T3T_CB* p_cb = &rw_cb.tcb.t3t; |
| memcpy(&p_cb->ndef_attrib, &t3t_detect, sizeof(t3t_detect)); |
| |
| // workaround of issue b/139424089 |
| p_cb->p_cur_cmd_buf->offset = 1; |
| p_cb->p_cur_cmd_buf->len = 0; |
| return true; |
| } |
| |
| static bool Init_CheckNDef(Fuzz_Context& /*ctx*/) { |
| return NFC_STATUS_OK == RW_T3tCheckNDef(); |
| } |
| |
| static bool Init_UpdateNDef(Fuzz_Context& ctx) { |
| const uint8_t data[] = {0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04, |
| 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04}; |
| |
| auto scratch = ctx.GetBuffer(sizeof(data), data); |
| return NFC_STATUS_OK == RW_T3tUpdateNDef(sizeof(data), scratch); |
| } |
| |
| static bool Init_Check(Fuzz_Context& /*ctx*/) { |
| tT3T_BLOCK_DESC t3t_blocks = {0x000B, 5}; |
| return NFC_STATUS_OK == RW_T3tCheck(1, &t3t_blocks); |
| } |
| |
| static bool Init_Update(Fuzz_Context& ctx) { |
| const uint8_t data[] = {0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04, |
| 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04}; |
| auto scratch = ctx.GetBuffer(sizeof(data), data); |
| tT3T_BLOCK_DESC t3t_blocks = {0x000B, 5}; |
| return NFC_STATUS_OK == RW_T3tUpdate(1, &t3t_blocks, scratch); |
| } |
| |
| static bool Init_SendRawFrame(Fuzz_Context& /*ctx*/) { |
| uint8_t data[] = {0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04, |
| 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04}; |
| |
| return NFC_STATUS_OK == RW_T3tSendRawFrame(sizeof(data), data); |
| } |
| |
| static bool Init_DetectNDef(Fuzz_Context& /*ctx*/) { |
| return NFC_STATUS_OK == RW_T3tDetectNDef(); |
| } |
| |
| static bool Init_PresenceCheck(Fuzz_Context& /*ctx*/) { |
| return NFC_STATUS_OK == RW_T3tPresenceCheck(); |
| } |
| |
| static bool Init_Poll(Fuzz_Context& /*ctx*/) { |
| return NFC_STATUS_OK == RW_T3tPoll(0, 1, 0); |
| } |
| |
| static bool Init_GetSystemCode(Fuzz_Context& /*ctx*/) { |
| return NFC_STATUS_OK == RW_T3tGetSystemCodes(); |
| } |
| |
| static bool Init_FormatNDef(Fuzz_Context& /*ctx*/) { |
| return NFC_STATUS_OK == RW_T3tFormatNDef(); |
| } |
| |
| static bool Init_SetReadonly(Fuzz_Context& /*ctx*/) { |
| return NFC_STATUS_OK == RW_T3tSetReadOnly(true); |
| } |
| |
| static bool Fuzz_Init(Fuzz_Context& ctx) { |
| if (!Init(ctx)) { |
| FUZZLOG(MODULE_NAME ": initialization failed"); |
| return false; |
| } |
| |
| bool result = false; |
| switch (ctx.SubType) { |
| case SUB_TYPE_CHECK_NDEF: |
| result = Init_CheckNDef(ctx); |
| break; |
| case SUB_TYPE_UPDATE_NDEF: |
| result = Init_UpdateNDef(ctx); |
| break; |
| case SUB_TYPE_CHECK: |
| result = Init_Check(ctx); |
| break; |
| case SUB_TYPE_UPDATE: |
| result = Init_Update(ctx); |
| break; |
| case SUB_TYPE_SEND_RAW_FRAME: |
| result = Init_SendRawFrame(ctx); |
| break; |
| case SUB_TYPE_DETECT_NDEF: |
| result = Init_DetectNDef(ctx); |
| break; |
| case SUB_TYPE_PRESENCE_CHECK: |
| result = Init_PresenceCheck(ctx); |
| break; |
| case SUB_TYPE_POLL: |
| result = Init_Poll(ctx); |
| break; |
| case SUB_TYPE_GET_SYSTEM_CODES: |
| result = Init_GetSystemCode(ctx); |
| break; |
| case SUB_TYPE_FORMAT_NDEF: |
| result = Init_FormatNDef(ctx); |
| break; |
| case SUB_TYPE_SET_READ_ONLY_SOFT: |
| case SUB_TYPE_SET_READ_ONLY_HARD: |
| result = Init_SetReadonly(ctx); |
| break; |
| default: |
| FUZZLOG(MODULE_NAME ": Unknown command %d", ctx.SubType); |
| result = false; |
| break; |
| } |
| |
| if (!result) { |
| FUZZLOG(MODULE_NAME ": Initializing command %02X failed", ctx.SubType); |
| } |
| |
| return result; |
| } |
| |
| static void Fuzz_Deinit(Fuzz_Context& /*ctx*/) { |
| if (rf_cback) { |
| tNFC_CONN conn = { |
| .deactivate = {.status = NFC_STATUS_OK, |
| .type = NFC_DEACTIVATE_TYPE_IDLE, |
| .is_ntf = true, |
| .reason = NFC_DEACTIVATE_REASON_DH_REQ_FAILED}}; |
| |
| rf_cback(NFC_RF_CONN_ID, NFC_DEACTIVATE_CEVT, &conn); |
| } |
| } |
| |
| static void t3t_nci_msg(NFC_HDR* p_msg) { |
| uint8_t status; |
| uint8_t num_responses; |
| |
| uint8_t* p = (uint8_t*)(p_msg + 1) + p_msg->offset; |
| uint8_t plen = p_msg->len; |
| |
| if (plen >= 2) { |
| /* Pass result to RW_T3T for processing */ |
| STREAM_TO_UINT8(status, p); |
| STREAM_TO_UINT8(num_responses, p); |
| plen -= NFC_TL_SIZE; |
| rw_t3t_handle_nci_poll_ntf(status, num_responses, (uint8_t)plen, p); |
| } |
| |
| GKI_freebuf(p_msg); |
| } |
| |
| static void t3t_data_msg(NFC_HDR* p_msg) { |
| tNFC_CONN conn = {.data = { |
| .status = NFC_STATUS_OK, |
| .p_data = p_msg, |
| }}; |
| if (p_msg->len < 1) { |
| FUZZLOG(MODULE_NAME ": Ivalid message length=%hu", p_msg->len); |
| return; |
| } |
| p_msg->len--; |
| |
| rf_cback(NFC_RF_CONN_ID, NFC_DATA_CEVT, &conn); |
| } |
| |
| static void Fuzz_Run(Fuzz_Context& ctx) { |
| for (auto it = ctx.Data.cbegin() + 1; it != ctx.Data.cend(); ++it) { |
| NFC_HDR* p_msg; |
| p_msg = (NFC_HDR*)GKI_getbuf(sizeof(NFC_HDR) + it->size()); |
| if (p_msg == nullptr) { |
| FUZZLOG(MODULE_NAME ": GKI_getbuf returns null, size=%zu", it->size()); |
| return; |
| } |
| |
| /* Initialize NFC_HDR */ |
| p_msg->len = it->size(); |
| p_msg->offset = 0; |
| |
| uint8_t* p = (uint8_t*)(p_msg + 1) + p_msg->offset; |
| memcpy(p, it->data(), it->size()); |
| |
| FUZZLOG(MODULE_NAME ": SubType=%02X, Response[%zd/%zd]=%s", ctx.SubType, |
| it - ctx.Data.cbegin(), ctx.Data.size() - 1, |
| BytesToHex(*it).c_str()); |
| |
| if (ctx.SubType >= SUB_TYPE_NCI_CMD_FIRST) { |
| t3t_nci_msg(p_msg); |
| } else { |
| t3t_data_msg(p_msg); |
| } |
| } |
| } |
| |
| void Type3_FixPackets(uint8_t SubType, std::vector<bytes_t>& Packets) { |
| for (auto it = Packets.begin() + 1; it != Packets.end(); ++it) { |
| if (SubType >= SUB_TYPE_NCI_CMD_FIRST) { |
| if (it->size() < 3) { |
| it->resize(3); |
| memset(it->data(), 0, it->size()); |
| } |
| } else { |
| if (it->size() <= T3T_MSG_RSP_COMMON_HDR_LEN) { |
| it->resize(T3T_MSG_RSP_COMMON_HDR_LEN + 1); |
| memset(it->data(), 0, it->size()); |
| } |
| |
| uint8_t* p = it->data(); |
| p[0] = it->size(); |
| p[it->size() - 1] = NFC_STATUS_OK; |
| |
| auto rsp = &p[1]; |
| rsp[T3T_MSG_RSP_OFFSET_STATUS1] = T3T_MSG_RSP_STATUS_OK; |
| memcpy(&rsp[T3T_MSG_RSP_OFFSET_IDM], TEST_NFCID, sizeof(TEST_NFCID)); |
| } |
| } |
| } |
| |
| void Type3_Fuzz(uint8_t SubType, const std::vector<bytes_t>& Packets) { |
| Fuzz_Context ctx(SubType % SUB_TYPE_MAX, Packets); |
| if (Fuzz_Init(ctx)) { |
| Fuzz_Run(ctx); |
| } |
| Fuzz_Deinit(ctx); |
| } |