diff options
author | Pablo Neira Ayuso <pablo@netfilter.org> | 2012-02-24 06:18:38 -0500 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2012-02-24 06:19:57 -0500 |
commit | 279072882dc0149e5740dace075e1a49f087046d (patch) | |
tree | 0a375ec930d918c2a0a622e613a59cd8b9b15486 /net | |
parent | 4a2258ddddefeef3291c0fc66437c73d84261a1e (diff) |
Revert "netfilter: ctnetlink: fix soft lockup when netlink adds new entries"
This reverts commit af14cca162ddcdea017b648c21b9b091e4bf1fa4.
This patch contains a race condition between packets and ctnetlink
in the conntrack addition. A new patch to fix this issue follows up.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'net')
-rw-r--r-- | net/netfilter/nf_conntrack_netlink.c | 43 |
1 files changed, 27 insertions, 16 deletions
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index cc705175765c..9307b033c0c9 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c | |||
@@ -1367,12 +1367,15 @@ ctnetlink_create_conntrack(struct net *net, u16 zone, | |||
1367 | nf_ct_protonum(ct)); | 1367 | nf_ct_protonum(ct)); |
1368 | if (helper == NULL) { | 1368 | if (helper == NULL) { |
1369 | rcu_read_unlock(); | 1369 | rcu_read_unlock(); |
1370 | spin_unlock_bh(&nf_conntrack_lock); | ||
1370 | #ifdef CONFIG_MODULES | 1371 | #ifdef CONFIG_MODULES |
1371 | if (request_module("nfct-helper-%s", helpname) < 0) { | 1372 | if (request_module("nfct-helper-%s", helpname) < 0) { |
1373 | spin_lock_bh(&nf_conntrack_lock); | ||
1372 | err = -EOPNOTSUPP; | 1374 | err = -EOPNOTSUPP; |
1373 | goto err1; | 1375 | goto err1; |
1374 | } | 1376 | } |
1375 | 1377 | ||
1378 | spin_lock_bh(&nf_conntrack_lock); | ||
1376 | rcu_read_lock(); | 1379 | rcu_read_lock(); |
1377 | helper = __nf_conntrack_helper_find(helpname, | 1380 | helper = __nf_conntrack_helper_find(helpname, |
1378 | nf_ct_l3num(ct), | 1381 | nf_ct_l3num(ct), |
@@ -1466,10 +1469,7 @@ ctnetlink_create_conntrack(struct net *net, u16 zone, | |||
1466 | tstamp->start = ktime_to_ns(ktime_get_real()); | 1469 | tstamp->start = ktime_to_ns(ktime_get_real()); |
1467 | 1470 | ||
1468 | add_timer(&ct->timeout); | 1471 | add_timer(&ct->timeout); |
1469 | spin_lock_bh(&nf_conntrack_lock); | ||
1470 | nf_conntrack_hash_insert(ct); | 1472 | nf_conntrack_hash_insert(ct); |
1471 | nf_conntrack_get(&ct->ct_general); | ||
1472 | spin_unlock_bh(&nf_conntrack_lock); | ||
1473 | rcu_read_unlock(); | 1473 | rcu_read_unlock(); |
1474 | 1474 | ||
1475 | return ct; | 1475 | return ct; |
@@ -1490,7 +1490,6 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, | |||
1490 | struct nf_conntrack_tuple otuple, rtuple; | 1490 | struct nf_conntrack_tuple otuple, rtuple; |
1491 | struct nf_conntrack_tuple_hash *h = NULL; | 1491 | struct nf_conntrack_tuple_hash *h = NULL; |
1492 | struct nfgenmsg *nfmsg = nlmsg_data(nlh); | 1492 | struct nfgenmsg *nfmsg = nlmsg_data(nlh); |
1493 | struct nf_conn *ct; | ||
1494 | u_int8_t u3 = nfmsg->nfgen_family; | 1493 | u_int8_t u3 = nfmsg->nfgen_family; |
1495 | u16 zone; | 1494 | u16 zone; |
1496 | int err; | 1495 | int err; |
@@ -1513,22 +1512,25 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, | |||
1513 | 1512 | ||
1514 | spin_lock_bh(&nf_conntrack_lock); | 1513 | spin_lock_bh(&nf_conntrack_lock); |
1515 | if (cda[CTA_TUPLE_ORIG]) | 1514 | if (cda[CTA_TUPLE_ORIG]) |
1516 | h = nf_conntrack_find_get(net, zone, &otuple); | 1515 | h = __nf_conntrack_find(net, zone, &otuple); |
1517 | else if (cda[CTA_TUPLE_REPLY]) | 1516 | else if (cda[CTA_TUPLE_REPLY]) |
1518 | h = nf_conntrack_find_get(net, zone, &rtuple); | 1517 | h = __nf_conntrack_find(net, zone, &rtuple); |
1519 | spin_unlock_bh(&nf_conntrack_lock); | ||
1520 | 1518 | ||
1521 | if (h == NULL) { | 1519 | if (h == NULL) { |
1522 | err = -ENOENT; | 1520 | err = -ENOENT; |
1523 | if (nlh->nlmsg_flags & NLM_F_CREATE) { | 1521 | if (nlh->nlmsg_flags & NLM_F_CREATE) { |
1522 | struct nf_conn *ct; | ||
1524 | enum ip_conntrack_events events; | 1523 | enum ip_conntrack_events events; |
1525 | 1524 | ||
1526 | ct = ctnetlink_create_conntrack(net, zone, cda, &otuple, | 1525 | ct = ctnetlink_create_conntrack(net, zone, cda, &otuple, |
1527 | &rtuple, u3); | 1526 | &rtuple, u3); |
1528 | if (IS_ERR(ct)) | 1527 | if (IS_ERR(ct)) { |
1529 | return PTR_ERR(ct); | 1528 | err = PTR_ERR(ct); |
1530 | 1529 | goto out_unlock; | |
1530 | } | ||
1531 | err = 0; | 1531 | err = 0; |
1532 | nf_conntrack_get(&ct->ct_general); | ||
1533 | spin_unlock_bh(&nf_conntrack_lock); | ||
1532 | if (test_bit(IPS_EXPECTED_BIT, &ct->status)) | 1534 | if (test_bit(IPS_EXPECTED_BIT, &ct->status)) |
1533 | events = IPCT_RELATED; | 1535 | events = IPCT_RELATED; |
1534 | else | 1536 | else |
@@ -1543,19 +1545,23 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, | |||
1543 | ct, NETLINK_CB(skb).pid, | 1545 | ct, NETLINK_CB(skb).pid, |
1544 | nlmsg_report(nlh)); | 1546 | nlmsg_report(nlh)); |
1545 | nf_ct_put(ct); | 1547 | nf_ct_put(ct); |
1546 | } | 1548 | } else |
1549 | spin_unlock_bh(&nf_conntrack_lock); | ||
1547 | 1550 | ||
1548 | return err; | 1551 | return err; |
1549 | } | 1552 | } |
1550 | /* implicit 'else' */ | 1553 | /* implicit 'else' */ |
1551 | 1554 | ||
1555 | /* We manipulate the conntrack inside the global conntrack table lock, | ||
1556 | * so there's no need to increase the refcount */ | ||
1552 | err = -EEXIST; | 1557 | err = -EEXIST; |
1553 | ct = nf_ct_tuplehash_to_ctrack(h); | ||
1554 | if (!(nlh->nlmsg_flags & NLM_F_EXCL)) { | 1558 | if (!(nlh->nlmsg_flags & NLM_F_EXCL)) { |
1555 | spin_lock_bh(&nf_conntrack_lock); | 1559 | struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h); |
1560 | |||
1556 | err = ctnetlink_change_conntrack(ct, cda); | 1561 | err = ctnetlink_change_conntrack(ct, cda); |
1557 | spin_unlock_bh(&nf_conntrack_lock); | ||
1558 | if (err == 0) { | 1562 | if (err == 0) { |
1563 | nf_conntrack_get(&ct->ct_general); | ||
1564 | spin_unlock_bh(&nf_conntrack_lock); | ||
1559 | nf_conntrack_eventmask_report((1 << IPCT_REPLY) | | 1565 | nf_conntrack_eventmask_report((1 << IPCT_REPLY) | |
1560 | (1 << IPCT_ASSURED) | | 1566 | (1 << IPCT_ASSURED) | |
1561 | (1 << IPCT_HELPER) | | 1567 | (1 << IPCT_HELPER) | |
@@ -1564,10 +1570,15 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, | |||
1564 | (1 << IPCT_MARK), | 1570 | (1 << IPCT_MARK), |
1565 | ct, NETLINK_CB(skb).pid, | 1571 | ct, NETLINK_CB(skb).pid, |
1566 | nlmsg_report(nlh)); | 1572 | nlmsg_report(nlh)); |
1567 | } | 1573 | nf_ct_put(ct); |
1574 | } else | ||
1575 | spin_unlock_bh(&nf_conntrack_lock); | ||
1576 | |||
1577 | return err; | ||
1568 | } | 1578 | } |
1569 | 1579 | ||
1570 | nf_ct_put(ct); | 1580 | out_unlock: |
1581 | spin_unlock_bh(&nf_conntrack_lock); | ||
1571 | return err; | 1582 | return err; |
1572 | } | 1583 | } |
1573 | 1584 | ||