/branches/18.06.1/target/linux/generic/backport-4.14/313-v4.16-netfilter-remove-defensive-check-on-malformed-packet.patch |
@@ -0,0 +1,302 @@ |
From: Pablo Neira Ayuso <pablo@netfilter.org> |
Date: Sat, 30 Dec 2017 22:41:46 +0100 |
Subject: [PATCH] netfilter: remove defensive check on malformed packets from |
raw sockets |
|
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> |
--- |
|
--- a/net/ipv4/netfilter/iptable_filter.c |
+++ b/net/ipv4/netfilter/iptable_filter.c |
@@ -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); |
} |
|
--- a/net/ipv4/netfilter/iptable_mangle.c |
+++ b/net/ipv4/netfilter/iptable_mangle.c |
@@ -49,11 +49,6 @@ ipt_mangle_out(struct sk_buff *skb, cons |
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); |
--- a/net/ipv4/netfilter/iptable_raw.c |
+++ b/net/ipv4/netfilter/iptable_raw.c |
@@ -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); |
} |
|
--- a/net/ipv4/netfilter/iptable_security.c |
+++ b/net/ipv4/netfilter/iptable_security.c |
@@ -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); |
} |
|
--- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c |
+++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c |
@@ -154,11 +154,6 @@ static unsigned int ipv4_conntrack_local |
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 */ |
enum ip_conntrack_info ctinfo; |
struct nf_conn *tmpl; |
--- a/net/ipv4/netfilter/nf_nat_l3proto_ipv4.c |
+++ b/net/ipv4/netfilter/nf_nat_l3proto_ipv4.c |
@@ -355,11 +355,6 @@ nf_nat_ipv4_out(void *priv, struct sk_bu |
#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 && |
@@ -395,11 +390,6 @@ nf_nat_ipv4_local_fn(void *priv, struct |
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) { |
--- a/net/ipv4/netfilter/nf_tables_ipv4.c |
+++ b/net/ipv4/netfilter/nf_tables_ipv4.c |
@@ -30,21 +30,6 @@ static unsigned int nft_do_chain_ipv4(vo |
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 |
(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, |
--- a/net/ipv4/netfilter/nft_chain_route_ipv4.c |
+++ b/net/ipv4/netfilter/nft_chain_route_ipv4.c |
@@ -33,11 +33,6 @@ static unsigned int nf_route_table_hook( |
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); |
|
--- a/net/ipv6/netfilter/ip6table_mangle.c |
+++ b/net/ipv6/netfilter/ip6table_mangle.c |
@@ -42,14 +42,6 @@ ip6t_mangle_out(struct sk_buff *skb, con |
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)); |
--- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c |
+++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c |
@@ -176,11 +176,6 @@ static unsigned int ipv6_conntrack_local |
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); |
} |
|
--- a/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c |
+++ b/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c |
@@ -372,10 +372,6 @@ nf_nat_ipv6_out(void *priv, struct sk_bu |
#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 && |
@@ -411,10 +407,6 @@ nf_nat_ipv6_local_fn(void *priv, struct |
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) { |
--- a/net/ipv6/netfilter/nf_tables_ipv6.c |
+++ b/net/ipv6/netfilter/nf_tables_ipv6.c |
@@ -28,20 +28,6 @@ static unsigned int nft_do_chain_ipv6(vo |
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 |
(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, |
--- a/net/netfilter/nf_tables_inet.c |
+++ b/net/netfilter/nf_tables_inet.c |
@@ -38,38 +38,6 @@ static unsigned int nft_do_chain_inet(vo |
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 |
(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, |