Commit 29421198 authored by Liping Zhang's avatar Liping Zhang Committed by Pablo Neira Ayuso

netfilter: ipv4: fix NULL dereference

Commit fa50d974 ("ipv4: Namespaceify ip_default_ttl sysctl knob")
use sock_net(skb->sk) to get the net namespace, but we can't assume
that sk_buff->sk is always exist, so when it is NULL, oops will happen.
Signed-off-by: default avatarLiping Zhang <liping.zhang@spreadtrum.com>
Reviewed-by: default avatarNikolay Borisov <kernel@kyup.com>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent b301f253
...@@ -40,7 +40,8 @@ static void nft_reject_br_push_etherhdr(struct sk_buff *oldskb, ...@@ -40,7 +40,8 @@ static void nft_reject_br_push_etherhdr(struct sk_buff *oldskb,
/* We cannot use oldskb->dev, it can be either bridge device (NF_BRIDGE INPUT) /* We cannot use oldskb->dev, it can be either bridge device (NF_BRIDGE INPUT)
* or the bridge port (NF_BRIDGE PREROUTING). * or the bridge port (NF_BRIDGE PREROUTING).
*/ */
static void nft_reject_br_send_v4_tcp_reset(struct sk_buff *oldskb, static void nft_reject_br_send_v4_tcp_reset(struct net *net,
struct sk_buff *oldskb,
const struct net_device *dev, const struct net_device *dev,
int hook) int hook)
{ {
...@@ -48,7 +49,6 @@ static void nft_reject_br_send_v4_tcp_reset(struct sk_buff *oldskb, ...@@ -48,7 +49,6 @@ static void nft_reject_br_send_v4_tcp_reset(struct sk_buff *oldskb,
struct iphdr *niph; struct iphdr *niph;
const struct tcphdr *oth; const struct tcphdr *oth;
struct tcphdr _oth; struct tcphdr _oth;
struct net *net = sock_net(oldskb->sk);
if (!nft_bridge_iphdr_validate(oldskb)) if (!nft_bridge_iphdr_validate(oldskb))
return; return;
...@@ -75,7 +75,8 @@ static void nft_reject_br_send_v4_tcp_reset(struct sk_buff *oldskb, ...@@ -75,7 +75,8 @@ static void nft_reject_br_send_v4_tcp_reset(struct sk_buff *oldskb,
br_deliver(br_port_get_rcu(dev), nskb); br_deliver(br_port_get_rcu(dev), nskb);
} }
static void nft_reject_br_send_v4_unreach(struct sk_buff *oldskb, static void nft_reject_br_send_v4_unreach(struct net *net,
struct sk_buff *oldskb,
const struct net_device *dev, const struct net_device *dev,
int hook, u8 code) int hook, u8 code)
{ {
...@@ -86,7 +87,6 @@ static void nft_reject_br_send_v4_unreach(struct sk_buff *oldskb, ...@@ -86,7 +87,6 @@ static void nft_reject_br_send_v4_unreach(struct sk_buff *oldskb,
void *payload; void *payload;
__wsum csum; __wsum csum;
u8 proto; u8 proto;
struct net *net = sock_net(oldskb->sk);
if (oldskb->csum_bad || !nft_bridge_iphdr_validate(oldskb)) if (oldskb->csum_bad || !nft_bridge_iphdr_validate(oldskb))
return; return;
...@@ -273,17 +273,17 @@ static void nft_reject_bridge_eval(const struct nft_expr *expr, ...@@ -273,17 +273,17 @@ static void nft_reject_bridge_eval(const struct nft_expr *expr,
case htons(ETH_P_IP): case htons(ETH_P_IP):
switch (priv->type) { switch (priv->type) {
case NFT_REJECT_ICMP_UNREACH: case NFT_REJECT_ICMP_UNREACH:
nft_reject_br_send_v4_unreach(pkt->skb, pkt->in, nft_reject_br_send_v4_unreach(pkt->net, pkt->skb,
pkt->hook, pkt->in, pkt->hook,
priv->icmp_code); priv->icmp_code);
break; break;
case NFT_REJECT_TCP_RST: case NFT_REJECT_TCP_RST:
nft_reject_br_send_v4_tcp_reset(pkt->skb, pkt->in, nft_reject_br_send_v4_tcp_reset(pkt->net, pkt->skb,
pkt->hook); pkt->in, pkt->hook);
break; break;
case NFT_REJECT_ICMPX_UNREACH: case NFT_REJECT_ICMPX_UNREACH:
nft_reject_br_send_v4_unreach(pkt->skb, pkt->in, nft_reject_br_send_v4_unreach(pkt->net, pkt->skb,
pkt->hook, pkt->in, pkt->hook,
nft_reject_icmp_code(priv->icmp_code)); nft_reject_icmp_code(priv->icmp_code));
break; break;
} }
......
...@@ -18,10 +18,10 @@ ...@@ -18,10 +18,10 @@
#include <net/netfilter/nf_conntrack_synproxy.h> #include <net/netfilter/nf_conntrack_synproxy.h>
static struct iphdr * static struct iphdr *
synproxy_build_ip(struct sk_buff *skb, __be32 saddr, __be32 daddr) synproxy_build_ip(struct net *net, struct sk_buff *skb, __be32 saddr,
__be32 daddr)
{ {
struct iphdr *iph; struct iphdr *iph;
struct net *net = sock_net(skb->sk);
skb_reset_network_header(skb); skb_reset_network_header(skb);
iph = (struct iphdr *)skb_put(skb, sizeof(*iph)); iph = (struct iphdr *)skb_put(skb, sizeof(*iph));
...@@ -40,14 +40,12 @@ synproxy_build_ip(struct sk_buff *skb, __be32 saddr, __be32 daddr) ...@@ -40,14 +40,12 @@ synproxy_build_ip(struct sk_buff *skb, __be32 saddr, __be32 daddr)
} }
static void static void
synproxy_send_tcp(const struct synproxy_net *snet, synproxy_send_tcp(struct net *net,
const struct sk_buff *skb, struct sk_buff *nskb, const struct sk_buff *skb, struct sk_buff *nskb,
struct nf_conntrack *nfct, enum ip_conntrack_info ctinfo, struct nf_conntrack *nfct, enum ip_conntrack_info ctinfo,
struct iphdr *niph, struct tcphdr *nth, struct iphdr *niph, struct tcphdr *nth,
unsigned int tcp_hdr_size) unsigned int tcp_hdr_size)
{ {
struct net *net = nf_ct_net(snet->tmpl);
nth->check = ~tcp_v4_check(tcp_hdr_size, niph->saddr, niph->daddr, 0); nth->check = ~tcp_v4_check(tcp_hdr_size, niph->saddr, niph->daddr, 0);
nskb->ip_summed = CHECKSUM_PARTIAL; nskb->ip_summed = CHECKSUM_PARTIAL;
nskb->csum_start = (unsigned char *)nth - nskb->head; nskb->csum_start = (unsigned char *)nth - nskb->head;
...@@ -72,7 +70,7 @@ synproxy_send_tcp(const struct synproxy_net *snet, ...@@ -72,7 +70,7 @@ synproxy_send_tcp(const struct synproxy_net *snet,
} }
static void static void
synproxy_send_client_synack(const struct synproxy_net *snet, synproxy_send_client_synack(struct net *net,
const struct sk_buff *skb, const struct tcphdr *th, const struct sk_buff *skb, const struct tcphdr *th,
const struct synproxy_options *opts) const struct synproxy_options *opts)
{ {
...@@ -91,7 +89,7 @@ synproxy_send_client_synack(const struct synproxy_net *snet, ...@@ -91,7 +89,7 @@ synproxy_send_client_synack(const struct synproxy_net *snet,
return; return;
skb_reserve(nskb, MAX_TCP_HEADER); skb_reserve(nskb, MAX_TCP_HEADER);
niph = synproxy_build_ip(nskb, iph->daddr, iph->saddr); niph = synproxy_build_ip(net, nskb, iph->daddr, iph->saddr);
skb_reset_transport_header(nskb); skb_reset_transport_header(nskb);
nth = (struct tcphdr *)skb_put(nskb, tcp_hdr_size); nth = (struct tcphdr *)skb_put(nskb, tcp_hdr_size);
...@@ -109,15 +107,16 @@ synproxy_send_client_synack(const struct synproxy_net *snet, ...@@ -109,15 +107,16 @@ synproxy_send_client_synack(const struct synproxy_net *snet,
synproxy_build_options(nth, opts); synproxy_build_options(nth, opts);
synproxy_send_tcp(snet, skb, nskb, skb->nfct, IP_CT_ESTABLISHED_REPLY, synproxy_send_tcp(net, skb, nskb, skb->nfct, IP_CT_ESTABLISHED_REPLY,
niph, nth, tcp_hdr_size); niph, nth, tcp_hdr_size);
} }
static void static void
synproxy_send_server_syn(const struct synproxy_net *snet, synproxy_send_server_syn(struct net *net,
const struct sk_buff *skb, const struct tcphdr *th, const struct sk_buff *skb, const struct tcphdr *th,
const struct synproxy_options *opts, u32 recv_seq) const struct synproxy_options *opts, u32 recv_seq)
{ {
struct synproxy_net *snet = synproxy_pernet(net);
struct sk_buff *nskb; struct sk_buff *nskb;
struct iphdr *iph, *niph; struct iphdr *iph, *niph;
struct tcphdr *nth; struct tcphdr *nth;
...@@ -132,7 +131,7 @@ synproxy_send_server_syn(const struct synproxy_net *snet, ...@@ -132,7 +131,7 @@ synproxy_send_server_syn(const struct synproxy_net *snet,
return; return;
skb_reserve(nskb, MAX_TCP_HEADER); skb_reserve(nskb, MAX_TCP_HEADER);
niph = synproxy_build_ip(nskb, iph->saddr, iph->daddr); niph = synproxy_build_ip(net, nskb, iph->saddr, iph->daddr);
skb_reset_transport_header(nskb); skb_reset_transport_header(nskb);
nth = (struct tcphdr *)skb_put(nskb, tcp_hdr_size); nth = (struct tcphdr *)skb_put(nskb, tcp_hdr_size);
...@@ -153,12 +152,12 @@ synproxy_send_server_syn(const struct synproxy_net *snet, ...@@ -153,12 +152,12 @@ synproxy_send_server_syn(const struct synproxy_net *snet,
synproxy_build_options(nth, opts); synproxy_build_options(nth, opts);
synproxy_send_tcp(snet, skb, nskb, &snet->tmpl->ct_general, IP_CT_NEW, synproxy_send_tcp(net, skb, nskb, &snet->tmpl->ct_general, IP_CT_NEW,
niph, nth, tcp_hdr_size); niph, nth, tcp_hdr_size);
} }
static void static void
synproxy_send_server_ack(const struct synproxy_net *snet, synproxy_send_server_ack(struct net *net,
const struct ip_ct_tcp *state, const struct ip_ct_tcp *state,
const struct sk_buff *skb, const struct tcphdr *th, const struct sk_buff *skb, const struct tcphdr *th,
const struct synproxy_options *opts) const struct synproxy_options *opts)
...@@ -177,7 +176,7 @@ synproxy_send_server_ack(const struct synproxy_net *snet, ...@@ -177,7 +176,7 @@ synproxy_send_server_ack(const struct synproxy_net *snet,
return; return;
skb_reserve(nskb, MAX_TCP_HEADER); skb_reserve(nskb, MAX_TCP_HEADER);
niph = synproxy_build_ip(nskb, iph->daddr, iph->saddr); niph = synproxy_build_ip(net, nskb, iph->daddr, iph->saddr);
skb_reset_transport_header(nskb); skb_reset_transport_header(nskb);
nth = (struct tcphdr *)skb_put(nskb, tcp_hdr_size); nth = (struct tcphdr *)skb_put(nskb, tcp_hdr_size);
...@@ -193,11 +192,11 @@ synproxy_send_server_ack(const struct synproxy_net *snet, ...@@ -193,11 +192,11 @@ synproxy_send_server_ack(const struct synproxy_net *snet,
synproxy_build_options(nth, opts); synproxy_build_options(nth, opts);
synproxy_send_tcp(snet, skb, nskb, NULL, 0, niph, nth, tcp_hdr_size); synproxy_send_tcp(net, skb, nskb, NULL, 0, niph, nth, tcp_hdr_size);
} }
static void static void
synproxy_send_client_ack(const struct synproxy_net *snet, synproxy_send_client_ack(struct net *net,
const struct sk_buff *skb, const struct tcphdr *th, const struct sk_buff *skb, const struct tcphdr *th,
const struct synproxy_options *opts) const struct synproxy_options *opts)
{ {
...@@ -215,7 +214,7 @@ synproxy_send_client_ack(const struct synproxy_net *snet, ...@@ -215,7 +214,7 @@ synproxy_send_client_ack(const struct synproxy_net *snet,
return; return;
skb_reserve(nskb, MAX_TCP_HEADER); skb_reserve(nskb, MAX_TCP_HEADER);
niph = synproxy_build_ip(nskb, iph->saddr, iph->daddr); niph = synproxy_build_ip(net, nskb, iph->saddr, iph->daddr);
skb_reset_transport_header(nskb); skb_reset_transport_header(nskb);
nth = (struct tcphdr *)skb_put(nskb, tcp_hdr_size); nth = (struct tcphdr *)skb_put(nskb, tcp_hdr_size);
...@@ -231,15 +230,16 @@ synproxy_send_client_ack(const struct synproxy_net *snet, ...@@ -231,15 +230,16 @@ synproxy_send_client_ack(const struct synproxy_net *snet,
synproxy_build_options(nth, opts); synproxy_build_options(nth, opts);
synproxy_send_tcp(snet, skb, nskb, skb->nfct, IP_CT_ESTABLISHED_REPLY, synproxy_send_tcp(net, skb, nskb, skb->nfct, IP_CT_ESTABLISHED_REPLY,
niph, nth, tcp_hdr_size); niph, nth, tcp_hdr_size);
} }
static bool static bool
synproxy_recv_client_ack(const struct synproxy_net *snet, synproxy_recv_client_ack(struct net *net,
const struct sk_buff *skb, const struct tcphdr *th, const struct sk_buff *skb, const struct tcphdr *th,
struct synproxy_options *opts, u32 recv_seq) struct synproxy_options *opts, u32 recv_seq)
{ {
struct synproxy_net *snet = synproxy_pernet(net);
int mss; int mss;
mss = __cookie_v4_check(ip_hdr(skb), th, ntohl(th->ack_seq) - 1); mss = __cookie_v4_check(ip_hdr(skb), th, ntohl(th->ack_seq) - 1);
...@@ -255,7 +255,7 @@ synproxy_recv_client_ack(const struct synproxy_net *snet, ...@@ -255,7 +255,7 @@ synproxy_recv_client_ack(const struct synproxy_net *snet,
if (opts->options & XT_SYNPROXY_OPT_TIMESTAMP) if (opts->options & XT_SYNPROXY_OPT_TIMESTAMP)
synproxy_check_timestamp_cookie(opts); synproxy_check_timestamp_cookie(opts);
synproxy_send_server_syn(snet, skb, th, opts, recv_seq); synproxy_send_server_syn(net, skb, th, opts, recv_seq);
return true; return true;
} }
...@@ -263,7 +263,8 @@ static unsigned int ...@@ -263,7 +263,8 @@ static unsigned int
synproxy_tg4(struct sk_buff *skb, const struct xt_action_param *par) synproxy_tg4(struct sk_buff *skb, const struct xt_action_param *par)
{ {
const struct xt_synproxy_info *info = par->targinfo; const struct xt_synproxy_info *info = par->targinfo;
struct synproxy_net *snet = synproxy_pernet(par->net); struct net *net = par->net;
struct synproxy_net *snet = synproxy_pernet(net);
struct synproxy_options opts = {}; struct synproxy_options opts = {};
struct tcphdr *th, _th; struct tcphdr *th, _th;
...@@ -292,12 +293,12 @@ synproxy_tg4(struct sk_buff *skb, const struct xt_action_param *par) ...@@ -292,12 +293,12 @@ synproxy_tg4(struct sk_buff *skb, const struct xt_action_param *par)
XT_SYNPROXY_OPT_SACK_PERM | XT_SYNPROXY_OPT_SACK_PERM |
XT_SYNPROXY_OPT_ECN); XT_SYNPROXY_OPT_ECN);
synproxy_send_client_synack(snet, skb, th, &opts); synproxy_send_client_synack(net, skb, th, &opts);
return NF_DROP; return NF_DROP;
} else if (th->ack && !(th->fin || th->rst || th->syn)) { } else if (th->ack && !(th->fin || th->rst || th->syn)) {
/* ACK from client */ /* ACK from client */
synproxy_recv_client_ack(snet, skb, th, &opts, ntohl(th->seq)); synproxy_recv_client_ack(net, skb, th, &opts, ntohl(th->seq));
return NF_DROP; return NF_DROP;
} }
...@@ -308,7 +309,8 @@ static unsigned int ipv4_synproxy_hook(void *priv, ...@@ -308,7 +309,8 @@ static unsigned int ipv4_synproxy_hook(void *priv,
struct sk_buff *skb, struct sk_buff *skb,
const struct nf_hook_state *nhs) const struct nf_hook_state *nhs)
{ {
struct synproxy_net *snet = synproxy_pernet(nhs->net); struct net *net = nhs->net;
struct synproxy_net *snet = synproxy_pernet(net);
enum ip_conntrack_info ctinfo; enum ip_conntrack_info ctinfo;
struct nf_conn *ct; struct nf_conn *ct;
struct nf_conn_synproxy *synproxy; struct nf_conn_synproxy *synproxy;
...@@ -365,7 +367,7 @@ static unsigned int ipv4_synproxy_hook(void *priv, ...@@ -365,7 +367,7 @@ static unsigned int ipv4_synproxy_hook(void *priv,
* therefore we need to add 1 to make the SYN sequence * therefore we need to add 1 to make the SYN sequence
* number match the one of first SYN. * number match the one of first SYN.
*/ */
if (synproxy_recv_client_ack(snet, skb, th, &opts, if (synproxy_recv_client_ack(net, skb, th, &opts,
ntohl(th->seq) + 1)) ntohl(th->seq) + 1))
this_cpu_inc(snet->stats->cookie_retrans); this_cpu_inc(snet->stats->cookie_retrans);
...@@ -391,12 +393,12 @@ static unsigned int ipv4_synproxy_hook(void *priv, ...@@ -391,12 +393,12 @@ static unsigned int ipv4_synproxy_hook(void *priv,
XT_SYNPROXY_OPT_SACK_PERM); XT_SYNPROXY_OPT_SACK_PERM);
swap(opts.tsval, opts.tsecr); swap(opts.tsval, opts.tsecr);
synproxy_send_server_ack(snet, state, skb, th, &opts); synproxy_send_server_ack(net, state, skb, th, &opts);
nf_ct_seqadj_init(ct, ctinfo, synproxy->isn - ntohl(th->seq)); nf_ct_seqadj_init(ct, ctinfo, synproxy->isn - ntohl(th->seq));
swap(opts.tsval, opts.tsecr); swap(opts.tsval, opts.tsecr);
synproxy_send_client_ack(snet, skb, th, &opts); synproxy_send_client_ack(net, skb, th, &opts);
consume_skb(skb); consume_skb(skb);
return NF_STOLEN; return NF_STOLEN;
......
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