Convert the sites that pull and do version and ihl checks on the ipv4
header and validate the packet transport offset to use ip4_parse.

Sites that validate a read-only copy instead of pulling - the nft
and nft_inner header_pointer validators, ip_check_defrag()'s
skb_copy_bits, the flow dissector - stay open-coded for now.

Signed-off-by: Michael S. Tsirkin <[email protected]>
Assisted-by: LLM
---
 net/bridge/br_netfilter_hooks.c     | 15 +++++----------
 net/ipv4/ip_input.c                 | 13 +++++--------
 net/ipv4/netfilter/nf_reject_ipv4.c | 13 +++++--------
 3 files changed, 15 insertions(+), 26 deletions(-)

diff --git a/net/bridge/br_netfilter_hooks.c b/net/bridge/br_netfilter_hooks.c
index 0a394e5f43916..e89da0e415426 100644
--- a/net/bridge/br_netfilter_hooks.c
+++ b/net/bridge/br_netfilter_hooks.c
@@ -206,18 +206,13 @@ static inline void 
nf_bridge_pull_encap_header_rcsum(struct sk_buff *skb)
 static int br_validate_ipv4(struct net *net, struct sk_buff *skb)
 {
        const struct iphdr *iph;
-       u32 len;
+       u32 len, thoff;
 
-       if (!pskb_may_pull(skb, sizeof(struct iphdr)))
+       iph = ip4_parse(skb, 0, &thoff);
+       if (!iph)
                goto inhdr_error;
 
-       iph = ip_hdr(skb);
-
-       /* Basic sanity checks */
-       if (iph->ihl < 5 || iph->version != 4)
-               goto inhdr_error;
-
-       if (!pskb_may_pull(skb, iph->ihl*4))
+       if (!pskb_may_pull(skb, thoff))
                goto inhdr_error;
 
        iph = ip_hdr(skb);
@@ -228,7 +223,7 @@ static int br_validate_ipv4(struct net *net, struct sk_buff 
*skb)
        if (skb->len < len) {
                __IP_INC_STATS(net, IPSTATS_MIB_INTRUNCATEDPKTS);
                goto drop;
-       } else if (len < (iph->ihl*4))
+       } else if (len < thoff)
                goto inhdr_error;
 
        if (pskb_trim_rcsum(skb, len)) {
diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c
index 9860178752b8c..5adf01763e857 100644
--- a/net/ipv4/ip_input.c
+++ b/net/ipv4/ip_input.c
@@ -500,7 +500,7 @@ static struct sk_buff *ip_rcv_core(struct sk_buff *skb, 
struct net *net)
 {
        const struct iphdr *iph;
        int drop_reason;
-       u32 len;
+       u32 len, thoff;
 
        /* When the interface is in promisc. mode, drop all the crap
         * that it receives, do not try to analyse it.
@@ -520,10 +520,6 @@ static struct sk_buff *ip_rcv_core(struct sk_buff *skb, 
struct net *net)
        }
 
        drop_reason = SKB_DROP_REASON_NOT_SPECIFIED;
-       if (!pskb_may_pull(skb, sizeof(struct iphdr)))
-               goto inhdr_error;
-
-       iph = ip_hdr(skb);
 
        /*
         *      RFC1122: 3.2.1.2 MUST silently discard any IP frame that fails 
the checksum.
@@ -536,7 +532,8 @@ static struct sk_buff *ip_rcv_core(struct sk_buff *skb, 
struct net *net)
         *      4.      Doesn't have a bogus length
         */
 
-       if (iph->ihl < 5 || iph->version != 4)
+       iph = ip4_parse(skb, 0, &thoff);
+       if (!iph)
                goto inhdr_error;
 
        BUILD_BUG_ON(IPSTATS_MIB_ECT1PKTS != IPSTATS_MIB_NOECTPKTS + 
INET_ECN_ECT_1);
@@ -546,7 +543,7 @@ static struct sk_buff *ip_rcv_core(struct sk_buff *skb, 
struct net *net)
                       IPSTATS_MIB_NOECTPKTS + (iph->tos & INET_ECN_MASK),
                       max_t(unsigned short, 1, skb_shinfo(skb)->gso_segs));
 
-       if (!pskb_may_pull(skb, iph->ihl*4))
+       if (!pskb_may_pull(skb, thoff))
                goto inhdr_error;
 
        iph = ip_hdr(skb);
@@ -559,7 +556,7 @@ static struct sk_buff *ip_rcv_core(struct sk_buff *skb, 
struct net *net)
                drop_reason = SKB_DROP_REASON_PKT_TOO_SMALL;
                __IP_INC_STATS(net, IPSTATS_MIB_INTRUNCATEDPKTS);
                goto drop;
-       } else if (len < (iph->ihl*4))
+       } else if (len < thoff)
                goto inhdr_error;
 
        /* Our transport medium may have padded the buffer out. Now we know it
diff --git a/net/ipv4/netfilter/nf_reject_ipv4.c 
b/net/ipv4/netfilter/nf_reject_ipv4.c
index 59ec465a9df98..42d639854ddf1 100644
--- a/net/ipv4/netfilter/nf_reject_ipv4.c
+++ b/net/ipv4/netfilter/nf_reject_ipv4.c
@@ -25,22 +25,19 @@ nf_reject_ip_tcphdr_get(struct sk_buff *oldskb,
 static int nf_reject_iphdr_validate(struct sk_buff *skb)
 {
        struct iphdr *iph;
-       u32 len;
+       u32 len, thoff;
 
-       if (!pskb_may_pull(skb, sizeof(struct iphdr)))
-               return 0;
-
-       iph = ip_hdr(skb);
-       if (iph->ihl < 5 || iph->version != 4)
+       iph = ip4_parse(skb, 0, &thoff);
+       if (!iph)
                return 0;
 
        len = ntohs(iph->tot_len);
        if (skb->len < len)
                return 0;
-       else if (len < (iph->ihl*4))
+       else if (len < thoff)
                return 0;
 
-       if (!pskb_may_pull(skb, iph->ihl*4))
+       if (!pskb_may_pull(skb, thoff))
                return 0;
 
        return 1;
-- 
MST


Reply via email to