Skip to content

fix(gvisor): preserve trace connections across interrupted reads - #1052

Merged
matthyx merged 1 commit into
kubescape:mainfrom
dakshhhhh16:gvisor-start-loss-diagnostics
Oct 27, 2026
Merged

matthyx merged 1 commit into
kubescape:mainfrom
dakshhhhh16:gvisor-start-loss-diagnostics

Conversation

@dakshhhhh16

@dakshhhhh16 dakshhhhh16 commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

The live trial in #1051 included a run with one missing start. I added receiver counters to investigate loss and found a reproducible connection failure: a signal interrupting a timed socket read made the receiver close an otherwise valid connection.

This retries interrupted reads and handshake responses while keeping cancellation and the handshake deadline bounded. The probe now has an optional --diagnostics flag that writes final counters to stderr without retaining message contents or container identities. Tests cover interruption, deadline handling, malformed input, and queue-loss accounting.

The report keeps the distinction between what was reproduced and what remains unknown. A controlled test loses the next start before the fix and receives it afterward. Two fresh real runsc trials received 20/20 starts each. Neither observed an interrupted read, so these results do not prove that this bug caused the earlier missing event.

I also attempted the outstanding node-agent comparison on the local Linux VM. Both ordinary and gVisor workloads completed successfully and their runtime identities were verified, but the ordinary positive control had no retained exec records. The report includes this inconclusive result and setup details. The visibility comparison and production integration gates remain open.

Validation:

  • All 12 focused receiver tests passed on Linux ARM64.
  • Four focused probe tests passed, including full-pipe cancellation and normal output.
  • Linux-targeted vet passed for both packages.
  • Both new real-run evidence sets passed the count/privacy checker, and its 14 unit tests passed.
  • Formatting and git diff --check passed.

The focused packages were built in an isolated module with cached Go 1.26.8 and their pinned direct dependencies. The repository requires Go 1.27; this was not a full repository build or race run, and dependency files were not changed. No managed GKE or x86_64 validation is claimed.

Follows #1051 and the experiment in kubescape/designs-and-proposals#23.

Summary by CodeRabbit

  • New Features
    • Added an opt-in diagnostics option that prints receiver health counters to standard error when the probe shuts down.
  • Bug Fixes
    • Improved handling of interrupted reads and handshake responses, helping the receiver remain connected and process later start events.
  • Documentation
    • Added guidance on interpreting diagnostics, including their limits: counters do not confirm event completeness or successful output.
    • Documented controlled experiments that recorded successful start-event processing after the change; these results do not guarantee reliable delivery.

Signed-off-by: Daksh Pathak <daksh.pathak.ug24@nsut.ac.in>
Copilot AI balanced review requested due to automatic review settings October 26, 2026 18:55

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

@coderabbitai

coderabbitai Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review.

Recent review info
Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: c7cd6b0d-609a-44ac-8f42-10f5a64a3c0e
Commits

Reviewing files that changed from the base of the PR and between 3608bcc and 4e9d7a2.

Files selected for processing: 26
  • cmd/gvisor-start-probe/main_linux.go
  • docs/experiments/gvisor-start-loss-20261026/README.md
  • docs/experiments/gvisor-start-loss-20261026/comparison-values.yaml
  • docs/experiments/gvisor-start-loss-20261026/comparison-workloads.json
  • docs/experiments/gvisor-start-loss-20261026/evidence-sha256.json
  • docs/experiments/gvisor-start-loss-20261026/evidence/checker-results.json
  • docs/experiments/gvisor-start-loss-20261026/evidence/fixed-run-1/ledger.json
  • docs/experiments/gvisor-start-loss-20261026/evidence/fixed-run-1/starts-expected.json
  • docs/experiments/gvisor-start-loss-20261026/evidence/fixed-run-1/starts.jsonl
  • docs/experiments/gvisor-start-loss-20261026/evidence/fixed-run-1/starts.stderr
  • docs/experiments/gvisor-start-loss-20261026/evidence/fixed-run-2/ledger.json
  • docs/experiments/gvisor-start-loss-20261026/evidence/fixed-run-2/starts-expected.json
  • docs/experiments/gvisor-start-loss-20261026/evidence/fixed-run-2/starts.jsonl
  • docs/experiments/gvisor-start-loss-20261026/evidence/fixed-run-2/starts.stderr
  • docs/experiments/gvisor-start-loss-20261026/evidence/node-agent-comparison.json
  • docs/experiments/gvisor-start-loss-20261026/evidence/signal-after/health.jsonl
  • docs/experiments/gvisor-start-loss-20261026/evidence/signal-after/starts.jsonl
  • docs/experiments/gvisor-start-loss-20261026/evidence/signal-before/health.jsonl
  • docs/experiments/gvisor-start-loss-20261026/evidence/signal-before/starts.jsonl
  • docs/experiments/gvisor-start-loss-20261026/interrupted-read.py
  • docs/experiments/gvisor-start-loss-20261026/repeat-diagnostics.py
  • docs/gvisor-start-probe.md
  • pkg/gvisor/interrupted_read_linux_test.go
  • pkg/gvisor/receiver_linux.go
  • pkg/gvisor/receiver_linux_test.go
  • pkg/gvisor/stats_linux.go

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

Walkthrough

The Linux gVisor receiver retries interrupted reads and handshake responses and tracks receiver activity through diagnostic counters. The probe can write those counters to stderr. The pull request also adds receiver tests, controlled trial evidence, and a separate node-agent comparison.

Changes: gVisor start receiver

Layer / File(s) Summary
Receiver retries and counters
pkg/gvisor/stats_linux.go, pkg/gvisor/receiver_linux.go, pkg/gvisor/interrupted_read_linux_test.go, pkg/gvisor/receiver_linux_test.go
The receiver adds atomic counters for connection, handshake, frame, read, callback, start-resolution, and drop activity. Packet reads retry EINTR, check cancellation, and bound receive timeouts by the context deadline. Tests cover interrupted reads, cancellation, deadline behavior, invalid frames, and queue drops.
Probe diagnostics output
cmd/gvisor-start-probe/main_linux.go, docs/gvisor-start-probe.md
The probe adds a disabled-by-default -diagnostics flag. When enabled, it writes receiver statistics as JSON to stderr after receiver.Run returns. The documentation explains counter meanings and limits.
Signal tests and runsc trial evidence
docs/experiments/gvisor-start-loss-20261026/README.md, docs/experiments/gvisor-start-loss-20261026/*.py, docs/experiments/gvisor-start-loss-20261026/evidence/*, docs/experiments/gvisor-start-loss-20261026/evidence-sha256.json
The experiment scripts inject signals or run repeated starts while collecting diagnostics. The report records two 20-of-20 runsc trials and explains that the controlled reproduction does not establish the cause of the historical missing start. It also records validation limits.

Node-agent runtime comparison

Layer / File(s) Summary
Comparison setup and evidence
docs/experiments/gvisor-start-loss-20261026/comparison-values.yaml, docs/experiments/gvisor-start-loss-20261026/comparison-workloads.json, docs/experiments/gvisor-start-loss-20261026/evidence/node-agent-comparison.json, docs/experiments/gvisor-start-loss-20261026/README.md
The comparison defines ordinary and gVisor BusyBox workloads and records node-agent results. The report marks the result inconclusive because the ordinary positive control had no retained exec records and the gVisor workload had no final profile.

Priority: Normal

Estimated code review effort: 3 (Moderate) | ~25 minutes

Change: Bug fix

Possibly related issues

  • kubescape/kubescape#3424 — The issue concerns real-time runsc trace ingestion; this change retries interrupted reads and handshake responses in the gVisor trace receiver.

Possibly related PRs

  • kubescape/node-agent#1046 — It adds repeated ID-based start trials and an evidence checker used by this pull request’s investigation.
  • kubescape/node-agent#1051 — It records the earlier 19-of-20 trial that this pull request investigates with receiver retries and replacement trials.

Suggested reviewers: matthyx

Merge Risk: Minimal · up to 4e9d7

No actionable merge-blocking issue is established. The remaining runtime-visibility comparison is explicitly inconclusive, so it should not be treated as validation of an integration claim.

Pre-merge checks: Passed 4 · Failed 1

Failed 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%. Docstring coverage is scoped to functions touched by this diff. Analyzed 8 functions across 7 files. (18 skipped: 1… Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title "fix(gvisor): preserve trace connections across interrupted reads" matches the main change. The receiver now retries reads and handshake sends interrupted by signals such as SIGURG, so valid…
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Title check

Explanation

The title "fix(gvisor): preserve trace connections across interrupted reads" matches the main change. The receiver now retries reads and handshake sends interrupted by signals such as SIGURG, so valid trace connections are no longer closed by an interrupted timed Recvmsg. The title is specific and concise. It does not mention the opt-in --diagnostics flag, but that is secondary and not required to convey the primary change.

Full details: Docstring Coverage

Explanation

Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 8 functions across 7 files. (18 skipped: 18 unsupported.)

Resolution

Write docstrings for the functions missing them to satisfy the coverage threshold.

Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

@matthyx matthyx 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.

Approve 4e9d7a2318042771f8a587adb54f29dbcd39b4af against main at 3608bcc6e188623d5e15948c690df51ae6cf865e. No material blockers found. Independent code review recommends APPROVE; architecture review is CLEAR.

The fix is needed: target-branch pkg/gvisor/receiver_linux.go:153–171 treats EINTR from timed socket reads as fatal, closing an otherwise valid trace connection before a later start arrives. The new readPacket retries interruption, checks cancellation, and recalculates the receive timeout against the absolute deadline. Other errors still terminate the connection. Numeric atomic counters preserve the payload/privacy boundary and settle before final diagnostics. No new dependencies or normal node-agent startup integration. Scope and resource bounds remain appropriate for the opt-in experiment.

History: #1024 introduced the receiver, #1046 supplied trial tooling, and #1051 recorded the 19/20 run. These are merged prerequisites, not superseding fixes. Issue #894 and accepted design #23 establish project fit. Design #14 is broader companion work; its approval dismissal explicitly concerned LFX timing, not technical rejection. Earlier output/shutdown/privacy/endpoint objections were corrected before the prerequisite PRs were approved. Closed #918 concerns a different eBPF-to-profile loss path. The existing #1051 sender-drop-ledger suggestion remains nonblocking and does not invalidate these zero-reported-drop records.

Bounded GitHub searches covered open/closed/merged PRs with gVisor, SecCheck, EINTR, interrupted, receiver, receiver_linux.go, remote sink and container/start terms, plus gVisor/missing-start issues (50–100 results per query). No superseding fix found within this scope; searches cannot exclude unlinked work. Current PR has no inline threads or changes-requested review; Copilot did not execute because of quota.

Fresh validation in credential-free Bubblewrap isolation with networking disabled, read-only source and private temporary storage, using Linux amd64 Go 1.27.3:

  • go test -race ./pkg/gvisor ./cmd/gvisor-start-probe -count=1 -timeout=90s passed, including signal recovery, deadline, cancellation, queue-loss and actual-process output tests.
  • go vet ./pkg/gvisor ./cmd/gvisor-start-probe passed.
  • All 14 Python checker tests passed; both new retained trials passed the count/privacy checker with stderr and ledgers, receiving 20 starts each. All 14 listed evidence hashes matched.
  • git diff --check origin/main HEAD passed. GitHub reports successful cross-platform build, component, benchmark and security checks for this head (build workflow).

Limits: I did not independently rerun the pre-fix live reproduction, privileged runsc trials, full repository suite, managed GKE or ARM64 trials. Signal recovery is freshly tested on the fixed code; baseline failure is supported by target-code inspection and the retained controlled before/after evidence. Handshake-send interruption has no direct regression test. Diagnostics intentionally documents regular-file stderr. The original missing start remains unexplained, and the node-agent comparison is inconclusive because its ordinary positive control failed; neither proves production readiness, and both remain explicit integration gates.

Immediately before submission, confirmed unchanged head/target, open/non-draft/mergeable status and no new review blockers. Verdict: approve this experimental transport fix.

@matthyx
matthyx merged commit 97b7c2c into kubescape:main Oct 27, 2026
39 checks passed
@dakshhhhh16
dakshhhhh16 deleted the gvisor-start-loss-diagnostics branch October 27, 2026 07:03
@matthyx matthyx moved this to To Archive in KS PRs tracking Oct 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

3 participants