Commit f55a0707 authored by Taehee Yoo's avatar Taehee Yoo Committed by Jakub Kicinski

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: default avatarJakub Kicinski <kuba@kernel.org>
Fixes: cbc21dc1 ("amt: add data plane of amt interface")
Signed-off-by: default avatarTaehee Yoo <ap420073@gmail.com>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent c76acfb7
...@@ -2220,8 +2220,7 @@ static bool amt_advertisement_handler(struct amt_dev *amt, struct sk_buff *skb) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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)) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment