All of lore.kernel.org
 help / color / mirror / Atom feed
From: Martin Josefsson <gandalf@wlug.westbo.se>
To: Patrick McHardy <kaber@trash.net>
Cc: netfilter-devel <netfilter-devel@lists.netfilter.org>
Subject: [PATCH] Check returnvalue of nfct_nat()
Date: Sun, 26 Nov 2006 11:13:31 +0100	[thread overview]
Message-ID: <1164536011.30244.10.camel@localhost.localdomain> (raw)

[-- Attachment #1: Type: text/plain, Size: 12431 bytes --]

We need to check the returnvalue of nfct_nat() (and nfct_help())
Otherwise we end up with the calltraces below.

Steps to reproduce:
1. Slow qemu machine without connectivity to the dns-servers.
2. Load nf_nat in the qemu machine.
3. Start an ssh to the qemu machine, this takes time as the qemu machine is
   slow and lacks dns.
4. Load iptable_nat in the qemu machine before the ssh has completed.
5. Watch it blow up as it tries to use the returnvalue of nfct_nat() on a
   connection without nat info, I believe it is a resend of a dns-query as it
   is an udp packet that causes the crash in one of the cases below.

Some of the checks in the patch might not be strictly neccessary, I havn't
audited the calls, it was 4 AM :) The check added in nf_nat_fn() should take
care of things for us...

BUG: unable to handle kernel NULL pointer dereference at virtual address 00000000
EIP is at __list_add+0x28/0x70
 [<c01fd66e>] list_add+0x1e/0x20
 [<c8814892>] nf_nat_setup_info+0x292/0x620 [nf_nat]
 [<c886a0d6>] alloc_null_binding_confirmed+0x46/0x60 [iptable_nat]
 [<c886a551>] nf_nat_fn+0x1c1/0x1d0 [iptable_nat]
 [<c886a865>] nf_nat_local_fn+0x65/0xf0 [iptable_nat]
 [<c02879f0>] nf_iterate+0x60/0x90
 [<c0287b82>] nf_hook_slow+0x52/0xd0
 [<c0290f7a>] ip_push_pending_frames+0x3ea/0x4b0
 [<c02b0d4b>] udp_push_pending_frames+0x15b/0x360
 [<c02b1f99>] udp_sendmsg+0x2c9/0x690
 [<c02b84c5>] inet_sendmsg+0x35/0x60
 [<c02650bd>] sock_sendmsg+0xcd/0x100
 [<c0265433>] sys_sendto+0xd3/0x100
 [<c0265492>] sys_send+0x32/0x40
 [<c02662a2>] sys_socketcall+0x142/0x260
 [<c01031f3>] syscall_call+0x7/0xb

or this:

BUG: unable to handle kernel NULL pointer dereference at virtual address 00000000
EIP is at __list_add+0x28/0x70
 [<c01fd66e>] list_add+0x1e/0x20
 [<c8814892>] nf_nat_setup_info+0x292/0x620 [nf_nat]
 [<c886a367>] nf_nat_rule_find+0x97/0xc0 [iptable_nat]
 [<c886a46f>] nf_nat_fn+0xdf/0x1d0 [iptable_nat]
 [<c886a5fe>] nf_nat_in+0x3e/0xb0 [iptable_nat]
 [<c02879f0>] nf_iterate+0x60/0x90
 [<c0287b82>] nf_hook_slow+0x52/0xd0
 [<c028de9d>] ip_rcv+0x31d/0x5a0
 [<c026ffbf>] netif_receive_skb+0x23f/0x3b0
 [<c0235d95>] cp_rx_poll+0x235/0x540
 [<c0271d98>] net_rx_action+0xa8/0x160
 [<c0121412>] __do_softirq+0x92/0x120
 [<c0121505>] do_softirq+0x65/0x70
 [<c01218d5>] irq_exit+0x45/0x50
 [<c010ebf7>] smp_apic_timer_interrupt+0xb7/0xe0
 [<c0103ca2>] apic_timer_interrupt+0x2a/0x30
 [<c0101d8c>] cpu_idle+0x6c/0x90
 [<c0100725>] rest_init+0x35/0x40
 [<c03958ee>] start_kernel+0x37e/0x430
 [<00000000>] 0x0

Signed-off-by: Martin Josefsson <gandalf@wlug.westbo.se>

---
 net/ipv4/netfilter/nf_nat_core.c        |   17 ++++++++++++++--
 net/ipv4/netfilter/nf_nat_h323.c        |   32 +++++++++++++++++++++++++++----
 net/ipv4/netfilter/nf_nat_helper.c      |    9 ++++++++
 net/ipv4/netfilter/nf_nat_helper_pptp.c |   33 +++++++++++++++++++++++++-------
 net/ipv4/netfilter/nf_nat_standalone.c  |    3 ++
 net/netfilter/nf_conntrack_core.c       |    2 -
 6 files changed, 82 insertions(+), 14 deletions(-)

Index: nf-2.6.20-nat.quilt/net/ipv4/netfilter/nf_nat_core.c
===================================================================
--- nf-2.6.20-nat.quilt.orig/net/ipv4/netfilter/nf_nat_core.c	2006-11-26 03:46:57.000000000 +0100
+++ nf-2.6.20-nat.quilt/net/ipv4/netfilter/nf_nat_core.c	2006-11-26 03:47:14.000000000 +0100
@@ -98,6 +98,9 @@ static void nf_nat_cleanup_conntrack(str
 		return;
 
 	nat = nfct_nat(conn);
+	if (!nat)
+		return;
+
 	write_lock_bh(&nf_nat_lock);
 	list_del(&nat->info.bysource);
 	write_unlock_bh(&nf_nat_lock);
@@ -289,8 +292,8 @@ nf_nat_setup_info(struct nf_conn *conntr
 		  unsigned int hooknum)
 {
 	struct nf_conntrack_tuple curr_tuple, new_tuple;
-	struct nf_conn_nat *nat = nfct_nat(conntrack);
-	struct nf_nat_info *info = &nat->info;
+	struct nf_conn_nat *nat;
+	struct nf_nat_info *info;
 	int have_to_hash = !(conntrack->status & IPS_NAT_DONE_MASK);
 	enum nf_nat_manip_type maniptype = HOOK2MANIP(hooknum);
 
@@ -300,6 +303,12 @@ nf_nat_setup_info(struct nf_conn *conntr
 		     || hooknum == NF_IP_LOCAL_OUT);
 	BUG_ON(nf_nat_initialized(conntrack, maniptype));
 
+	nat = nfct_nat(conntrack);
+	if (!nat)
+		return NF_DROP;
+
+	info = &nat->info;
+
 	/* What we've got will look like inverse of reply. Normally
 	   this is what is in the conntrack, except for prior
 	   manipulations (future optimization: if num_manips == 0,
@@ -626,6 +635,10 @@ static int __init nf_nat_init(void)
 static int clean_nat(struct nf_conn *i, void *data)
 {
 	struct nf_conn_nat *nat = nfct_nat(i);
+
+	if (!nat)
+		return 0;
+
 	memset(nat, 0, sizeof(nat));
 	i->status &= ~(IPS_NAT_MASK | IPS_NAT_DONE_MASK | IPS_SEQ_ADJUST);
 	return 0;
Index: nf-2.6.20-nat.quilt/net/ipv4/netfilter/nf_nat_helper.c
===================================================================
--- nf-2.6.20-nat.quilt.orig/net/ipv4/netfilter/nf_nat_helper.c	2006-11-26 03:46:56.000000000 +0100
+++ nf-2.6.20-nat.quilt/net/ipv4/netfilter/nf_nat_helper.c	2006-11-26 03:47:14.000000000 +0100
@@ -56,6 +56,9 @@ adjust_tcp_sequence(u32 seq,
 	struct nf_nat_seq *this_way, *other_way;
 	struct nf_conn_nat *nat = nfct_nat(ct);
 
+	if (!nat)
+		return;
+
 	DEBUGP("nf_nat_resize_packet: old_size = %u, new_size = %u\n",
 		(*skb)->len, new_size);
 
@@ -329,6 +332,9 @@ nf_nat_sack_adjust(struct sk_buff **pskb
 	unsigned int dir, optoff, optend;
 	struct nf_conn_nat *nat = nfct_nat(ct);
 
+	if (!nat)
+		return 0;
+
 	optoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct tcphdr);
 	optend = (*pskb)->nh.iph->ihl*4 + tcph->doff*4;
 
@@ -377,6 +383,9 @@ nf_nat_seq_adjust(struct sk_buff **pskb,
 	struct nf_conn_nat *nat = nfct_nat(ct);
 	struct nf_nat_seq *this_way, *other_way;
 
+	if (!nat)
+		return 0;
+
 	dir = CTINFO2DIR(ctinfo);
 
 	this_way = &nat->info.seq[dir];
Index: nf-2.6.20-nat.quilt/net/ipv4/netfilter/nf_nat_helper_pptp.c
===================================================================
--- nf-2.6.20-nat.quilt.orig/net/ipv4/netfilter/nf_nat_helper_pptp.c	2006-11-26 03:46:56.000000000 +0100
+++ nf-2.6.20-nat.quilt/net/ipv4/netfilter/nf_nat_helper_pptp.c	2006-11-26 03:47:14.000000000 +0100
@@ -53,9 +53,14 @@ static void pptp_nat_expected(struct nf_
 	struct nf_ct_pptp_master *ct_pptp_info;
 	struct nf_nat_pptp *nat_pptp_info;
 	struct ip_nat_range range;
+	struct nf_conn_help *help = nfct_help(master);
+	struct nf_conn_nat *nat = nfct_nat(master);
 
-	ct_pptp_info = &nfct_help(master)->help.ct_pptp_info;
-	nat_pptp_info = &nfct_nat(master)->help.nat_pptp_info;
+	if (!help || !nat)
+		return;
+
+	ct_pptp_info = &help->help.ct_pptp_info;
+	nat_pptp_info = &nat->help.nat_pptp_info;
 
 	/* And here goes the grand finale of corrosion... */
 	if (exp->dir == IP_CT_DIR_ORIGINAL) {
@@ -129,9 +134,14 @@ pptp_outbound_pkt(struct sk_buff **pskb,
 	u_int16_t msg;
 	__be16 new_callid;
 	unsigned int cid_off;
+	struct nf_conn_help *help = nfct_help(ct);
+	struct nf_conn_nat *nat = nfct_nat(ct);
+
+	if (!help || !nat)
+		return NF_DROP;
 
-	ct_pptp_info  = &nfct_help(ct)->help.ct_pptp_info;
-	nat_pptp_info = &nfct_nat(ct)->help.nat_pptp_info;
+	ct_pptp_info  = &help->help.ct_pptp_info;
+	nat_pptp_info = &nat->help.nat_pptp_info;
 
 	new_callid = ct_pptp_info->pns_call_id;
 
@@ -198,9 +208,14 @@ pptp_exp_gre(struct nf_conntrack_expect 
 	struct nf_conn *ct = expect_orig->master;
 	struct nf_ct_pptp_master *ct_pptp_info;
 	struct nf_nat_pptp *nat_pptp_info;
+	struct nf_conn_help *help = nfct_help(ct);
+	struct nf_conn_nat *nat = nfct_nat(ct);
 
-	ct_pptp_info  = &nfct_help(ct)->help.ct_pptp_info;
-	nat_pptp_info = &nfct_nat(ct)->help.nat_pptp_info;
+	if (!help || !nat)
+		return;
+
+	ct_pptp_info  = &help->help.ct_pptp_info;
+	nat_pptp_info = &nat->help.nat_pptp_info;
 
 	/* save original PAC call ID in nat_info */
 	nat_pptp_info->pac_call_id = ct_pptp_info->pac_call_id;
@@ -230,8 +245,12 @@ pptp_inbound_pkt(struct sk_buff **pskb,
 	u_int16_t msg;
 	__be16 new_pcid;
 	unsigned int pcid_off;
+	struct nf_conn_nat *nat = nfct_nat(ct);
+
+	if (!nat)
+		return NF_DROP;
 
-	nat_pptp_info = &nfct_nat(ct)->help.nat_pptp_info;
+	nat_pptp_info = &nat->help.nat_pptp_info;
 	new_pcid = nat_pptp_info->pns_call_id;
 
 	switch (msg = ntohs(ctlh->messageType)) {
Index: nf-2.6.20-nat.quilt/net/ipv4/netfilter/nf_nat_standalone.c
===================================================================
--- nf-2.6.20-nat.quilt.orig/net/ipv4/netfilter/nf_nat_standalone.c	2006-11-26 03:46:56.000000000 +0100
+++ nf-2.6.20-nat.quilt/net/ipv4/netfilter/nf_nat_standalone.c	2006-11-26 03:47:14.000000000 +0100
@@ -138,6 +138,9 @@ nf_nat_fn(unsigned int hooknum,
 		return NF_ACCEPT;
 
 	nat = nfct_nat(ct);
+	if (!nat)
+		return NF_DROP;
+
 	switch (ctinfo) {
 	case IP_CT_RELATED:
 	case IP_CT_RELATED+IP_CT_IS_REPLY:
Index: nf-2.6.20-nat.quilt/net/ipv4/netfilter/nf_nat_h323.c
===================================================================
--- nf-2.6.20-nat.quilt.orig/net/ipv4/netfilter/nf_nat_h323.c	2006-11-26 03:46:56.000000000 +0100
+++ nf-2.6.20-nat.quilt/net/ipv4/netfilter/nf_nat_h323.c	2006-11-26 03:47:14.000000000 +0100
@@ -107,12 +107,18 @@ static int set_sig_addr(struct sk_buff *
 			unsigned char **data,
 			TransportAddress *taddr, int count)
 {
-	struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info;
+	struct nf_conn_help *help = nfct_help(ct);
+	struct nf_ct_h323_master *info;
 	int dir = CTINFO2DIR(ctinfo);
 	int i;
 	__be16 port;
 	union nf_conntrack_address addr;
 
+	if (!help)
+		return 0;
+
+	info = &help->help.ct_h323_info;
+
 	for (i = 0; i < count; i++) {
 		if (get_h225_addr(ct, *data, &taddr[i], &addr, &port)) {
 			if (addr.ip == ct->tuplehash[dir].tuple.src.u3.ip &&
@@ -196,11 +202,17 @@ static int nat_rtp_rtcp(struct sk_buff *
 			struct nf_conntrack_expect *rtp_exp,
 			struct nf_conntrack_expect *rtcp_exp)
 {
-	struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info;
+	struct nf_conn_help *help = nfct_help(ct);
+	struct nf_ct_h323_master *info;
 	int dir = CTINFO2DIR(ctinfo);
 	int i;
 	u_int16_t nated_port;
 
+	if (!help)
+		return 0;
+
+	info = &help->help.ct_h323_info;
+
 	/* Set expectations for NAT */
 	rtp_exp->saved_proto.udp.port = rtp_exp->tuple.dst.u.udp.port;
 	rtp_exp->expectfn = nf_nat_follow_master;
@@ -343,10 +355,16 @@ static int nat_h245(struct sk_buff **psk
 		    TransportAddress *taddr, __be16 port,
 		    struct nf_conntrack_expect *exp)
 {
-	struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info;
+	struct nf_conn_help *help = nfct_help(ct);
+	struct nf_ct_h323_master *info;
 	int dir = CTINFO2DIR(ctinfo);
 	u_int16_t nated_port = ntohs(port);
 
+	if (!help)
+		return 0;
+
+	info = &help->help.ct_h323_info;
+
 	/* Set expectations for NAT */
 	exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
 	exp->expectfn = ip_nat_h245_expect;
@@ -431,11 +449,17 @@ static int nat_q931(struct sk_buff **psk
 		    unsigned char **data, TransportAddress *taddr, int idx,
 		    __be16 port, struct nf_conntrack_expect *exp)
 {
-	struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info;
+	struct nf_conn_help *help = nfct_help(ct);
+	struct nf_ct_h323_master *info;
 	int dir = CTINFO2DIR(ctinfo);
 	u_int16_t nated_port = ntohs(port);
 	union nf_conntrack_address addr;
 
+	if (!help)
+		return 0;
+
+	info = &help->help.ct_h323_info;
+
 	/* Set expectations for NAT */
 	exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
 	exp->expectfn = ip_nat_q931_expect;
Index: nf-2.6.20-nat.quilt/net/netfilter/nf_conntrack_core.c
===================================================================
--- nf-2.6.20-nat.quilt.orig/net/netfilter/nf_conntrack_core.c	2006-11-26 03:46:57.000000000 +0100
+++ nf-2.6.20-nat.quilt/net/netfilter/nf_conntrack_core.c	2006-11-26 03:47:43.000000000 +0100
@@ -859,7 +859,7 @@ void nf_conntrack_alter_reply(struct nf_
 	NF_CT_DUMP_TUPLE(newreply);
 
 	conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply;
-	if (!conntrack->master && help->expecting == 0)
+	if (!conntrack->master && help && help->expecting == 0)
 		help->helper = __nf_ct_helper_find(newreply);
 	write_unlock_bh(&nf_conntrack_lock);
 }

-- 
/Martin

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

             reply	other threads:[~2006-11-26 10:13 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2006-11-26 10:13 Martin Josefsson [this message]
2006-11-27 16:24 ` [PATCH] Check returnvalue of nfct_nat() Patrick McHardy
2006-11-27 16:51   ` Martin Josefsson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1164536011.30244.10.camel@localhost.localdomain \
    --to=gandalf@wlug.westbo.se \
    --cc=kaber@trash.net \
    --cc=netfilter-devel@lists.netfilter.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.