is_last_ethertype_ip() is used to check IP/IPv6 protocol before
parsing IP/IPv6 headers.

But __vlan_get_protocol() is only bound to skb->len, a malicious
packet could exhaust all skb->len by inserting sufficient ETH_P_8021AD
headers, and it may not even contain an IP/IPv6 header at all, so we
have to check if we are still safe to continue to parse IP/IPv6 header.
If not, treat it as non-IP packet.

This should not cause any crash as we stil have tail room in skb,
but we can't just rely on it either.

Cc: Tariq Toukan <tar...@mellanox.com>
Cc: Saeed Mahameed <sae...@mellanox.com>
Signed-off-by: Cong Wang <xiyou.wangc...@gmail.com>
---
 drivers/net/ethernet/mellanox/mlx5/core/en_rx.c | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c 
b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
index 624eed345b5d..1e505013ebfd 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
@@ -693,7 +693,18 @@ static inline bool is_last_ethertype_ip(struct sk_buff 
*skb, int *network_depth,
 {
        *proto = ((struct ethhdr *)skb->data)->h_proto;
        *proto = __vlan_get_protocol(skb, *proto, network_depth);
-       return (*proto == htons(ETH_P_IP) || *proto == htons(ETH_P_IPV6));
+
+       if (*proto == htons(ETH_P_IP)) {
+               if (unlikely(*network_depth > skb->len - sizeof(struct iphdr)))
+                       return false;
+               return true;
+       } else if (*proto == htons(ETH_P_IPV6)) {
+               if (unlikely(*network_depth > skb->len - sizeof(struct 
ipv6hdr)))
+                       return false;
+               return true;
+       }
+
+       return false;
 }
 
 static inline void mlx5e_enable_ecn(struct mlx5e_rq *rq, struct sk_buff *skb)
-- 
2.19.1

Reply via email to