From dc21b2f96607b7d69583074eb369dca405e7e09f Mon Sep 17 00:00:00 2001 From: aka320 <86738756+aka320@users.noreply.github.com> Date: Wed, 19 Jun 2024 11:14:44 +0000 Subject: [PATCH] Incorrect L4 offset for IP packets with Options field --- connection-limit/connection_limit_kern.c | 9 +++++++-- ipfix-flow-exporter/bpf_ipfix_egress_kern.c | 10 +++++++--- ipfix-flow-exporter/bpf_ipfix_ingress_kern.c | 10 +++++++--- ratelimiting/ratelimiting_kern.c | 7 ++++++- traffic-mirroring/mirroring_egress_kern.c | 8 +++++--- traffic-mirroring/mirroring_ingress_kern.c | 8 +++++--- 6 files changed, 37 insertions(+), 15 deletions(-) diff --git a/connection-limit/connection_limit_kern.c b/connection-limit/connection_limit_kern.c index a8f1dd4..2c0f91a 100644 --- a/connection-limit/connection_limit_kern.c +++ b/connection-limit/connection_limit_kern.c @@ -275,15 +275,20 @@ int _xdp_limit_conn(struct xdp_md *ctx) /* Check if its valid ip packet */ struct iphdr *iph = (struct iphdr *)(data + sizeof(struct ethhdr)); - if (iph + 1 > data_end) + __u8 ip_hdr_len = iph->ihl * 4; + + /* Validating IP Header */ + if ((iph->ihl < 5 || iph->ihl > 15) || + ((__u8 *)iph + ip_hdr_len) > data_end) { return XDP_PASS; + } /* Ignore other than TCP packets */ if (iph->protocol != IPPROTO_TCP) return XDP_PASS; /* Check if its valid tcp packet */ - struct tcphdr *tcph = (struct tcphdr *)(iph + 1); + struct tcphdr *tcph = (struct tcphdr *)((__u8 *)iph + ip_hdr_len); if (tcph + 1 > data_end) return XDP_PASS; diff --git a/ipfix-flow-exporter/bpf_ipfix_egress_kern.c b/ipfix-flow-exporter/bpf_ipfix_egress_kern.c index ff345f9..07b6353 100755 --- a/ipfix-flow-exporter/bpf_ipfix_egress_kern.c +++ b/ipfix-flow-exporter/bpf_ipfix_egress_kern.c @@ -226,6 +226,7 @@ void parse_ipv4(struct __sk_buff *skb, u64 l3_offset) u16 pckt_size = data_end - data; struct iphdr *iph = data + l3_offset; + u8 ip_hdr_len = (iph->ihl * 4); if (iph > data_end) return; @@ -238,13 +239,16 @@ void parse_ipv4(struct __sk_buff *skb, u64 l3_offset) u16 control_bit = 0; u16 icmp_type = 0; - if (iph + 1 > data_end) + /* Validating IP Header */ + if ((iph->ihl < 5 || iph->ihl > 15) || + ((u8 *)iph + ip_hdr_len) > data_end) { return; + } if(iph->protocol == ICMP) - parse_icmp_type(iph+1, data_end, &icmp_type); + parse_icmp_type(((u8 *)iph + ip_hdr_len), data_end, &icmp_type); - parse_port(iph+1, data_end, iph->protocol, &dport, &sport, &control_bit); + parse_port(((u8 *)iph + ip_hdr_len), data_end, iph->protocol, &dport, &sport, &control_bit); memset(&flow_key, 0, sizeof(flow_key)); flow_key.sa = iph->saddr; diff --git a/ipfix-flow-exporter/bpf_ipfix_ingress_kern.c b/ipfix-flow-exporter/bpf_ipfix_ingress_kern.c index 7c9173d..fdd6dae 100755 --- a/ipfix-flow-exporter/bpf_ipfix_ingress_kern.c +++ b/ipfix-flow-exporter/bpf_ipfix_ingress_kern.c @@ -226,6 +226,7 @@ void parse_ipv4(struct __sk_buff *skb, u64 l3_offset) u16 pckt_size = data_end - data; struct iphdr *iph = data + l3_offset; + u8 ip_hdr_len = (iph->ihl * 4); if (iph > data_end) return; @@ -238,13 +239,16 @@ void parse_ipv4(struct __sk_buff *skb, u64 l3_offset) u16 control_bit = 0; u16 icmp_type = 0; - if (iph + 1 > data_end) + /* Validating IP Header */ + if ((iph->ihl < 5 || iph->ihl > 15) || + ((u8 *)iph + ip_hdr_len) > data_end) { return; + } if(iph->protocol == ICMP) - parse_icmp_type(iph+1, data_end, &icmp_type); + parse_icmp_type(((u8 *)iph + ip_hdr_len), data_end, &icmp_type); - parse_port(iph+1, data_end, iph->protocol, &dport, &sport, &control_bit); + parse_port(((u8 *)iph + ip_hdr_len), data_end, iph->protocol, &dport, &sport, &control_bit); memset(&flow_key, 0, sizeof(flow_key)); flow_key.sa = iph->saddr; diff --git a/ratelimiting/ratelimiting_kern.c b/ratelimiting/ratelimiting_kern.c index ad70f08..eae8003 100644 --- a/ratelimiting/ratelimiting_kern.c +++ b/ratelimiting/ratelimiting_kern.c @@ -99,8 +99,13 @@ static __always_inline int _xdp_ratelimit(struct xdp_md *ctx) /* Ignore other than IP packets */ struct iphdr *iph = data + sizeof(struct ethhdr); - if (iph + 1 > data_end) + uint8_t ip_hdr_len = iph->ihl * 4; + + /* Validating IP Header */ + if ((iph->ihl < 5 || iph->ihl > 15) || + ((uint8_t *)iph + ip_hdr_len) > data_end) { return XDP_PASS; + } /* Ignore other than TCP packets */ if (iph->protocol != IPPROTO_TCP) diff --git a/traffic-mirroring/mirroring_egress_kern.c b/traffic-mirroring/mirroring_egress_kern.c index d9e6886..7da3b5f 100644 --- a/traffic-mirroring/mirroring_egress_kern.c +++ b/traffic-mirroring/mirroring_egress_kern.c @@ -128,7 +128,8 @@ static __always_inline int egress_redirect(struct __sk_buff *skb) void *data_end = (void *)(long)skb->data_end; const int l3_off = ETH_HLEN; // IP header offset - const int l4_off = l3_off + sizeof(struct iphdr); // TCP header offset + struct iphdr *iph = (struct iphdr *)(data + l3_off); + const int l4_off = l3_off + (iph->ihl * 4); // TCP header offset struct ethhdr *eth = data; int l7_off; @@ -142,10 +143,11 @@ static __always_inline int egress_redirect(struct __sk_buff *skb) return TC_ACT_OK; } - if (data + l4_off > data_end) { + /* Validating IP Header */ + if ((iph->ihl < 5 || iph->ihl > 15) || + (data + l4_off > data_end)) { return TC_ACT_OK; // Not our packet, handover to kernel } - struct iphdr *iph = (struct iphdr *)(data + l3_off); if (iph->protocol == IPPROTO_TCP) { l7_off = l4_off + sizeof(struct tcphdr); // L7 (e.g. HTTP) header offset diff --git a/traffic-mirroring/mirroring_ingress_kern.c b/traffic-mirroring/mirroring_ingress_kern.c index 04a1e2e..d3c1fc2 100644 --- a/traffic-mirroring/mirroring_ingress_kern.c +++ b/traffic-mirroring/mirroring_ingress_kern.c @@ -127,7 +127,8 @@ static __always_inline int ingress_redirect(struct __sk_buff *skb) void *data_end = (void *)(long)skb->data_end; const int l3_off = ETH_HLEN; // IP header offset - const int l4_off = l3_off + sizeof(struct iphdr); // TCP header offset + struct iphdr *iph = (struct iphdr *)(data + l3_off); + const int l4_off = l3_off + (iph->ihl * 4); // TCP header offset // TCP header offset struct ethhdr *eth = data; int l7_off; @@ -141,10 +142,11 @@ static __always_inline int ingress_redirect(struct __sk_buff *skb) return TC_ACT_OK; } - if (data + l4_off > data_end) { + /* Validating IP Header */ + if ((iph->ihl < 5 || iph->ihl > 15) || + (data + l4_off > data_end)) { return TC_ACT_OK; // Not our packet, handover to kernel } - struct iphdr *iph = (struct iphdr *)(data + l3_off); if (iph->protocol == IPPROTO_TCP) { l7_off = l4_off + sizeof(struct tcphdr); // L7 (e.g. HTTP) header offset