diff options
author | Nicolas Dichtel <nicolas.dichtel@6wind.com> | 2018-01-25 13:03:03 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-01-25 16:27:34 -0500 |
commit | f15ca723c1ebe6c1a06bc95fda6b62cd87b44559 (patch) | |
tree | d81f5825fe96dbfc589b19561961814fed78b4fc | |
parent | 4ee806d51176ba7b8ff1efd81f271d7252e03a1d (diff) |
net: don't call update_pmtu unconditionally
Some dst_ops (e.g. md_dst_ops)) doesn't set this handler. It may result to:
"BUG: unable to handle kernel NULL pointer dereference at (null)"
Let's add a helper to check if update_pmtu is available before calling it.
Fixes: 52a589d51f10 ("geneve: update skb dst pmtu on tx path")
Fixes: a93bf0ff4490 ("vxlan: update skb dst pmtu on tx path")
CC: Roman Kapl <code@rkapl.cz>
CC: Xin Long <lucien.xin@gmail.com>
Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/infiniband/ulp/ipoib/ipoib_cm.c | 3 | ||||
-rw-r--r-- | drivers/net/geneve.c | 4 | ||||
-rw-r--r-- | drivers/net/vxlan.c | 6 | ||||
-rw-r--r-- | include/net/dst.h | 8 | ||||
-rw-r--r-- | net/ipv4/ip_tunnel.c | 3 | ||||
-rw-r--r-- | net/ipv4/ip_vti.c | 2 | ||||
-rw-r--r-- | net/ipv6/ip6_tunnel.c | 6 | ||||
-rw-r--r-- | net/ipv6/ip6_vti.c | 2 | ||||
-rw-r--r-- | net/ipv6/sit.c | 4 |
9 files changed, 20 insertions, 18 deletions
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c index 2c13123bfd69..71ea9e26666c 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c | |||
@@ -1456,8 +1456,7 @@ void ipoib_cm_skb_too_long(struct net_device *dev, struct sk_buff *skb, | |||
1456 | struct ipoib_dev_priv *priv = ipoib_priv(dev); | 1456 | struct ipoib_dev_priv *priv = ipoib_priv(dev); |
1457 | int e = skb_queue_empty(&priv->cm.skb_queue); | 1457 | int e = skb_queue_empty(&priv->cm.skb_queue); |
1458 | 1458 | ||
1459 | if (skb_dst(skb)) | 1459 | skb_dst_update_pmtu(skb, mtu); |
1460 | skb_dst(skb)->ops->update_pmtu(skb_dst(skb), NULL, skb, mtu); | ||
1461 | 1460 | ||
1462 | skb_queue_tail(&priv->cm.skb_queue, skb); | 1461 | skb_queue_tail(&priv->cm.skb_queue, skb); |
1463 | if (e) | 1462 | if (e) |
diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c index 0a48b3073d3d..64fda2e1040e 100644 --- a/drivers/net/geneve.c +++ b/drivers/net/geneve.c | |||
@@ -829,7 +829,7 @@ static int geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev, | |||
829 | int mtu = dst_mtu(&rt->dst) - sizeof(struct iphdr) - | 829 | int mtu = dst_mtu(&rt->dst) - sizeof(struct iphdr) - |
830 | GENEVE_BASE_HLEN - info->options_len - 14; | 830 | GENEVE_BASE_HLEN - info->options_len - 14; |
831 | 831 | ||
832 | skb_dst(skb)->ops->update_pmtu(skb_dst(skb), NULL, skb, mtu); | 832 | skb_dst_update_pmtu(skb, mtu); |
833 | } | 833 | } |
834 | 834 | ||
835 | sport = udp_flow_src_port(geneve->net, skb, 1, USHRT_MAX, true); | 835 | sport = udp_flow_src_port(geneve->net, skb, 1, USHRT_MAX, true); |
@@ -875,7 +875,7 @@ static int geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev, | |||
875 | int mtu = dst_mtu(dst) - sizeof(struct ipv6hdr) - | 875 | int mtu = dst_mtu(dst) - sizeof(struct ipv6hdr) - |
876 | GENEVE_BASE_HLEN - info->options_len - 14; | 876 | GENEVE_BASE_HLEN - info->options_len - 14; |
877 | 877 | ||
878 | skb_dst(skb)->ops->update_pmtu(skb_dst(skb), NULL, skb, mtu); | 878 | skb_dst_update_pmtu(skb, mtu); |
879 | } | 879 | } |
880 | 880 | ||
881 | sport = udp_flow_src_port(geneve->net, skb, 1, USHRT_MAX, true); | 881 | sport = udp_flow_src_port(geneve->net, skb, 1, USHRT_MAX, true); |
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 31f4b7911ef8..c3e34e3c82a7 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c | |||
@@ -2158,8 +2158,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, | |||
2158 | if (skb_dst(skb)) { | 2158 | if (skb_dst(skb)) { |
2159 | int mtu = dst_mtu(ndst) - VXLAN_HEADROOM; | 2159 | int mtu = dst_mtu(ndst) - VXLAN_HEADROOM; |
2160 | 2160 | ||
2161 | skb_dst(skb)->ops->update_pmtu(skb_dst(skb), NULL, | 2161 | skb_dst_update_pmtu(skb, mtu); |
2162 | skb, mtu); | ||
2163 | } | 2162 | } |
2164 | 2163 | ||
2165 | tos = ip_tunnel_ecn_encap(tos, old_iph, skb); | 2164 | tos = ip_tunnel_ecn_encap(tos, old_iph, skb); |
@@ -2200,8 +2199,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, | |||
2200 | if (skb_dst(skb)) { | 2199 | if (skb_dst(skb)) { |
2201 | int mtu = dst_mtu(ndst) - VXLAN6_HEADROOM; | 2200 | int mtu = dst_mtu(ndst) - VXLAN6_HEADROOM; |
2202 | 2201 | ||
2203 | skb_dst(skb)->ops->update_pmtu(skb_dst(skb), NULL, | 2202 | skb_dst_update_pmtu(skb, mtu); |
2204 | skb, mtu); | ||
2205 | } | 2203 | } |
2206 | 2204 | ||
2207 | tos = ip_tunnel_ecn_encap(tos, old_iph, skb); | 2205 | tos = ip_tunnel_ecn_encap(tos, old_iph, skb); |
diff --git a/include/net/dst.h b/include/net/dst.h index b091fd536098..d49d607dd2b3 100644 --- a/include/net/dst.h +++ b/include/net/dst.h | |||
@@ -521,4 +521,12 @@ static inline struct xfrm_state *dst_xfrm(const struct dst_entry *dst) | |||
521 | } | 521 | } |
522 | #endif | 522 | #endif |
523 | 523 | ||
524 | static inline void skb_dst_update_pmtu(struct sk_buff *skb, u32 mtu) | ||
525 | { | ||
526 | struct dst_entry *dst = skb_dst(skb); | ||
527 | |||
528 | if (dst && dst->ops->update_pmtu) | ||
529 | dst->ops->update_pmtu(dst, NULL, skb, mtu); | ||
530 | } | ||
531 | |||
524 | #endif /* _NET_DST_H */ | 532 | #endif /* _NET_DST_H */ |
diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c index 5ddb1cb52bd4..6d21068f9b55 100644 --- a/net/ipv4/ip_tunnel.c +++ b/net/ipv4/ip_tunnel.c | |||
@@ -520,8 +520,7 @@ static int tnl_update_pmtu(struct net_device *dev, struct sk_buff *skb, | |||
520 | else | 520 | else |
521 | mtu = skb_dst(skb) ? dst_mtu(skb_dst(skb)) : dev->mtu; | 521 | mtu = skb_dst(skb) ? dst_mtu(skb_dst(skb)) : dev->mtu; |
522 | 522 | ||
523 | if (skb_dst(skb)) | 523 | skb_dst_update_pmtu(skb, mtu); |
524 | skb_dst(skb)->ops->update_pmtu(skb_dst(skb), NULL, skb, mtu); | ||
525 | 524 | ||
526 | if (skb->protocol == htons(ETH_P_IP)) { | 525 | if (skb->protocol == htons(ETH_P_IP)) { |
527 | if (!skb_is_gso(skb) && | 526 | if (!skb_is_gso(skb) && |
diff --git a/net/ipv4/ip_vti.c b/net/ipv4/ip_vti.c index 949f432a5f04..51b1669334fe 100644 --- a/net/ipv4/ip_vti.c +++ b/net/ipv4/ip_vti.c | |||
@@ -200,7 +200,7 @@ static netdev_tx_t vti_xmit(struct sk_buff *skb, struct net_device *dev, | |||
200 | 200 | ||
201 | mtu = dst_mtu(dst); | 201 | mtu = dst_mtu(dst); |
202 | if (skb->len > mtu) { | 202 | if (skb->len > mtu) { |
203 | skb_dst(skb)->ops->update_pmtu(skb_dst(skb), NULL, skb, mtu); | 203 | skb_dst_update_pmtu(skb, mtu); |
204 | if (skb->protocol == htons(ETH_P_IP)) { | 204 | if (skb->protocol == htons(ETH_P_IP)) { |
205 | icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, | 205 | icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, |
206 | htonl(mtu)); | 206 | htonl(mtu)); |
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 9a7cf355bc8c..1ee5584c3555 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c | |||
@@ -642,8 +642,7 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
642 | if (rel_info > dst_mtu(skb_dst(skb2))) | 642 | if (rel_info > dst_mtu(skb_dst(skb2))) |
643 | goto out; | 643 | goto out; |
644 | 644 | ||
645 | skb_dst(skb2)->ops->update_pmtu(skb_dst(skb2), NULL, skb2, | 645 | skb_dst_update_pmtu(skb2, rel_info); |
646 | rel_info); | ||
647 | } | 646 | } |
648 | 647 | ||
649 | icmp_send(skb2, rel_type, rel_code, htonl(rel_info)); | 648 | icmp_send(skb2, rel_type, rel_code, htonl(rel_info)); |
@@ -1131,8 +1130,7 @@ route_lookup: | |||
1131 | mtu = 576; | 1130 | mtu = 576; |
1132 | } | 1131 | } |
1133 | 1132 | ||
1134 | if (skb_dst(skb) && !t->parms.collect_md) | 1133 | skb_dst_update_pmtu(skb, mtu); |
1135 | skb_dst(skb)->ops->update_pmtu(skb_dst(skb), NULL, skb, mtu); | ||
1136 | if (skb->len - t->tun_hlen - eth_hlen > mtu && !skb_is_gso(skb)) { | 1134 | if (skb->len - t->tun_hlen - eth_hlen > mtu && !skb_is_gso(skb)) { |
1137 | *pmtu = mtu; | 1135 | *pmtu = mtu; |
1138 | err = -EMSGSIZE; | 1136 | err = -EMSGSIZE; |
diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c index dbb74f3c57a7..8c184f84f353 100644 --- a/net/ipv6/ip6_vti.c +++ b/net/ipv6/ip6_vti.c | |||
@@ -483,7 +483,7 @@ vti6_xmit(struct sk_buff *skb, struct net_device *dev, struct flowi *fl) | |||
483 | 483 | ||
484 | mtu = dst_mtu(dst); | 484 | mtu = dst_mtu(dst); |
485 | if (!skb->ignore_df && skb->len > mtu) { | 485 | if (!skb->ignore_df && skb->len > mtu) { |
486 | skb_dst(skb)->ops->update_pmtu(dst, NULL, skb, mtu); | 486 | skb_dst_update_pmtu(skb, mtu); |
487 | 487 | ||
488 | if (skb->protocol == htons(ETH_P_IPV6)) { | 488 | if (skb->protocol == htons(ETH_P_IPV6)) { |
489 | if (mtu < IPV6_MIN_MTU) | 489 | if (mtu < IPV6_MIN_MTU) |
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index d7dc23c1b2ca..3873d3877135 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c | |||
@@ -934,8 +934,8 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, | |||
934 | df = 0; | 934 | df = 0; |
935 | } | 935 | } |
936 | 936 | ||
937 | if (tunnel->parms.iph.daddr && skb_dst(skb)) | 937 | if (tunnel->parms.iph.daddr) |
938 | skb_dst(skb)->ops->update_pmtu(skb_dst(skb), NULL, skb, mtu); | 938 | skb_dst_update_pmtu(skb, mtu); |
939 | 939 | ||
940 | if (skb->len > mtu && !skb_is_gso(skb)) { | 940 | if (skb->len > mtu && !skb_is_gso(skb)) { |
941 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); | 941 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); |