-
Notifications
You must be signed in to change notification settings - Fork 45
OCPBUGS-67363: fixes ip traffic fragmentation verification #730
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -95,8 +95,9 @@ volatile const __u32 debug_lookup = 0; | |
| * __u8 *icmpType: pointer to ICMP or ICMPv6's type value. | ||
| * __u8 *icmpCode: pointer to ICMP or ICMPv6's code value. | ||
| * Return: | ||
| * 0 for Success. | ||
| * -1 for Failure. | ||
| * L4_OK (0): extracted L4 info successfully. | ||
| * L4_TRUNCATED (-1): packet too short; pass to kernel for rejection. | ||
| * L4_FRAGMENTED (-2): fragmented packet; deny (INF cannot reassemble). | ||
| */ | ||
| __attribute__((__always_inline__)) static inline int | ||
| ip_extract_l4info(void *data, void *dataEnd, __u8 *proto, __u16 *dstPort, | ||
|
|
@@ -107,14 +108,19 @@ ip_extract_l4info(void *data, void *dataEnd, __u8 *proto, __u16 *dstPort, | |
| struct iphdr *iph = dataStart; | ||
| dataStart += sizeof(struct iphdr); | ||
| if (unlikely(dataStart > dataEnd)) { | ||
| return -1; | ||
| return L4_TRUNCATED; | ||
| } | ||
| *proto = iph->protocol; | ||
|
|
||
| __u16 frag_off = bpf_ntohs(iph->frag_off); | ||
| if (unlikely((frag_off & IP_OFFSET_MASK) || (frag_off & IP_MF))) { | ||
| return L4_FRAGMENTED; | ||
| } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Indeed, since it is stateless, better to drop all fragmented traffic. |
||
| } else { | ||
| struct ipv6hdr *iph = dataStart; | ||
| dataStart += sizeof(struct ipv6hdr); | ||
| if (unlikely(dataStart > dataEnd)) { | ||
| return -1; | ||
| return L4_TRUNCATED; | ||
| } | ||
| *proto = iph->nexthdr; | ||
| } | ||
|
|
@@ -123,7 +129,7 @@ ip_extract_l4info(void *data, void *dataEnd, __u8 *proto, __u16 *dstPort, | |
| struct tcphdr *tcph = (struct tcphdr *)dataStart; | ||
| dataStart += sizeof(struct tcphdr); | ||
| if (unlikely(dataStart > dataEnd)) { | ||
| return -1; | ||
| return L4_TRUNCATED; | ||
| } | ||
| *dstPort = tcph->dest; | ||
| break; | ||
|
|
@@ -132,7 +138,7 @@ ip_extract_l4info(void *data, void *dataEnd, __u8 *proto, __u16 *dstPort, | |
| struct udphdr *udph = (struct udphdr *)dataStart; | ||
| dataStart += sizeof(struct udphdr); | ||
| if (unlikely(dataStart > dataEnd)) { | ||
| return -1; | ||
| return L4_TRUNCATED; | ||
| } | ||
| *dstPort = udph->dest; | ||
| break; | ||
|
|
@@ -141,7 +147,7 @@ ip_extract_l4info(void *data, void *dataEnd, __u8 *proto, __u16 *dstPort, | |
| struct sctphdr *sctph = (struct sctphdr *)dataStart; | ||
| dataStart += sizeof(struct sctphdr); | ||
| if (unlikely(dataStart > dataEnd)) { | ||
| return -1; | ||
| return L4_TRUNCATED; | ||
| } | ||
| *dstPort = sctph->dest; | ||
| break; | ||
|
|
@@ -150,7 +156,7 @@ ip_extract_l4info(void *data, void *dataEnd, __u8 *proto, __u16 *dstPort, | |
| struct icmphdr *icmph = (struct icmphdr *)dataStart; | ||
| dataStart += sizeof(struct icmphdr); | ||
| if (unlikely(dataStart > dataEnd)) { | ||
| return -1; | ||
| return L4_TRUNCATED; | ||
| } | ||
| *icmpType = icmph->type; | ||
| *icmpCode = icmph->code; | ||
|
|
@@ -160,16 +166,16 @@ ip_extract_l4info(void *data, void *dataEnd, __u8 *proto, __u16 *dstPort, | |
| struct icmp6hdr *icmp6h = (struct icmp6hdr *)dataStart; | ||
| dataStart += sizeof(struct icmp6hdr); | ||
| if (unlikely(dataStart > dataEnd)) { | ||
| return -1; | ||
| return L4_TRUNCATED; | ||
| } | ||
| *icmpType = icmp6h->icmp6_type; | ||
| *icmpCode = icmp6h->icmp6_code; | ||
| break; | ||
| } | ||
| default: | ||
| return -1; | ||
| return L4_TRUNCATED; | ||
| } | ||
| return 0; | ||
| return L4_OK; | ||
| } | ||
|
|
||
| /* | ||
|
|
@@ -195,8 +201,12 @@ ipv4_firewall_lookup(void *data, void *data_end, __u32 ifId) { | |
| __u8 icmpCode = 0, icmpType = 0, proto = 0; | ||
| int i; | ||
|
|
||
| if (unlikely(ip_extract_l4info(data, data_end, &proto, &dstPort, &icmpType, | ||
| &icmpCode, 1) < 0)) { | ||
| int l4_result = ip_extract_l4info(data, data_end, &proto, &dstPort, &icmpType, | ||
| &icmpCode, 1); | ||
| if (unlikely(l4_result != L4_OK)) { | ||
| if (l4_result == L4_FRAGMENTED) { | ||
| return SET_ACTIONRULE_RESPONSE(DENY, INVALID_RULE_ID); | ||
| } | ||
| ingress_node_firewall_printk("failed to extract l4 info"); | ||
| return SET_ACTION(UNDEF); | ||
| } | ||
|
|
@@ -291,8 +301,12 @@ ipv6_firewall_lookup(void *data, void *data_end, __u32 ifId) { | |
| __u8 icmpCode = 0, icmpType = 0, proto = 0; | ||
| int i; | ||
|
|
||
| if (unlikely(ip_extract_l4info(data, data_end, &proto, &dstPort, &icmpType, | ||
| &icmpCode, 0) < 0)) { | ||
| int l4_result = ip_extract_l4info(data, data_end, &proto, &dstPort, &icmpType, | ||
| &icmpCode, 0); | ||
| if (unlikely(l4_result != L4_OK)) { | ||
| if (l4_result == L4_FRAGMENTED) { | ||
| return SET_ACTIONRULE_RESPONSE(DENY, INVALID_RULE_ID); | ||
| } | ||
| ingress_node_firewall_printk("failed to extract l4 info"); | ||
| return SET_ACTION(UNDEF); | ||
| } | ||
|
Comment on lines
+304
to
312
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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.cRepository: 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.cRepository: openshift/ingress-node-firewall Length of output: 4810 IPv6 fragments still bypass port matching 🤖 Prompt for AI Agents
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @danwinship should this PR address this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no, we'll do a followup PR There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,6 @@ | ||
| FROM alpine:latest | ||
|
|
||
| RUN apk add --no-cache --update --verbose bash nmap-ncat && \ | ||
| apk add --no-cache --verbose hping3 \ | ||
| --repository=https://dl-cdn.alpinelinux.org/alpine/edge/testing && \ | ||
| rm -rf /var/cache/apk/* /tmp/* |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated for local testing.