Skip to content

OCPBUGS-67363: fixes ip traffic fragmentation verification#730

Open
raphaelvrosa wants to merge 1 commit into
openshift:masterfrom
raphaelvrosa:67363
Open

OCPBUGS-67363: fixes ip traffic fragmentation verification#730
raphaelvrosa wants to merge 1 commit into
openshift:masterfrom
raphaelvrosa:67363

Conversation

@raphaelvrosa

@raphaelvrosa raphaelvrosa commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Impact: Attackers can access blocked ports by fragmenting IP packets in specific ways that exploit the firewall's failure to validate IP fragmentation headers before extracting Layer 4 port information.

Root Cause: The eBPF code assumes all packets have complete TCP/UDP/SCTP headers immediately following the IP header, without checking if the packet is a non-first fragment that contains only payload data.

Solution:

  • Check iph->frag_off before extracting L4 headers
  • Deny all non-first fragments (secure by default)
  • First fragments (offset = 0) still processed normally with L4 inspection

The solution was verified and validate locally with kind and ovn-kubernetes as CNI. The ebpf program was loaded, and traffic was blocked.
End to end tests with hping3 are added to validate the solution.

- What this PR does and why is it needed

- Special notes for reviewers

- How to verify it

- Description for the changelog

Summary by CodeRabbit

  • Bug Fixes

    • Improved firewall handling of fragmented IPv4 traffic by denying non-initial fragments that lack transport-layer information.
    • Added coverage to verify fragmented TCP traffic cannot bypass blocked-port rules across supported network protocols and IP versions.
  • Chores

    • Updated the bundled cert-manager version for installation and local cluster cleanup workflows.
    • Enhanced network testing tools to support fragmented traffic validation.

@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label Jul 9, 2026
@openshift-ci-robot

Copy link
Copy Markdown

@raphaelvrosa: This pull request references Jira Issue OCPBUGS-67363, which is invalid:

  • expected the bug to target the "5.0.0" version, but no target version was set

Comment /jira refresh to re-evaluate validity if changes to the Jira bug are made, or edit the title of this pull request to link to a different bug.

The bug has been updated to refer to the pull request using the external bug tracker.

Details

In response to this:

Impact: Attackers can access blocked ports by fragmenting IP packets in specific ways that exploit the firewall's failure to validate IP fragmentation headers before extracting Layer 4 port information.

Root Cause: The eBPF code assumes all packets have complete TCP/UDP/SCTP headers immediately following the IP header, without checking if the packet is a non-first fragment that contains only payload data.

Solution:

  • Check iph->frag_off before extracting L4 headers
  • Deny all non-first fragments (secure by default)
  • First fragments (offset = 0) still processed normally with L4 inspection

The solution was verified and validate locally with kind and ovn-kubernetes as CNI. The ebpf program was loaded, and traffic was blocked.
The verification of the fragmentation issue could not be fully verified, as docker and host were probably dropping fragmented packets before it reached the cluster.

- What this PR does and why is it needed

- Special notes for reviewers

- How to verify it

- Description for the changelog

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@openshift-ci-robot openshift-ci-robot added the jira/invalid-bug Indicates that a referenced Jira bug is invalid for the branch this PR is targeting. label Jul 9, 2026
@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

The firewall now identifies and denies non-first IPv4 fragments. E2E transport tooling adds hping3-based fragmented probes, raw-network capability, and validation for blocked fragmented TCP traffic. The Makefile also updates the cert-manager version.

Changes

Fragmented Traffic Denial

Layer / File(s) Summary
Kernel fragment detection and denial
bpf/ingress_node_firewall.h, bpf/ingress_node_firewall_kernel.c
IPv4 fragmentation constants and a -2 extraction result identify non-first fragments, which IPv4 and IPv6 lookup paths explicitly deny.
Fragmented probe execution
test/Dockerfile.netcat, test/e2e/transport/transport.go
The test image installs hping3, the client gains NET_RAW, and transport helpers execute fragmented TCP/UDP probes and parse responses.
Fragmentation e2e validation
test/e2e/functional/tests/e2e.go
Functional tests add blocked-port fragmented TCP coverage and validate fragmented responses across applicable IP families.

Cert-manager Version Update

Layer / File(s) Summary
Cert-manager release configuration
Makefile
CERT_MANAGER_VERSION is updated from v1.9.1 to v1.20.2 for generated cert-manager URLs.

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

Sequence Diagram(s)

sequenceDiagram
  participant E2ETest
  participant Transport
  participant Hping3
  participant Firewall
  E2ETest->>Transport: HpingFragmentedConnect()
  Transport->>Hping3: Execute fragmented probe
  Hping3->>Firewall: Send fragmented packets
  Firewall-->>Hping3: Deny non-first fragments
  Hping3-->>Transport: Return command output
  Transport-->>E2ETest: Report response presence
Loading

Suggested reviewers: tssurya, jcaamano, anuragthehatter

🚥 Pre-merge checks | ✅ 14 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Single Node Openshift (Sno) Test Compatibility ⚠️ Warning The new fragmented-packet test reuses client/server pods with required pod anti-affinity on hostname, so it needs separate nodes and lacks any SNO skip. Add a [Skipped:SingleReplicaTopology] label or runtime SNO guard, or change the setup so client/server do not require distinct nodes.
✅ Passed checks (14 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
Stable And Deterministic Test Names ✅ Passed New Ginkgo title is static ('should deny fragmented TCP packets to blocked port'); no dynamic values or runtime-generated identifiers were added.
Test Structure And Quality ✅ Passed The new fragmentation coverage uses existing setup/cleanup patterns, explicit timeouts, and clear failure messages, with no new resource-leak or wait-pattern issues.
Microshift Test Compatibility ✅ Passed The new fragmented-packet Ginkgo test uses only pod traffic checks; I found no OpenShift-only APIs, forbidden namespaces, or MicroShift guards needed.
Topology-Aware Scheduling Compatibility ✅ Passed PASS: Changed files are Makefile/BPF/e2e tests only; no deployment manifests/operator/controllers or topology-related scheduling constraints were introduced.
Ote Binary Stdout Contract ✅ Passed PASS: The patch adds fragmentation helpers and test logic only; no new fmt.Print/Printf/Println, klog, or log.SetOutput in process-level setup.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed The new e2e fragmentation test uses cluster pod IPs and branches for IPv4/IPv6; it doesn’t hardcode IPv4-only values or require external connectivity.
No-Weak-Crypto ✅ Passed Touched files contain no MD5/SHA1/DES/RC4/3DES/Blowfish/ECB or constant-time/secret-comparison code; changes are fragmentation and test tooling only.
Container-Privileges ✅ Passed The patch only adds NET_RAW to the test client pod; it does not introduce privileged, hostPID/hostNetwork/hostIPC, SYS_ADMIN, allowPrivilegeEscalation, or explicit root settings.
No-Sensitive-Data-In-Logs ✅ Passed The new logs only print pod names/IPs, ports, and hping errors; I found no passwords, tokens, API keys, session IDs, or raw payload dumps.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is clearly related to the fragmentation fix and added verification coverage, though it is slightly narrower than the full change set.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@openshift-ci-robot openshift-ci-robot added jira/valid-bug Indicates that a referenced Jira bug is valid for the branch this PR is targeting. and removed jira/invalid-bug Indicates that a referenced Jira bug is invalid for the branch this PR is targeting. labels Jul 9, 2026
@openshift-ci-robot

Copy link
Copy Markdown

@raphaelvrosa: This pull request references Jira Issue OCPBUGS-67363, which is valid. The bug has been moved to the POST state.

3 validation(s) were run on this bug
  • bug is open, matching expected state (open)
  • bug target version (5.0.0) matches configured target version for branch (5.0.0)
  • bug is in the state ASSIGNED, which is one of the valid states (NEW, ASSIGNED, POST)

Requesting review from QA contact:
/cc @anuragthehatter

Details

In response to this:

Impact: Attackers can access blocked ports by fragmenting IP packets in specific ways that exploit the firewall's failure to validate IP fragmentation headers before extracting Layer 4 port information.

Root Cause: The eBPF code assumes all packets have complete TCP/UDP/SCTP headers immediately following the IP header, without checking if the packet is a non-first fragment that contains only payload data.

Solution:

  • Check iph->frag_off before extracting L4 headers
  • Deny all non-first fragments (secure by default)
  • First fragments (offset = 0) still processed normally with L4 inspection

The solution was verified and validate locally with kind and ovn-kubernetes as CNI. The ebpf program was loaded, and traffic was blocked.
The verification of the fragmentation issue could not be fully verified, as docker and host were probably dropping fragmented packets before it reached the cluster.

- What this PR does and why is it needed

- Special notes for reviewers

- How to verify it

- Description for the changelog

Summary by CodeRabbit

  • Bug Fixes

  • Improved handling of fragmented IPv4 traffic so packets that are not the first fragment are now denied instead of being processed incorrectly.

  • Updated firewall behavior to more reliably reject packets missing layer 4 header information.

  • Chores

  • Updated the cert-manager version used by deployment and cleanup workflows to a newer release.

  • Added IPv4 fragmentation constants to support packet handling changes.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@openshift-ci

openshift-ci Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: raphaelvrosa
Once this PR has been reviewed and has the lgtm label, please assign danwinship for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@bpf/ingress_node_firewall_kernel.c`:
- Around line 309-318: The current fragment-handling branch in
ip_extract_l4info() only denies IPv4 non-first fragments via the -2 return path,
but IPv6 Fragment headers are still not detected. Update the IPv6 parsing path
in bpf/ingress_node_firewall_kernel.c so ip_extract_l4info() walks IPv6
extension headers, explicitly checks for NEXTHDR_FRAGMENT, and identifies
non-first fragments as a deny case; then make the existing caller logic in the
l4_result check return DENY for those IPv6 fragments instead of falling through
to SET_ACTION(UNDEF).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: openshift/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: d4ba6ea4-4664-4622-95ab-3845b7991dd2

📥 Commits

Reviewing files that changed from the base of the PR and between f1e4ccd and 8247162.

⛔ Files ignored due to path filters (4)
  • pkg/ebpf/bpf_arm64_bpfel.o is excluded by !**/*.o
  • pkg/ebpf/bpf_powerpc_bpfel.o is excluded by !**/*.o
  • pkg/ebpf/bpf_s390_bpfeb.o is excluded by !**/*.o
  • pkg/ebpf/bpf_x86_bpfel.o is excluded by !**/*.o
📒 Files selected for processing (3)
  • Makefile
  • bpf/ingress_node_firewall.h
  • bpf/ingress_node_firewall_kernel.c

Comment on lines +309 to 318
int l4_result = ip_extract_l4info(data, data_end, &proto, &dstPort, &icmpType,
&icmpCode, 0);
if (unlikely(l4_result < 0)) {
if (l4_result == -2) {
// Non-first IP fragment: deny by security policy
return SET_ACTIONRULE_RESPONSE(DENY, INVALID_RULE_ID);
}
ingress_node_firewall_printk("failed to extract l4 info");
return SET_ACTION(UNDEF);
}

@coderabbitai coderabbitai Bot Jul 9, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Confirm there's no other IPv6 extension-header walking logic elsewhere in the bpf dir
rg -n 'nexthdr|NEXTHDR|ipv6hdr' bpf/

Repository: openshift/ingress-node-firewall

Length of output: 1822


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the relevant IPv4/IPv6 parsing and lookup flow.
sed -n '80,170p' bpf/ingress_node_firewall_kernel.c
printf '\n---\n'
sed -n '280,340p' bpf/ingress_node_firewall_kernel.c
printf '\n---\n'
sed -n '340,420p' bpf/ingress_node_firewall_kernel.c

# Look for any IPv6 fragment/extension-header handling in the repo.
printf '\n=== search ===\n'
rg -n 'NEXTHDR_FRAGMENT|fragment|ext header|extension header|ipv6 fragment|IPV6_EXT' bpf/ .

Repository: openshift/ingress-node-firewall

Length of output: 18706


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find how UNDEF propagates to the final packet decision.
rg -n 'SET_ACTION\(UNDEF\)|UNDEF|DENY|ALLOW|SET_ACTIONRULE_RESPONSE' bpf/ingress_node_firewall_kernel.c bpf/ingress_node_firewall.h

printf '\n=== action helpers ===\n'
sed -n '1,140p' bpf/ingress_node_firewall.h

printf '\n=== lookup callers ===\n'
rg -n 'ipv6_firewall_lookup|ipv4_firewall_lookup|SET_ACTIONRULE_RESPONSE|SET_ACTION\(' bpf/ingress_node_firewall_kernel.c

Repository: openshift/ingress-node-firewall

Length of output: 7842


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Read the final action mapping for XDP and TCX paths.
sed -n '440,575p' bpf/ingress_node_firewall_kernel.c

Repository: openshift/ingress-node-firewall

Length of output: 4810


IPv6 fragments still bypass port matching
ip_extract_l4info() only returns -2 for IPv4; the IPv6 path never checks NEXTHDR_FRAGMENT or walks extension headers. IPv6 packets with a Fragment header fall through as UNDEF and are passed, so this does not close the fragmentation bypass for IPv6. Add IPv6 extension-header parsing and deny non-first fragments.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@bpf/ingress_node_firewall_kernel.c` around lines 309 - 318, The current
fragment-handling branch in ip_extract_l4info() only denies IPv4 non-first
fragments via the -2 return path, but IPv6 Fragment headers are still not
detected. Update the IPv6 parsing path in bpf/ingress_node_firewall_kernel.c so
ip_extract_l4info() walks IPv6 extension headers, explicitly checks for
NEXTHDR_FRAGMENT, and identifies non-first fragments as a deny case; then make
the existing caller logic in the l4_result check return DENY for those IPv6
fragments instead of falling through to SET_ACTION(UNDEF).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@danwinship should this PR address this?

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

no, we'll do a followup PR

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

@raphaelvrosa raphaelvrosa changed the title OCPBUGS-67363: fixes ip traffic fragmentation OCPBUGS-67363: fixes ip traffic fragmentation verification Jul 9, 2026
@openshift-ci-robot

Copy link
Copy Markdown

@raphaelvrosa: This pull request references Jira Issue OCPBUGS-67363, which is valid.

3 validation(s) were run on this bug
  • bug is open, matching expected state (open)
  • bug target version (5.0.0) matches configured target version for branch (5.0.0)
  • bug is in the state POST, which is one of the valid states (NEW, ASSIGNED, POST)

Requesting review from QA contact:
/cc @anuragthehatter

The bug has been updated to refer to the pull request using the external bug tracker.

Details

In response to this:

Impact: Attackers can access blocked ports by fragmenting IP packets in specific ways that exploit the firewall's failure to validate IP fragmentation headers before extracting Layer 4 port information.

Root Cause: The eBPF code assumes all packets have complete TCP/UDP/SCTP headers immediately following the IP header, without checking if the packet is a non-first fragment that contains only payload data.

Solution:

  • Check iph->frag_off before extracting L4 headers
  • Deny all non-first fragments (secure by default)
  • First fragments (offset = 0) still processed normally with L4 inspection

The solution was verified and validate locally with kind and ovn-kubernetes as CNI. The ebpf program was loaded, and traffic was blocked.
The verification of the fragmentation issue could not be fully verified, as docker and host were probably dropping fragmented packets before it reached the cluster.

- What this PR does and why is it needed

- Special notes for reviewers

- How to verify it

- Description for the changelog

Summary by CodeRabbit

  • Bug Fixes
  • Improved handling of fragmented IPv4 traffic so packets that aren’t the first fragment are denied rather than processed incorrectly.
  • Updated firewall behavior to more reliably reject packets missing layer 4 header information.
  • Tests
  • Added end-to-end coverage for fragmented TCP connectivity to ensure blocked ports deny fragmented packets (IPv4 and IPv6).
  • Chores
  • Updated the cert-manager version used by deployment and cleanup workflows.
  • Enhanced test tooling to support fragmentation checks and added needed IPv4 fragmentation constants.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test/e2e/functional/tests/e2e.go`:
- Around line 1679-1681: Update the protocol filtering in the Hping
fragmented-connect probe loop to explicitly exclude SCTP after the
IsTransportProtocol check. Ensure SCTP is skipped or reported as unsupported so
HpingFragmentedConnect does not produce a false successful assertion without
sending traffic.

In `@test/e2e/transport/transport.go`:
- Around line 287-289: Preserve hping3 execution errors in hpingClient by
removing the shell fallback that appends “|| true”
(test/e2e/transport/transport.go:287-289). In
test/e2e/functional/tests/e2e.go:1562-1565, handle and log or fail on the
returned error; in the IPv4 assertion at 1687-1692 and IPv6 assertion at
1699-1704, fail the assertion when the probe cannot execute instead of parsing
its output as no response. Ensure no error return is ignored.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: openshift/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 0e4a1a7b-9965-4789-a6b5-e881dfa4adcc

📥 Commits

Reviewing files that changed from the base of the PR and between 8247162 and fa33b53.

⛔ Files ignored due to path filters (4)
  • pkg/ebpf/bpf_arm64_bpfel.o is excluded by !**/*.o
  • pkg/ebpf/bpf_powerpc_bpfel.o is excluded by !**/*.o
  • pkg/ebpf/bpf_s390_bpfeb.o is excluded by !**/*.o
  • pkg/ebpf/bpf_x86_bpfel.o is excluded by !**/*.o
📒 Files selected for processing (6)
  • Makefile
  • bpf/ingress_node_firewall.h
  • bpf/ingress_node_firewall_kernel.c
  • test/Dockerfile.netcat
  • test/e2e/functional/tests/e2e.go
  • test/e2e/transport/transport.go
🚧 Files skipped from review as they are similar to previous changes (3)
  • bpf/ingress_node_firewall.h
  • Makefile
  • bpf/ingress_node_firewall_kernel.c

Comment thread test/e2e/functional/tests/e2e.go Outdated
Comment thread test/e2e/transport/transport.go

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@config/manager/kustomization.yaml`:
- Around line 12-13: Keep config/manager/kustomization.yaml lines 12-13 using
the registry-backed controller image, moving the localhost/...:dev override to
the local kind/development overlay. Keep config/manager/env.yaml line 13 using
the deployable DaemonSet image in the shared configuration, moving the local
DAEMONSET_IMAGE override to that same local overlay.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: openshift/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 7daa3340-9028-4d87-89aa-e7d87d8dc635

📥 Commits

Reviewing files that changed from the base of the PR and between fa33b53 and 75656f0.

⛔ Files ignored due to path filters (4)
  • pkg/ebpf/bpf_arm64_bpfel.o is excluded by !**/*.o
  • pkg/ebpf/bpf_powerpc_bpfel.o is excluded by !**/*.o
  • pkg/ebpf/bpf_s390_bpfeb.o is excluded by !**/*.o
  • pkg/ebpf/bpf_x86_bpfel.o is excluded by !**/*.o
📒 Files selected for processing (8)
  • Makefile
  • bpf/ingress_node_firewall.h
  • bpf/ingress_node_firewall_kernel.c
  • config/manager/env.yaml
  • config/manager/kustomization.yaml
  • test/Dockerfile.netcat
  • test/e2e/functional/tests/e2e.go
  • test/e2e/transport/transport.go
🚧 Files skipped from review as they are similar to previous changes (6)
  • test/Dockerfile.netcat
  • bpf/ingress_node_firewall.h
  • Makefile
  • test/e2e/transport/transport.go
  • bpf/ingress_node_firewall_kernel.c
  • test/e2e/functional/tests/e2e.go

Comment thread config/manager/kustomization.yaml Outdated
@raphaelvrosa
raphaelvrosa force-pushed the 67363 branch 3 times, most recently from c83761f to 888780d Compare July 16, 2026 09:25

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test/Dockerfile.netcat`:
- Around line 3-4: Update the Dockerfile’s Alpine base image reference to a
fixed digest and replace the floating edge/testing repository in the
package-install command with a repository matching the pinned Alpine release; if
hping3 requires testing, scope that repository only to hping3 while keeping bash
and nmap-ncat on the release repository.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: openshift/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: d23b7778-891e-4e10-bae4-12716ccb9bd0

📥 Commits

Reviewing files that changed from the base of the PR and between 75656f0 and 976ce2a.

⛔ Files ignored due to path filters (4)
  • pkg/ebpf/bpf_arm64_bpfel.o is excluded by !**/*.o
  • pkg/ebpf/bpf_powerpc_bpfel.o is excluded by !**/*.o
  • pkg/ebpf/bpf_s390_bpfeb.o is excluded by !**/*.o
  • pkg/ebpf/bpf_x86_bpfel.o is excluded by !**/*.o
📒 Files selected for processing (8)
  • Makefile
  • bpf/ingress_node_firewall.h
  • bpf/ingress_node_firewall_kernel.c
  • config/manager/env.yaml
  • config/manager/kustomization.yaml
  • test/Dockerfile.netcat
  • test/e2e/functional/tests/e2e.go
  • test/e2e/transport/transport.go
🚧 Files skipped from review as they are similar to previous changes (5)
  • config/manager/env.yaml
  • bpf/ingress_node_firewall.h
  • bpf/ingress_node_firewall_kernel.c
  • test/e2e/functional/tests/e2e.go
  • test/e2e/transport/transport.go

Comment thread test/Dockerfile.netcat Outdated

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test/e2e/transport/transport.go`:
- Around line 248-250: Update the SCTP branch in the hping probe helper to
return a non-nil error instead of empty output with nil, ensuring unsupported
SCTP probes cannot be interpreted as denied packets. Preserve the existing
behavior for supported protocol types and follow the Go error-handling
requirement.
- Around line 287-289: Update hpingClient to remove the sh -c wrapper and avoid
interpolating destinationIP or dPort into a shell command. Build the hping3
argument list as separate arguments, including flags, port, and destination IP,
then pass it directly to exec.RunExecCommand while preserving the existing
return behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: openshift/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: e1a1f3e3-6951-48fb-a9a6-ee7c44488f61

📥 Commits

Reviewing files that changed from the base of the PR and between 976ce2a and 888780d.

⛔ Files ignored due to path filters (4)
  • pkg/ebpf/bpf_arm64_bpfel.o is excluded by !**/*.o
  • pkg/ebpf/bpf_powerpc_bpfel.o is excluded by !**/*.o
  • pkg/ebpf/bpf_s390_bpfeb.o is excluded by !**/*.o
  • pkg/ebpf/bpf_x86_bpfel.o is excluded by !**/*.o
📒 Files selected for processing (6)
  • Makefile
  • bpf/ingress_node_firewall.h
  • bpf/ingress_node_firewall_kernel.c
  • test/Dockerfile.netcat
  • test/e2e/functional/tests/e2e.go
  • test/e2e/transport/transport.go
🚧 Files skipped from review as they are similar to previous changes (3)
  • bpf/ingress_node_firewall.h
  • test/e2e/functional/tests/e2e.go
  • bpf/ingress_node_firewall_kernel.c

Comment thread test/e2e/transport/transport.go Outdated
Comment thread test/e2e/transport/transport.go
Impact: Attackers can access blocked ports by fragmenting IP packets
in specific ways that exploit the firewall's failure to validate IP
fragmentation headers before extracting Layer 4 port information.

Root Cause: The eBPF code assumes all packets have complete
TCP/UDP/SCTP headers immediately following the IP header,
without checking if the packet is a non-first fragment that
contains only payload data.

Solution:
- Check iph->frag_off before extracting L4 headers
- Deny all non-first fragments (secure by default)
- First fragments (offset = 0) still processed normally with L4 inspection

The solution was verified and validate locally with kind
and ovn-kubernetes as CNI. The ebpf program was loaded, and
traffic was blocked.
The verification of the fragmentation issue could not be
fully verified, as docker and host were probably dropping
fragmented packets before it reached the cluster.

Signed-off-by: Raphael Rosa <raprosa@redhat.com>
@raphaelvrosa

Copy link
Copy Markdown
Contributor Author

/assign @danwinship

@raphaelvrosa

Copy link
Copy Markdown
Contributor Author

/retest required

@openshift-ci

openshift-ci Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

@raphaelvrosa: The /retest command does not accept any targets.
The following commands are available to trigger required jobs:

/test ci-index-ingress-node-firewall-bundle
/test images
/test ingress-node-firewall-e2e-metal-ipi
/test lint
/test test-fmt
/test unit-test
/test verify-deps

Use /test all to run all jobs.

Details

In response to this:

/retest required

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@openshift-ci

openshift-ci Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

@raphaelvrosa: all tests passed!

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

// Fragment offset > 0: this is a non-first fragment
// No L4 header present, deny by policy
return -2;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

If we're going to deny non-first fragments, it seems like we should deny first fragments too, since without the followup fragments the initial fragment will be useless.

So something like unlikely((frag_off & IP_OFFSET_MASK) != 0 || (frag_off & IP_MF))

* Return:
* 0 for Success.
* -1 for Failure.
* -2 for non-first IP fragment (security: deny fragments without L4 headers).

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Should probably have #defined return values.

And this should be clearer about what the different statuses imply:

  • 0: success (extracted L4 info)
  • -1: packet is truncated; allow it to continue to the kernel, where it should be rejected
  • -2: packet is fragmented; reject and do not pass to kernel (because INF does not support reassembling and checking fragmented packets, so we have to assume all fragmented packets are denied).

Comment on lines +309 to 318
int l4_result = ip_extract_l4info(data, data_end, &proto, &dstPort, &icmpType,
&icmpCode, 0);
if (unlikely(l4_result < 0)) {
if (l4_result == -2) {
// Non-first IP fragment: deny by security policy
return SET_ACTIONRULE_RESPONSE(DENY, INVALID_RULE_ID);
}
ingress_node_firewall_printk("failed to extract l4 info");
return SET_ACTION(UNDEF);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

no, we'll do a followup PR

},
},
{
"should deny fragmented TCP packets to blocked port",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This is just a dup of the "block a port with a single rule defining the destinations port" case isn't it?

}
// test fragmented packets are always denied
for _, reach := range entry.reachables {
reach := reach

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

the reach := reach is not needed with go >= 1.22

for _, reach := range entry.reachables {
reach := reach
reachabilityCheckFragmentation(reach, podNameObj, entry.protocols)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

why is this loop needed if you also check this from isConnectivitySeen?

case ingressnodefwv1alpha1.ProtocolTypeSCTP:
return "", "", fmt.Errorf("hping3 does not support SCTP")
default:
panic("Unsupported protocol for hping3")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

weird to return an error for SCTP but panic for ICMP

func IsHpingResponseSeen(stdout, stderr string) bool {
combined := stdout + stderr
// hping3 prints "flags=SA" (SYN-ACK) or "flags=RA" (RST-ACK) when a response is received.
if strings.Contains(combined, "flags=") {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This seems potentially flaky... can we distinguish based on exit status 0 vs non-0?


func hpingTCPFragV6(client *testclient.ClientSet, sourcePod *corev1.Pod, destinationIP, dPort string) (string, string, error) {
return hpingClient(client, sourcePod, destinationIP, dPort, "-S", "-f", "-c", "1", "-6")
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Not sure all these helper functions actually make things clearer. It seems like it might be better to just have HpingFragmentedConnect assemble the hping args based on proto, then add a "-6" if v6, then call exec.RunExecCommand?

Comment thread Makefile
CSV_VERSION := 0.0.0
endif
CERT_MANAGER_VERSION=v1.9.1
CERT_MANAGER_VERSION=v1.20.2

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

where does this change come from?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

jira/valid-bug Indicates that a referenced Jira bug is valid for the branch this PR is targeting. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants