[NFC] Bound ISO14443-3A UID cascade to 3 levels (fixes potential uid[] overflow) (#1078)

ISO14443-3 defines at most 3 cascade levels (10-byte UID), but the
anticollision loop continued for as long as the tag asserted the SAK
cascade bit, appending 3 UID bytes per level and overflowing the 10-byte
data->uid[] buffer. A malformed or hostile NFC-A tag could exploit this
during a Read (the adjacent uid_len field doubles as the write offset, so
past the first overflow both content and destination are tag-controlled).
Cap the cascade at 3 levels, guarding on cascade_level. Pre-existing and
independent of the 0x88 read fix; genuine cards are unaffected.

Fixes #1077

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Mykhailo Shevchuk
2026-08-15 23:56:27 +03:00
committed by GitHub
co-authored by Claude Opus 4.8
parent 58b01d1584
commit 4e8b746fd6
2 changed files with 9 additions and 0 deletions
+1
View File
@@ -12,6 +12,7 @@
- NFC: **Fix "Update from Initial Card" dropping sectors from a MIFARE Classic dump** (by @mishamyte | PR #1066 | Fixes #1064)
- NFC, LF RFID, iButton: **Renaming a saved file no longer deletes it before the replacement is written** (by @mishamyte | PR #1067 | Fixes #1065)
- NFC: **Fix cards whose 4-byte UID starts with 0x88 failing to read** (by @mishamyte | PR #1075 | Fixes #1074)
- NFC: **Harden ISO14443-3A anticollision against an unbounded UID cascade** (by @mishamyte | PR #1078 | Fixes #1077)
- RPC: **Fix crash when starting an app over RPC** (by @apfxtech | PR #1076)
- Apps: Build tag (**15aug2026**) - **Check out more Apps updates and fixes by following** [this link](https://github.com/xMasterX/all-the-plugins/commits/dev)
@@ -216,6 +216,14 @@ Iso14443_3aError
// first UID byte: a real 4-byte UID can begin with the 0x88 cascade tag
// value (non-compliant, but seen on some MIFARE Classic / magic cards).
if(instance->col_res.sel_resp.sak & ISO14443_3A_POLLER_SAK_CASCADE_BIT) {
// ISO14443-3 defines at most 3 cascade levels (10-byte UID); a tag
// that keeps asserting the cascade bit would overflow data->uid[10].
if(instance->col_res.cascade_level >= 2) {
FURI_LOG_E(TAG, "Too many cascade levels");
instance->state = Iso14443_3aPollerStateColResFailed;
ret = Iso14443_3aErrorColResFailed;
break;
}
// UID incomplete: keep the 3 bytes after the cascade tag
memcpy(
&instance->data->uid[instance->data->uid_len],