Commit 03b6d0ef authored by Rusty Russell's avatar Rusty Russell Committed by Linus Torvalds

[PATCH] ftp nonlinear packet fix

FTP connection tracking assumes it can just dereference tcphdr; not
neccessarily true now we don't linearize in ftp conntrack helper or
tcp connection tracking.  Also found by nfsim.
Signed-off-by: default avatarRusty Russell <rusty@rustcorp.com.au>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent d2e7f926
...@@ -169,18 +169,16 @@ static int (*mangle[])(struct sk_buff **, u_int32_t, u_int16_t, ...@@ -169,18 +169,16 @@ static int (*mangle[])(struct sk_buff **, u_int32_t, u_int16_t,
static int ftp_data_fixup(const struct ip_ct_ftp_expect *exp_ftp_info, static int ftp_data_fixup(const struct ip_ct_ftp_expect *exp_ftp_info,
struct ip_conntrack *ct, struct ip_conntrack *ct,
struct sk_buff **pskb, struct sk_buff **pskb,
u32 tcp_seq,
enum ip_conntrack_info ctinfo, enum ip_conntrack_info ctinfo,
struct ip_conntrack_expect *expect) struct ip_conntrack_expect *expect)
{ {
u_int32_t newip; u_int32_t newip;
struct iphdr *iph = (*pskb)->nh.iph;
struct tcphdr *tcph = (void *)iph + iph->ihl*4;
u_int16_t port; u_int16_t port;
struct ip_conntrack_tuple newtuple; struct ip_conntrack_tuple newtuple;
DEBUGP("FTP_NAT: seq %u + %u in %u\n", DEBUGP("FTP_NAT: seq %u + %u in %u\n",
expect->seq, exp_ftp_info->len, expect->seq, exp_ftp_info->len, tcp_seq);
ntohl(tcph->seq));
/* Change address inside packet to match way we're mapping /* Change address inside packet to match way we're mapping
this connection. */ this connection. */
...@@ -217,7 +215,7 @@ static int ftp_data_fixup(const struct ip_ct_ftp_expect *exp_ftp_info, ...@@ -217,7 +215,7 @@ static int ftp_data_fixup(const struct ip_ct_ftp_expect *exp_ftp_info,
return 0; return 0;
if (!mangle[exp_ftp_info->ftptype](pskb, newip, port, if (!mangle[exp_ftp_info->ftptype](pskb, newip, port,
expect->seq - ntohl(tcph->seq), expect->seq - tcp_seq,
exp_ftp_info->len, ct, ctinfo)) exp_ftp_info->len, ct, ctinfo))
return 0; return 0;
...@@ -232,7 +230,7 @@ static unsigned int help(struct ip_conntrack *ct, ...@@ -232,7 +230,7 @@ static unsigned int help(struct ip_conntrack *ct,
struct sk_buff **pskb) struct sk_buff **pskb)
{ {
struct iphdr *iph = (*pskb)->nh.iph; struct iphdr *iph = (*pskb)->nh.iph;
struct tcphdr *tcph = (void *)iph + iph->ihl*4; struct tcphdr _tcph, *tcph;
unsigned int datalen; unsigned int datalen;
int dir; int dir;
struct ip_ct_ftp_expect *exp_ftp_info; struct ip_ct_ftp_expect *exp_ftp_info;
...@@ -255,12 +253,17 @@ static unsigned int help(struct ip_conntrack *ct, ...@@ -255,12 +253,17 @@ static unsigned int help(struct ip_conntrack *ct,
return NF_ACCEPT; return NF_ACCEPT;
} }
/* We passed tcp tracking, plus ftp helper: this must succeed. */
tcph = skb_header_pointer(*pskb, iph->ihl * 4, sizeof(_tcph), &_tcph);
BUG_ON(!tcph);
datalen = (*pskb)->len - iph->ihl * 4 - tcph->doff * 4; datalen = (*pskb)->len - iph->ihl * 4 - tcph->doff * 4;
/* If it's in the right range... */ /* If it's in the right range... */
if (between(exp->seq + exp_ftp_info->len, if (between(exp->seq + exp_ftp_info->len,
ntohl(tcph->seq), ntohl(tcph->seq),
ntohl(tcph->seq) + datalen)) { ntohl(tcph->seq) + datalen)) {
if (!ftp_data_fixup(exp_ftp_info, ct, pskb, ctinfo, exp)) if (!ftp_data_fixup(exp_ftp_info, ct, pskb, ntohl(tcph->seq),
ctinfo, exp))
return NF_DROP; return NF_DROP;
} else { } else {
/* Half a match? This means a partial retransmisison. /* Half a match? This means a partial retransmisison.
......
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