CVE-2026-58823 AI-generated analysis
platform/hardware/st/nfc, libstpropnci (libstpropnci-vendor), libstpropnci/src/stpropnci_std.cc
Adds length and array-capacity checks in stpropnci_process_std() of the ST NFC HAL, so that RF_NFCEE_DISCOVERY_REQ_NTF and NFCEE_MODE_SET_NTF messages from the NFC controller can no longer write past the fixed-size ee_info and active_nfcee_ids arrays in the global stpropnci_state.
Root cause
In stpropnci_process_std(), the NCI_MSG_RF_EE_DISCOVERY_REQ notification handler took the entry count from payload[3]. For every NFCEE id not already stored, it wrote stpropnci_state.ee_info[stpropnci_state.nb_ee_info].nfcee_id and incremented nb_ee_info without checking the capacity of the ee_info array. The only length check was `payloadlen <= NFC_EE_DISCOVER_ENTRY_LEN`, which did not relate payloadlen to the claimed entry count, so the loop could also read entries (payload[6 + i * 5]) beyond the received payload. Similarly, whenever wait_nfcee_ntf was set, the NFCEE_MODE_SET_NTF handler wrote stpropnci_state.active_nfcee_ids[stpropnci_state.nb_active_nfcees] and incremented the counter with no capacity check. Both counters are driven by notifications from the controller. Per the commit message, a compromised NFC controller could push them past the array bounds and overwrite adjacent global state.
How the fix works
- libstpropnci/src/stpropnci_std.cc:stpropnci_process_std, case NCI_MSG_RF_EE_DISCOVERY_REQ (NTF): the length check changes from `payloadlen <= NFC_EE_DISCOVER_ENTRY_LEN` to `payloadlen < 4 + payload[3] * NFC_EE_DISCOVER_ENTRY_LEN`, so the payload must contain the number of entries it claims. If it does not, the handler calls LOG_E and breaks, and the notification is neither backed up nor parsed.
- Same case, inside the per-entry loop when the NFCEE id is new (idx == 0xFF): before `idx = stpropnci_state.nb_ee_info` and the write to ee_info[idx].nfcee_id, a check `nb_ee_info >= sizeof(ee_info)/sizeof(ee_info[0])` logs "nb_ee_info array is full" and breaks out of the entry loop. This stops the write and the counter increment once the array is full. Entries already processed in that notification keep their effect; any remaining entries in the same notification are skipped.
- Same file, NFCEE_MODE_SET_NTF block (activation path, when stpropnci_state.wait_nfcee_ntf is set): the write `active_nfcee_ids[nb_active_nfcees] = waiting_nfcee_id; nb_active_nfcees++` is wrapped in `if (nb_active_nfcees < sizeof(active_nfcee_ids)/sizeof(active_nfcee_ids[0]))`. Its else branch only logs "nb_active_nfcees array is full". The handling that follows (the waiting_nfcee_id == 0x86 case) still runs in both branches.
Completeness
- Covers both array writes named in the commit message: ee_info[] in the RF_EE_DISCOVERY_REQ NTF handler and active_nfcee_ids[] in the NFCEE_MODE_SET_NTF handler. Each check is derived from the actual array size (sizeof/sizeof).
- The new length check reads payload[3] before confirming payloadlen >= 4. Depending on the value of NFC_EE_DISCOVER_ENTRY_LEN (not shown), the old check may have rejected such short payloads before any indexed access. The material does not show whether callers guarantee a minimum length.
- If NFC_EE_DISCOVER_ENTRY_LEN is 5 (matching the i * 5 stride, but not shown), the nfcee_id read payload[6 + i * 5] for i < payload[3] stays within payloadlen under the new check. The rest of the per-entry parsing after line 715 is not shown.
- The backup `memcpy(stpropnci_state.last_ee_discovery_req, payload, payloadlen)` in the same handler is unchanged. The material does not show the size of last_ee_discovery_req relative to the maximum payloadlen, so the diff does not show whether this copy needs its own bound.
- The fix does not change where nb_ee_info and nb_active_nfcees are reset. Once the arrays are full, new NFCEE ids are dropped with an error log instead of being stored.
Behavior changes
- RF_NFCEE_DISCOVERY_REQ_NTF payloads shorter than 4 + payload[3] * NFC_EE_DISCOVER_ENTRY_LEN are now rejected (logged as "length too short") and are not backed up into last_ee_discovery_req. Before the fix, only payloads of NFC_EE_DISCOVER_ENTRY_LEN bytes or fewer were rejected.
- When ee_info is full, new NFCEE ids in a discovery notification are no longer recorded. The entry loop stops with LOG_E "nb_ee_info array is full".
- When active_nfcee_ids is full, an NFCEE_MODE_SET_NTF activation no longer records the id or increments nb_active_nfcees. It logs "nb_active_nfcees array is full" and the rest of the handler continues.
Per major
- Android 14: Not affected per the bulletin. libstpropnci/src/stpropnci_std.cc is absent at android-security-14.0.0_r29 (code absent).
- Android 15: Not affected per the bulletin. The patched file is absent at android-security-15.0.0_r17 (code absent).
- Android 16: Not affected per the bulletin. The patched file is absent at android-security-16.0.0_r8 (code absent).
- Android 17: Same fix. Commit 8a18f3300dd5 (cherry-pick of 95123eb7e942, Change-Id If415e9cff5a3320849be70d0b35a84bd649c8e8e) is in android-security-17.0.0_r1. The resolver reports 7/8 lines of the patched region present, and the code context shown contains the new length check and the nb_ee_info bound.
Unknowns
- The sizes of stpropnci_state.ee_info, active_nfcee_ids and last_ee_discovery_req, and the value of NFC_EE_DISCOVER_ENTRY_LEN, are not shown.
- Whether callers guarantee payloadlen >= 4 before the handler reads payload[3] is not shown.
- Which fields of stpropnci_state sit next to the overflowed arrays is not shown.
- The material does not explain why the resolver reports 7/8 rather than 8/8 lines present at android-security-17.0.0_r1. The context shown matches the fix.
- The per-entry parsing after line 715 is not shown.