From f9dcdc7fefcab5ec9b15b0f3c87dfebef37ecaa3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 8 May 2018 09:40:43 +0200 Subject: kernel: mark source kernel for netfilter backports MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This helps keeping track on patches & adding new kernels in the future. Signed-off-by: Rafał Miłecki --- ...emove-defensive-check-on-malformed-packet.patch | 302 +++++++++++++++++++++ 1 file changed, 302 insertions(+) create mode 100644 target/linux/generic/backport-4.14/313-v4.16-netfilter-remove-defensive-check-on-malformed-packet.patch (limited to 'target/linux/generic/backport-4.14/313-v4.16-netfilter-remove-defensive-check-on-malformed-packet.patch') diff --git a/target/linux/generic/backport-4.14/313-v4.16-netfilter-remove-defensive-check-on-malformed-packet.patch b/target/linux/generic/backport-4.14/313-v4.16-netfilter-remove-defensive-check-on-malformed-packet.patch new file mode 100644 index 0000000000..5e56d0dc49 --- /dev/null +++ b/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 +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 +--- + +--- 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, -- cgit v1.2.3