netfilter: remove defensive check on malformed packets from raw sockets
authorPablo Neira Ayuso <pablo@netfilter.org>
Sat, 30 Dec 2017 21:41:46 +0000 (22:41 +0100)
committerPablo Neira Ayuso <pablo@netfilter.org>
Mon, 8 Jan 2018 17:11:04 +0000 (18:11 +0100)
Users cannot forge malformed IPv4/IPv6 headers via raw sockets that they
can inject into the stack. Specifically, not for IPv4 since 55888dfb6ba7
("AF_RAW: Augment raw_send_hdrinc to expand skb to fit iphdr->ihl
(v2)"). IPv6 raw sockets also ensure that packets have a well-formed
IPv6 header available in the skbuff.

At quick glance, br_netfilter also validates layer 3 headers and it
drops malformed both IPv4 and IPv6 packets.

Therefore, let's remove this defensive check all over the place.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
13 files changed:
net/ipv4/netfilter/iptable_filter.c
net/ipv4/netfilter/iptable_mangle.c
net/ipv4/netfilter/iptable_raw.c
net/ipv4/netfilter/iptable_security.c
net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
net/ipv4/netfilter/nf_nat_l3proto_ipv4.c
net/ipv4/netfilter/nf_tables_ipv4.c
net/ipv4/netfilter/nft_chain_route_ipv4.c
net/ipv6/netfilter/ip6table_mangle.c
net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
net/ipv6/netfilter/nf_nat_l3proto_ipv6.c
net/ipv6/netfilter/nf_tables_ipv6.c
net/netfilter/nf_tables_inet.c

index 7667f223d7f8c12321537919dbc5260c0813e474..9ac92ea7b93c2798d6220f66995e354217cc2a60 100644 (file)
@@ -38,12 +38,6 @@ static unsigned int
 iptable_filter_hook(void *priv, struct sk_buff *skb,
                    const struct nf_hook_state *state)
 {
-       if (state->hook == NF_INET_LOCAL_OUT &&
-           (skb->len < sizeof(struct iphdr) ||
-            ip_hdrlen(skb) < sizeof(struct iphdr)))
-               /* root is playing with raw sockets. */
-               return NF_ACCEPT;
-
        return ipt_do_table(skb, state, state->net->ipv4.iptable_filter);
 }
 
index aebdb337fd7ed2f3ad9ba5b8d30e6d59ff3aa8fc..dea138ca892543cbc560f56cb6aedc7aa93336f2 100644 (file)
@@ -49,11 +49,6 @@ ipt_mangle_out(struct sk_buff *skb, const struct nf_hook_state *state)
        u_int32_t mark;
        int err;
 
-       /* root is playing with raw sockets. */
-       if (skb->len < sizeof(struct iphdr) ||
-           ip_hdrlen(skb) < sizeof(struct iphdr))
-               return NF_ACCEPT;
-
        /* Save things which could affect route */
        mark = skb->mark;
        iph = ip_hdr(skb);
index 2642ecd2645c4887f9f4013f37ed7ac4fcbcbcd0..a869d1fea7d9bf441b259167191510b553cbe95a 100644 (file)
@@ -26,12 +26,6 @@ static unsigned int
 iptable_raw_hook(void *priv, struct sk_buff *skb,
                 const struct nf_hook_state *state)
 {
-       if (state->hook == NF_INET_LOCAL_OUT &&
-           (skb->len < sizeof(struct iphdr) ||
-            ip_hdrlen(skb) < sizeof(struct iphdr)))
-               /* root is playing with raw sockets. */
-               return NF_ACCEPT;
-
        return ipt_do_table(skb, state, state->net->ipv4.iptable_raw);
 }
 
index ff226596e4b5e3d504d88700ccb5651c1be0799d..e5379fe57b64184c9c5f3340c268ff968ed1131e 100644 (file)
@@ -43,12 +43,6 @@ static unsigned int
 iptable_security_hook(void *priv, struct sk_buff *skb,
                      const struct nf_hook_state *state)
 {
-       if (state->hook == NF_INET_LOCAL_OUT &&
-           (skb->len < sizeof(struct iphdr) ||
-            ip_hdrlen(skb) < sizeof(struct iphdr)))
-               /* Somebody is playing with raw sockets. */
-               return NF_ACCEPT;
-
        return ipt_do_table(skb, state, state->net->ipv4.iptable_security);
 }
 
index bb2c868a562100ec5367709aec9b0f6bff84edd3..de213a397ea897eefae022254ec01229fa3c9647 100644 (file)
@@ -154,11 +154,6 @@ static unsigned int ipv4_conntrack_local(void *priv,
                                         struct sk_buff *skb,
                                         const struct nf_hook_state *state)
 {
-       /* root is playing with raw sockets. */
-       if (skb->len < sizeof(struct iphdr) ||
-           ip_hdrlen(skb) < sizeof(struct iphdr))
-               return NF_ACCEPT;
-
        if (ip_is_fragment(ip_hdr(skb))) /* IP_NODEFRAG setsockopt set */
                return NF_ACCEPT;
 
index 0443ca4120b09ce248df7e63dbdb4958901f17de..f7ff6a364d7bcd556645b20f4aae74093620290b 100644 (file)
@@ -356,11 +356,6 @@ nf_nat_ipv4_out(void *priv, struct sk_buff *skb,
 #endif
        unsigned int ret;
 
-       /* root is playing with raw sockets. */
-       if (skb->len < sizeof(struct iphdr) ||
-           ip_hdrlen(skb) < sizeof(struct iphdr))
-               return NF_ACCEPT;
-
        ret = nf_nat_ipv4_fn(priv, skb, state, do_chain);
 #ifdef CONFIG_XFRM
        if (ret != NF_DROP && ret != NF_STOLEN &&
@@ -396,11 +391,6 @@ nf_nat_ipv4_local_fn(void *priv, struct sk_buff *skb,
        unsigned int ret;
        int err;
 
-       /* root is playing with raw sockets. */
-       if (skb->len < sizeof(struct iphdr) ||
-           ip_hdrlen(skb) < sizeof(struct iphdr))
-               return NF_ACCEPT;
-
        ret = nf_nat_ipv4_fn(priv, skb, state, do_chain);
        if (ret != NF_DROP && ret != NF_STOLEN &&
            (ct = nf_ct_get(skb, &ctinfo)) != NULL) {
index 8aeb15c2b9b21046520cb067d46fd41adcbfe6b0..f4675253f1e64102129077f86b347b9b78c6a606 100644 (file)
@@ -30,21 +30,6 @@ static unsigned int nft_do_chain_ipv4(void *priv,
        return nft_do_chain(&pkt, priv);
 }
 
-static unsigned int nft_ipv4_output(void *priv,
-                                   struct sk_buff *skb,
-                                   const struct nf_hook_state *state)
-{
-       if (unlikely(skb->len < sizeof(struct iphdr) ||
-                    ip_hdr(skb)->ihl < sizeof(struct iphdr) / 4)) {
-               if (net_ratelimit())
-                       pr_info("nf_tables_ipv4: ignoring short SOCK_RAW "
-                               "packet\n");
-               return NF_ACCEPT;
-       }
-
-       return nft_do_chain_ipv4(priv, skb, state);
-}
-
 static struct nft_af_info nft_af_ipv4 __read_mostly = {
        .family         = NFPROTO_IPV4,
        .nhooks         = NF_INET_NUMHOOKS,
@@ -91,7 +76,7 @@ static const struct nf_chain_type filter_ipv4 = {
                          (1 << NF_INET_POST_ROUTING),
        .hooks          = {
                [NF_INET_LOCAL_IN]      = nft_do_chain_ipv4,
-               [NF_INET_LOCAL_OUT]     = nft_ipv4_output,
+               [NF_INET_LOCAL_OUT]     = nft_do_chain_ipv4,
                [NF_INET_FORWARD]       = nft_do_chain_ipv4,
                [NF_INET_PRE_ROUTING]   = nft_do_chain_ipv4,
                [NF_INET_POST_ROUTING]  = nft_do_chain_ipv4,
index fb3d49fb62fe697a892332408086e42f43b77ff2..d965c225b9f621a54106db1828fdad692224c1c6 100644 (file)
@@ -33,11 +33,6 @@ static unsigned int nf_route_table_hook(void *priv,
        const struct iphdr *iph;
        int err;
 
-       /* root is playing with raw sockets. */
-       if (skb->len < sizeof(struct iphdr) ||
-           ip_hdrlen(skb) < sizeof(struct iphdr))
-               return NF_ACCEPT;
-
        nft_set_pktinfo(&pkt, skb, state);
        nft_set_pktinfo_ipv4(&pkt, skb);
 
index 2b1a9dcdbcb3d08e0fe681065efc24748a63bd7a..b0524b18c4fb3b64f941ea2531c3e0ccba800ba7 100644 (file)
@@ -42,14 +42,6 @@ ip6t_mangle_out(struct sk_buff *skb, const struct nf_hook_state *state)
        u_int8_t hop_limit;
        u_int32_t flowlabel, mark;
        int err;
-#if 0
-       /* root is playing with raw sockets. */
-       if (skb->len < sizeof(struct iphdr) ||
-           ip_hdrlen(skb) < sizeof(struct iphdr)) {
-               net_warn_ratelimited("ip6t_hook: happy cracking\n");
-               return NF_ACCEPT;
-       }
-#endif
 
        /* save source/dest address, mark, hoplimit, flowlabel, priority,  */
        memcpy(&saddr, &ipv6_hdr(skb)->saddr, sizeof(saddr));
index 7340ca7cc362f59c787f0b7b47eed0f2dec8c3a0..11a313fd9273dc72b35828a651a9571d5a7b57b0 100644 (file)
@@ -176,11 +176,6 @@ static unsigned int ipv6_conntrack_local(void *priv,
                                         struct sk_buff *skb,
                                         const struct nf_hook_state *state)
 {
-       /* root is playing with raw sockets. */
-       if (skb->len < sizeof(struct ipv6hdr)) {
-               net_notice_ratelimited("ipv6_conntrack_local: packet too short\n");
-               return NF_ACCEPT;
-       }
        return nf_conntrack_in(state->net, PF_INET6, state->hook, skb);
 }
 
index 1d2fb9267d6fa85179fd062c59eefbaf5eda491a..bed57ee65f7b10c5fb4ae9fc6f086d7bbfffa7af 100644 (file)
@@ -369,10 +369,6 @@ nf_nat_ipv6_out(void *priv, struct sk_buff *skb,
 #endif
        unsigned int ret;
 
-       /* root is playing with raw sockets. */
-       if (skb->len < sizeof(struct ipv6hdr))
-               return NF_ACCEPT;
-
        ret = nf_nat_ipv6_fn(priv, skb, state, do_chain);
 #ifdef CONFIG_XFRM
        if (ret != NF_DROP && ret != NF_STOLEN &&
@@ -408,10 +404,6 @@ nf_nat_ipv6_local_fn(void *priv, struct sk_buff *skb,
        unsigned int ret;
        int err;
 
-       /* root is playing with raw sockets. */
-       if (skb->len < sizeof(struct ipv6hdr))
-               return NF_ACCEPT;
-
        ret = nf_nat_ipv6_fn(priv, skb, state, do_chain);
        if (ret != NF_DROP && ret != NF_STOLEN &&
            (ct = nf_ct_get(skb, &ctinfo)) != NULL) {
index d4c9ef030e4f75eb05dd01b071f111f3ccf6850f..9cd45b964123512335eddfddb0f4ea513d6f84f4 100644 (file)
@@ -28,20 +28,6 @@ static unsigned int nft_do_chain_ipv6(void *priv,
        return nft_do_chain(&pkt, priv);
 }
 
-static unsigned int nft_ipv6_output(void *priv,
-                                   struct sk_buff *skb,
-                                   const struct nf_hook_state *state)
-{
-       if (unlikely(skb->len < sizeof(struct ipv6hdr))) {
-               if (net_ratelimit())
-                       pr_info("nf_tables_ipv6: ignoring short SOCK_RAW "
-                               "packet\n");
-               return NF_ACCEPT;
-       }
-
-       return nft_do_chain_ipv6(priv, skb, state);
-}
-
 static struct nft_af_info nft_af_ipv6 __read_mostly = {
        .family         = NFPROTO_IPV6,
        .nhooks         = NF_INET_NUMHOOKS,
@@ -88,7 +74,7 @@ static const struct nf_chain_type filter_ipv6 = {
                          (1 << NF_INET_POST_ROUTING),
        .hooks          = {
                [NF_INET_LOCAL_IN]      = nft_do_chain_ipv6,
-               [NF_INET_LOCAL_OUT]     = nft_ipv6_output,
+               [NF_INET_LOCAL_OUT]     = nft_do_chain_ipv6,
                [NF_INET_FORWARD]       = nft_do_chain_ipv6,
                [NF_INET_PRE_ROUTING]   = nft_do_chain_ipv6,
                [NF_INET_POST_ROUTING]  = nft_do_chain_ipv6,
index 313987e2b1fe5ea9c5fa330d65b2750517ccc422..58b9be7480bbd3d2a3454fa85270bc64c9383e53 100644 (file)
@@ -38,38 +38,6 @@ static unsigned int nft_do_chain_inet(void *priv, struct sk_buff *skb,
        return nft_do_chain(&pkt, priv);
 }
 
-static unsigned int nft_inet_output(void *priv, struct sk_buff *skb,
-                                   const struct nf_hook_state *state)
-{
-       struct nft_pktinfo pkt;
-
-       nft_set_pktinfo(&pkt, skb, state);
-
-       switch (state->pf) {
-       case NFPROTO_IPV4:
-               if (unlikely(skb->len < sizeof(struct iphdr) ||
-                            ip_hdr(skb)->ihl < sizeof(struct iphdr) / 4)) {
-                       if (net_ratelimit())
-                               pr_info("ignoring short SOCK_RAW packet\n");
-                       return NF_ACCEPT;
-               }
-               nft_set_pktinfo_ipv4(&pkt, skb);
-               break;
-       case NFPROTO_IPV6:
-               if (unlikely(skb->len < sizeof(struct ipv6hdr))) {
-                       if (net_ratelimit())
-                               pr_info("ignoring short SOCK_RAW packet\n");
-                       return NF_ACCEPT;
-               }
-               nft_set_pktinfo_ipv6(&pkt, skb);
-               break;
-       default:
-               break;
-       }
-
-       return nft_do_chain(&pkt, priv);
-}
-
 static struct nft_af_info nft_af_inet __read_mostly = {
        .family         = NFPROTO_INET,
        .nhooks         = NF_INET_NUMHOOKS,
@@ -116,7 +84,7 @@ static const struct nf_chain_type filter_inet = {
                          (1 << NF_INET_POST_ROUTING),
        .hooks          = {
                [NF_INET_LOCAL_IN]      = nft_do_chain_inet,
-               [NF_INET_LOCAL_OUT]     = nft_inet_output,
+               [NF_INET_LOCAL_OUT]     = nft_do_chain_inet,
                [NF_INET_FORWARD]       = nft_do_chain_inet,
                [NF_INET_PRE_ROUTING]   = nft_do_chain_inet,
                [NF_INET_POST_ROUTING]  = nft_do_chain_inet,