CVE: CVE-2021-0956
Tested Versions:
- RQ1A.210205.004
Product URL(s):
Description of the vulnerability
There is a Out-Of-Bounds Write problem found in libnfc_nci_jni.so
, within the NFC endpoints discovering and activation. Specifically, in file packages/apps/Nfc/nci/jni/NfcTag.cpp, function NfcTag::discoverTechnologies (activation)
, when a new NFC endpoint is actived, its information is append to some arrays. Since there is no bound check when append data, it may result in a Out-of-bounds Write vulnerability.
When the NFC service is operating on Reader/Writer mode, it has ability to discover Remote NFC Endpoints. While polling, if the NFCC discovers more than one Remote NFC Endpoint, or a Remote NFC Endpoint that supports more than one RF Protocol, NFC Controller start sending RF_DISCOVER_NTF messages to the Device Host for each endpoint and each RF protocol.
The discovery data from NFC Endpoints are stored in several arrays of NfcTag
object. It is done by NfcTag::discoverTechnologies (discovery)
function.
packages/apps/Nfc/nci/jni/NfcTag.cpp
431 void NfcTag::discoverTechnologies(tNFA_DISC_RESULT& discoveryData) {
432 static const char fn[] = "NfcTag::discoverTechnologies (discovery)";
433 tNFC_RESULT_DEVT& discovery_ntf = discoveryData.discovery_ntf;
434 uint8_t index = mNumDiscNtf;
435
436 DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
437 "%s: enter: rf disc. id=%u; protocol=%u, mNumTechList=%u", fn,
438 discovery_ntf.rf_disc_id, discovery_ntf.protocol, mNumTechList);
439 if (index >= MAX_NUM_TECHNOLOGY) {
440 LOG(ERROR) << StringPrintf("%s: exceed max=%d", fn, MAX_NUM_TECHNOLOGY);
441 goto TheEnd;
442 }
443 mTechHandlesDiscData[index] = discovery_ntf.rf_disc_id; // <-- store data in array
444 mTechLibNfcTypesDiscData[index] = discovery_ntf.protocol; // <-- store data in array
445 if (mNumDiscTechList < MAX_NUM_TECHNOLOGY) {
446 mNumDiscTechList++;
447 }
448 if (discovery_ntf.more != NCI_DISCOVER_NTF_MORE) {
449 for (int i = 0; i < mNumDiscTechList; i++) {
450 DLOG_IF(INFO, nfc_debug_enabled)
451 << StringPrintf("%s: index=%d; handle=%d; nfc type=%d", fn, i,
452 mTechHandlesDiscData[i], mTechLibNfcTypesDiscData[i]);
453 }
454 }
455 DLOG_IF(INFO, nfc_debug_enabled)
456 << StringPrintf("%s; mNumDiscTechList=%x", fn, mNumDiscTechList);
457
458 TheEnd:
459 DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: exit", fn);
460 }
The maximum number of endpoints can be discovered is MAX_NUM_TECHNOLOGY
= 11.
After discovery phase, all discovered endpoints are actived one by one. Activation data from NFC endpoints are process in NfcTag::discoverTechnologies (activation)
function:
packages/apps/Nfc/nci/jni/NfcTag.cpp
285 void NfcTag::discoverTechnologies(tNFA_ACTIVATED& activationData) {
286 static const char fn[] = "NfcTag::discoverTechnologies (activation)";
287 DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: enter", fn);
288 tNFC_ACTIVATE_DEVT& rfDetail = activationData.activate_ntf;
289
290 if (mTechListTail < (MAX_NUM_TECHNOLOGY - 1)) {
291 mNumTechList = mTechListTail;
292 }
293 mTechHandles[mNumTechList] = rfDetail.rf_disc_id;
294 mTechLibNfcTypes[mNumTechList] = rfDetail.protocol;
295
296 // save the stack's data structure for interpretation later
297 memcpy(&(mTechParams[mNumTechList]), &(rfDetail.rf_tech_param),
298 sizeof(rfDetail.rf_tech_param));
/* ... */
410 mNumTechList++;
411 for (int i = 0; i < mNumTechList; i++) {
412 DLOG_IF(INFO, nfc_debug_enabled)
413 << StringPrintf("%s: index=%d; tech=%d; handle=%d; nfc type=%d", fn, i,
414 mTechList[i], mTechHandles[i], mTechLibNfcTypes[i]);
415 }
416 DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: exit", fn);
417 }
Similar to NfcTag::discoverTechnologies (discovery)
, activation data are store in several arrays of NfcTag
object: mTechList
, mTechHandles
, mTechLibNfcTypes
, mTechLibNfcTypes
. The variable mNumTechList
is used as index when append data. There is a check in the head of function discoverTechnologies
(line 290->292), but this check seems useless because although value of mTechListTail
exceed MAX_NUM_TECHNOLOGY
, the function still continue and the value of mNumTechList
is still increase.
The declaration size of all storage arrays is MAX_NUM_TECHNOLOGY
= 11 which equals to the maximum NFC endpoints can be discovered. Bt in the NfcTag::discoverTechnologies (activation)
, the mNumTechList
variable can be increase by 2 when handle activation data of several technologies:
packages/apps/Nfc/nci/jni/NfcTag.cpp
/* ... */
391 } else if (NFC_PROTOCOL_MIFARE == rfDetail.protocol) { <-- handle Mifare activation data
392 DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: Mifare Classic", fn);
393 EXTNS_MfcInit(activationData);
394 mTechList[mNumTechList] =
395 TARGET_TYPE_ISO14443_3A; // is TagTechnology.NFC_A by Java API
396 mNumTechList++; <-- 1st increase mNumTechList
397 mTechHandles[mNumTechList] = rfDetail.rf_disc_id;
398 mTechLibNfcTypes[mNumTechList] = rfDetail.protocol;
399 // save the stack's data structure for interpretation later
400 memcpy(&(mTechParams[mNumTechList]), &(rfDetail.rf_tech_param),
401 sizeof(rfDetail.rf_tech_param));
402 mTechList[mNumTechList] =
403 TARGET_TYPE_MIFARE_CLASSIC; // is TagTechnology.MIFARE_CLASSIC by Java
404 // API
405 } else {
/* ... */
410 mNumTechList++; <-- 2nd increase mNumTechList
411 for (int i = 0; i < mNumTechList; i++) {
412 DLOG_IF(INFO, nfc_debug_enabled)
413 << StringPrintf("%s: index=%d; tech=%d; handle=%d; nfc type=%d", fn, i,
414 mTechList[i], mTechHandles[i], mTechLibNfcTypes[i]);
415 }
416 DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: exit", fn);
Since the check in the head of NfcTag::discoverTechnologies (activation)
function cannot prevent the mNumTechList
exceed the MAX_NUM_TECHNOLOGY
value. A Out-Of-Bounds Write can be occur in this function.
Timeline
- 2021-05-28 Reported to Vendor
- 2022-01-18 Vendor fixed and assign CVE