Skip to content

fingerprint: fix stack overflow building the TLS blocks string#3190

Merged
IvanNardi merged 1 commit into
ntop:devfrom
cmonroe:tls-crash
Jul 14, 2026
Merged

fingerprint: fix stack overflow building the TLS blocks string#3190
IvanNardi merged 1 commit into
ntop:devfrom
cmonroe:tls-crash

Conversation

@cmonroe

@cmonroe cmonroe commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Please sign (check) the below before submitting the Pull Request:

Link to the related issue:

Describe changes:
The tls-blocks loop advanced idx by the raw snprintf() return value, which on truncation is the would-be length rather than what was written. With tls.max_num_blocks_to_analyze=32 and application block tracking enabled the blocks string regularly exceeds the 256-byte buffer, idx walks past it and the unsigned fp_buf_len-idx-1 size underflows, so the next snprintf() writes far out of bounds and trips the stack protector (SIGSEGV via __stack_chk_fail in ndpi_compute_ndpi_flow_fingerprint on aarch64/musl).

Bound each round by the space actually remaining and stop at the first truncation, keeping the chars that fit so the digest input stays deterministic. Also bound the ignore_sni_extension patch byte to the formatted length instead of writing at strlen(l4_fp)+4 unconditionally.

Reproduced the overflow with an ASan harness of the old loop (32 blocks of ",23=-14600" overflow a 256-byte buffer); the fixed loop caps at idx=255.

The tls-blocks loop advanced idx by the raw snprintf() return value,
which on truncation is the would-be length rather than what was
written. With tls.max_num_blocks_to_analyze=32 and application block
tracking enabled the blocks string regularly exceeds the 256-byte
buffer, idx walks past it and the unsigned fp_buf_len-idx-1 size
underflows, so the next snprintf() writes far out of bounds and
trips the stack protector (SIGSEGV via __stack_chk_fail in
ndpi_compute_ndpi_flow_fingerprint on aarch64/musl).

Bound each round by the space actually remaining and stop at the
first truncation, keeping the chars that fit so the digest input
stays deterministic. Also bound the ignore_sni_extension patch byte
to the formatted length instead of writing at strlen(l4_fp)+4
unconditionally.

Reproduced the overflow with an ASan harness of the old loop (32
blocks of ",23=-14600" overflow a 256-byte buffer); the fixed loop
caps at idx=255.

Signed-off-by: Chad Monroe <chad@monroe.io>
@sonarqubecloud

sonarqubecloud Bot commented Jul 6, 2026

Copy link
Copy Markdown

@IvanNardi IvanNardi left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The fix makes sense.
Could you share the complete code to trigger this issue, please? Maybe, we might add a new fuzzer about this function... what do you think @cmonroe ?

@cmonroe

cmonroe commented Jul 11, 2026

Copy link
Copy Markdown
Contributor Author

That seems reasonable, but I'm not entirely sure how to go about this.

The entry point to the crash is via ndpi_detection_process_packet() from classifi.c:1724

In case it's useful, here's the full backtrace from gdb as well:

Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x0000007fb2a87538 in a_crash () at ./src/internal/atomic.h:250
250             *(volatile char *)0=0;
(gdb) bt
#0  0x0000007fb2a87538 in a_crash () at ./src/internal/atomic.h:250
#1  __stack_chk_fail () at src/env/__stack_chk_fail.c:26
#2  0x0000007fb283e53c in ndpi_compute_ndpi_flow_fingerprint (ndpi_str=ndpi_str@entry=0x7fb26f0050, flow=flow@entry=0x7fb07c2030) at ndpi_fingerprint.c:292
#3  0x0000007fb284c070 in internal_giveup (ndpi_struct=0x7fb26f0050, flow=0x7fb07c2030) at ndpi_main.c:9346
#4  internal_giveup (ndpi_struct=0x7fb26f0050, flow=0x7fb07c2030) at ndpi_main.c:9306
#5  0x0000007fb28585dc in ndpi_internal_detection_process_packet (ndpi_str=0x7fb26f0050, flow=0x7fb07c2030, packet_data=0x7fb26f0050 "Ɍ]\003", packetlen=0, current_time_ms=<optimized out>, input_info=0x7fb26f0930) at ndpi_main.c:10515
#6  ndpi_detection_process_packet (ndpi_str=0x7fb26f0050, flow=0x7fb07c2030, packet_data=packet_data@entry=0x7fb0abf238 <error: Cannot access memory at address 0x7fb0abf238>, packetlen=packetlen@entry=1500, current_time_ms=<optimized out>, input_info=input_info@entry=0x7fb0896340) at ndpi_main.c:10646
#7  0x00000000004067e4 in classify_packet (ctx=ctx@entry=0x7fd1dc7e80, sample=sample@entry=0x7fb0abf1e0) at /sandbox/cmonroe/smartos-rpc/polecat/openwrt/build_dir/target-aarch64_cortex-a53_musl/classifi-2026.07.01~d0bc03e8/src/classifi.c:1724
#8  0x0000000000406ca4 in handle_sample (ctx=0x7fd1dc7e80, data=0x7fb0abf1e0, len=<optimized out>) at /sandbox/cmonroe/smartos-rpc/polecat/openwrt/build_dir/target-aarch64_cortex-a53_musl/classifi-2026.07.01~d0bc03e8/src/classifi.c:1757
#9  handle_sample (ctx=0x7fd1dc7e80, data=0x7fb0abf1e0, len=<optimized out>) at /sandbox/cmonroe/smartos-rpc/polecat/openwrt/build_dir/target-aarch64_cortex-a53_musl/classifi-2026.07.01~d0bc03e8/src/classifi.c:1736
#10 0x0000007fb2a3fb8c in ringbuf_process_ring (r=0x7fb2510b70, n=n@entry=2147483647) at ringbuf.c:260
#11 0x0000007fb2a40320 in ring_buffer__consume (rb=0x7fb1d3dee0) at ringbuf.c:320
#12 0x0000000000403d68 in ringbuf_fd_cb (fd=<optimized out>, events=<optimized out>) at /sandbox/cmonroe/smartos-rpc/polecat/openwrt/build_dir/target-aarch64_cortex-a53_musl/classifi-2026.07.01~d0bc03e8/src/classifi.c:2083
#13 0x0000007fb27608cc in uloop_run_events (timeout=<optimized out>) at uloop.c:234
#14 uloop_run_timeout (timeout=timeout@entry=-1) at uloop.c:685

@IvanNardi IvanNardi left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thank you

@IvanNardi IvanNardi merged commit 380d9f0 into ntop:dev Jul 14, 2026
27 of 28 checks passed
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.

2 participants