diff options
Diffstat (limited to 'net/netfilter/xt_TCPOPTSTRIP.c')
| -rw-r--r-- | net/netfilter/xt_TCPOPTSTRIP.c | 32 | 
1 files changed, 24 insertions, 8 deletions
diff --git a/net/netfilter/xt_TCPOPTSTRIP.c b/net/netfilter/xt_TCPOPTSTRIP.c index 9dc9ecfdd54..625fa1d636a 100644 --- a/net/netfilter/xt_TCPOPTSTRIP.c +++ b/net/netfilter/xt_TCPOPTSTRIP.c @@ -30,28 +30,43 @@ static inline unsigned int optlen(const u_int8_t *opt, unsigned int offset)  static unsigned int  tcpoptstrip_mangle_packet(struct sk_buff *skb, -			  const struct xt_tcpoptstrip_target_info *info, +			  const struct xt_action_param *par,  			  unsigned int tcphoff, unsigned int minlen)  { +	const struct xt_tcpoptstrip_target_info *info = par->targinfo;  	unsigned int optl, i, j;  	struct tcphdr *tcph;  	u_int16_t n, o;  	u_int8_t *opt; +	int len, tcp_hdrlen; + +	/* This is a fragment, no TCP header is available */ +	if (par->fragoff != 0) +		return XT_CONTINUE;  	if (!skb_make_writable(skb, skb->len))  		return NF_DROP; +	len = skb->len - tcphoff; +	if (len < (int)sizeof(struct tcphdr)) +		return NF_DROP; +  	tcph = (struct tcphdr *)(skb_network_header(skb) + tcphoff); +	tcp_hdrlen = tcph->doff * 4; + +	if (len < tcp_hdrlen) +		return NF_DROP; +  	opt  = (u_int8_t *)tcph;  	/*  	 * Walk through all TCP options - if we find some option to remove,  	 * set all octets to %TCPOPT_NOP and adjust checksum.  	 */ -	for (i = sizeof(struct tcphdr); i < tcp_hdrlen(skb); i += optl) { +	for (i = sizeof(struct tcphdr); i < tcp_hdrlen - 1; i += optl) {  		optl = optlen(opt, i); -		if (i + optl > tcp_hdrlen(skb)) +		if (i + optl > tcp_hdrlen)  			break;  		if (!tcpoptstrip_test_bit(info->strip_bmap, opt[i])) @@ -76,24 +91,25 @@ tcpoptstrip_mangle_packet(struct sk_buff *skb,  static unsigned int  tcpoptstrip_tg4(struct sk_buff *skb, const struct xt_action_param *par)  { -	return tcpoptstrip_mangle_packet(skb, par->targinfo, ip_hdrlen(skb), +	return tcpoptstrip_mangle_packet(skb, par, ip_hdrlen(skb),  	       sizeof(struct iphdr) + sizeof(struct tcphdr));  } -#if defined(CONFIG_IP6_NF_MANGLE) || defined(CONFIG_IP6_NF_MANGLE_MODULE) +#if IS_ENABLED(CONFIG_IP6_NF_MANGLE)  static unsigned int  tcpoptstrip_tg6(struct sk_buff *skb, const struct xt_action_param *par)  {  	struct ipv6hdr *ipv6h = ipv6_hdr(skb);  	int tcphoff;  	u_int8_t nexthdr; +	__be16 frag_off;  	nexthdr = ipv6h->nexthdr; -	tcphoff = ipv6_skip_exthdr(skb, sizeof(*ipv6h), &nexthdr); +	tcphoff = ipv6_skip_exthdr(skb, sizeof(*ipv6h), &nexthdr, &frag_off);  	if (tcphoff < 0)  		return NF_DROP; -	return tcpoptstrip_mangle_packet(skb, par->targinfo, tcphoff, +	return tcpoptstrip_mangle_packet(skb, par, tcphoff,  	       sizeof(*ipv6h) + sizeof(struct tcphdr));  }  #endif @@ -108,7 +124,7 @@ static struct xt_target tcpoptstrip_tg_reg[] __read_mostly = {  		.targetsize = sizeof(struct xt_tcpoptstrip_target_info),  		.me         = THIS_MODULE,  	}, -#if defined(CONFIG_IP6_NF_MANGLE) || defined(CONFIG_IP6_NF_MANGLE_MODULE) +#if IS_ENABLED(CONFIG_IP6_NF_MANGLE)  	{  		.name       = "TCPOPTSTRIP",  		.family     = NFPROTO_IPV6,  | 
