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

netfilter: conntrack: check netns when comparing conntrack objects

Once we place all conntracks in the same hash table we must also compare
the netns pointer to skip conntracks that belong to a different namespace.

Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

authored by

Florian Westphal and committed by
Pablo Neira Ayuso
e0c7d472 245cfdca

+22 -12
+6 -2
net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c
··· 115 115 #endif 116 116 117 117 static bool ct_seq_should_skip(const struct nf_conn *ct, 118 + const struct net *net, 118 119 const struct nf_conntrack_tuple_hash *hash) 119 120 { 120 121 /* we only want to print DIR_ORIGINAL */ ··· 123 122 return true; 124 123 125 124 if (nf_ct_l3num(ct) != AF_INET) 125 + return true; 126 + 127 + if (!net_eq(nf_ct_net(ct), net)) 126 128 return true; 127 129 128 130 return false; ··· 140 136 int ret = 0; 141 137 142 138 NF_CT_ASSERT(ct); 143 - if (ct_seq_should_skip(ct, hash)) 139 + if (ct_seq_should_skip(ct, seq_file_net(s), hash)) 144 140 return 0; 145 141 146 142 if (unlikely(!atomic_inc_not_zero(&ct->ct_general.use))) ··· 148 144 149 145 /* check if we raced w. object reuse */ 150 146 if (!nf_ct_is_confirmed(ct) || 151 - ct_seq_should_skip(ct, hash)) 147 + ct_seq_should_skip(ct, seq_file_net(s), hash)) 152 148 goto release; 153 149 154 150 l3proto = __nf_ct_l3proto_find(nf_ct_l3num(ct));
+13 -10
net/netfilter/nf_conntrack_core.c
··· 447 447 static inline bool 448 448 nf_ct_key_equal(struct nf_conntrack_tuple_hash *h, 449 449 const struct nf_conntrack_tuple *tuple, 450 - const struct nf_conntrack_zone *zone) 450 + const struct nf_conntrack_zone *zone, 451 + const struct net *net) 451 452 { 452 453 struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h); 453 454 ··· 457 456 */ 458 457 return nf_ct_tuple_equal(tuple, &h->tuple) && 459 458 nf_ct_zone_equal(ct, zone, NF_CT_DIRECTION(h)) && 460 - nf_ct_is_confirmed(ct); 459 + nf_ct_is_confirmed(ct) && 460 + net_eq(net, nf_ct_net(ct)); 461 461 } 462 462 463 463 /* ··· 483 481 } while (read_seqcount_retry(&nf_conntrack_generation, sequence)); 484 482 485 483 hlist_nulls_for_each_entry_rcu(h, n, &ct_hash[bucket], hnnode) { 486 - if (nf_ct_key_equal(h, tuple, zone)) { 484 + if (nf_ct_key_equal(h, tuple, zone, net)) { 487 485 NF_CT_STAT_INC_ATOMIC(net, found); 488 486 return h; 489 487 } ··· 519 517 !atomic_inc_not_zero(&ct->ct_general.use))) 520 518 h = NULL; 521 519 else { 522 - if (unlikely(!nf_ct_key_equal(h, tuple, zone))) { 520 + if (unlikely(!nf_ct_key_equal(h, tuple, zone, net))) { 523 521 nf_ct_put(ct); 524 522 goto begin; 525 523 } ··· 575 573 /* See if there's one in the list already, including reverse */ 576 574 hlist_nulls_for_each_entry(h, n, &net->ct.hash[hash], hnnode) 577 575 if (nf_ct_key_equal(h, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, 578 - zone)) 576 + zone, net)) 579 577 goto out; 580 578 581 579 hlist_nulls_for_each_entry(h, n, &net->ct.hash[reply_hash], hnnode) 582 580 if (nf_ct_key_equal(h, &ct->tuplehash[IP_CT_DIR_REPLY].tuple, 583 - zone)) 581 + zone, net)) 584 582 goto out; 585 583 586 584 add_timer(&ct->timeout); ··· 665 663 not in the hash. If there is, we lost race. */ 666 664 hlist_nulls_for_each_entry(h, n, &net->ct.hash[hash], hnnode) 667 665 if (nf_ct_key_equal(h, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, 668 - zone)) 666 + zone, net)) 669 667 goto out; 670 668 671 669 hlist_nulls_for_each_entry(h, n, &net->ct.hash[reply_hash], hnnode) 672 670 if (nf_ct_key_equal(h, &ct->tuplehash[IP_CT_DIR_REPLY].tuple, 673 - zone)) 671 + zone, net)) 674 672 goto out; 675 673 676 674 /* Timer relative to confirmation time, not original ··· 742 740 hlist_nulls_for_each_entry_rcu(h, n, &ct_hash[hash], hnnode) { 743 741 ct = nf_ct_tuplehash_to_ctrack(h); 744 742 if (ct != ignored_conntrack && 745 - nf_ct_key_equal(h, tuple, zone)) { 743 + nf_ct_key_equal(h, tuple, zone, net)) { 746 744 NF_CT_STAT_INC_ATOMIC(net, found); 747 745 rcu_read_unlock(); 748 746 return 1; ··· 1385 1383 if (NF_CT_DIRECTION(h) != IP_CT_DIR_ORIGINAL) 1386 1384 continue; 1387 1385 ct = nf_ct_tuplehash_to_ctrack(h); 1388 - if (iter(ct, data)) 1386 + if (net_eq(nf_ct_net(ct), net) && 1387 + iter(ct, data)) 1389 1388 goto found; 1390 1389 } 1391 1390 }
+3
net/netfilter/nf_conntrack_netlink.c
··· 837 837 if (NF_CT_DIRECTION(h) != IP_CT_DIR_ORIGINAL) 838 838 continue; 839 839 ct = nf_ct_tuplehash_to_ctrack(h); 840 + if (!net_eq(net, nf_ct_net(ct))) 841 + continue; 842 + 840 843 /* Dump entries of a given L3 protocol number. 841 844 * If it is not specified, ie. l3proto == 0, 842 845 * then dump everything. */