Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+27 -16
+27 -16
net/netfilter/nf_conntrack_netlink.c
··· 1367 1367 nf_ct_protonum(ct)); 1368 1368 if (helper == NULL) { 1369 1369 rcu_read_unlock(); 1370 + spin_unlock_bh(&nf_conntrack_lock); 1370 1371 #ifdef CONFIG_MODULES 1371 1372 if (request_module("nfct-helper-%s", helpname) < 0) { 1373 + spin_lock_bh(&nf_conntrack_lock); 1372 1374 err = -EOPNOTSUPP; 1373 1375 goto err1; 1374 1376 } 1375 1377 1378 + spin_lock_bh(&nf_conntrack_lock); 1376 1379 rcu_read_lock(); 1377 1380 helper = __nf_conntrack_helper_find(helpname, 1378 1381 nf_ct_l3num(ct), ··· 1469 1466 tstamp->start = ktime_to_ns(ktime_get_real()); 1470 1467 1471 1468 add_timer(&ct->timeout); 1472 - spin_lock_bh(&nf_conntrack_lock); 1473 1469 nf_conntrack_hash_insert(ct); 1474 - nf_conntrack_get(&ct->ct_general); 1475 - spin_unlock_bh(&nf_conntrack_lock); 1476 1470 rcu_read_unlock(); 1477 1471 1478 1472 return ct; ··· 1490 1490 struct nf_conntrack_tuple otuple, rtuple; 1491 1491 struct nf_conntrack_tuple_hash *h = NULL; 1492 1492 struct nfgenmsg *nfmsg = nlmsg_data(nlh); 1493 - struct nf_conn *ct; 1494 1493 u_int8_t u3 = nfmsg->nfgen_family; 1495 1494 u16 zone; 1496 1495 int err; ··· 1512 1513 1513 1514 spin_lock_bh(&nf_conntrack_lock); 1514 1515 if (cda[CTA_TUPLE_ORIG]) 1515 - h = nf_conntrack_find_get(net, zone, &otuple); 1516 + h = __nf_conntrack_find(net, zone, &otuple); 1516 1517 else if (cda[CTA_TUPLE_REPLY]) 1517 - h = nf_conntrack_find_get(net, zone, &rtuple); 1518 - spin_unlock_bh(&nf_conntrack_lock); 1518 + h = __nf_conntrack_find(net, zone, &rtuple); 1519 1519 1520 1520 if (h == NULL) { 1521 1521 err = -ENOENT; 1522 1522 if (nlh->nlmsg_flags & NLM_F_CREATE) { 1523 + struct nf_conn *ct; 1523 1524 enum ip_conntrack_events events; 1524 1525 1525 1526 ct = ctnetlink_create_conntrack(net, zone, cda, &otuple, 1526 1527 &rtuple, u3); 1527 - if (IS_ERR(ct)) 1528 - return PTR_ERR(ct); 1529 - 1528 + if (IS_ERR(ct)) { 1529 + err = PTR_ERR(ct); 1530 + goto out_unlock; 1531 + } 1530 1532 err = 0; 1533 + nf_conntrack_get(&ct->ct_general); 1534 + spin_unlock_bh(&nf_conntrack_lock); 1531 1535 if (test_bit(IPS_EXPECTED_BIT, &ct->status)) 1532 1536 events = IPCT_RELATED; 1533 1537 else ··· 1545 1543 ct, NETLINK_CB(skb).pid, 1546 1544 nlmsg_report(nlh)); 1547 1545 nf_ct_put(ct); 1548 - } 1546 + } else 1547 + spin_unlock_bh(&nf_conntrack_lock); 1549 1548 1550 1549 return err; 1551 1550 } 1552 1551 /* implicit 'else' */ 1553 1552 1553 + /* We manipulate the conntrack inside the global conntrack table lock, 1554 + * so there's no need to increase the refcount */ 1554 1555 err = -EEXIST; 1555 - ct = nf_ct_tuplehash_to_ctrack(h); 1556 1556 if (!(nlh->nlmsg_flags & NLM_F_EXCL)) { 1557 - spin_lock_bh(&nf_conntrack_lock); 1557 + struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h); 1558 + 1558 1559 err = ctnetlink_change_conntrack(ct, cda); 1559 - spin_unlock_bh(&nf_conntrack_lock); 1560 1560 if (err == 0) { 1561 + nf_conntrack_get(&ct->ct_general); 1562 + spin_unlock_bh(&nf_conntrack_lock); 1561 1563 nf_conntrack_eventmask_report((1 << IPCT_REPLY) | 1562 1564 (1 << IPCT_ASSURED) | 1563 1565 (1 << IPCT_HELPER) | ··· 1570 1564 (1 << IPCT_MARK), 1571 1565 ct, NETLINK_CB(skb).pid, 1572 1566 nlmsg_report(nlh)); 1573 - } 1567 + nf_ct_put(ct); 1568 + } else 1569 + spin_unlock_bh(&nf_conntrack_lock); 1570 + 1571 + return err; 1574 1572 } 1575 1573 1576 - nf_ct_put(ct); 1574 + out_unlock: 1575 + spin_unlock_bh(&nf_conntrack_lock); 1577 1576 return err; 1578 1577 } 1579 1578