mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	amt: fix wrong usage of pskb_may_pull()
It adds missing pskb_may_pull() in amt_update_handler() and
amt_multicast_data_handler().
And it fixes wrong parameter of pskb_may_pull() in
amt_advertisement_handler() and amt_membership_query_handler().
Reported-by: Jakub Kicinski <kuba@kernel.org>
Fixes: cbc21dc1cf ("amt: add data plane of amt interface")
Signed-off-by: Taehee Yoo <ap420073@gmail.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
			
			
This commit is contained in:
		
							parent
							
								
									c76acfb7e1
								
							
						
					
					
						commit
						f55a07074f
					
				
					 1 changed files with 37 additions and 18 deletions
				
			
		| 
						 | 
					@ -2220,8 +2220,7 @@ static bool amt_advertisement_handler(struct amt_dev *amt, struct sk_buff *skb)
 | 
				
			||||||
	struct amt_header_advertisement *amta;
 | 
						struct amt_header_advertisement *amta;
 | 
				
			||||||
	int hdr_size;
 | 
						int hdr_size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	hdr_size = sizeof(*amta) - sizeof(struct amt_header);
 | 
						hdr_size = sizeof(*amta) + sizeof(struct udphdr);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!pskb_may_pull(skb, hdr_size))
 | 
						if (!pskb_may_pull(skb, hdr_size))
 | 
				
			||||||
		return true;
 | 
							return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2251,19 +2250,27 @@ static bool amt_multicast_data_handler(struct amt_dev *amt, struct sk_buff *skb)
 | 
				
			||||||
	struct ethhdr *eth;
 | 
						struct ethhdr *eth;
 | 
				
			||||||
	struct iphdr *iph;
 | 
						struct iphdr *iph;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						hdr_size = sizeof(*amtmd) + sizeof(struct udphdr);
 | 
				
			||||||
 | 
						if (!pskb_may_pull(skb, hdr_size))
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	amtmd = (struct amt_header_mcast_data *)(udp_hdr(skb) + 1);
 | 
						amtmd = (struct amt_header_mcast_data *)(udp_hdr(skb) + 1);
 | 
				
			||||||
	if (amtmd->reserved || amtmd->version)
 | 
						if (amtmd->reserved || amtmd->version)
 | 
				
			||||||
		return true;
 | 
							return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	hdr_size = sizeof(*amtmd) + sizeof(struct udphdr);
 | 
					 | 
				
			||||||
	if (iptunnel_pull_header(skb, hdr_size, htons(ETH_P_IP), false))
 | 
						if (iptunnel_pull_header(skb, hdr_size, htons(ETH_P_IP), false))
 | 
				
			||||||
		return true;
 | 
							return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	skb_reset_network_header(skb);
 | 
						skb_reset_network_header(skb);
 | 
				
			||||||
	skb_push(skb, sizeof(*eth));
 | 
						skb_push(skb, sizeof(*eth));
 | 
				
			||||||
	skb_reset_mac_header(skb);
 | 
						skb_reset_mac_header(skb);
 | 
				
			||||||
	skb_pull(skb, sizeof(*eth));
 | 
						skb_pull(skb, sizeof(*eth));
 | 
				
			||||||
	eth = eth_hdr(skb);
 | 
						eth = eth_hdr(skb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!pskb_may_pull(skb, sizeof(*iph)))
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
	iph = ip_hdr(skb);
 | 
						iph = ip_hdr(skb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (iph->version == 4) {
 | 
						if (iph->version == 4) {
 | 
				
			||||||
		if (!ipv4_is_multicast(iph->daddr))
 | 
							if (!ipv4_is_multicast(iph->daddr))
 | 
				
			||||||
			return true;
 | 
								return true;
 | 
				
			||||||
| 
						 | 
					@ -2274,6 +2281,9 @@ static bool amt_multicast_data_handler(struct amt_dev *amt, struct sk_buff *skb)
 | 
				
			||||||
	} else if (iph->version == 6) {
 | 
						} else if (iph->version == 6) {
 | 
				
			||||||
		struct ipv6hdr *ip6h;
 | 
							struct ipv6hdr *ip6h;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!pskb_may_pull(skb, sizeof(*ip6h)))
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		ip6h = ipv6_hdr(skb);
 | 
							ip6h = ipv6_hdr(skb);
 | 
				
			||||||
		if (!ipv6_addr_is_multicast(&ip6h->daddr))
 | 
							if (!ipv6_addr_is_multicast(&ip6h->daddr))
 | 
				
			||||||
			return true;
 | 
								return true;
 | 
				
			||||||
| 
						 | 
					@ -2306,8 +2316,7 @@ static bool amt_membership_query_handler(struct amt_dev *amt,
 | 
				
			||||||
	struct iphdr *iph;
 | 
						struct iphdr *iph;
 | 
				
			||||||
	int hdr_size, len;
 | 
						int hdr_size, len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	hdr_size = sizeof(*amtmq) - sizeof(struct amt_header);
 | 
						hdr_size = sizeof(*amtmq) + sizeof(struct udphdr);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!pskb_may_pull(skb, hdr_size))
 | 
						if (!pskb_may_pull(skb, hdr_size))
 | 
				
			||||||
		return true;
 | 
							return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2315,22 +2324,27 @@ static bool amt_membership_query_handler(struct amt_dev *amt,
 | 
				
			||||||
	if (amtmq->reserved || amtmq->version)
 | 
						if (amtmq->reserved || amtmq->version)
 | 
				
			||||||
		return true;
 | 
							return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	hdr_size = sizeof(*amtmq) + sizeof(struct udphdr) - sizeof(*eth);
 | 
						hdr_size -= sizeof(*eth);
 | 
				
			||||||
	if (iptunnel_pull_header(skb, hdr_size, htons(ETH_P_TEB), false))
 | 
						if (iptunnel_pull_header(skb, hdr_size, htons(ETH_P_TEB), false))
 | 
				
			||||||
		return true;
 | 
							return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	oeth = eth_hdr(skb);
 | 
						oeth = eth_hdr(skb);
 | 
				
			||||||
	skb_reset_mac_header(skb);
 | 
						skb_reset_mac_header(skb);
 | 
				
			||||||
	skb_pull(skb, sizeof(*eth));
 | 
						skb_pull(skb, sizeof(*eth));
 | 
				
			||||||
	skb_reset_network_header(skb);
 | 
						skb_reset_network_header(skb);
 | 
				
			||||||
	eth = eth_hdr(skb);
 | 
						eth = eth_hdr(skb);
 | 
				
			||||||
 | 
						if (!pskb_may_pull(skb, sizeof(*iph)))
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	iph = ip_hdr(skb);
 | 
						iph = ip_hdr(skb);
 | 
				
			||||||
	if (iph->version == 4) {
 | 
						if (iph->version == 4) {
 | 
				
			||||||
		if (!ipv4_is_multicast(iph->daddr))
 | 
					 | 
				
			||||||
			return true;
 | 
					 | 
				
			||||||
		if (!pskb_may_pull(skb, sizeof(*iph) + AMT_IPHDR_OPTS +
 | 
							if (!pskb_may_pull(skb, sizeof(*iph) + AMT_IPHDR_OPTS +
 | 
				
			||||||
				   sizeof(*ihv3)))
 | 
									   sizeof(*ihv3)))
 | 
				
			||||||
			return true;
 | 
								return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!ipv4_is_multicast(iph->daddr))
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		ihv3 = skb_pull(skb, sizeof(*iph) + AMT_IPHDR_OPTS);
 | 
							ihv3 = skb_pull(skb, sizeof(*iph) + AMT_IPHDR_OPTS);
 | 
				
			||||||
		skb_reset_transport_header(skb);
 | 
							skb_reset_transport_header(skb);
 | 
				
			||||||
		skb_push(skb, sizeof(*iph) + AMT_IPHDR_OPTS);
 | 
							skb_push(skb, sizeof(*iph) + AMT_IPHDR_OPTS);
 | 
				
			||||||
| 
						 | 
					@ -2345,15 +2359,17 @@ static bool amt_membership_query_handler(struct amt_dev *amt,
 | 
				
			||||||
		ip_eth_mc_map(iph->daddr, eth->h_dest);
 | 
							ip_eth_mc_map(iph->daddr, eth->h_dest);
 | 
				
			||||||
#if IS_ENABLED(CONFIG_IPV6)
 | 
					#if IS_ENABLED(CONFIG_IPV6)
 | 
				
			||||||
	} else if (iph->version == 6) {
 | 
						} else if (iph->version == 6) {
 | 
				
			||||||
		struct ipv6hdr *ip6h = ipv6_hdr(skb);
 | 
					 | 
				
			||||||
		struct mld2_query *mld2q;
 | 
							struct mld2_query *mld2q;
 | 
				
			||||||
 | 
							struct ipv6hdr *ip6h;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (!ipv6_addr_is_multicast(&ip6h->daddr))
 | 
					 | 
				
			||||||
			return true;
 | 
					 | 
				
			||||||
		if (!pskb_may_pull(skb, sizeof(*ip6h) + AMT_IP6HDR_OPTS +
 | 
							if (!pskb_may_pull(skb, sizeof(*ip6h) + AMT_IP6HDR_OPTS +
 | 
				
			||||||
				   sizeof(*mld2q)))
 | 
									   sizeof(*mld2q)))
 | 
				
			||||||
			return true;
 | 
								return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ip6h = ipv6_hdr(skb);
 | 
				
			||||||
 | 
							if (!ipv6_addr_is_multicast(&ip6h->daddr))
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		mld2q = skb_pull(skb, sizeof(*ip6h) + AMT_IP6HDR_OPTS);
 | 
							mld2q = skb_pull(skb, sizeof(*ip6h) + AMT_IP6HDR_OPTS);
 | 
				
			||||||
		skb_reset_transport_header(skb);
 | 
							skb_reset_transport_header(skb);
 | 
				
			||||||
		skb_push(skb, sizeof(*ip6h) + AMT_IP6HDR_OPTS);
 | 
							skb_push(skb, sizeof(*ip6h) + AMT_IP6HDR_OPTS);
 | 
				
			||||||
| 
						 | 
					@ -2389,23 +2405,23 @@ static bool amt_update_handler(struct amt_dev *amt, struct sk_buff *skb)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct amt_header_membership_update *amtmu;
 | 
						struct amt_header_membership_update *amtmu;
 | 
				
			||||||
	struct amt_tunnel_list *tunnel;
 | 
						struct amt_tunnel_list *tunnel;
 | 
				
			||||||
	struct udphdr *udph;
 | 
					 | 
				
			||||||
	struct ethhdr *eth;
 | 
						struct ethhdr *eth;
 | 
				
			||||||
	struct iphdr *iph;
 | 
						struct iphdr *iph;
 | 
				
			||||||
	int len;
 | 
						int len, hdr_size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	iph = ip_hdr(skb);
 | 
						iph = ip_hdr(skb);
 | 
				
			||||||
	udph = udp_hdr(skb);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (__iptunnel_pull_header(skb, sizeof(*udph), skb->protocol,
 | 
						hdr_size = sizeof(*amtmu) + sizeof(struct udphdr);
 | 
				
			||||||
				   false, false))
 | 
						if (!pskb_may_pull(skb, hdr_size))
 | 
				
			||||||
		return true;
 | 
							return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	amtmu = (struct amt_header_membership_update *)skb->data;
 | 
						amtmu = (struct amt_header_membership_update *)(udp_hdr(skb) + 1);
 | 
				
			||||||
	if (amtmu->reserved || amtmu->version)
 | 
						if (amtmu->reserved || amtmu->version)
 | 
				
			||||||
		return true;
 | 
							return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	skb_pull(skb, sizeof(*amtmu));
 | 
						if (iptunnel_pull_header(skb, hdr_size, skb->protocol, false))
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	skb_reset_network_header(skb);
 | 
						skb_reset_network_header(skb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	list_for_each_entry_rcu(tunnel, &amt->tunnel_list, list) {
 | 
						list_for_each_entry_rcu(tunnel, &amt->tunnel_list, list) {
 | 
				
			||||||
| 
						 | 
					@ -2426,6 +2442,9 @@ static bool amt_update_handler(struct amt_dev *amt, struct sk_buff *skb)
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
report:
 | 
					report:
 | 
				
			||||||
 | 
						if (!pskb_may_pull(skb, sizeof(*iph)))
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	iph = ip_hdr(skb);
 | 
						iph = ip_hdr(skb);
 | 
				
			||||||
	if (iph->version == 4) {
 | 
						if (iph->version == 4) {
 | 
				
			||||||
		if (ip_mc_check_igmp(skb)) {
 | 
							if (ip_mc_check_igmp(skb)) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue