diff options
author | Pablo Neira Ayuso <pablo@netfilter.org> | 2013-07-25 04:37:49 -0400 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2013-08-01 05:42:53 -0400 |
commit | 71ffe9c77dd7a2b62207953091efa8dafec958dd (patch) | |
tree | d0251ec9b294378915562e50a62ae095616d5430 /net | |
parent | a661b43fd047ef501da43a19975415f861c7c3db (diff) |
netfilter: xt_TCPMSS: fix handling of malformed TCP header and options
Make sure the packet has enough room for the TCP header and
that it is not malformed.
While at it, store tcph->doff*4 in a variable, as it is used
several times.
This patch also fixes a possible off by one in case of malformed
TCP options.
Reported-by: Julian Anastasov <ja@ssi.bg>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'net')
-rw-r--r-- | net/netfilter/xt_TCPMSS.c | 28 |
1 files changed, 16 insertions, 12 deletions
diff --git a/net/netfilter/xt_TCPMSS.c b/net/netfilter/xt_TCPMSS.c index 7011c71646f0..6113cc7efffc 100644 --- a/net/netfilter/xt_TCPMSS.c +++ b/net/netfilter/xt_TCPMSS.c | |||
@@ -52,7 +52,8 @@ tcpmss_mangle_packet(struct sk_buff *skb, | |||
52 | { | 52 | { |
53 | const struct xt_tcpmss_info *info = par->targinfo; | 53 | const struct xt_tcpmss_info *info = par->targinfo; |
54 | struct tcphdr *tcph; | 54 | struct tcphdr *tcph; |
55 | unsigned int tcplen, i; | 55 | int len, tcp_hdrlen; |
56 | unsigned int i; | ||
56 | __be16 oldval; | 57 | __be16 oldval; |
57 | u16 newmss; | 58 | u16 newmss; |
58 | u8 *opt; | 59 | u8 *opt; |
@@ -64,11 +65,14 @@ tcpmss_mangle_packet(struct sk_buff *skb, | |||
64 | if (!skb_make_writable(skb, skb->len)) | 65 | if (!skb_make_writable(skb, skb->len)) |
65 | return -1; | 66 | return -1; |
66 | 67 | ||
67 | tcplen = skb->len - tcphoff; | 68 | len = skb->len - tcphoff; |
69 | if (len < (int)sizeof(struct tcphdr)) | ||
70 | return -1; | ||
71 | |||
68 | tcph = (struct tcphdr *)(skb_network_header(skb) + tcphoff); | 72 | tcph = (struct tcphdr *)(skb_network_header(skb) + tcphoff); |
73 | tcp_hdrlen = tcph->doff * 4; | ||
69 | 74 | ||
70 | /* Header cannot be larger than the packet */ | 75 | if (len < tcp_hdrlen) |
71 | if (tcplen < tcph->doff*4) | ||
72 | return -1; | 76 | return -1; |
73 | 77 | ||
74 | if (info->mss == XT_TCPMSS_CLAMP_PMTU) { | 78 | if (info->mss == XT_TCPMSS_CLAMP_PMTU) { |
@@ -87,9 +91,8 @@ tcpmss_mangle_packet(struct sk_buff *skb, | |||
87 | newmss = info->mss; | 91 | newmss = info->mss; |
88 | 92 | ||
89 | opt = (u_int8_t *)tcph; | 93 | opt = (u_int8_t *)tcph; |
90 | for (i = sizeof(struct tcphdr); i < tcph->doff*4; i += optlen(opt, i)) { | 94 | for (i = sizeof(struct tcphdr); i <= tcp_hdrlen - TCPOLEN_MSS; i += optlen(opt, i)) { |
91 | if (opt[i] == TCPOPT_MSS && tcph->doff*4 - i >= TCPOLEN_MSS && | 95 | if (opt[i] == TCPOPT_MSS && opt[i+1] == TCPOLEN_MSS) { |
92 | opt[i+1] == TCPOLEN_MSS) { | ||
93 | u_int16_t oldmss; | 96 | u_int16_t oldmss; |
94 | 97 | ||
95 | oldmss = (opt[i+2] << 8) | opt[i+3]; | 98 | oldmss = (opt[i+2] << 8) | opt[i+3]; |
@@ -112,9 +115,10 @@ tcpmss_mangle_packet(struct sk_buff *skb, | |||
112 | } | 115 | } |
113 | 116 | ||
114 | /* There is data after the header so the option can't be added | 117 | /* There is data after the header so the option can't be added |
115 | without moving it, and doing so may make the SYN packet | 118 | * without moving it, and doing so may make the SYN packet |
116 | itself too large. Accept the packet unmodified instead. */ | 119 | * itself too large. Accept the packet unmodified instead. |
117 | if (tcplen > tcph->doff*4) | 120 | */ |
121 | if (len > tcp_hdrlen) | ||
118 | return 0; | 122 | return 0; |
119 | 123 | ||
120 | /* | 124 | /* |
@@ -143,10 +147,10 @@ tcpmss_mangle_packet(struct sk_buff *skb, | |||
143 | newmss = min(newmss, (u16)1220); | 147 | newmss = min(newmss, (u16)1220); |
144 | 148 | ||
145 | opt = (u_int8_t *)tcph + sizeof(struct tcphdr); | 149 | opt = (u_int8_t *)tcph + sizeof(struct tcphdr); |
146 | memmove(opt + TCPOLEN_MSS, opt, tcplen - sizeof(struct tcphdr)); | 150 | memmove(opt + TCPOLEN_MSS, opt, len - sizeof(struct tcphdr)); |
147 | 151 | ||
148 | inet_proto_csum_replace2(&tcph->check, skb, | 152 | inet_proto_csum_replace2(&tcph->check, skb, |
149 | htons(tcplen), htons(tcplen + TCPOLEN_MSS), 1); | 153 | htons(len), htons(len + TCPOLEN_MSS), 1); |
150 | opt[0] = TCPOPT_MSS; | 154 | opt[0] = TCPOPT_MSS; |
151 | opt[1] = TCPOLEN_MSS; | 155 | opt[1] = TCPOLEN_MSS; |
152 | opt[2] = (newmss & 0xff00) >> 8; | 156 | opt[2] = (newmss & 0xff00) >> 8; |