Commit a7f1a2f4 authored by Xin Long's avatar Xin Long Committed by Florian Westphal
Browse files

netfilter: bridge: check len before accessing more nh data



In the while loop of br_nf_check_hbh_len(), similar to ip6_parse_tlv(),
before accessing 'nh[off + 1]', it should add a check 'len < 2'; and
before parsing IPV6_TLV_JUMBO, it should add a check 'optlen > len',
in case of overflows.

Signed-off-by: default avatarXin Long <lucien.xin@gmail.com>
Reviewed-by: default avatarSimon Horman <simon.horman@corigine.com>
Acked-by: default avatarNikolay Aleksandrov <razor@blackwall.org>
Reviewed-by: default avatarAaron Conole <aconole@redhat.com>
Signed-off-by: default avatarFlorian Westphal <fw@strlen.de>
parent 9ccff83b
Loading
Loading
Loading
Loading
+20 −25
Original line number Diff line number Diff line
@@ -50,54 +50,49 @@ static int br_nf_check_hbh_len(struct sk_buff *skb)
	u32 pkt_len;

	if (!pskb_may_pull(skb, off + 8))
		goto bad;
		return -1;
	nh = (unsigned char *)(ipv6_hdr(skb) + 1);
	len = (nh[1] + 1) << 3;

	if (!pskb_may_pull(skb, off + len))
		goto bad;
		return -1;
	nh = skb_network_header(skb);

	off += 2;
	len -= 2;

	while (len > 0) {
		int optlen = nh[off + 1] + 2;

		switch (nh[off]) {
		case IPV6_TLV_PAD1:
			optlen = 1;
			break;
		int optlen;

		case IPV6_TLV_PADN:
			break;
		if (nh[off] == IPV6_TLV_PAD1) {
			off++;
			len--;
			continue;
		}
		if (len < 2)
			return -1;
		optlen = nh[off + 1] + 2;
		if (optlen > len)
			return -1;

		case IPV6_TLV_JUMBO:
		if (nh[off] == IPV6_TLV_JUMBO) {
			if (nh[off + 1] != 4 || (off & 3) != 2)
				goto bad;
				return -1;
			pkt_len = ntohl(*(__be32 *)(nh + off + 2));
			if (pkt_len <= IPV6_MAXPLEN ||
			    ipv6_hdr(skb)->payload_len)
				goto bad;
				return -1;
			if (pkt_len > skb->len - sizeof(struct ipv6hdr))
				goto bad;
				return -1;
			if (pskb_trim_rcsum(skb,
					    pkt_len + sizeof(struct ipv6hdr)))
				goto bad;
				return -1;
			nh = skb_network_header(skb);
			break;
		default:
			if (optlen > len)
				goto bad;
			break;
		}
		off += optlen;
		len -= optlen;
	}
	if (len == 0)
		return 0;
bad:
	return -1;

	return len ? -1 : 0;
}

int br_validate_ipv6(struct net *net, struct sk_buff *skb)