Received: by oss.sgi.com id ; Mon, 3 Apr 2000 08:22:52 -0700 Received: from dialup-ad-13-116.camtech.net.au ([203.55.243.244]:9732 "EHLO halfway.linuxcare.com.au") by oss.sgi.com with ESMTP id ; Mon, 3 Apr 2000 08:22:36 -0700 Received: from linuxcare.com.au (really [127.0.0.1]) by linuxcare.com.au via in.smtpd with esmtp id (Debian Smail3.2.0.102) for ; Tue, 4 Apr 2000 00:51:17 +0930 (CST) Message-Id: From: Rusty Russell To: torvalds@transmeta.com cc: netdev@oss.sgi.com Subject: [PATCH] netfilter fixes v2.3.99-pre4-2 Date: Tue, 04 Apr 2000 00:51:06 +0930 Sender: owner-netdev@oss.sgi.com Precedence: bulk Return-Path: X-Orcpt: rfc822;netdev-outgoing Linus, please apply. Note to all: I am out this week (knee reconstruction). If I post before Thursday, I'm probably on pain medication, so check my patches carefully 8). This fixes: 1) Module unload races. 2) NAT on fragment issues (GameSpy crash). 3) Partially-initialized NAT entries if protocol doesn't like packet. 4) `check' failure one-too-many-down() bug. Some paranoia issues: 1) Now doing an external lookup will never create a new connection. 2) Extra checks for locally-injected truncated IP packets (raw sockets). Enjoy! Rusty. diff -urN --minimal --exclude *.lds --exclude *.sgml --exclude classlist.h --exclude devlist.h --exclude autoconf.h --exclude compile.h --exclude version.h --exclude .* --exclude *.[oa] --exclude *.orig --exclude config --exclude asm --exclude modules --exclude *.[Ss] --exclude System.map --exclude consolemap_deftbl.c --exclude *~ --exclude TAGS --exclude tags --exclude modversions.h --exclude install-kernel linux-2.3.99-pre4-2/include/linux/netfilter_ipv4/ip_conntrack_protocol.h working/include/linux/netfilter_ipv4/ip_conntrack_protocol.h --- linux-2.3.99-pre4-2/include/linux/netfilter_ipv4/ip_conntrack_protocol.h Sat Apr 8 18:10:12 2000 +++ working/include/linux/netfilter_ipv4/ip_conntrack_protocol.h Mon Apr 3 14:47:59 2000 @@ -37,10 +37,10 @@ struct iphdr *iph, size_t len, enum ip_conntrack_info ctinfo); - /* Called when a new connection for this protocol found; returns - * TRUE if it's OK. If so, packet() called next. */ - int (*new)(struct ip_conntrack *conntrack, - struct iphdr *iph, size_t len); + /* Called when a new connection for this protocol found; + * returns timeout. If so, packet() called next. */ + unsigned long (*new)(struct ip_conntrack *conntrack, + struct iphdr *iph, size_t len); /* Module (if any) which this is connected to. */ struct module *me; diff -urN --minimal --exclude *.lds --exclude *.sgml --exclude classlist.h --exclude devlist.h --exclude autoconf.h --exclude compile.h --exclude version.h --exclude .* --exclude *.[oa] --exclude *.orig --exclude config --exclude asm --exclude modules --exclude *.[Ss] --exclude System.map --exclude consolemap_deftbl.c --exclude *~ --exclude TAGS --exclude tags --exclude modversions.h --exclude install-kernel linux-2.3.99-pre4-2/include/linux/netfilter_ipv4/ipt_state.h working/include/linux/netfilter_ipv4/ipt_state.h --- linux-2.3.99-pre4-2/include/linux/netfilter_ipv4/ipt_state.h Sat Mar 18 05:26:20 2000 +++ working/include/linux/netfilter_ipv4/ipt_state.h Mon Apr 3 14:18:20 2000 @@ -1,8 +1,7 @@ #ifndef _IPT_STATE_H #define _IPT_STATE_H -#define _IPT_STATE_BIT(ctinfo) (1 << ((ctinfo)+1)) -#define IPT_STATE_BIT(ctinfo) ((ctinfo) >= IP_CT_IS_REPLY ? _IPT_STATE_BIT((ctinfo)-IP_CT_IS_REPLY) : _IPT_STATE_BIT(ctinfo)) +#define IPT_STATE_BIT(ctinfo) (1 << ((ctinfo)%IP_CT_IS_REPLY+1)) #define IPT_STATE_INVALID (1 << 0) struct ipt_state_info diff -urN --minimal --exclude *.lds --exclude *.sgml --exclude classlist.h --exclude devlist.h --exclude autoconf.h --exclude compile.h --exclude version.h --exclude .* --exclude *.[oa] --exclude *.orig --exclude config --exclude asm --exclude modules --exclude *.[Ss] --exclude System.map --exclude consolemap_deftbl.c --exclude *~ --exclude TAGS --exclude tags --exclude modversions.h --exclude install-kernel linux-2.3.99-pre4-2/net/ipv4/ip_fragment.c working/net/ipv4/ip_fragment.c --- linux-2.3.99-pre4-2/net/ipv4/ip_fragment.c Thu Feb 10 14:38:09 2000 +++ working/net/ipv4/ip_fragment.c Mon Apr 3 14:18:20 2000 @@ -387,8 +387,13 @@ */ skb->security = qp->fragments->skb->security; +#ifdef CONFIG_NETFILTER + /* Connection association is same as fragment (if any). */ + skb->nfct = qp->fragments->skb->nfct; + nf_conntrack_get(skb->nfct); #ifdef CONFIG_NETFILTER_DEBUG skb->nf_debug = qp->fragments->skb->nf_debug; +#endif #endif /* Done with all fragments. Fixup the new IP header. */ diff -urN --minimal --exclude *.lds --exclude *.sgml --exclude classlist.h --exclude devlist.h --exclude autoconf.h --exclude compile.h --exclude version.h --exclude .* --exclude *.[oa] --exclude *.orig --exclude config --exclude asm --exclude modules --exclude *.[Ss] --exclude System.map --exclude consolemap_deftbl.c --exclude *~ --exclude TAGS --exclude tags --exclude modversions.h --exclude install-kernel linux-2.3.99-pre4-2/net/ipv4/netfilter/ip_conntrack_core.c working/net/ipv4/netfilter/ip_conntrack_core.c --- linux-2.3.99-pre4-2/net/ipv4/netfilter/ip_conntrack_core.c Sat Apr 1 19:03:03 2000 +++ working/net/ipv4/netfilter/ip_conntrack_core.c Mon Apr 3 14:18:20 2000 @@ -343,6 +343,7 @@ size_t hash, repl_hash; struct ip_conntrack_expect *expected; enum ip_conntrack_info ctinfo; + unsigned long extra_jiffies; int i; if (!invert_tuple(&repl_tuple, tuple, protocol)) { @@ -366,19 +367,24 @@ repl_hash = hash_conntrack(&repl_tuple); memset(conntrack, 0, sizeof(struct ip_conntrack)); - atomic_set(&conntrack->ct_general.use, 1); + atomic_set(&conntrack->ct_general.use, 2); conntrack->ct_general.destroy = destroy_conntrack; conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple = *tuple; conntrack->tuplehash[IP_CT_DIR_ORIGINAL].ctrack = conntrack; conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = repl_tuple; conntrack->tuplehash[IP_CT_DIR_REPLY].ctrack = conntrack; - for(i=0; i < IP_CT_NUMBER; i++) + for (i=0; i < IP_CT_NUMBER; i++) conntrack->infos[i].master = &conntrack->ct_general; - if (!protocol->new(conntrack, skb->nh.iph, skb->len)) { + extra_jiffies = protocol->new(conntrack, skb->nh.iph, skb->len); + if (!extra_jiffies) { kmem_cache_free(ip_conntrack_cachep, conntrack); return 1; } + conntrack->timeout.data = (unsigned long)conntrack; + conntrack->timeout.function = death_by_timeout; + conntrack->timeout.expires = jiffies + extra_jiffies; + add_timer(&conntrack->timeout); /* Sew in at head of hash list. */ WRITE_LOCK(&ip_conntrack_lock); @@ -421,7 +427,7 @@ } static void -resolve_normal_ct(struct sk_buff *skb) +resolve_normal_ct(struct sk_buff *skb, int create) { struct ip_conntrack_tuple tuple; struct ip_conntrack_tuple_hash *h; @@ -436,7 +442,7 @@ do { /* look for tuple match */ h = ip_conntrack_find_get(&tuple, NULL); - if (!h && init_conntrack(&tuple, proto, skb)) + if (!h && (!create || init_conntrack(&tuple, proto, skb))) return; } while (!h); @@ -464,13 +470,15 @@ } /* Return conntrack and conntrack_info a given skb */ -struct ip_conntrack * -ip_conntrack_get(struct sk_buff *skb, enum ip_conntrack_info *ctinfo) +static struct ip_conntrack * +__ip_conntrack_get(struct sk_buff *skb, + enum ip_conntrack_info *ctinfo, + int create) { if (!skb->nfct) { /* It may be an icmp error... */ if (!icmp_error_track(skb)) - resolve_normal_ct(skb); + resolve_normal_ct(skb, create); } if (skb->nfct) { @@ -485,6 +493,12 @@ return NULL; } +struct ip_conntrack * +ip_conntrack_get(struct sk_buff *skb, enum ip_conntrack_info *ctinfo) +{ + return __ip_conntrack_get(skb, ctinfo, 0); +} + /* Netfilter hook itself. */ unsigned int ip_conntrack_in(unsigned int hooknum, struct sk_buff **pskb, @@ -512,13 +526,13 @@ return NF_STOLEN; } - ct = ip_conntrack_get(*pskb, &ctinfo); - if (!ct) + ct = __ip_conntrack_get(*pskb, &ctinfo, 1); + if (!ct) { /* Not valid part of a connection */ return NF_ACCEPT; + } proto = find_proto((*pskb)->nh.iph->protocol); - /* If this is new, this is first time timer will be set */ ret = proto->packet(ct, (*pskb)->nh.iph, (*pskb)->len, ctinfo); if (ret == -1) { @@ -645,24 +659,16 @@ MOD_DEC_USE_COUNT; } -/* Refresh conntrack for this many jiffies: if noone calls this, - conntrack will vanish with current skb. */ +/* Refresh conntrack for this many jiffies. */ void ip_ct_refresh(struct ip_conntrack *ct, unsigned long extra_jiffies) { + IP_NF_ASSERT(ct->timeout.data == (unsigned long)ct); + WRITE_LOCK(&ip_conntrack_lock); - /* If this hasn't had a timer before, it's still being set up */ - if (ct->timeout.data == 0) { - ct->timeout.data = (unsigned long)ct; - ct->timeout.function = death_by_timeout; + /* Need del_timer for race avoidance (may already be dying). */ + if (del_timer(&ct->timeout)) { ct->timeout.expires = jiffies + extra_jiffies; - atomic_inc(&ct->ct_general.use); add_timer(&ct->timeout); - } else { - /* Need del_timer for race avoidance (may already be dying). */ - if (del_timer(&ct->timeout)) { - ct->timeout.expires = jiffies + extra_jiffies; - add_timer(&ct->timeout); - } } WRITE_UNLOCK(&ip_conntrack_lock); } diff -urN --minimal --exclude *.lds --exclude *.sgml --exclude classlist.h --exclude devlist.h --exclude autoconf.h --exclude compile.h --exclude version.h --exclude .* --exclude *.[oa] --exclude *.orig --exclude config --exclude asm --exclude modules --exclude *.[Ss] --exclude System.map --exclude consolemap_deftbl.c --exclude *~ --exclude TAGS --exclude tags --exclude modversions.h --exclude install-kernel linux-2.3.99-pre4-2/net/ipv4/netfilter/ip_conntrack_proto_generic.c working/net/ipv4/netfilter/ip_conntrack_proto_generic.c --- linux-2.3.99-pre4-2/net/ipv4/netfilter/ip_conntrack_proto_generic.c Sat Mar 18 05:26:20 2000 +++ working/net/ipv4/netfilter/ip_conntrack_proto_generic.c Mon Apr 3 14:18:20 2000 @@ -48,9 +48,10 @@ } /* Called when a new connection for this protocol found. */ -static int new(struct ip_conntrack *conntrack, struct iphdr *iph, size_t len) +static unsigned long +new(struct ip_conntrack *conntrack, struct iphdr *iph, size_t len) { - return 1; + return GENERIC_TIMEOUT; } struct ip_conntrack_protocol ip_conntrack_generic_protocol diff -urN --minimal --exclude *.lds --exclude *.sgml --exclude classlist.h --exclude devlist.h --exclude autoconf.h --exclude compile.h --exclude version.h --exclude .* --exclude *.[oa] --exclude *.orig --exclude config --exclude asm --exclude modules --exclude *.[Ss] --exclude System.map --exclude consolemap_deftbl.c --exclude *~ --exclude TAGS --exclude tags --exclude modversions.h --exclude install-kernel linux-2.3.99-pre4-2/net/ipv4/netfilter/ip_conntrack_proto_icmp.c working/net/ipv4/netfilter/ip_conntrack_proto_icmp.c --- linux-2.3.99-pre4-2/net/ipv4/netfilter/ip_conntrack_proto_icmp.c Sat Apr 1 19:03:03 2000 +++ working/net/ipv4/netfilter/ip_conntrack_proto_icmp.c Mon Apr 3 14:18:20 2000 @@ -86,8 +86,8 @@ } /* Called when a new connection for this protocol found. */ -static int icmp_new(struct ip_conntrack *conntrack, - struct iphdr *iph, size_t len) +static unsigned long icmp_new(struct ip_conntrack *conntrack, + struct iphdr *iph, size_t len) { static u_int8_t valid_new[] = { [ICMP_ECHO] = 1, @@ -103,7 +103,7 @@ DUMP_TUPLE(&conntrack->tuplehash[0].tuple); return 0; } - return 1; + return ICMP_TIMEOUT; } struct ip_conntrack_protocol ip_conntrack_protocol_icmp diff -urN --minimal --exclude *.lds --exclude *.sgml --exclude classlist.h --exclude devlist.h --exclude autoconf.h --exclude compile.h --exclude version.h --exclude .* --exclude *.[oa] --exclude *.orig --exclude config --exclude asm --exclude modules --exclude *.[Ss] --exclude System.map --exclude consolemap_deftbl.c --exclude *~ --exclude TAGS --exclude tags --exclude modversions.h --exclude install-kernel linux-2.3.99-pre4-2/net/ipv4/netfilter/ip_conntrack_proto_tcp.c working/net/ipv4/netfilter/ip_conntrack_proto_tcp.c --- linux-2.3.99-pre4-2/net/ipv4/netfilter/ip_conntrack_proto_tcp.c Sat Apr 1 19:03:03 2000 +++ working/net/ipv4/netfilter/ip_conntrack_proto_tcp.c Mon Apr 3 14:18:20 2000 @@ -189,14 +189,13 @@ conntrack->proto.tcp_state = newconntrack; WRITE_UNLOCK(&tcp_lock); - /* Refresh: need write lock to write to conntrack. */ ip_ct_refresh(conntrack, tcp_timeouts[conntrack->proto.tcp_state]); return NF_ACCEPT; } /* Called when a new connection for this protocol found. */ -static int tcp_new(struct ip_conntrack *conntrack, - struct iphdr *iph, size_t len) +static unsigned long tcp_new(struct ip_conntrack *conntrack, + struct iphdr *iph, size_t len) { enum tcp_conntrack newconntrack; struct tcphdr *tcph = (struct tcphdr *)((u_int32_t *)iph + iph->ihl); @@ -210,11 +209,10 @@ if (newconntrack == TCP_CONNTRACK_MAX) { DEBUGP("ip_conntrack_tcp: invalid new deleting.\n"); return 0; - } else { - conntrack->proto.tcp_state = newconntrack; - ip_ct_refresh(conntrack, tcp_timeouts[conntrack->proto.tcp_state]); } - return 1; + + conntrack->proto.tcp_state = newconntrack; + return tcp_timeouts[conntrack->proto.tcp_state]; } struct ip_conntrack_protocol ip_conntrack_protocol_tcp diff -urN --minimal --exclude *.lds --exclude *.sgml --exclude classlist.h --exclude devlist.h --exclude autoconf.h --exclude compile.h --exclude version.h --exclude .* --exclude *.[oa] --exclude *.orig --exclude config --exclude asm --exclude modules --exclude *.[Ss] --exclude System.map --exclude consolemap_deftbl.c --exclude *~ --exclude TAGS --exclude tags --exclude modversions.h --exclude install-kernel linux-2.3.99-pre4-2/net/ipv4/netfilter/ip_conntrack_proto_udp.c working/net/ipv4/netfilter/ip_conntrack_proto_udp.c --- linux-2.3.99-pre4-2/net/ipv4/netfilter/ip_conntrack_proto_udp.c Sat Apr 1 19:03:03 2000 +++ working/net/ipv4/netfilter/ip_conntrack_proto_udp.c Mon Apr 3 14:18:20 2000 @@ -54,10 +54,10 @@ } /* Called when a new connection for this protocol found. */ -static int udp_new(struct ip_conntrack *conntrack, - struct iphdr *iph, size_t len) +static unsigned long udp_new(struct ip_conntrack *conntrack, + struct iphdr *iph, size_t len) { - return 1; + return UDP_TIMEOUT; } struct ip_conntrack_protocol ip_conntrack_protocol_udp diff -urN --minimal --exclude *.lds --exclude *.sgml --exclude classlist.h --exclude devlist.h --exclude autoconf.h --exclude compile.h --exclude version.h --exclude .* --exclude *.[oa] --exclude *.orig --exclude config --exclude asm --exclude modules --exclude *.[Ss] --exclude System.map --exclude consolemap_deftbl.c --exclude *~ --exclude TAGS --exclude tags --exclude modversions.h --exclude install-kernel linux-2.3.99-pre4-2/net/ipv4/netfilter/ip_conntrack_standalone.c working/net/ipv4/netfilter/ip_conntrack_standalone.c --- linux-2.3.99-pre4-2/net/ipv4/netfilter/ip_conntrack_standalone.c Sat Apr 1 19:03:03 2000 +++ working/net/ipv4/netfilter/ip_conntrack_standalone.c Mon Apr 3 14:18:20 2000 @@ -169,8 +169,6 @@ interface. We degfragment them at LOCAL_OUT, however, so we have to refragment them here. */ if ((*pskb)->len > rt->u.dst.pmtu) { - DEBUGP("ip_conntrack: refragm %p (size %u) to %u (okfn %p)\n", - *pskb, (*pskb)->len, rt->u.dst.pmtu, okfn); /* No hook can be after us, so this should be OK. */ ip_fragment(*pskb, okfn); return NF_STOLEN; @@ -178,13 +176,29 @@ return NF_ACCEPT; } +static unsigned int ip_conntrack_local(unsigned int hooknum, + struct sk_buff **pskb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + /* root is playing with raw sockets. */ + if ((*pskb)->len < sizeof(struct iphdr) + || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) { + if (net_ratelimit()) + printk("ipt_hook: happy cracking.\n"); + return NF_ACCEPT; + } + return ip_conntrack_in(hooknum, pskb, in, out, okfn); +} + /* Connection tracking may drop packets, but never alters them, so make it the first hook. */ static struct nf_hook_ops ip_conntrack_in_ops = { { NULL, NULL }, ip_conntrack_in, PF_INET, NF_IP_PRE_ROUTING, NF_IP_PRI_CONNTRACK }; static struct nf_hook_ops ip_conntrack_local_out_ops -= { { NULL, NULL }, ip_conntrack_in, PF_INET, NF_IP_LOCAL_OUT, += { { NULL, NULL }, ip_conntrack_local, PF_INET, NF_IP_LOCAL_OUT, NF_IP_PRI_CONNTRACK }; /* Refragmenter; last chance. */ static struct nf_hook_ops ip_conntrack_out_ops diff -urN --minimal --exclude *.lds --exclude *.sgml --exclude classlist.h --exclude devlist.h --exclude autoconf.h --exclude compile.h --exclude version.h --exclude .* --exclude *.[oa] --exclude *.orig --exclude config --exclude asm --exclude modules --exclude *.[Ss] --exclude System.map --exclude consolemap_deftbl.c --exclude *~ --exclude TAGS --exclude tags --exclude modversions.h --exclude install-kernel linux-2.3.99-pre4-2/net/ipv4/netfilter/ip_nat_standalone.c working/net/ipv4/netfilter/ip_nat_standalone.c --- linux-2.3.99-pre4-2/net/ipv4/netfilter/ip_nat_standalone.c Sat Apr 1 19:03:03 2000 +++ working/net/ipv4/netfilter/ip_nat_standalone.c Mon Apr 3 14:18:20 2000 @@ -130,6 +130,11 @@ const struct net_device *out, int (*okfn)(struct sk_buff *)) { + /* root is playing with raw sockets. */ + if ((*pskb)->len < sizeof(struct iphdr) + || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) + return NF_ACCEPT; + /* We can hit fragment here; forwarded packets get defragmented by connection tracking coming in, then fragmented (grr) by the forward code. @@ -150,6 +155,21 @@ return ip_nat_fn(hooknum, pskb, in, out, okfn); } +static unsigned int +ip_nat_local_fn(unsigned int hooknum, + struct sk_buff **pskb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + /* root is playing with raw sockets. */ + if ((*pskb)->len < sizeof(struct iphdr) + || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) + return NF_ACCEPT; + + return ip_nat_fn(hooknum, pskb, in, out, okfn); +} + /* We must be after connection tracking and before packet filtering. */ /* Before packet filtering, change destination */ @@ -160,7 +180,7 @@ = { { NULL, NULL }, ip_nat_out, PF_INET, NF_IP_POST_ROUTING, NF_IP_PRI_NAT_SRC}; /* Before packet filtering, change destination */ static struct nf_hook_ops ip_nat_local_out_ops -= { { NULL, NULL }, ip_nat_fn, PF_INET, NF_IP_LOCAL_OUT, NF_IP_PRI_NAT_DST }; += { { NULL, NULL }, ip_nat_local_fn, PF_INET, NF_IP_LOCAL_OUT, NF_IP_PRI_NAT_DST }; /* Protocol registration. */ int ip_nat_protocol_register(struct ip_nat_protocol *proto) diff -urN --minimal --exclude *.lds --exclude *.sgml --exclude classlist.h --exclude devlist.h --exclude autoconf.h --exclude compile.h --exclude version.h --exclude .* --exclude *.[oa] --exclude *.orig --exclude config --exclude asm --exclude modules --exclude *.[Ss] --exclude System.map --exclude consolemap_deftbl.c --exclude *~ --exclude TAGS --exclude tags --exclude modversions.h --exclude install-kernel linux-2.3.99-pre4-2/net/ipv4/netfilter/ip_tables.c working/net/ipv4/netfilter/ip_tables.c --- linux-2.3.99-pre4-2/net/ipv4/netfilter/ip_tables.c Sat Apr 1 19:03:03 2000 +++ working/net/ipv4/netfilter/ip_tables.c Mon Apr 3 14:52:21 2000 @@ -39,7 +39,7 @@ #define IP_NF_ASSERT(x) \ do { \ if (!(x)) \ - printk("IPT_ASSERT: %s:%s:%u\n", \ + printk("IP_NF_ASSERT: %s:%s:%u\n", \ __FUNCTION__, __FILE__, __LINE__); \ } while(0) #else @@ -683,7 +683,6 @@ target = find_target_lock(t->u.name, &ret, &ipt_mutex); if (!target) { duprintf("check_entry: `%s' not found\n", t->u.name); - up(&ipt_mutex); return ret; } if (target->me) @@ -1283,17 +1282,16 @@ { int ret; + MOD_INC_USE_COUNT; ret = down_interruptible(&ipt_mutex); if (ret != 0) return ret; - if (list_named_insert(&ipt_target, target)) { - MOD_INC_USE_COUNT; - ret = 0; - } else { + if (!list_named_insert(&ipt_target, target)) { duprintf("ipt_register_target: `%s' already in list!\n", target->name); ret = -EINVAL; + MOD_DEC_USE_COUNT; } up(&ipt_mutex); return ret; @@ -1313,16 +1311,18 @@ { int ret; + MOD_INC_USE_COUNT; ret = down_interruptible(&ipt_mutex); - if (ret != 0) + if (ret != 0) { + MOD_DEC_USE_COUNT; return ret; - + } if (list_named_insert(&ipt_match, match)) { - MOD_INC_USE_COUNT; ret = 0; } else { duprintf("ipt_register_match: `%s' already in list!\n", match->name); + MOD_DEC_USE_COUNT; ret = -EINVAL; } up(&ipt_mutex); @@ -1346,10 +1346,12 @@ static struct ipt_table_info bootstrap = { 0, 0, { 0 }, { 0 }, { }, { } }; + MOD_INC_USE_COUNT; newinfo = vmalloc(sizeof(struct ipt_table_info) + SMP_ALIGN(table->table->size) * smp_num_cpus); if (!newinfo) { ret = -ENOMEM; + MOD_DEC_USE_COUNT; return ret; } memcpy(newinfo->entries, table->table->entries, table->table->size); @@ -1361,12 +1363,14 @@ table->table->underflow); if (ret != 0) { vfree(newinfo); + MOD_DEC_USE_COUNT; return ret; } ret = down_interruptible(&ipt_mutex); if (ret != 0) { vfree(newinfo); + MOD_DEC_USE_COUNT; return ret; } @@ -1386,7 +1390,6 @@ table->lock = RW_LOCK_UNLOCKED; list_prepend(&ipt_tables, table); - MOD_INC_USE_COUNT; unlock: up(&ipt_mutex); @@ -1394,6 +1397,7 @@ free_unlock: vfree(newinfo); + MOD_DEC_USE_COUNT; goto unlock; } -- Hacking time.