[automerger skipped] NFC - Memory disclosure in rw_i93_sm_format am: 263e1127da am: 5ed331342b am: 29ae69655e -s ours am: 3bd1863ecb -s ours am: 0bb751d5a0 -s ours am: 5bb85f0455 -s ours am: 759cef9e12 -s ours am: 7d64b6a0a3 -s ours

am skip reason: Change-Id If6cd929624f8ae8c2c70295924bea206d82d48f4 with SHA-1 046b6676ad is in history

Original change: https://googleplex-android-review.googlesource.com/c/platform/system/nfc/+/12296015

Change-Id: I14d9f521c6d558a5574f5f67aa48630474025ca8
diff --git a/src/nfa/rw/nfa_rw_api.cc b/src/nfa/rw/nfa_rw_api.cc
index 9f176d2..1c130f7 100644
--- a/src/nfa/rw/nfa_rw_api.cc
+++ b/src/nfa/rw/nfa_rw_api.cc
@@ -25,6 +25,7 @@
 
 #include <android-base/stringprintf.h>
 #include <base/logging.h>
+#include <log/log.h>
 
 #include "nfa_api.h"
 #include "nfa_rw_int.h"
@@ -1097,7 +1098,7 @@
                                          uint16_t number_blocks,
                                          uint8_t* p_data) {
   tNFA_RW_OPERATION* p_msg;
-  uint16_t data_length;
+  uint32_t data_length;
 
   DLOG_IF(INFO, nfc_debug_enabled)
       << StringPrintf("%d, %d", first_block_number, number_blocks);
@@ -1113,6 +1114,11 @@
 
   data_length = nfa_rw_cb.i93_block_size * number_blocks;
 
+  if (data_length + sizeof(tNFA_RW_OPERATION) > UINT16_MAX) {
+    android_errorWriteLog(0x534e4554, "157650338");
+    return (NFA_STATUS_FAILED);
+  }
+
   p_msg = (tNFA_RW_OPERATION*)GKI_getbuf(
       (uint16_t)(sizeof(tNFA_RW_OPERATION) + data_length));
   if (p_msg != nullptr) {
diff --git a/src/nfc/include/nfc_api.h b/src/nfc/include/nfc_api.h
index 84a1426..5e4d6ca 100644
--- a/src/nfc/include/nfc_api.h
+++ b/src/nfc/include/nfc_api.h
@@ -313,6 +313,7 @@
   uint8_t nfcee_id;   /* NFCEE ID                         */
   uint8_t num_tlvs;   /* number of TLVs                   */
   uint8_t tlv_size;   /* the total len of all TLVs        */
+  uint8_t qualifier_type;                  /* qualifier type */
   uint8_t param_tlvs[NFC_MAX_EE_TLV_SIZE]; /* the TLVs         */
 } tNFC_GET_ROUTING_REVT;
 
diff --git a/src/nfc/nci/nci_hrcv.cc b/src/nfc/nci/nci_hrcv.cc
index 737bc9d..9329771 100644
--- a/src/nfc/nci/nci_hrcv.cc
+++ b/src/nfc/nci/nci_hrcv.cc
@@ -408,58 +408,93 @@
       << StringPrintf("nci_proc_ee_management_ntf opcode:0x%x", op_code);
   len = *pp++;
 
-  if (op_code == NCI_MSG_NFCEE_DISCOVER) {
-    nfc_response.nfcee_info.nfcee_id = *pp++;
+  switch (op_code) {
+    case NCI_MSG_NFCEE_DISCOVER:
+      if (len < 3) {
+        p_cback = nullptr;
+        break;
+      } else {
+        len -= 3;
+      }
+      nfc_response.nfcee_info.nfcee_id = *pp++;
 
-    nfc_response.nfcee_info.ee_status = *pp++;
-    yy = *pp;
-    nfc_response.nfcee_info.num_interface = *pp++;
-    p = pp;
-
-    if (nfc_response.nfcee_info.num_interface > NFC_MAX_EE_INTERFACE)
-      nfc_response.nfcee_info.num_interface = NFC_MAX_EE_INTERFACE;
-
-    for (xx = 0; xx < nfc_response.nfcee_info.num_interface; xx++) {
-      nfc_response.nfcee_info.ee_interface[xx] = *pp++;
-    }
-
-    pp = p + yy;
-    nfc_response.nfcee_info.num_tlvs = *pp++;
-    DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
-        "nfcee_id: 0x%x num_interface:0x%x/0x%x, num_tlvs:0x%x",
-        nfc_response.nfcee_info.nfcee_id, nfc_response.nfcee_info.num_interface,
-        yy, nfc_response.nfcee_info.num_tlvs);
-
-    if (nfc_response.nfcee_info.num_tlvs > NFC_MAX_EE_TLVS)
-      nfc_response.nfcee_info.num_tlvs = NFC_MAX_EE_TLVS;
-
-    p_tlv = &nfc_response.nfcee_info.ee_tlv[0];
-
-    for (xx = 0; xx < nfc_response.nfcee_info.num_tlvs; xx++, p_tlv++) {
-      p_tlv->tag = *pp++;
-      p_tlv->len = yy = *pp++;
-      DLOG_IF(INFO, nfc_debug_enabled)
-          << StringPrintf("tag:0x%x, len:0x%x", p_tlv->tag, p_tlv->len);
-      if (p_tlv->len > NFC_MAX_EE_INFO) p_tlv->len = NFC_MAX_EE_INFO;
+      nfc_response.nfcee_info.ee_status = *pp++;
+      yy = *pp;
+      nfc_response.nfcee_info.num_interface = *pp++;
+      if (len < yy + 1) {
+        p_cback = nullptr;
+        break;
+      } else {
+        len -= yy + 1;
+      }
       p = pp;
-      STREAM_TO_ARRAY(p_tlv->info, pp, p_tlv->len);
-      pp = p += yy;
-    }
-  } else if (op_code == NCI_MSG_NFCEE_MODE_SET) {
-    nfc_response.mode_set.status = *pp;
-    nfc_response.mode_set.nfcee_id = *p_old++;
-    nfc_response.mode_set.mode = *p_old++;
-    event = NFC_NFCEE_MODE_SET_REVT;
-    nfc_cb.flags &= ~NFC_FL_WAIT_MODE_SET_NTF;
-    nfc_stop_timer(&nfc_cb.nci_mode_set_ntf_timer);
-  } else if (op_code == NCI_MSG_NFCEE_STATUS) {
-    event = NFC_NFCEE_STATUS_REVT;
-    nfc_response.nfcee_status.status = NCI_STATUS_OK;
-    nfc_response.nfcee_status.nfcee_id = *pp++;
-    nfc_response.nfcee_status.nfcee_status = *pp;
-  } else {
-    p_cback = nullptr;
-    LOG(ERROR) << StringPrintf("unknown opcode:0x%x", op_code);
+
+      if (nfc_response.nfcee_info.num_interface > NFC_MAX_EE_INTERFACE)
+        nfc_response.nfcee_info.num_interface = NFC_MAX_EE_INTERFACE;
+
+      for (xx = 0; xx < nfc_response.nfcee_info.num_interface; xx++) {
+        nfc_response.nfcee_info.ee_interface[xx] = *pp++;
+      }
+
+      pp = p + yy;
+      nfc_response.nfcee_info.num_tlvs = *pp++;
+      DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
+          "nfcee_id: 0x%x num_interface:0x%x/0x%x, num_tlvs:0x%x",
+          nfc_response.nfcee_info.nfcee_id,
+          nfc_response.nfcee_info.num_interface, yy,
+          nfc_response.nfcee_info.num_tlvs);
+
+      if (nfc_response.nfcee_info.num_tlvs > 0 && len < 2) {
+        p_cback = nullptr;
+        break;
+      }
+      if (nfc_response.nfcee_info.num_tlvs > NFC_MAX_EE_TLVS)
+        nfc_response.nfcee_info.num_tlvs = NFC_MAX_EE_TLVS;
+
+      p_tlv = &nfc_response.nfcee_info.ee_tlv[0];
+
+      for (xx = 0; xx < nfc_response.nfcee_info.num_tlvs; xx++, p_tlv++) {
+        p_tlv->tag = *pp++;
+        p_tlv->len = yy = *pp++;
+        if (len < yy + 2) {
+          p_cback = nullptr;
+          break;
+        } else {
+          len -= yy + 2;
+        }
+        DLOG_IF(INFO, nfc_debug_enabled)
+            << StringPrintf("tag:0x%x, len:0x%x", p_tlv->tag, p_tlv->len);
+        if (p_tlv->len > NFC_MAX_EE_INFO) p_tlv->len = NFC_MAX_EE_INFO;
+        p = pp;
+        STREAM_TO_ARRAY(p_tlv->info, pp, p_tlv->len);
+        pp = p += yy;
+      }
+      break;
+    case NCI_MSG_NFCEE_MODE_SET:
+      if (len < 1) {
+        nfc_response.mode_set.status = NCI_STATUS_MESSAGE_CORRUPTED;
+      } else {
+        nfc_response.mode_set.status = *pp;
+      }
+      nfc_response.mode_set.nfcee_id = *p_old++;
+      nfc_response.mode_set.mode = *p_old++;
+      event = NFC_NFCEE_MODE_SET_REVT;
+      nfc_cb.flags &= ~NFC_FL_WAIT_MODE_SET_NTF;
+      nfc_stop_timer(&nfc_cb.nci_mode_set_ntf_timer);
+      break;
+    case NCI_MSG_NFCEE_STATUS:
+      event = NFC_NFCEE_STATUS_REVT;
+      if (len < 2) {
+        nfc_response.nfcee_status.status = NCI_STATUS_MESSAGE_CORRUPTED;
+        break;
+      }
+      nfc_response.nfcee_status.status = NCI_STATUS_OK;
+      nfc_response.nfcee_status.nfcee_id = *pp++;
+      nfc_response.nfcee_status.nfcee_status = *pp;
+      break;
+    default:
+      p_cback = nullptr;
+      LOG(ERROR) << StringPrintf("unknown opcode:0x%x", op_code);
   }
 
   if (p_cback) (*p_cback)(event, &nfc_response);
diff --git a/src/nfc/nfc/nfc_main.cc b/src/nfc/nfc/nfc_main.cc
index 991d320..a03fa7a 100644
--- a/src/nfc/nfc/nfc_main.cc
+++ b/src/nfc/nfc/nfc_main.cc
@@ -317,8 +317,9 @@
       memcpy(evt_data.enable.vs_interface, nfc_cb.vs_interface,
              NFC_NFCC_MAX_NUM_VS_INTERFACE);
     } else {
-      /* one byte is consumed in the top expression */
-      lremain -= sizeof(uint16_t) + NFC_NFCC_INFO_LEN;
+      /* For VERSION_UNKNOWN one byte is consumed in the top expression */
+      lremain -= sizeof(uint16_t) + NFC_NFCC_INFO_LEN +
+                 (nfc_cb.nci_version == NCI_VERSION_1_0 ? 1 : 0);
       if (lremain < 0) {
         nfc_status = NCI_STATUS_FAILED;
         goto plen_err;
diff --git a/src/nfc/nfc/nfc_ncif.cc b/src/nfc/nfc/nfc_ncif.cc
index 489b84f..3bde5bb 100644
--- a/src/nfc/nfc/nfc_ncif.cc
+++ b/src/nfc/nfc/nfc_ncif.cc
@@ -1426,16 +1426,26 @@
 void nfc_ncif_proc_ee_action(uint8_t* p, uint16_t plen) {
   tNFC_EE_ACTION_REVT evt_data;
   tNFC_RESPONSE_CBACK* p_cback = nfc_cb.p_resp_cback;
+  tNFC_RESPONSE nfc_response;
   uint8_t data_len, ulen, tag, *p_data;
   uint8_t max_len;
 
   if (p_cback) {
     memset(&evt_data.act_data, 0, sizeof(tNFC_ACTION_DATA));
+    if (plen > 3) {
+      plen -= 3;
+    } else {
+      evt_data.status = NFC_STATUS_FAILED;
+      evt_data.nfcee_id = 0;
+      nfc_response.ee_action = evt_data;
+      (*p_cback)(NFC_EE_ACTION_REVT, &nfc_response);
+      android_errorWriteLog(0x534e4554, "157649306");
+      return;
+    }
     evt_data.status = NFC_STATUS_OK;
     evt_data.nfcee_id = *p++;
     evt_data.act_data.trigger = *p++;
     data_len = *p++;
-    if (plen >= 3) plen -= 3;
     if (data_len > plen) data_len = (uint8_t)plen;
 
     switch (evt_data.act_data.trigger) {
@@ -1478,7 +1488,6 @@
         }
         break;
     }
-    tNFC_RESPONSE nfc_response;
     nfc_response.ee_action = evt_data;
     (*p_cback)(NFC_EE_ACTION_REVT, &nfc_response);
   }
@@ -1546,34 +1555,42 @@
 ** Returns          void
 **
 *******************************************************************************/
-void nfc_ncif_proc_get_routing(uint8_t* p,
-                               __attribute__((unused)) uint8_t len) {
+void nfc_ncif_proc_get_routing(uint8_t* p, uint8_t len) {
   tNFC_GET_ROUTING_REVT evt_data;
-  uint8_t more, num_entries, xx, yy, *pn, tl;
+  uint8_t more, num_entries, xx, *pn;
   tNFC_STATUS status = NFC_STATUS_CONTINUE;
 
-  if (nfc_cb.p_resp_cback) {
+  if (len >= 2 && nfc_cb.p_resp_cback) {
     more = *p++;
     num_entries = *p++;
+    if (num_entries == 0) return;
+    len -= 2;
+    if (len < 2) {
+      LOG(ERROR) << StringPrintf("Invalid len=%d", len);
+      return;
+    }
     for (xx = 0; xx < num_entries; xx++) {
       if ((more == false) && (xx == (num_entries - 1))) status = NFC_STATUS_OK;
       evt_data.status = (tNFC_STATUS)status;
-      evt_data.nfcee_id = *p++;
-      evt_data.num_tlvs = *p++;
-      evt_data.tlv_size = 0;
-      pn = evt_data.param_tlvs;
-      for (yy = 0; yy < evt_data.num_tlvs; yy++) {
-        tl = *(p + 1);
-        tl += NFC_TL_SIZE;
-        evt_data.tlv_size += tl;
-        if (evt_data.tlv_size > NFC_MAX_EE_TLV_SIZE) {
-          android_errorWriteLog(0x534e4554, "117554809");
-          LOG(ERROR) << __func__ << "Invalid data format";
-          return;
-        }
-        STREAM_TO_ARRAY(pn, p, tl);
-        pn += tl;
+      if (len >= 2)
+        len -= 2;
+      else
+        return;
+      evt_data.qualifier_type = *p++;
+      evt_data.num_tlvs = 1;
+      evt_data.tlv_size = *p++;
+      if (evt_data.tlv_size > NFC_MAX_EE_TLV_SIZE) {
+        android_errorWriteLog(0x534e4554, "117554809");
+        LOG(ERROR) << __func__ << "Invalid data format";
+        return;
       }
+      if (evt_data.tlv_size > len) {
+        LOG(ERROR) << StringPrintf("Invalid evt_data.tlv_size");
+        return;
+      } else
+        len -= evt_data.tlv_size;
+      pn = evt_data.param_tlvs;
+      STREAM_TO_ARRAY(pn, p, evt_data.tlv_size);
       tNFC_RESPONSE nfc_response;
       nfc_response.get_routing = evt_data;
       (*nfc_cb.p_resp_cback)(NFC_GET_ROUTING_REVT, &nfc_response);
@@ -1865,13 +1882,13 @@
 
       data_cevt.p_data = p_evt;
       /* adjust payload, if needed */
-      if (p_cb->conn_id == NFC_RF_CONN_ID) {
+      if (p_cb->conn_id == NFC_RF_CONN_ID && p_evt->len) {
         /* if NCI_PROTOCOL_T1T/NCI_PROTOCOL_T2T/NCI_PROTOCOL_T3T, the status
          * byte needs to be removed
          */
         if ((p_cb->act_protocol >= NCI_PROTOCOL_T1T) &&
             (p_cb->act_protocol <= NCI_PROTOCOL_T3T)) {
-          if (p_evt->len) p_evt->len--;
+          p_evt->len--;
           p = (uint8_t*)(p_evt + 1);
           data_cevt.status = *(p + p_evt->offset + p_evt->len);
           if ((NFC_GetNCIVersion() == NCI_VERSION_2_0) &&
@@ -1888,7 +1905,7 @@
         }
         if ((NFC_GetNCIVersion() == NCI_VERSION_2_0) &&
             (p_cb->act_protocol == NCI_PROTOCOL_T5T)) {
-          if (p_evt->len) p_evt->len--;
+          p_evt->len--;
           p = (uint8_t*)(p_evt + 1);
           data_cevt.status = *(p + p_evt->offset + p_evt->len);
         }
diff --git a/src/nfc/tags/ce_main.cc b/src/nfc/tags/ce_main.cc
index 27c218c..1afc848 100644
--- a/src/nfc/tags/ce_main.cc
+++ b/src/nfc/tags/ce_main.cc
@@ -27,6 +27,7 @@
 
 #include <android-base/stringprintf.h>
 #include <base/logging.h>
+#include <log/log.h>
 
 #include "nfc_target.h"
 
@@ -64,6 +65,12 @@
   uint8_t* p;
 
   if (ce_cb.p_cback) {
+    if (data_len > GKI_get_pool_bufsize(NFC_RW_POOL_ID) - NCI_MSG_OFFSET_SIZE -
+                       NCI_DATA_HDR_SIZE - 1) {
+      android_errorWriteLog(0x534e4554, "157649398");
+      return NFC_STATUS_FAILED;
+    }
+
     /* a valid opcode for RW */
     p_data = (NFC_HDR*)GKI_getpoolbuf(NFC_RW_POOL_ID);
     if (p_data) {
diff --git a/src/nfc/tags/ce_t4t.cc b/src/nfc/tags/ce_t4t.cc
index 5f80587..99baf75 100644
--- a/src/nfc/tags/ce_t4t.cc
+++ b/src/nfc/tags/ce_t4t.cc
@@ -731,7 +731,9 @@
         BE_STREAM_TO_UINT8(length, p_cmd);  /* Lc     */
 
         /* check if valid parameters */
-        if ((uint32_t)length <= CE_T4T_MAX_LC) {
+        if ((uint32_t)length <= CE_T4T_MAX_LC &&
+            /* check if data fits into the apdu */
+            (uint16_t)length <= p_c_apdu->len - T4T_CMD_MAX_HDR_SIZE) {
           if (length + offset > ce_cb.mem.t4t.max_file_size) {
             LOG(ERROR) << StringPrintf(
                 "CET4T: length (%d) + offset (%d) must be less than "
@@ -743,6 +745,7 @@
           LOG(ERROR) << StringPrintf(
               "CET4T: length (%d) must be less than MLc (%zu)", length,
               CE_T4T_MAX_LC);
+          android_errorWriteLog(0x534e4554, "157649298");
           length = 0;
         }
 
diff --git a/src/nfc/tags/rw_i93.cc b/src/nfc/tags/rw_i93.cc
index e06142b..1666246 100644
--- a/src/nfc/tags/rw_i93.cc
+++ b/src/nfc/tags/rw_i93.cc
@@ -1128,6 +1128,13 @@
 
   DLOG_IF(INFO, nfc_debug_enabled) << __func__;
 
+  if (number_blocks * rw_cb.tcb.i93.block_size >
+      GKI_get_pool_bufsize(NFC_RW_POOL_ID) - NCI_MSG_OFFSET_SIZE -
+          NCI_DATA_HDR_SIZE - 1 -
+          (rw_cb.tcb.i93.intl_flags & RW_I93_FLAG_EXT_COMMANDS ? 2 : 0) - 12) {
+    android_errorWriteLog(0x534e4554, "157650365");
+    return NFC_STATUS_FAILED;
+  }
   p_cmd = (NFC_HDR*)GKI_getpoolbuf(NFC_RW_POOL_ID);
 
   if (!p_cmd) {
@@ -1163,9 +1170,6 @@
         p, number_blocks - 1); /* Number of blocks, 0x00 to read one block */
   }
 
-  UINT8_TO_STREAM(
-      p, number_blocks - 1); /* Number of blocks, 0x00 to read one block */
-
   /* Data */
   ARRAY_TO_STREAM(p, p_data, number_blocks * rw_cb.tcb.i93.block_size);
 
@@ -4287,4 +4291,4 @@
     default:
       return "UNKNOWN";
   }
-}
\ No newline at end of file
+}
diff --git a/src/nfc/tags/rw_main.cc b/src/nfc/tags/rw_main.cc
index 24fe949..6ebf353 100644
--- a/src/nfc/tags/rw_main.cc
+++ b/src/nfc/tags/rw_main.cc
@@ -27,6 +27,7 @@
 
 #include <android-base/stringprintf.h>
 #include <base/logging.h>
+#include <log/log.h>
 
 #include "nfc_target.h"
 
@@ -173,6 +174,11 @@
   uint8_t* p;
 
   if (rw_cb.p_cback) {
+    if (data_len > GKI_get_pool_bufsize(NFC_RW_POOL_ID) - NCI_MSG_OFFSET_SIZE -
+                       NCI_DATA_HDR_SIZE - 1) {
+      android_errorWriteLog(0x534e4554, "157650117");
+      return NFC_STATUS_FAILED;
+    }
     /* a valid opcode for RW - remove */
     p_data = (NFC_HDR*)GKI_getpoolbuf(NFC_RW_POOL_ID);
     if (p_data) {
diff --git a/src/nfc/tags/rw_t3t.cc b/src/nfc/tags/rw_t3t.cc
index 4b41b8a..60afe38 100644
--- a/src/nfc/tags/rw_t3t.cc
+++ b/src/nfc/tags/rw_t3t.cc
@@ -1199,6 +1199,12 @@
   uint8_t* p;
   tNFC_STATUS retval = NFC_STATUS_OK;
 
+  /* GKI_BUF2 is used for NFC_RW_POOL */
+  if (len > GKI_BUF2_SIZE - NCI_MSG_OFFSET_SIZE - NCI_DATA_HDR_SIZE - 2) {
+    android_errorWriteLog(0x534e4554, "157649467");
+    return NFC_STATUS_NO_BUFFERS;
+  }
+
   p_cmd_buf = rw_t3t_get_cmd_buf();
   if (p_cmd_buf != nullptr) {
     /* Construct T3T message */