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