aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2006-08-17 21:12:38 -0400
committerDavid S. Miller <davem@davemloft.net>2006-08-17 21:12:38 -0400
commitd205dc40798d97d63ad348bfaf7394f445d152d4 (patch)
tree603d58aaacec053300396db71b7143ea115ee902
parent6e8fcbf64024f9056ba122abbb66554aa76bae5d (diff)
[NETFILTER]: ctnetlink: fix deadlock in table dumping
ip_conntrack_put must not be called while holding ip_conntrack_lock since destroy_conntrack takes it again. Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/ipv4/netfilter/ip_conntrack_netlink.c17
-rw-r--r--net/netfilter/nf_conntrack_netlink.c17
2 files changed, 14 insertions, 20 deletions
diff --git a/net/ipv4/netfilter/ip_conntrack_netlink.c b/net/ipv4/netfilter/ip_conntrack_netlink.c
index 33891bb1fde4..0d4cc92391fa 100644
--- a/net/ipv4/netfilter/ip_conntrack_netlink.c
+++ b/net/ipv4/netfilter/ip_conntrack_netlink.c
@@ -415,21 +415,18 @@ ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
415 cb->args[0], *id); 415 cb->args[0], *id);
416 416
417 read_lock_bh(&ip_conntrack_lock); 417 read_lock_bh(&ip_conntrack_lock);
418 last = (struct ip_conntrack *)cb->args[1];
418 for (; cb->args[0] < ip_conntrack_htable_size; cb->args[0]++) { 419 for (; cb->args[0] < ip_conntrack_htable_size; cb->args[0]++) {
419restart: 420restart:
420 last = (struct ip_conntrack *)cb->args[1];
421 list_for_each_prev(i, &ip_conntrack_hash[cb->args[0]]) { 421 list_for_each_prev(i, &ip_conntrack_hash[cb->args[0]]) {
422 h = (struct ip_conntrack_tuple_hash *) i; 422 h = (struct ip_conntrack_tuple_hash *) i;
423 if (DIRECTION(h) != IP_CT_DIR_ORIGINAL) 423 if (DIRECTION(h) != IP_CT_DIR_ORIGINAL)
424 continue; 424 continue;
425 ct = tuplehash_to_ctrack(h); 425 ct = tuplehash_to_ctrack(h);
426 if (last != NULL) { 426 if (cb->args[1]) {
427 if (ct == last) { 427 if (ct != last)
428 ip_conntrack_put(last);
429 cb->args[1] = 0;
430 last = NULL;
431 } else
432 continue; 428 continue;
429 cb->args[1] = 0;
433 } 430 }
434 if (ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid, 431 if (ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid,
435 cb->nlh->nlmsg_seq, 432 cb->nlh->nlmsg_seq,
@@ -440,17 +437,17 @@ restart:
440 goto out; 437 goto out;
441 } 438 }
442 } 439 }
443 if (last != NULL) { 440 if (cb->args[1]) {
444 ip_conntrack_put(last);
445 cb->args[1] = 0; 441 cb->args[1] = 0;
446 goto restart; 442 goto restart;
447 } 443 }
448 } 444 }
449out: 445out:
450 read_unlock_bh(&ip_conntrack_lock); 446 read_unlock_bh(&ip_conntrack_lock);
447 if (last)
448 ip_conntrack_put(last);
451 449
452 DEBUGP("leaving, last bucket=%lu id=%u\n", cb->args[0], *id); 450 DEBUGP("leaving, last bucket=%lu id=%u\n", cb->args[0], *id);
453
454 return skb->len; 451 return skb->len;
455} 452}
456 453
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index af4845971f70..6527d4e048d8 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -429,9 +429,9 @@ ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
429 cb->args[0], *id); 429 cb->args[0], *id);
430 430
431 read_lock_bh(&nf_conntrack_lock); 431 read_lock_bh(&nf_conntrack_lock);
432 last = (struct nf_conn *)cb->args[1];
432 for (; cb->args[0] < nf_conntrack_htable_size; cb->args[0]++) { 433 for (; cb->args[0] < nf_conntrack_htable_size; cb->args[0]++) {
433restart: 434restart:
434 last = (struct nf_conn *)cb->args[1];
435 list_for_each_prev(i, &nf_conntrack_hash[cb->args[0]]) { 435 list_for_each_prev(i, &nf_conntrack_hash[cb->args[0]]) {
436 h = (struct nf_conntrack_tuple_hash *) i; 436 h = (struct nf_conntrack_tuple_hash *) i;
437 if (DIRECTION(h) != IP_CT_DIR_ORIGINAL) 437 if (DIRECTION(h) != IP_CT_DIR_ORIGINAL)
@@ -442,13 +442,10 @@ restart:
442 * then dump everything. */ 442 * then dump everything. */
443 if (l3proto && L3PROTO(ct) != l3proto) 443 if (l3proto && L3PROTO(ct) != l3proto)
444 continue; 444 continue;
445 if (last != NULL) { 445 if (cb->args[1]) {
446 if (ct == last) { 446 if (ct != last)
447 nf_ct_put(last);
448 cb->args[1] = 0;
449 last = NULL;
450 } else
451 continue; 447 continue;
448 cb->args[1] = 0;
452 } 449 }
453 if (ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid, 450 if (ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid,
454 cb->nlh->nlmsg_seq, 451 cb->nlh->nlmsg_seq,
@@ -459,17 +456,17 @@ restart:
459 goto out; 456 goto out;
460 } 457 }
461 } 458 }
462 if (last != NULL) { 459 if (cb->args[1]) {
463 nf_ct_put(last);
464 cb->args[1] = 0; 460 cb->args[1] = 0;
465 goto restart; 461 goto restart;
466 } 462 }
467 } 463 }
468out: 464out:
469 read_unlock_bh(&nf_conntrack_lock); 465 read_unlock_bh(&nf_conntrack_lock);
466 if (last)
467 nf_ct_put(last);
470 468
471 DEBUGP("leaving, last bucket=%lu id=%u\n", cb->args[0], *id); 469 DEBUGP("leaving, last bucket=%lu id=%u\n", cb->args[0], *id);
472
473 return skb->len; 470 return skb->len;
474} 471}
475 472