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