From 02451e56d46469329eae738068e10ed971c6363b Mon Sep 17 00:00:00 2001 From: evershalik Date: Tue, 27 Jun 2023 04:53:41 +0530 Subject: [PATCH] l4-offset fixing Signed-off-by: evershalik --- connection-limit/connection_limit_kern.c | 28 ++++++++++++++------ ipfix-flow-exporter/bpf_ipfix_egress_kern.c | 28 +++++++++++++------- ipfix-flow-exporter/bpf_ipfix_ingress_kern.c | 28 +++++++++++++------- ratelimiting/ratelimiting_kern.c | 18 ++++++++----- 4 files changed, 68 insertions(+), 34 deletions(-) diff --git a/connection-limit/connection_limit_kern.c b/connection-limit/connection_limit_kern.c index ff060d7..217c66f 100644 --- a/connection-limit/connection_limit_kern.c +++ b/connection-limit/connection_limit_kern.c @@ -269,22 +269,34 @@ int _xdp_limit_conn(struct xdp_md *ctx) void *data_end = (void *)(long)ctx->data_end; void *data = (void *)(long)ctx->data; - /* Check if its valid ethernet packet */ - if (data + sizeof(struct ethhdr)+ 1 > data_end) + struct ethhdr *eth = data; + + /* Check if it is a valid ethernet packet */ + if (data + sizeof(*eth)+ 1 > data_end) return XDP_PASS; + + uint16_t eth_type = eth->h_proto; - /* Check if its valid ip packet */ - struct iphdr *iph = (struct iphdr *)(data + sizeof(struct ethhdr)); - if (iph + 1 > data_end) + /* Ignore other than IPV4 packets */ + if (ntohs(eth_type) != ETH_P_IP) + return XDP_PASS; + + struct iphdr *iph = (struct iphdr *)(data + sizeof(*eth)); + __u8 l4_offset = iph->ihl * 4; // ipv4 header length + + /* Check if it is a valid IPV4 packet */ + if (iph->ihl < 5 || ((unsigned char *)iph + l4_offset) > 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); - if (tcph + 1 > data_end) + struct tcphdr *tcph = (struct tcphdr *)((unsigned char *)iph + l4_offset); + __u16 data_offset = tcph->doff * 4; // tcp header length + + /* Check if it is a valid TCP packet */ + if (tcph->doff < 5 || ((unsigned char *)tcph + data_offset) > data_end) return XDP_PASS; /* Ignore other than TCP-SYN packets */ diff --git a/ipfix-flow-exporter/bpf_ipfix_egress_kern.c b/ipfix-flow-exporter/bpf_ipfix_egress_kern.c index fefc16f..ef6ca7f 100755 --- a/ipfix-flow-exporter/bpf_ipfix_egress_kern.c +++ b/ipfix-flow-exporter/bpf_ipfix_egress_kern.c @@ -180,8 +180,8 @@ static void parse_icmp_type(void *icmp_data,void *data_end, u16 *icmp_type){ static void parse_port(void *trans_data, void *data_end, u8 proto, u32 *dport, u32 *sport, u16 *control_bit) { - struct udphdr *udph; - struct tcphdr *tcph; + struct udphdr *udph; // size = 8 bytes + struct tcphdr *tcph; // size = 20-60 bytes u32 dstport = 0; u32 srcport = 0; @@ -190,17 +190,20 @@ static void parse_port(void *trans_data, void *data_end, u8 proto, switch (proto) { case IPPROTO_UDP: udph = trans_data; - if (udph + 1 > data_end) { + + if (udph + 1 > data_end) return; - } + dstport = ntohs(udph->dest); srcport = ntohs(udph->source); break; case IPPROTO_TCP: tcph = trans_data; - if (tcph + 1 > data_end) { + u16 data_offset = tcph->doff * 4; + + if (tcph->doff < 5 || ((unsigned char *)tcph + data_offset) > data_end) return; - } + dstport = ntohs(tcph->dest); srcport = ntohs(tcph->source); if (tcph->syn & TCP_FLAGS) { controlbit = controlbit | TH_SYN; } @@ -249,13 +252,18 @@ void parse_ipv4(struct __sk_buff *skb, u64 l3_offset) u16 control_bit = 0; u16 icmp_type = 0; - if (iph + 1 > data_end) - return; + u8 l4_offset = iph->ihl * 4; // ipv4 header length + /* Check if it's a valid IPv4 packet */ + if (iph->ihl < 5 || ((unsigned char *)iph + l4_offset) > data_end) + return; + + void *thdr = ((unsigned char *)iph + l4_offset); // transport layer header + if(iph->protocol == ICMP) - parse_icmp_type(iph+1, data_end, &icmp_type); + parse_icmp_type(thdr, data_end, &icmp_type); - parse_port(iph+1, data_end, iph->protocol, &dport, &sport, &control_bit); + parse_port(thdr, 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 318d6ab..42fc5c1 100755 --- a/ipfix-flow-exporter/bpf_ipfix_ingress_kern.c +++ b/ipfix-flow-exporter/bpf_ipfix_ingress_kern.c @@ -178,8 +178,8 @@ static void parse_icmp_type(void *icmp_data,void *data_end, u16 *icmp_type){ static void parse_port(void *trans_data, void *data_end, u8 proto, u32 *dport, u32 *sport, u16 *control_bit) { - struct udphdr *udph; - struct tcphdr *tcph; + struct udphdr *udph; // size = 8 bytes + struct tcphdr *tcph; // size = 20-60 bytes u32 dstport = 0; u32 srcport = 0; @@ -188,17 +188,20 @@ static void parse_port(void *trans_data, void *data_end, u8 proto, switch (proto) { case IPPROTO_UDP: udph = trans_data; - if (udph + 1 > data_end) { + + if (udph + 1 > data_end) return; - } + dstport = ntohs(udph->dest); srcport = ntohs(udph->source); break; case IPPROTO_TCP: tcph = trans_data; - if (tcph + 1 > data_end) { + u16 data_offset = tcph->doff * 4; + + if (tcph->doff < 5 || ((unsigned char *)tcph + data_offset) > data_end) return; - } + dstport = ntohs(tcph->dest); srcport = ntohs(tcph->source); if (tcph->syn & TCP_FLAGS) { controlbit = controlbit | TH_SYN; } @@ -247,13 +250,18 @@ void parse_ipv4(struct __sk_buff *skb, u64 l3_offset) u16 control_bit = 0; u16 icmp_type = 0; - if (iph + 1 > data_end) - return; + u8 l4_offset = iph->ihl * 4; // ipv4 header length + /* Check if it is a valid IPv4 packet */ + if (iph->ihl < 5 || ((unsigned char *)iph + l4_offset) > data_end) + return; + + void *thdr = ((unsigned char *)iph + l4_offset); // transport layer header + if(iph->protocol == ICMP) - parse_icmp_type(iph+1, data_end, &icmp_type); + parse_icmp_type(thdr, data_end, &icmp_type); - parse_port(iph+1, data_end, iph->protocol, &dport, &sport, &control_bit); + parse_port(thdr, 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..6741926 100644 --- a/ratelimiting/ratelimiting_kern.c +++ b/ratelimiting/ratelimiting_kern.c @@ -93,22 +93,28 @@ static __always_inline int _xdp_ratelimit(struct xdp_md *ctx) /* Ignore other than ethernet packets */ uint16_t eth_type = eth->h_proto; + + /* Ignore other than IPV4 packets */ if (ntohs(eth_type) != ETH_P_IP) { return XDP_PASS; } - /* Ignore other than IP packets */ - struct iphdr *iph = data + sizeof(struct ethhdr); - if (iph + 1 > data_end) + struct iphdr *iph = (struct iphdr *)(data + sizeof(*eth)); + __u8 l4_offset = iph->ihl * 4; // ipv4 header length + + /* Check if it is a valid IPV4 packet */ + if (iph->ihl < 5 || ((unsigned char *)iph + l4_offset) > 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); - if (tcph + 1 > data_end) + struct tcphdr *tcph = (struct tcphdr *)((unsigned char *)iph + l4_offset); + __u16 data_offset = tcph->doff * 4; // tcp header length + + /* Check if it is a valid TCP packet */ + if (tcph->doff < 5 || ((unsigned char *)tcph + data_offset) > data_end) return XDP_PASS; /* Ignore other than TCP-SYN packets */