Fix buffer overflow / off-by-one in claim and freebsd_ipfw collectors - #22710
Merged
vkalintiris merged 3 commits intoJun 16, 2026
Merged
Conversation
netdata_claim_convert_str() writes a NUL terminator at dst[copied], where copied can equal the len limit, so the buffer must hold len+1 bytes. The aToken allocation already obeys this (calloc(length), convert with length-1), but aRoom, aProxy, and aURL allocated calloc(length-1), one byte short. For ASCII-only room/proxy/url, wcstombs fills the entire buffer and the NUL terminator overflows the heap by one byte on every Windows claim operation.
rule_num_str was a 12-byte buffer formatted with sprintf() using "<uint32>_<uint32>", which can need up to 22 bytes (10 digits per uint32 plus separator and NUL). Any IPFW rule number or id with more than ~5 digits overflowed the stack. Enlarge the buffer to hold two MAX_INT_DIGITS values plus separator and NUL, and switch sprintf() to the clamping snprintfz() used by the rest of the plugin.
The /I (insecure) parser set length = wcslen(argv[i]) without +1, so for
the only meaningful input "/I 1" it called wcstombs with len=0, wrote
no bytes, and atoi("") always returned 0. As a result the Windows
claimer could never disable TLS verification via the documented /I flag
(insecure was always "no" in claim.conf).
Mirror the correct aToken pattern: length = wcslen(argv[i]) + 1, then
calloc(length) and convert_str(..., length - 1).
Contributor
There was a problem hiding this comment.
No issues found across 2 files
Confidence score: 5/5
- Automated review surfaced no issues in the provided summaries.
- No files require special attention.
Architecture diagram
sequenceDiagram
participant ClaimCLI as Claimer CLI
participant ParseArgs as nd_claim_parse_args()
participant PrepStrings as netdata_claim_prepare_strings()
participant WCharConv as netdata_claim_convert_str()
participant Heap as Windows Heap
participant IpfwPlugin as FreeBSD IPFW Plugin
participant IpfwLoop as do_ipfw() main loop
participant Stack as Stack Buffer
Note over ClaimCLI,Heap: Windows Claim Flow
ClaimCLI->>ParseArgs: Parse command-line argv (LPWSTR)
alt /I flag present
ParseArgs->>ParseArgs: wcslen(argv[i]) + 1 (now correct)
ParseArgs->>WCharConv: convert_str(tmp, length - 1)
WCharConv->>WCharConv: wcstombs with correct buffer size
WCharConv-->>ParseArgs: insecure flag value
else no /I flag
ParseArgs->>ParseArgs: continue processing
end
ParseArgs-->>PrepStrings: token, room, proxy, url strings
PrepStrings->>Heap: calloc(length) for aRoom (now length, not length-1)
PrepStrings->>Heap: calloc(length) for aProxy (now length, not length-1)
PrepStrings->>Heap: calloc(length) for aURL (now length, not length-1)
PrepStrings->>WCharConv: convert_str(buf, length - 1)
WCharConv->>Heap: wcstombs fills buffer
WCharConv->>Heap: Write NUL at dst[copied] (now safe, buffer has space)
Note over IpfwPlugin,Stack: FreeBSD IPFW Flow
IpfwPlugin->>IpfwLoop: do_ipfw(update_every, dt)
IpfwLoop->>IpfwLoop: Allocate rule_num_str on stack (now 22 bytes)
IpfwLoop->>Stack: snprintfz(rule_num_str, sizeof, format, rulenum, id)
alt Static rules
IpfwLoop->>Stack: Format "%"PRIu32"_%"PRIu32"" (safe with snprintfz)
Stack-->>IpfwLoop: rule_num_str content (no overflow)
else Dynamic rules
IpfwLoop->>Stack: Format "%d" (safe with snprintfz)
Stack-->>IpfwLoop: rule_num_str content (no overflow)
end
IpfwLoop->>IpfwLoop: Use rule_num_str as RRD dimension name
|
thiagoftsm
approved these changes
Jun 15, 2026
thiagoftsm
left a comment
Contributor
There was a problem hiding this comment.
PR is working as expected on FreeBSD and Windows. LGTM!
Merged
Ferroin
pushed a commit
that referenced
this pull request
Jul 15, 2026
…#22710) * claim: fix off-by-one buffer allocation in wide-char string conversion netdata_claim_convert_str() writes a NUL terminator at dst[copied], where copied can equal the len limit, so the buffer must hold len+1 bytes. The aToken allocation already obeys this (calloc(length), convert with length-1), but aRoom, aProxy, and aURL allocated calloc(length-1), one byte short. For ASCII-only room/proxy/url, wcstombs fills the entire buffer and the NUL terminator overflows the heap by one byte on every Windows claim operation. * freebsd_ipfw: fix stack buffer overflow in rule number formatting rule_num_str was a 12-byte buffer formatted with sprintf() using "<uint32>_<uint32>", which can need up to 22 bytes (10 digits per uint32 plus separator and NUL). Any IPFW rule number or id with more than ~5 digits overflowed the stack. Enlarge the buffer to hold two MAX_INT_DIGITS values plus separator and NUL, and switch sprintf() to the clamping snprintfz() used by the rest of the plugin. * claim: fix /I insecure flag being silently ignored The /I (insecure) parser set length = wcslen(argv[i]) without +1, so for the only meaningful input "/I 1" it called wcstombs with len=0, wrote no bytes, and atoi("") always returned 0. As a result the Windows claimer could never disable TLS verification via the documented /I flag (insecure was always "no" in claim.conf). Mirror the correct aToken pattern: length = wcslen(argv[i]) + 1, then calloc(length) and convert_str(..., length - 1). (cherry picked from commit 1bbc2cb)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Summary
Three related memory-safety and correctness fixes in the Windows claimer and the FreeBSD IPFW collector. All are pre-existing bugs surfaced during a focused audit of
sprintf/callocsizing in platform-specific collectors.Changes
1.
src/claim/main.c— off-by-one heap overflow in wide-char conversionnetdata_claim_convert_str()(claim/main.h:14) writes a NUL terminator atdst[copied]afterwcstombs, wherecopiedcan equal thelenlimit. The buffer must therefore holdlen + 1bytes. TheaTokenallocation already obeys this (calloc(length)withconvert_str(..., length - 1)), butaRoom,aProxy, andaURLallocatedcalloc(length - 1)— one byte short. For ASCII-only room/proxy/url,wcstombsfills the buffer and the NUL write overflows the heap by exactly one byte. Triggered on essentially every Windows claim.Fix: the three allocations now match
aToken(calloc(length)); theconvert_strcalls staylength - 1.2.
src/collectors/freebsd.plugin/freebsd_ipfw.c— stack buffer overflow in rule number formattingchar rule_num_str[12]was formatted withsprintf(..., "%"PRIu32"_%"PRIu32"", rulenum, id). Twouint32_tvalues joined by_can need up to 22 bytes (4294967295_4294967295\0). Any IPFW rule number or id ≥ 7 digits overflowed the 12-byte stack buffer.Fix: size the buffer as
(MAX_INT_DIGITS * 2) + 2(= 22, exact worst case) and switchsprintfto the in-tree clampingsnprintfz(already used elsewhere in the plugin). Both call sites updated.3.
src/claim/main.c—/Iinsecure flag silently ignoredThe
/Iparser setlength = wcslen(argv[i])without+1, so for the only meaningful input/I 1it calledwcstombs(..., 0), wrote no bytes, andatoi("")always returned 0. The Windows claimer therefore could not disable TLS verification via the documented/Iflag —insecurewas alwaysnoinclaim.confregardless of the user-supplied value.Fix: mirror the correct
aTokenpattern (length = wcslen(argv[i]) + 1,calloc(length),convert_str(..., length - 1)).Impact
/Idead flag/I <n>invocationNo public contract changes. No schema/config/metric/alert changes.
Notes
<windows.h>/ FreeBSD<netinet/ip_fw.h>) and not built on Linux; fixes were verified by inspection against the existing-correct patterns in the same files.netdata_claim_convert_strdoes not check the(size_t)-1return ofwcstombson encoding error, and three siblingsprintfcalls infreebsd_sysctl.c/freebsd_devstat.ccurrently fit by construction but could be migrated tosnprintfzfor defense-in-depth. Tracked separately if desired.Summary by cubic
Fixes off-by-one buffer overflows in the Windows claimer and the FreeBSD IPFW collector, and makes the Windows
/Iflag work as documented. Prevents memory corruption during claims and ensures TLS verification can be toggled.aRoom,aProxy, andaURLwithlengthbytes and keepconvert_str(..., length - 1)to avoid a 1-byte heap overflow on the NUL./Iparsing now useswcslen(...) + 1so the value converts correctly; TLS verification can be disabled as intended.rule_num_strto(MAX_INT_DIGITS * 2) + 2and replacesprintfwithsnprintfzto prevent stack overflow when formatting<rulenum>_<id>.Written for commit 4a12012. Summary will update on new commits.