Skip to content

fix http event data bleed#742

Merged
YakirOren merged 3 commits intomainfrom
fix/http-buf-len
Mar 5, 2026
Merged

fix http event data bleed#742
YakirOren merged 3 commits intomainfrom
fix/http-buf-len

Conversation

@YakirOren
Copy link
Contributor

@YakirOren YakirOren commented Mar 5, 2026

BEFORE: ring buffer reuses memory, stale data bleeds through
[ GET /health\r\n | ####GARBAGE_FROM_PREV_EVENT#### ]
                   ^-- parser sees corrupted data


AFTER: buf_len marks valid data boundary  
[ GET /health\r\n | (ignored) ]
  <-- buf_len -->

Summary by CodeRabbit

  • New Features

    • Added buffer length tracking to HTTP event data for more accurate capture and processing.
  • Bug Fixes

    • Improved HTTP response and request parsing by using only valid buffer portions, eliminating trailing garbage bytes from data processing.
  • Tests

    • Added comprehensive tests for buffer length handling and edge-case scenarios.

@coderabbitai
Copy link

coderabbitai bot commented Mar 5, 2026

📝 Walkthrough

Walkthrough

Introduces buf_len field tracking to HTTP events across eBPF kernel and Go userspace layers. The httpevent struct in eBPF now stores the actual amount of data copied; Go-side accessors expose this value, and a GetValidBuf helper uses buf_len to parse only valid buffer portions during HTTP request/response handling.

Changes

Cohort / File(s) Summary
eBPF Event Structure
pkg/ebpf/gadgets/http/program.h
Added new buf_len (u16) field to httpevent struct to track actual copied buffer size.
eBPF Buffer Population
pkg/ebpf/gadgets/http/program.bpf.c
Populates buf_len in process_packet and process_msg to record the actual number of bytes copied via bpf_probe_read_user, ensuring length accuracy at kernel level.
Go Interface Extensions
pkg/utils/events.go, pkg/utils/datasource_event.go, pkg/utils/struct_event.go
Added GetBufLen() uint16 method to HttpRawEvent interface and implemented on DatasourceEvent and StructEvent to expose buffer length values.
HTTP Parsing Logic
pkg/containerwatcher/v2/tracers/httpparse.go
Introduced GetValidBuf helper that returns valid buffer slice using buf_len if available; updated CreateEventFromRequest to use GetValidBuf for accurate request parsing.
HTTP Response Handling
pkg/containerwatcher/v2/tracers/http.go
Modified GroupEvents to use GetValidBuf for Response event buffer parsing instead of direct FromCString conversion.
Test Coverage
pkg/containerwatcher/v2/tracers/httpparse_test.go, pkg/containerwatcher/v2/tracers/http_test.go
Added comprehensive GetValidBuf tests with edge cases and buf_len validation; updated HTTP field assertions to include buf_len.

Sequence Diagram

sequenceDiagram
    participant eBPF as eBPF Kernel
    participant RingBuf as Ring Buffer
    participant GoParser as Go Parser
    participant HTTPParse as HTTP Parse

    eBPF->>eBPF: Compute buf_copy_len<br/>(min of total_size, MAX_DATAEVENT_BUFFER)
    eBPF->>eBPF: Store buf_copy_len<br/>into dataevent.buf_len
    eBPF->>eBPF: Copy data via bpf_probe_read_user<br/>using buf_copy_len
    eBPF->>RingBuf: Send httpevent with buf_len populated
    RingBuf->>GoParser: Deliver event with buf_len field
    GoParser->>GoParser: Call GetBufLen() to read buf_len value
    GoParser->>GoParser: Call GetValidBuf(event)<br/>returns buf[:buf_len]
    GoParser->>HTTPParse: Pass validated buffer portion
    HTTPParse->>HTTPParse: Parse only valid bytes<br/>(no garbage/trailing data)
    HTTPParse-->>GoParser: Return parsed HTTP request/response
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • matthyx

Poem

🐰 A buffer once wild and untamed,
Now tracked with its length proclaimed—
buf_len marks the true extent,
No garbage bytes shall be sent,
Clean data flows, our parsing's blessed! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix http event data bleed' directly and concisely describes the main change: preventing stale data from being parsed due to ring buffer reuse.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/http-buf-len

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@YakirOren YakirOren marked this pull request as draft March 5, 2026 13:31
@YakirOren YakirOren changed the title fix http buf_len field handling fix http event data with stale data Mar 5, 2026
@YakirOren YakirOren force-pushed the fix/http-buf-len branch 3 times, most recently from 59a7c77 to 9ca5fa2 Compare March 5, 2026 13:35
Signed-off-by: Yakir Oren <yakiroren@gmail.com>
@YakirOren YakirOren changed the title fix http event data with stale data fix http event data bleed Mar 5, 2026
@YakirOren YakirOren marked this pull request as ready for review March 5, 2026 13:43
matthyx
matthyx previously approved these changes Mar 5, 2026
Signed-off-by: Yakir Oren <yakiroren@gmail.com>
Signed-off-by: Yakir Oren <yakiroren@gmail.com>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (1)
pkg/containerwatcher/v2/tracers/httpparse_test.go (1)

255-268: Tighten the first GetValidBuf subtests to explicitly exercise buf_len.

At Line 255 and Line 262, these cases use utils.StructEvent, so GetBufLen() defaults to len(Buf). Consider using mockHttpRawEvent with a full ring-style buffer plus explicit bufLen to make the assertions directly validate truncation behavior.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/containerwatcher/v2/tracers/httpparse_test.go` around lines 255 - 268,
The two subtests for GetValidBuf currently use utils.StructEvent (which makes
GetBufLen() default to len(Buf)); replace those with mockHttpRawEvent instances
that supply a full ring-style buffer and an explicit bufLen so the test actually
exercises truncation logic: for the "uses buf_len when set" case create a
mockHttpRawEvent with Buf containing httpData plus extra garbage and BufLen set
to len(httpData) and assert GetValidBuf returns only httpData; for the "buf_len
truncates garbage from ring buffer" case continue to use makeBPFBuffer but wrap
it into mockHttpRawEvent with BufLen explicitly set to len(httpData) to validate
garbage is truncated. Ensure you reference GetValidBuf and mockHttpRawEvent in
the updated subtests.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@pkg/containerwatcher/v2/tracers/httpparse.go`:
- Around line 180-183: The code currently returns the whole buffer when
event.GetBufLen() is zero or out-of-range, which can reintroduce stale data;
update the logic in the httpparse.go slice-return site to return an empty slice
when n := event.GetBufLen() is <= 0 or int(n) > len(buf) so only a valid
positive length yields buf[:n]; specifically modify the branch that uses
event.GetBufLen() and buf to fail-closed (return empty slice) instead of
returning buf.

In `@pkg/ebpf/gadgets/http/program.bpf.c`:
- Around line 231-233: The code currently assigns dataevent->buf_len before
checking whether bpf_probe_read_user succeeded, allowing stale/invalid data to
be published; change the flow in the functions using dataevent, buf_copy_len,
and bpf_probe_read_user so that you first call bpf_probe_read_user and check its
return value, and only on success set dataevent->buf_len and keep/publish the
event — on failure either discard the reserved event (return early) or set
buf_len to 0 and avoid publishing; apply the same change for the second
occurrence that uses packet->buf and buf_copy_len to ensure buffer length and
data remain consistent with the copy result.

In `@pkg/utils/struct_event.go`:
- Around line 119-121: GetBufLen currently returns uint16(len(e.Buf)) which
loses the original kernel buf_len marker for fixed-capacity Buf; change
StructEvent to carry an explicit buf_len field (e.g., BufLen uint16) and
implement GetBufLen to return that field instead of len(e.Buf). Ensure the code
that constructs/parses StructEvent sets BufLen from the kernel/event metadata
and update any consumers (notably GetValidBuf) to rely on the explicit BufLen
when deciding truncation/valid length.

---

Nitpick comments:
In `@pkg/containerwatcher/v2/tracers/httpparse_test.go`:
- Around line 255-268: The two subtests for GetValidBuf currently use
utils.StructEvent (which makes GetBufLen() default to len(Buf)); replace those
with mockHttpRawEvent instances that supply a full ring-style buffer and an
explicit bufLen so the test actually exercises truncation logic: for the "uses
buf_len when set" case create a mockHttpRawEvent with Buf containing httpData
plus extra garbage and BufLen set to len(httpData) and assert GetValidBuf
returns only httpData; for the "buf_len truncates garbage from ring buffer" case
continue to use makeBPFBuffer but wrap it into mockHttpRawEvent with BufLen
explicitly set to len(httpData) to validate garbage is truncated. Ensure you
reference GetValidBuf and mockHttpRawEvent in the updated subtests.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b55cfacf-b198-4d4b-9dbe-16a95586c67c

📥 Commits

Reviewing files that changed from the base of the PR and between 55c207f and 3819b3e.

📒 Files selected for processing (9)
  • pkg/containerwatcher/v2/tracers/http.go
  • pkg/containerwatcher/v2/tracers/http_test.go
  • pkg/containerwatcher/v2/tracers/httpparse.go
  • pkg/containerwatcher/v2/tracers/httpparse_test.go
  • pkg/ebpf/gadgets/http/program.bpf.c
  • pkg/ebpf/gadgets/http/program.h
  • pkg/utils/datasource_event.go
  • pkg/utils/events.go
  • pkg/utils/struct_event.go

Comment on lines +180 to +183
if n := event.GetBufLen(); n > 0 && int(n) <= len(buf) {
return buf[:n]
}
return buf
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Fail closed when buf_len is zero or invalid.

On Line 180 and Line 183, buf_len == 0 (or out-of-range) falls back to the full buffer, which can reintroduce stale-data parsing. For this bug class, safer behavior is returning an empty slice when length metadata is invalid/unset.

🔧 Proposed fix
 func GetValidBuf(event utils.HttpRawEvent) []byte {
 	buf := event.GetBuf()
-	if n := event.GetBufLen(); n > 0 && int(n) <= len(buf) {
-		return buf[:n]
-	}
-	return buf
+	n := int(event.GetBufLen())
+	if n <= 0 || n > len(buf) {
+		return buf[:0]
+	}
+	return buf[:n]
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/containerwatcher/v2/tracers/httpparse.go` around lines 180 - 183, The
code currently returns the whole buffer when event.GetBufLen() is zero or
out-of-range, which can reintroduce stale data; update the logic in the
httpparse.go slice-return site to return an empty slice when n :=
event.GetBufLen() is <= 0 or int(n) > len(buf) so only a valid positive length
yields buf[:n]; specifically modify the branch that uses event.GetBufLen() and
buf to fail-closed (return empty slice) instead of returning buf.

Comment on lines +231 to +233
__u64 buf_copy_len = min_size(total_size, MAX_DATAEVENT_BUFFER);
dataevent->buf_len = (__u16)buf_copy_len;
bpf_probe_read_user(&dataevent->buf, buf_copy_len, (void *)packet->buf);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Validate payload copy success before publishing buf_len.

At Line 233 and Line 323, buf_len is set before verifying bpf_probe_read_user succeeded. If the copy fails, the event can still advertise valid bytes and reintroduce parse corruption/stale-data behavior.
Please gate publication on successful copy (or discard the reserved event on failure) so buf_len and buf stay consistent.

Also applies to: 322-323

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/ebpf/gadgets/http/program.bpf.c` around lines 231 - 233, The code
currently assigns dataevent->buf_len before checking whether bpf_probe_read_user
succeeded, allowing stale/invalid data to be published; change the flow in the
functions using dataevent, buf_copy_len, and bpf_probe_read_user so that you
first call bpf_probe_read_user and check its return value, and only on success
set dataevent->buf_len and keep/publish the event — on failure either discard
the reserved event (return early) or set buf_len to 0 and avoid publishing;
apply the same change for the second occurrence that uses packet->buf and
buf_copy_len to ensure buffer length and data remain consistent with the copy
result.

Comment on lines +119 to +121
func (e *StructEvent) GetBufLen() uint16 {
return uint16(len(e.Buf))
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

StructEvent.GetBufLen() loses explicit kernel buf_len semantics.

GetBufLen() currently derives from len(Buf), which does not preserve the actual buf_len marker when Buf is fixed-capacity. This can skip truncation in GetValidBuf for StructEvent paths.

Suggested fix
 type StructEvent struct {
 	Addresses            []string                `json:"addresses,omitempty" yaml:"addresses,omitempty"`
 	Args                 []string                `json:"args,omitempty" yaml:"args,omitempty"`
 	AttrSize             uint32                  `json:"attrSize,omitempty" yaml:"attrSize,omitempty"`
 	Buf                  []byte                  `json:"buf,omitempty" yaml:"buf,omitempty"`
+	BufLen               uint16                  `json:"bufLen,omitempty" yaml:"bufLen,omitempty"`
 	CapName              string                  `json:"capName,omitempty" yaml:"capName,omitempty"`
 	...
 }

 func (e *StructEvent) GetBufLen() uint16 {
-	return uint16(len(e.Buf))
+	if e.BufLen > 0 {
+		return e.BufLen
+	}
+	return uint16(len(e.Buf))
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/utils/struct_event.go` around lines 119 - 121, GetBufLen currently
returns uint16(len(e.Buf)) which loses the original kernel buf_len marker for
fixed-capacity Buf; change StructEvent to carry an explicit buf_len field (e.g.,
BufLen uint16) and implement GetBufLen to return that field instead of
len(e.Buf). Ensure the code that constructs/parses StructEvent sets BufLen from
the kernel/event metadata and update any consumers (notably GetValidBuf) to rely
on the explicit BufLen when deciding truncation/valid length.

@YakirOren YakirOren merged commit f34b773 into main Mar 5, 2026
27 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