[NETFILTER]: nf_conntrack: fix ct_extend ->move operation
The ->move operation has two bugs: - It is called with the same extension as source and destination, so it doesn't update the new extension. - The address of the old extension is calculated incorrectly, instead of (void *)ct->ext + ct->ext->offset[i] it uses ct->ext + ct->ext->offset[i]. Fixes a crash on x86_64 reported by Chuck Ebbert <cebbert@redhat.com> and Thomas Woerner <twoerner@redhat.com>. Tested-by: Thomas Woerner <twoerner@redhat.com> Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
b2155e7f70
commit
86577c661b
@@ -67,7 +67,7 @@ struct nf_ct_ext_type
|
|||||||
void (*destroy)(struct nf_conn *ct);
|
void (*destroy)(struct nf_conn *ct);
|
||||||
/* Called when realloacted (can be NULL).
|
/* Called when realloacted (can be NULL).
|
||||||
Contents has already been moved. */
|
Contents has already been moved. */
|
||||||
void (*move)(struct nf_conn *ct, void *old);
|
void (*move)(void *new, void *old);
|
||||||
|
|
||||||
enum nf_ct_ext_id id;
|
enum nf_ct_ext_id id;
|
||||||
|
|
||||||
|
@@ -600,10 +600,10 @@ static void nf_nat_cleanup_conntrack(struct nf_conn *ct)
|
|||||||
spin_unlock_bh(&nf_nat_lock);
|
spin_unlock_bh(&nf_nat_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nf_nat_move_storage(struct nf_conn *conntrack, void *old)
|
static void nf_nat_move_storage(void *new, void *old)
|
||||||
{
|
{
|
||||||
struct nf_conn_nat *new_nat = nf_ct_ext_find(conntrack, NF_CT_EXT_NAT);
|
struct nf_conn_nat *new_nat = new;
|
||||||
struct nf_conn_nat *old_nat = (struct nf_conn_nat *)old;
|
struct nf_conn_nat *old_nat = old;
|
||||||
struct nf_conn *ct = old_nat->ct;
|
struct nf_conn *ct = old_nat->ct;
|
||||||
|
|
||||||
if (!ct || !(ct->status & IPS_NAT_DONE_MASK))
|
if (!ct || !(ct->status & IPS_NAT_DONE_MASK))
|
||||||
|
@@ -109,7 +109,8 @@ void *__nf_ct_ext_add(struct nf_conn *ct, enum nf_ct_ext_id id, gfp_t gfp)
|
|||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
t = rcu_dereference(nf_ct_ext_types[i]);
|
t = rcu_dereference(nf_ct_ext_types[i]);
|
||||||
if (t && t->move)
|
if (t && t->move)
|
||||||
t->move(ct, ct->ext + ct->ext->offset[i]);
|
t->move((void *)new + new->offset[i],
|
||||||
|
(void *)ct->ext + ct->ext->offset[i]);
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
}
|
}
|
||||||
kfree(ct->ext);
|
kfree(ct->ext);
|
||||||
|
Reference in New Issue
Block a user