Skip to content

Commit

Permalink
netfilter: xt_TCPMSS: fix handling of malformed TCP header and options
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Pablo Neira Ayuso committed Aug 1, 2013
1 parent a661b43 commit 71ffe9c
Showing 1 changed file with 16 additions and 12 deletions.
28 changes: 16 additions & 12 deletions net/netfilter/xt_TCPMSS.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ tcpmss_mangle_packet(struct sk_buff *skb,
{
const struct xt_tcpmss_info *info = par->targinfo;
struct tcphdr *tcph;
unsigned int tcplen, i;
int len, tcp_hdrlen;
unsigned int i;
__be16 oldval;
u16 newmss;
u8 *opt;
Expand All @@ -64,11 +65,14 @@ tcpmss_mangle_packet(struct sk_buff *skb,
if (!skb_make_writable(skb, skb->len))
return -1;

tcplen = skb->len - tcphoff;
len = skb->len - tcphoff;
if (len < (int)sizeof(struct tcphdr))
return -1;

tcph = (struct tcphdr *)(skb_network_header(skb) + tcphoff);
tcp_hdrlen = tcph->doff * 4;

/* Header cannot be larger than the packet */
if (tcplen < tcph->doff*4)
if (len < tcp_hdrlen)
return -1;

if (info->mss == XT_TCPMSS_CLAMP_PMTU) {
Expand All @@ -87,9 +91,8 @@ tcpmss_mangle_packet(struct sk_buff *skb,
newmss = info->mss;

opt = (u_int8_t *)tcph;
for (i = sizeof(struct tcphdr); i < tcph->doff*4; i += optlen(opt, i)) {
if (opt[i] == TCPOPT_MSS && tcph->doff*4 - i >= TCPOLEN_MSS &&
opt[i+1] == TCPOLEN_MSS) {
for (i = sizeof(struct tcphdr); i <= tcp_hdrlen - TCPOLEN_MSS; i += optlen(opt, i)) {
if (opt[i] == TCPOPT_MSS && opt[i+1] == TCPOLEN_MSS) {
u_int16_t oldmss;

oldmss = (opt[i+2] << 8) | opt[i+3];
Expand All @@ -112,9 +115,10 @@ tcpmss_mangle_packet(struct sk_buff *skb,
}

/* There is data after the header so the option can't be added
without moving it, and doing so may make the SYN packet
itself too large. Accept the packet unmodified instead. */
if (tcplen > tcph->doff*4)
* without moving it, and doing so may make the SYN packet
* itself too large. Accept the packet unmodified instead.
*/
if (len > tcp_hdrlen)
return 0;

/*
Expand Down Expand Up @@ -143,10 +147,10 @@ tcpmss_mangle_packet(struct sk_buff *skb,
newmss = min(newmss, (u16)1220);

opt = (u_int8_t *)tcph + sizeof(struct tcphdr);
memmove(opt + TCPOLEN_MSS, opt, tcplen - sizeof(struct tcphdr));
memmove(opt + TCPOLEN_MSS, opt, len - sizeof(struct tcphdr));

inet_proto_csum_replace2(&tcph->check, skb,
htons(tcplen), htons(tcplen + TCPOLEN_MSS), 1);
htons(len), htons(len + TCPOLEN_MSS), 1);
opt[0] = TCPOPT_MSS;
opt[1] = TCPOLEN_MSS;
opt[2] = (newmss & 0xff00) >> 8;
Expand Down

0 comments on commit 71ffe9c

Please sign in to comment.