Fix stack OOB read in decode_tag_number_and_value() - #1299
Fix stack OOB read in decode_tag_number_and_value()#1299JorgeBarredo14 wants to merge 2 commits into
Conversation
The legacy decode_tag_number_and_value() function takes no buffer-length parameter. When the first APDU byte has IS_EXTENDED_VALUE set, the function reads apdu[1] unconditionally, causing an up-to-5-byte out-of-bounds read on a 1-byte caller buffer. Add an early-return guard that rejects extended-value tags before any dereference past apdu[0]. The length-aware variant bacnet_tag_number_and_value_decode() is unaffected and should be used by all new code. CWE-125 (Out-of-bounds Read) Advisory: GHSA-cr77-f6f9-494h Found during academic security research.
|
Hi Steve, The CI There are two approaches to fix this: Approach A — Update the tests (recommended)Migrate the 8 failing test call-sites to use // Before (unsafe, no bounds check):
len = decode_tag_number_and_value(&apdu[0], &tag_number, &value);
// After (safe, bounds-checked):
len = bacnet_tag_number_and_value_decode(&apdu[0], sizeof(apdu), &tag_number, &value);I'm happy to push this update to the PR if you prefer this approach. Approach B — Narrow the guard Let me know which direction you'd prefer and I'll update the PR accordingly. |
|
Use approach A: Migrate the 8 failing test call-sites to use bacnet_tag_number_and_value_decode() |
…de() Replace 3 calls to the legacy decode_tag_number_and_value() in tests that were not protected by BACNET_STACK_DEPRECATED_DISABLE guards. These calls now use the length-aware bacnet_tag_number_and_value_decode() variant, fixing the unittest failures caused by the extended-value rejection guard added in the previous commit.
|
Pushed a follow-up commit migrating the 3 unguarded test call-sites to bacnet_tag_number_and_value_decode() as discussed. CI should pass now. |
Summary
decode_tag_number_and_value()insrc/bacnet/bacdcode.creads up to 5 bytes past the caller buffer when the first APDU byte hasIS_EXTENDED_VALUEset, because the function takes no buffer-length parameter.Root cause
Lines 695-712: when
IS_EXTENDED_VALUE(apdu[0])is true, the function unconditionally readsapdu[1]. If that byte equals0xFF, it callsdecode_unsigned32which reads four more bytes -- all without any length check.Fix
Add an early-return guard before
decode_tag_number()that rejects extended-value tags withBACNET_STATUS_ERROR. The existing code block becomes unreachable and can be removed in a follow-up cleanup. The length-aware variantbacnet_tag_number_and_value_decode()is unaffected.Metadata