aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2006-06-09 15:17:41 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2006-06-18 00:30:07 -0400
commita0e889bb1bdc083dbbdb02cce9698765847b841f (patch)
tree3f176b4be0d7821f7104303f856839579deb0091
parent4e5ab4cb85683cf77b507ba0c4d48871e1562305 (diff)
[NETFILTER]: recent match: fix "sleeping function called from invalid context"
create_proc_entry must not be called with locks held. Use a mutex instead to protect data only changed in user context. Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/ipv4/netfilter/ipt_recent.c15
1 files changed, 10 insertions, 5 deletions
diff --git a/net/ipv4/netfilter/ipt_recent.c b/net/ipv4/netfilter/ipt_recent.c
index 9686c4d2057d..9b09e481957d 100644
--- a/net/ipv4/netfilter/ipt_recent.c
+++ b/net/ipv4/netfilter/ipt_recent.c
@@ -69,6 +69,7 @@ struct recent_table {
69 69
70static LIST_HEAD(tables); 70static LIST_HEAD(tables);
71static DEFINE_SPINLOCK(recent_lock); 71static DEFINE_SPINLOCK(recent_lock);
72static DEFINE_MUTEX(recent_mutex);
72 73
73#ifdef CONFIG_PROC_FS 74#ifdef CONFIG_PROC_FS
74static struct proc_dir_entry *proc_dir; 75static struct proc_dir_entry *proc_dir;
@@ -249,7 +250,7 @@ ipt_recent_checkentry(const char *tablename, const void *ip,
249 strnlen(info->name, IPT_RECENT_NAME_LEN) == IPT_RECENT_NAME_LEN) 250 strnlen(info->name, IPT_RECENT_NAME_LEN) == IPT_RECENT_NAME_LEN)
250 return 0; 251 return 0;
251 252
252 spin_lock_bh(&recent_lock); 253 mutex_lock(&recent_mutex);
253 t = recent_table_lookup(info->name); 254 t = recent_table_lookup(info->name);
254 if (t != NULL) { 255 if (t != NULL) {
255 t->refcnt++; 256 t->refcnt++;
@@ -258,7 +259,7 @@ ipt_recent_checkentry(const char *tablename, const void *ip,
258 } 259 }
259 260
260 t = kzalloc(sizeof(*t) + sizeof(t->iphash[0]) * ip_list_hash_size, 261 t = kzalloc(sizeof(*t) + sizeof(t->iphash[0]) * ip_list_hash_size,
261 GFP_ATOMIC); 262 GFP_KERNEL);
262 if (t == NULL) 263 if (t == NULL)
263 goto out; 264 goto out;
264 strcpy(t->name, info->name); 265 strcpy(t->name, info->name);
@@ -274,10 +275,12 @@ ipt_recent_checkentry(const char *tablename, const void *ip,
274 t->proc->proc_fops = &recent_fops; 275 t->proc->proc_fops = &recent_fops;
275 t->proc->data = t; 276 t->proc->data = t;
276#endif 277#endif
278 spin_lock_bh(&recent_lock);
277 list_add_tail(&t->list, &tables); 279 list_add_tail(&t->list, &tables);
280 spin_unlock_bh(&recent_lock);
278 ret = 1; 281 ret = 1;
279out: 282out:
280 spin_unlock_bh(&recent_lock); 283 mutex_unlock(&recent_mutex);
281 return ret; 284 return ret;
282} 285}
283 286
@@ -288,17 +291,19 @@ ipt_recent_destroy(const struct xt_match *match, void *matchinfo,
288 const struct ipt_recent_info *info = matchinfo; 291 const struct ipt_recent_info *info = matchinfo;
289 struct recent_table *t; 292 struct recent_table *t;
290 293
291 spin_lock_bh(&recent_lock); 294 mutex_lock(&recent_mutex);
292 t = recent_table_lookup(info->name); 295 t = recent_table_lookup(info->name);
293 if (--t->refcnt == 0) { 296 if (--t->refcnt == 0) {
297 spin_lock_bh(&recent_lock);
294 list_del(&t->list); 298 list_del(&t->list);
299 spin_unlock_bh(&recent_lock);
295 recent_table_flush(t); 300 recent_table_flush(t);
296#ifdef CONFIG_PROC_FS 301#ifdef CONFIG_PROC_FS
297 remove_proc_entry(t->name, proc_dir); 302 remove_proc_entry(t->name, proc_dir);
298#endif 303#endif
299 kfree(t); 304 kfree(t);
300 } 305 }
301 spin_unlock_bh(&recent_lock); 306 mutex_unlock(&recent_mutex);
302} 307}
303 308
304#ifdef CONFIG_PROC_FS 309#ifdef CONFIG_PROC_FS