Skip to content

Fix buffer overflows in bsc_node_parse_urls() - #1365

Merged
skarg merged 2 commits into
bacnet-stack:masterfrom
TristanInSec:fix/bsc-node-url-parser-overflow
May 29, 2026
Merged

Fix buffer overflows in bsc_node_parse_urls()#1365
skarg merged 2 commits into
bacnet-stack:masterfrom
TristanInSec:fix/bsc-node-url-parser-overflow

Conversation

@TristanInSec

Copy link
Copy Markdown
Contributor

Summary

Three buffer overflow bugs in the BACnet/SC Address Resolution ACK URL parser (bsc_node_parse_urls() in src/bacnet/datalink/bsc/bsc-node.c):

Bug 1 -- NUL byte write past buffer (CWE-787): The NUL terminator at lines 414/423 uses the absolute string position i as an array index (r->utf8_urls[j][i] = 0) instead of the relative URL length i - start. For URLs starting past byte 128 in the URI string, i exceeds the 129-byte utf8_urls[j] buffer, writing a zero byte up to ~1389 bytes out of bounds.

Bug 2 -- Unbounded URL count (CWE-787): The URL index j is never checked against BSC_CONF_NODE_MAX_URIS_NUM_IN_ADDRESS_RESOLUTION_ACK. With 11+ space-separated short URLs in a single Address Resolution ACK, both memcpy and the NUL write access past the 10-element utf8_urls array, corrupting urls_num, fresh_timer, and adjacent BSC_ADDRESS_RESOLUTION entries in the static array.

Bug 3 -- Incorrect length comparison: The skip check at line 408 compares the absolute position i against the max URI size instead of the actual URL length (i - start). This causes valid short URLs at high string offsets to be incorrectly rejected.

Fix

  • Use (i - start) for URL length in both the skip check and NUL terminator index
  • Add j < BSC_CONF_NODE_MAX_URIS_NUM_IN_ADDRESS_RESOLUTION_ACK bounds check before every array write
  • Break out of the loop when the URL count limit is reached

Impact

An authenticated BACnet/SC peer can send a crafted Address Resolution ACK message to trigger out-of-bounds writes, corrupting static data structures. Bug 2 is the most exploitable -- a 21-byte URI string with 11 single-character URLs is sufficient.

Three bugs in the BACnet/SC Address Resolution ACK URL parser:

1. NUL terminator used absolute string position 'i' as array index
   instead of relative position 'i - start', writing past the
   129-byte utf8_urls buffer for URLs starting past position 128.

2. No bounds check on URL count index 'j', allowing writes past
   the 10-element utf8_urls array when parsing 11+ URLs, corrupting
   urls_num, fresh_timer, and adjacent structures.

3. Length check compared absolute position 'i' against the max URI
   size instead of the actual URL length '(i - start)', incorrectly
   rejecting valid short URLs at high string offsets.

Fixes all three by using relative lengths and adding array bounds
checks before every write.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR hardens BACnet/SC Address Resolution ACK URL parsing in bsc_node_parse_urls() to prevent out-of-bounds writes and incorrect rejection of valid URLs.

Changes:

  • Uses relative URL length (i - start) for size checks and NUL terminator placement.
  • Adds URL-count bounds checks before writing into utf8_urls.
  • Stops parsing once the configured URL count limit is reached.

Comment on lines +408 to +416
if ((i - start) >
BSC_CONF_NODE_MAX_URI_SIZE_IN_ADDRESS_RESOLUTION_ACK ||
(i - start) == 0) {
start = i + 1;
continue;
} else {
} else if (j <
BSC_CONF_NODE_MAX_URIS_NUM_IN_ADDRESS_RESOLUTION_ACK) {
memcpy(&r->utf8_urls[j][0], &url[start], i - start);
r->utf8_urls[j][i] = 0;
r->utf8_urls[j][i - start] = 0;
@skarg

skarg commented May 29, 2026

Copy link
Copy Markdown
Collaborator

Please run "pre-commit" to fix the style failure in the pipeline.

@TristanInSec

Copy link
Copy Markdown
Contributor Author

Please run "pre-commit" to fix the style failure in the pipeline.

Hi Steve,
I pushed a clang-format fix so the pre-commit check should pass now.

@skarg
skarg merged commit 964cf91 into bacnet-stack:master May 29, 2026
36 checks passed
skarg added a commit that referenced this pull request Jun 25, 2026
* Fix buffer overflows in bsc_node_parse_urls()

Three bugs in the BACnet/SC Address Resolution ACK URL parser:

1. NUL terminator used absolute string position 'i' as array index
   instead of relative position 'i - start', writing past the
   129-byte utf8_urls buffer for URLs starting past position 128.

2. No bounds check on URL count index 'j', allowing writes past
   the 10-element utf8_urls array when parsing 11+ URLs, corrupting
   urls_num, fresh_timer, and adjacent structures.

3. Length check compared absolute position 'i' against the max URI
   size instead of the actual URL length '(i - start)', incorrectly
   rejecting valid short URLs at high string offsets.

Fixes all three by using relative lengths and adding array bounds
checks before every write.

Add test-only shim for bsc_node_parse_urls() to support unit testing (#1369)
skarg added a commit that referenced this pull request Jul 5, 2026
* Fix buffer overflows in bsc_node_parse_urls()

Three bugs in the BACnet/SC Address Resolution ACK URL parser:

1. NUL terminator used absolute string position 'i' as array index
   instead of relative position 'i - start', writing past the
   129-byte utf8_urls buffer for URLs starting past position 128.

2. No bounds check on URL count index 'j', allowing writes past
   the 10-element utf8_urls array when parsing 11+ URLs, corrupting
   urls_num, fresh_timer, and adjacent structures.

3. Length check compared absolute position 'i' against the max URI
   size instead of the actual URL length '(i - start)', incorrectly
   rejecting valid short URLs at high string offsets.

Fixes all three by using relative lengths and adding array bounds
checks before every write.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants