Skip to content

Commit

Permalink
Revert "netfilter: move nat hlist_head to nf_conn"
Browse files Browse the repository at this point in the history
This reverts commit 7c96643 as it is
not working properly.  Please move to 4.9 to get the full fix.

Reported-by: Pablo Neira Ayuso <pablo@netfilter.org>
Cc: Florian Westphal <fw@strlen.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Greg Kroah-Hartman committed Jan 6, 2017
1 parent 99d6d4e commit f199bdb
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 12 deletions.
3 changes: 0 additions & 3 deletions include/net/netfilter/nf_conntrack.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,6 @@ struct nf_conn {
/* Extensions */
struct nf_ct_ext *ext;

#if IS_ENABLED(CONFIG_NF_NAT)
struct hlist_node nat_bysource;
#endif
/* Storage reserved for other modules, must be the last member */
union nf_conntrack_proto proto;
};
Expand Down
3 changes: 3 additions & 0 deletions include/net/netfilter/nf_conntrack_extend.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@ void *__nf_ct_ext_add_length(struct nf_conn *ct, enum nf_ct_ext_id id,
struct nf_ct_ext_type {
/* Destroys relationships (can be NULL). */
void (*destroy)(struct nf_conn *ct);
/* Called when realloacted (can be NULL).
Contents has already been moved. */
void (*move)(void *new, void *old);

enum nf_ct_ext_id id;

Expand Down
2 changes: 2 additions & 0 deletions include/net/netfilter/nf_nat.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ struct nf_conn;

/* The structure embedded in the conntrack structure. */
struct nf_conn_nat {
struct hlist_node bysource;
struct nf_conn *ct;
union nf_conntrack_nat_help help;
#if IS_ENABLED(CONFIG_NF_NAT_MASQUERADE_IPV4) || \
IS_ENABLED(CONFIG_NF_NAT_MASQUERADE_IPV6)
Expand Down
15 changes: 13 additions & 2 deletions net/netfilter/nf_conntrack_extend.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ void *__nf_ct_ext_add_length(struct nf_conn *ct, enum nf_ct_ext_id id,
size_t var_alloc_len, gfp_t gfp)
{
struct nf_ct_ext *old, *new;
int newlen, newoff;
int i, newlen, newoff;
struct nf_ct_ext_type *t;

/* Conntrack must not be confirmed to avoid races on reallocation. */
Expand All @@ -99,8 +99,19 @@ void *__nf_ct_ext_add_length(struct nf_conn *ct, enum nf_ct_ext_id id,
return NULL;

if (new != old) {
for (i = 0; i < NF_CT_EXT_NUM; i++) {
if (!__nf_ct_ext_exist(old, i))
continue;

rcu_read_lock();
t = rcu_dereference(nf_ct_ext_types[i]);
if (t && t->move)
t->move((void *)new + new->offset[i],
(void *)old + old->offset[i]);
rcu_read_unlock();
}
kfree_rcu(old, rcu);
rcu_assign_pointer(ct->ext, new);
ct->ext = new;
}

new->offset[id] = newoff;
Expand Down
33 changes: 26 additions & 7 deletions net/netfilter/nf_nat_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -198,9 +198,11 @@ find_appropriate_src(struct net *net,
const struct nf_nat_range *range)
{
unsigned int h = hash_by_src(net, tuple);
const struct nf_conn_nat *nat;
const struct nf_conn *ct;

hlist_for_each_entry_rcu(ct, &nf_nat_bysource[h], nat_bysource) {
hlist_for_each_entry_rcu(nat, &nf_nat_bysource[h], bysource) {
ct = nat->ct;
if (same_src(ct, tuple) &&
net_eq(net, nf_ct_net(ct)) &&
nf_ct_zone_equal(ct, zone, IP_CT_DIR_ORIGINAL)) {
Expand Down Expand Up @@ -434,7 +436,8 @@ nf_nat_setup_info(struct nf_conn *ct,
spin_lock_bh(&nf_nat_lock);
/* nf_conntrack_alter_reply might re-allocate extension aera */
nat = nfct_nat(ct);
hlist_add_head_rcu(&ct->nat_bysource,
nat->ct = ct;
hlist_add_head_rcu(&nat->bysource,
&nf_nat_bysource[srchash]);
spin_unlock_bh(&nf_nat_lock);
}
Expand Down Expand Up @@ -541,7 +544,7 @@ static int nf_nat_proto_clean(struct nf_conn *ct, void *data)
if (nf_nat_proto_remove(ct, data))
return 1;

if (!nat)
if (!nat || !nat->ct)
return 0;

/* This netns is being destroyed, and conntrack has nat null binding.
Expand All @@ -554,8 +557,9 @@ static int nf_nat_proto_clean(struct nf_conn *ct, void *data)
return 1;

spin_lock_bh(&nf_nat_lock);
hlist_del_rcu(&ct->nat_bysource);
hlist_del_rcu(&nat->bysource);
ct->status &= ~IPS_NAT_DONE_MASK;
nat->ct = NULL;
spin_unlock_bh(&nf_nat_lock);

add_timer(&ct->timeout);
Expand Down Expand Up @@ -685,20 +689,35 @@ static void nf_nat_cleanup_conntrack(struct nf_conn *ct)
{
struct nf_conn_nat *nat = nf_ct_ext_find(ct, NF_CT_EXT_NAT);

if (!nat)
if (nat == NULL || nat->ct == NULL)
return;

NF_CT_ASSERT(ct->status & IPS_SRC_NAT_DONE);
NF_CT_ASSERT(nat->ct->status & IPS_SRC_NAT_DONE);

spin_lock_bh(&nf_nat_lock);
hlist_del_rcu(&nat->bysource);
spin_unlock_bh(&nf_nat_lock);
}

static void nf_nat_move_storage(void *new, void *old)
{
struct nf_conn_nat *new_nat = new;
struct nf_conn_nat *old_nat = old;
struct nf_conn *ct = old_nat->ct;

if (!ct || !(ct->status & IPS_SRC_NAT_DONE))
return;

spin_lock_bh(&nf_nat_lock);
hlist_del_rcu(&ct->nat_bysource);
hlist_replace_rcu(&old_nat->bysource, &new_nat->bysource);
spin_unlock_bh(&nf_nat_lock);
}

static struct nf_ct_ext_type nat_extend __read_mostly = {
.len = sizeof(struct nf_conn_nat),
.align = __alignof__(struct nf_conn_nat),
.destroy = nf_nat_cleanup_conntrack,
.move = nf_nat_move_storage,
.id = NF_CT_EXT_NAT,
.flags = NF_CT_EXT_F_PREALLOC,
};
Expand Down

0 comments on commit f199bdb

Please sign in to comment.