On 10/22/26 11:22 AM, Jamal Hadi Salim wrote:
> The issue:
> pop_mpls() restores MAC_PROTO_ETHERNET when the popped ethertype is
> ETH_P_TEB, but skb_mpls_pop() only guarantees that the MPLS shim is in
> the linear area.  When the inner Ethernet header sits in a page
> fragment, the datapath now claims an Ethernet header it cannot access
> linearly.
> 
> Output to an OVS internal vport then calls eth_type_trans(), which
> pulls ETH_HLEN from an empty linear area and triggers the BUG in
> __skb_pull():
> 
>   kernel BUG at ./include/linux/skbuff.h:2830!
>   RIP: 0010:eth_type_trans+0x335/0x500
>   internal_dev_recv
>   ovs_vport_send
>   do_output
>   do_execute_actions
>   ovs_execute_actions
>   ovs_dp_process_packet
>   ovs_vport_receive
>   internal_dev_xmit
> 
> Conditions to recreate the bug:
> On a system with 4 KiB pages and CONFIG_OPENVSWITCH and CONFIG_PACKET
> enabled, use CAP_NET_ADMIN to create an OVS datapath and bring its local
> internal port up with MTU 9000.  Install a flow matching an Ethernet/MPLS
> packet with one bottom-of-stack label and actions pop_eth,
> pop_mpls(0x6558), output to the local port.  With CAP_NET_RAW, send a
> 4128-byte AF_PACKET/SOCK_RAW frame containing outer Ethernet, the MPLS
> label, inner Ethernet and 4096 payload bytes.  The two pops consume the
> linear headers and expose the inner Ethernet header in page fragments.
> 
> The Fix:
> Pull the inner Ethernet header into the linear area before restoring
> MAC_PROTO_ETHERNET.
> 
> Fixes: f66b53fdbb22 ("openvswitch: New MPLS actions for layer 2 tunnelling")
> Link: 
> https://lore.kernel.org/netdev/[email protected]/
> Cc: [email protected]
> Signed-off-by: Jamal Hadi Salim <[email protected]>
> ---
>  net/openvswitch/actions.c | 5 ++++-
>  1 file changed, 4 insertions(+), 1 deletion(-)
> 
> diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c
> index 27152bca8a8c..03b31e33e880 100644
> --- a/net/openvswitch/actions.c
> +++ b/net/openvswitch/actions.c
> @@ -153,8 +153,11 @@ static int pop_mpls(struct sk_buff *skb, struct 
> sw_flow_key *key,
>       if (err)
>               return err;
>  
> -     if (ethertype == htons(ETH_P_TEB))
> +     if (ethertype == htons(ETH_P_TEB)) {
> +             if (!pskb_may_pull(skb, ETH_HLEN))
> +                     return -ENOMEM;
>               key->mac_proto = MAC_PROTO_ETHERNET;
> +     }
>  
>       invalidate_flow_key(key);
>       return 0;

Reviewed-by: Ilya Maximets <[email protected]>
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to