On Sun, Oct 11, 2026 at 09:23:06PM +0200, Andrea Mayer wrote:
> seg6_pop_srh() already fails when a Fragment or AH header comes before
> the SRH with other headers in between, and the packet is dropped ("we
> expect SRH before FRAG and AUTH" in the code). But when the SRH directly
> follows the Fragment or AH header, it is removed:
> 
>   (a) IPv6 | FRAG/AH | DOPT | SRH | ...   the packet is dropped
>   (b) IPv6 | FRAG/AH | SRH | ...          the SRH is removed
> 
> In both packets the Fragment or AH header comes before the SRH.
> 
> Align the two cases: check first whether a header is a Fragment or AH
> header, and only then look at its Next Header field. In this way, the
> packet is dropped also when the Fragment or AH header comes directly
> before the SRH. A Fragment or AH header before the SRH, with or without
> other headers in between, does not follow RFC 8200 and RFC 4302: a
> Fragment header must not come before the Routing header, as the
> Per-Fragment headers must include the Routing header [1], and AH should
> not come before the routing and fragmentation headers [2].
> 
> At the penultimate segment, End with the PSP flavor alone today drops
> (a) and forwards (b) with the SRH removed. Packets with the Fragment or
> AH header after the SRH are not affected: seg6_pop_srh() does not look
> at the headers after the SRH.
> 
> Found by manual code inspection and reproduced in a VM without kernel
> changes or error injection, by sending to End with PSP the packets
> shown in the diagram, both with a Fragment header and with AH. With this
> change, the packets are dropped in both cases, all tests in
> srv6_end_flavors_test.sh pass, and KASAN reports no error. With the
> whole series, all the srv6_*.sh selftests pass.
> 
> [1] - https://datatracker.ietf.org/doc/html/rfc8200#section-4.5
> [2] - https://datatracker.ietf.org/doc/html/rfc4302#section-3.1.1
> 
> Fixes: bdf3c0b9c10b ("seg6: add PSP flavor support for SRv6 End behavior")
> Signed-off-by: Andrea Mayer <[email protected]>
> ---
>  net/ipv6/seg6_local.c | 10 +++++-----
>  1 file changed, 5 insertions(+), 5 deletions(-)
> 
> diff --git a/net/ipv6/seg6_local.c b/net/ipv6/seg6_local.c
> index 0c3d1be7f129..da8225591fe3 100644
> --- a/net/ipv6/seg6_local.c
> +++ b/net/ipv6/seg6_local.c
> @@ -796,11 +796,6 @@ static bool seg6_pop_srh(struct sk_buff *skb, int srhoff)
>                       if (unlikely(!hp))
>                               return false;
>  
> -                     if (hp->nexthdr == NEXTHDR_ROUTING) {
> -                             hp->nexthdr = srh_nexthdr;
> -                             break;
> -                     }
> -
>                       switch (nexthdr) {
>                       case NEXTHDR_FRAGMENT:
>                               fallthrough;
> @@ -812,6 +807,11 @@ static bool seg6_pop_srh(struct sk_buff *skb, int srhoff)
>                               break;
>                       }
>  
> +                     if (hp->nexthdr == NEXTHDR_ROUTING) {
> +                             hp->nexthdr = srh_nexthdr;
> +                             break;
> +                     }
> +
>                       nexthdr = hp->nexthdr;
>               }
>       }
> -- 
> 2.43.0
> 

After changing the order, we can check the FRAG/AH header first and
return false and drop the pkt.

Reviewed-by: Hangbin Liu <[email protected]>

Reply via email to