Commit 530aad77 authored by Florian Westphal's avatar Florian Westphal Committed by Pablo Neira Ayuso

netfilter: seqadj: re-load tcp header pointer after possible head reallocation

When adjusting sack block sequence numbers, skb_make_writable() gets
called to make sure tcp options are all in the linear area, and buffer
is not shared.

This can cause tcp header pointer to get reallocated, so we must
reaload it to avoid memory corruption.

This bug pre-dates git history.
Reported-by: default avatarNeel Mehta <nmehta@google.com>
Reported-by: default avatarShane Huntley <shuntley@google.com>
Reported-by: default avatarHeather Adkins <argv@google.com>
Signed-off-by: default avatarFlorian Westphal <fw@strlen.de>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent 4c05ec47
...@@ -115,12 +115,12 @@ static void nf_ct_sack_block_adjust(struct sk_buff *skb, ...@@ -115,12 +115,12 @@ static void nf_ct_sack_block_adjust(struct sk_buff *skb,
/* TCP SACK sequence number adjustment */ /* TCP SACK sequence number adjustment */
static unsigned int nf_ct_sack_adjust(struct sk_buff *skb, static unsigned int nf_ct_sack_adjust(struct sk_buff *skb,
unsigned int protoff, unsigned int protoff,
struct tcphdr *tcph,
struct nf_conn *ct, struct nf_conn *ct,
enum ip_conntrack_info ctinfo) enum ip_conntrack_info ctinfo)
{ {
unsigned int dir, optoff, optend; struct tcphdr *tcph = (void *)skb->data + protoff;
struct nf_conn_seqadj *seqadj = nfct_seqadj(ct); struct nf_conn_seqadj *seqadj = nfct_seqadj(ct);
unsigned int dir, optoff, optend;
optoff = protoff + sizeof(struct tcphdr); optoff = protoff + sizeof(struct tcphdr);
optend = protoff + tcph->doff * 4; optend = protoff + tcph->doff * 4;
...@@ -128,6 +128,7 @@ static unsigned int nf_ct_sack_adjust(struct sk_buff *skb, ...@@ -128,6 +128,7 @@ static unsigned int nf_ct_sack_adjust(struct sk_buff *skb,
if (!skb_make_writable(skb, optend)) if (!skb_make_writable(skb, optend))
return 0; return 0;
tcph = (void *)skb->data + protoff;
dir = CTINFO2DIR(ctinfo); dir = CTINFO2DIR(ctinfo);
while (optoff < optend) { while (optoff < optend) {
...@@ -207,7 +208,7 @@ int nf_ct_seq_adjust(struct sk_buff *skb, ...@@ -207,7 +208,7 @@ int nf_ct_seq_adjust(struct sk_buff *skb,
ntohl(newack)); ntohl(newack));
tcph->ack_seq = newack; tcph->ack_seq = newack;
res = nf_ct_sack_adjust(skb, protoff, tcph, ct, ctinfo); res = nf_ct_sack_adjust(skb, protoff, ct, ctinfo);
out: out:
spin_unlock_bh(&ct->lock); spin_unlock_bh(&ct->lock);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment