From 3e2c98420be001927514764fdadfcb05626203e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Mon, 27 Jul 2026 21:51:39 +0200 Subject: [PATCH] nRF52: don't truncate the AES-CTR block length to uint8_t (#11261) blockLen() rounds numBytes up to the AES block size, so 241..256 returns 256. Stored in a uint8_t that truncates to 0, giving a zero-length encBuf that Process() then writes numBytes bytes into, smashing the stack with attacker-controlled ciphertext. encrypted.size is a 256-byte protobuf field and encryptPacket admits numBytes up to MAX_BLOCKSIZE, so sizes above the 239-byte LoRa frame limit arrive via the MQTT and UDP multicast ingress paths, which pass the packet to the router without clamping. Only the hardware AES path for keys of 16 bytes or less is affected, which includes the default channel. --- src/platform/nrf52/NRF52CryptoEngine.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/platform/nrf52/NRF52CryptoEngine.cpp b/src/platform/nrf52/NRF52CryptoEngine.cpp index 5de13c58b..e8844065f 100644 --- a/src/platform/nrf52/NRF52CryptoEngine.cpp +++ b/src/platform/nrf52/NRF52CryptoEngine.cpp @@ -18,7 +18,10 @@ class NRF52CryptoEngine : public CryptoEngine } else if (_key.length > 0) { nRFCrypto.begin(); nRFCrypto_AES ctx; - uint8_t myLen = ctx.blockLen(numBytes); + // Must not be uint8_t: blockLen() rounds up to the AES block size, so numBytes in + // 241..256 yields 256, which truncates to 0 and leaves Process() writing numBytes + // attacker-controlled bytes onto a zero-length stack buffer. + size_t myLen = ctx.blockLen(numBytes); char encBuf[myLen] = {0}; ctx.begin(); ctx.Process((char *)bytes, numBytes, _nonce, _key.bytes, _key.length, encBuf, ctx.encryptFlag, ctx.ctrMode);