Skip to content

Commit

Permalink
netfilter: nf_conncount: Fix garbage collection with zones
Browse files Browse the repository at this point in the history
Currently, we use check_hlist() for garbage colleciton. However, we
use the ‘zone’ from the counted entry to query the existence of
existing entries in the hlist. This could be wrong when they are in
different zones, and this patch fixes this issue.

Fixes: e59ea3d ("netfilter: xt_connlimit: honor conntrack zone if available")
Signed-off-by: Yi-Hung Wei <yihung.wei@gmail.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
  • Loading branch information
Yi-Hung Wei authored and Pablo Neira Ayuso committed Jun 12, 2018
1 parent fc6ddbe commit 21ba884
Show file tree
Hide file tree
Showing 3 changed files with 12 additions and 6 deletions.
3 changes: 2 additions & 1 deletion include/net/netfilter/nf_conntrack_count.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ unsigned int nf_conncount_lookup(struct net *net, struct hlist_head *head,
bool *addit);

bool nf_conncount_add(struct hlist_head *head,
const struct nf_conntrack_tuple *tuple);
const struct nf_conntrack_tuple *tuple,
const struct nf_conntrack_zone *zone);

void nf_conncount_cache_free(struct hlist_head *hhead);

Expand Down
13 changes: 9 additions & 4 deletions net/netfilter/nf_conncount.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
struct nf_conncount_tuple {
struct hlist_node node;
struct nf_conntrack_tuple tuple;
struct nf_conntrack_zone zone;
};

struct nf_conncount_rb {
Expand Down Expand Up @@ -80,14 +81,16 @@ static int key_diff(const u32 *a, const u32 *b, unsigned int klen)
}

bool nf_conncount_add(struct hlist_head *head,
const struct nf_conntrack_tuple *tuple)
const struct nf_conntrack_tuple *tuple,
const struct nf_conntrack_zone *zone)
{
struct nf_conncount_tuple *conn;

conn = kmem_cache_alloc(conncount_conn_cachep, GFP_ATOMIC);
if (conn == NULL)
return false;
conn->tuple = *tuple;
conn->zone = *zone;
hlist_add_head(&conn->node, head);
return true;
}
Expand All @@ -108,7 +111,7 @@ unsigned int nf_conncount_lookup(struct net *net, struct hlist_head *head,

/* check the saved connections */
hlist_for_each_entry_safe(conn, n, head, node) {
found = nf_conntrack_find_get(net, zone, &conn->tuple);
found = nf_conntrack_find_get(net, &conn->zone, &conn->tuple);
if (found == NULL) {
hlist_del(&conn->node);
kmem_cache_free(conncount_conn_cachep, conn);
Expand All @@ -117,7 +120,8 @@ unsigned int nf_conncount_lookup(struct net *net, struct hlist_head *head,

found_ct = nf_ct_tuplehash_to_ctrack(found);

if (tuple && nf_ct_tuple_equal(&conn->tuple, tuple)) {
if (tuple && nf_ct_tuple_equal(&conn->tuple, tuple) &&
nf_ct_zone_equal(found_ct, zone, zone->dir)) {
/*
* Just to be sure we have it only once in the list.
* We should not see tuples twice unless someone hooks
Expand Down Expand Up @@ -196,7 +200,7 @@ count_tree(struct net *net, struct rb_root *root,
if (!addit)
return count;

if (!nf_conncount_add(&rbconn->hhead, tuple))
if (!nf_conncount_add(&rbconn->hhead, tuple, zone))
return 0; /* hotdrop */

return count + 1;
Expand Down Expand Up @@ -238,6 +242,7 @@ count_tree(struct net *net, struct rb_root *root,
}

conn->tuple = *tuple;
conn->zone = *zone;
memcpy(rbconn->key, key, sizeof(u32) * keylen);

INIT_HLIST_HEAD(&rbconn->hhead);
Expand Down
2 changes: 1 addition & 1 deletion net/netfilter/nft_connlimit.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ static inline void nft_connlimit_do_eval(struct nft_connlimit *priv,
if (!addit)
goto out;

if (!nf_conncount_add(&priv->hhead, tuple_ptr)) {
if (!nf_conncount_add(&priv->hhead, tuple_ptr, zone)) {
regs->verdict.code = NF_DROP;
spin_unlock_bh(&priv->lock);
return;
Expand Down

0 comments on commit 21ba884

Please sign in to comment.