Commit a7f87b47 authored by Pablo Neira Ayuso's avatar Pablo Neira Ayuso

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 55888dfb
("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: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent f6931f5f
...@@ -38,12 +38,6 @@ static unsigned int ...@@ -38,12 +38,6 @@ static unsigned int
iptable_filter_hook(void *priv, struct sk_buff *skb, iptable_filter_hook(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state) 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); return ipt_do_table(skb, state, state->net->ipv4.iptable_filter);
} }
......
...@@ -49,11 +49,6 @@ ipt_mangle_out(struct sk_buff *skb, const struct nf_hook_state *state) ...@@ -49,11 +49,6 @@ ipt_mangle_out(struct sk_buff *skb, const struct nf_hook_state *state)
u_int32_t mark; u_int32_t mark;
int err; 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 */ /* Save things which could affect route */
mark = skb->mark; mark = skb->mark;
iph = ip_hdr(skb); iph = ip_hdr(skb);
......
...@@ -26,12 +26,6 @@ static unsigned int ...@@ -26,12 +26,6 @@ static unsigned int
iptable_raw_hook(void *priv, struct sk_buff *skb, iptable_raw_hook(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state) 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); return ipt_do_table(skb, state, state->net->ipv4.iptable_raw);
} }
......
...@@ -43,12 +43,6 @@ static unsigned int ...@@ -43,12 +43,6 @@ static unsigned int
iptable_security_hook(void *priv, struct sk_buff *skb, iptable_security_hook(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state) 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); return ipt_do_table(skb, state, state->net->ipv4.iptable_security);
} }
......
...@@ -154,11 +154,6 @@ static unsigned int ipv4_conntrack_local(void *priv, ...@@ -154,11 +154,6 @@ static unsigned int ipv4_conntrack_local(void *priv,
struct sk_buff *skb, struct sk_buff *skb,
const struct nf_hook_state *state) 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 */ if (ip_is_fragment(ip_hdr(skb))) /* IP_NODEFRAG setsockopt set */
return NF_ACCEPT; return NF_ACCEPT;
......
...@@ -356,11 +356,6 @@ nf_nat_ipv4_out(void *priv, struct sk_buff *skb, ...@@ -356,11 +356,6 @@ nf_nat_ipv4_out(void *priv, struct sk_buff *skb,
#endif #endif
unsigned int ret; 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); ret = nf_nat_ipv4_fn(priv, skb, state, do_chain);
#ifdef CONFIG_XFRM #ifdef CONFIG_XFRM
if (ret != NF_DROP && ret != NF_STOLEN && if (ret != NF_DROP && ret != NF_STOLEN &&
...@@ -396,11 +391,6 @@ nf_nat_ipv4_local_fn(void *priv, struct sk_buff *skb, ...@@ -396,11 +391,6 @@ nf_nat_ipv4_local_fn(void *priv, struct sk_buff *skb,
unsigned int ret; unsigned int ret;
int err; 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); ret = nf_nat_ipv4_fn(priv, skb, state, do_chain);
if (ret != NF_DROP && ret != NF_STOLEN && if (ret != NF_DROP && ret != NF_STOLEN &&
(ct = nf_ct_get(skb, &ctinfo)) != NULL) { (ct = nf_ct_get(skb, &ctinfo)) != NULL) {
......
...@@ -30,21 +30,6 @@ static unsigned int nft_do_chain_ipv4(void *priv, ...@@ -30,21 +30,6 @@ static unsigned int nft_do_chain_ipv4(void *priv,
return nft_do_chain(&pkt, 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 = { static struct nft_af_info nft_af_ipv4 __read_mostly = {
.family = NFPROTO_IPV4, .family = NFPROTO_IPV4,
.nhooks = NF_INET_NUMHOOKS, .nhooks = NF_INET_NUMHOOKS,
...@@ -91,7 +76,7 @@ static const struct nf_chain_type filter_ipv4 = { ...@@ -91,7 +76,7 @@ static const struct nf_chain_type filter_ipv4 = {
(1 << NF_INET_POST_ROUTING), (1 << NF_INET_POST_ROUTING),
.hooks = { .hooks = {
[NF_INET_LOCAL_IN] = nft_do_chain_ipv4, [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_FORWARD] = nft_do_chain_ipv4,
[NF_INET_PRE_ROUTING] = nft_do_chain_ipv4, [NF_INET_PRE_ROUTING] = nft_do_chain_ipv4,
[NF_INET_POST_ROUTING] = nft_do_chain_ipv4, [NF_INET_POST_ROUTING] = nft_do_chain_ipv4,
......
...@@ -33,11 +33,6 @@ static unsigned int nf_route_table_hook(void *priv, ...@@ -33,11 +33,6 @@ static unsigned int nf_route_table_hook(void *priv,
const struct iphdr *iph; const struct iphdr *iph;
int err; 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(&pkt, skb, state);
nft_set_pktinfo_ipv4(&pkt, skb); nft_set_pktinfo_ipv4(&pkt, skb);
......
...@@ -42,14 +42,6 @@ ip6t_mangle_out(struct sk_buff *skb, const struct nf_hook_state *state) ...@@ -42,14 +42,6 @@ ip6t_mangle_out(struct sk_buff *skb, const struct nf_hook_state *state)
u_int8_t hop_limit; u_int8_t hop_limit;
u_int32_t flowlabel, mark; u_int32_t flowlabel, mark;
int err; 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, */ /* save source/dest address, mark, hoplimit, flowlabel, priority, */
memcpy(&saddr, &ipv6_hdr(skb)->saddr, sizeof(saddr)); memcpy(&saddr, &ipv6_hdr(skb)->saddr, sizeof(saddr));
......
...@@ -176,11 +176,6 @@ static unsigned int ipv6_conntrack_local(void *priv, ...@@ -176,11 +176,6 @@ static unsigned int ipv6_conntrack_local(void *priv,
struct sk_buff *skb, struct sk_buff *skb,
const struct nf_hook_state *state) 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); return nf_conntrack_in(state->net, PF_INET6, state->hook, skb);
} }
......
...@@ -369,10 +369,6 @@ nf_nat_ipv6_out(void *priv, struct sk_buff *skb, ...@@ -369,10 +369,6 @@ nf_nat_ipv6_out(void *priv, struct sk_buff *skb,
#endif #endif
unsigned int ret; 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); ret = nf_nat_ipv6_fn(priv, skb, state, do_chain);
#ifdef CONFIG_XFRM #ifdef CONFIG_XFRM
if (ret != NF_DROP && ret != NF_STOLEN && if (ret != NF_DROP && ret != NF_STOLEN &&
...@@ -408,10 +404,6 @@ nf_nat_ipv6_local_fn(void *priv, struct sk_buff *skb, ...@@ -408,10 +404,6 @@ nf_nat_ipv6_local_fn(void *priv, struct sk_buff *skb,
unsigned int ret; unsigned int ret;
int err; 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); ret = nf_nat_ipv6_fn(priv, skb, state, do_chain);
if (ret != NF_DROP && ret != NF_STOLEN && if (ret != NF_DROP && ret != NF_STOLEN &&
(ct = nf_ct_get(skb, &ctinfo)) != NULL) { (ct = nf_ct_get(skb, &ctinfo)) != NULL) {
......
...@@ -28,20 +28,6 @@ static unsigned int nft_do_chain_ipv6(void *priv, ...@@ -28,20 +28,6 @@ static unsigned int nft_do_chain_ipv6(void *priv,
return nft_do_chain(&pkt, 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 = { static struct nft_af_info nft_af_ipv6 __read_mostly = {
.family = NFPROTO_IPV6, .family = NFPROTO_IPV6,
.nhooks = NF_INET_NUMHOOKS, .nhooks = NF_INET_NUMHOOKS,
...@@ -88,7 +74,7 @@ static const struct nf_chain_type filter_ipv6 = { ...@@ -88,7 +74,7 @@ static const struct nf_chain_type filter_ipv6 = {
(1 << NF_INET_POST_ROUTING), (1 << NF_INET_POST_ROUTING),
.hooks = { .hooks = {
[NF_INET_LOCAL_IN] = nft_do_chain_ipv6, [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_FORWARD] = nft_do_chain_ipv6,
[NF_INET_PRE_ROUTING] = nft_do_chain_ipv6, [NF_INET_PRE_ROUTING] = nft_do_chain_ipv6,
[NF_INET_POST_ROUTING] = nft_do_chain_ipv6, [NF_INET_POST_ROUTING] = nft_do_chain_ipv6,
......
...@@ -38,38 +38,6 @@ static unsigned int nft_do_chain_inet(void *priv, struct sk_buff *skb, ...@@ -38,38 +38,6 @@ static unsigned int nft_do_chain_inet(void *priv, struct sk_buff *skb,
return nft_do_chain(&pkt, priv); 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 = { static struct nft_af_info nft_af_inet __read_mostly = {
.family = NFPROTO_INET, .family = NFPROTO_INET,
.nhooks = NF_INET_NUMHOOKS, .nhooks = NF_INET_NUMHOOKS,
...@@ -116,7 +84,7 @@ static const struct nf_chain_type filter_inet = { ...@@ -116,7 +84,7 @@ static const struct nf_chain_type filter_inet = {
(1 << NF_INET_POST_ROUTING), (1 << NF_INET_POST_ROUTING),
.hooks = { .hooks = {
[NF_INET_LOCAL_IN] = nft_do_chain_inet, [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_FORWARD] = nft_do_chain_inet,
[NF_INET_PRE_ROUTING] = nft_do_chain_inet, [NF_INET_PRE_ROUTING] = nft_do_chain_inet,
[NF_INET_POST_ROUTING] = nft_do_chain_inet, [NF_INET_POST_ROUTING] = nft_do_chain_inet,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment