Commit 86577c661bc01d5c4e477d74567df4470d6c5138

Authored by Patrick McHardy
Committed by David S. Miller
1 parent b2155e7f70

[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>

Showing 3 changed files with 6 additions and 5 deletions Side-by-side Diff

include/net/netfilter/nf_conntrack_extend.h
... ... @@ -67,7 +67,7 @@
67 67 void (*destroy)(struct nf_conn *ct);
68 68 /* Called when realloacted (can be NULL).
69 69 Contents has already been moved. */
70   - void (*move)(struct nf_conn *ct, void *old);
  70 + void (*move)(void *new, void *old);
71 71  
72 72 enum nf_ct_ext_id id;
73 73  
net/ipv4/netfilter/nf_nat_core.c
... ... @@ -600,10 +600,10 @@
600 600 spin_unlock_bh(&nf_nat_lock);
601 601 }
602 602  
603   -static void nf_nat_move_storage(struct nf_conn *conntrack, void *old)
  603 +static void nf_nat_move_storage(void *new, void *old)
604 604 {
605   - struct nf_conn_nat *new_nat = nf_ct_ext_find(conntrack, NF_CT_EXT_NAT);
606   - struct nf_conn_nat *old_nat = (struct nf_conn_nat *)old;
  605 + struct nf_conn_nat *new_nat = new;
  606 + struct nf_conn_nat *old_nat = old;
607 607 struct nf_conn *ct = old_nat->ct;
608 608  
609 609 if (!ct || !(ct->status & IPS_NAT_DONE_MASK))
net/netfilter/nf_conntrack_extend.c
... ... @@ -109,7 +109,8 @@
109 109 rcu_read_lock();
110 110 t = rcu_dereference(nf_ct_ext_types[i]);
111 111 if (t && t->move)
112   - t->move(ct, ct->ext + ct->ext->offset[i]);
  112 + t->move((void *)new + new->offset[i],
  113 + (void *)ct->ext + ct->ext->offset[i]);
113 114 rcu_read_unlock();
114 115 }
115 116 kfree(ct->ext);