]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
xfrm: Check inner packet family directly from skb_dst
authorJianbo Liu <jianbol@nvidia.com>
Tue, 28 Oct 2025 02:22:47 +0000 (04:22 +0200)
committerSteffen Klassert <steffen.klassert@secunet.com>
Thu, 30 Oct 2025 10:52:06 +0000 (11:52 +0100)
In the output path, xfrm_dev_offload_ok and xfrm_get_inner_ipproto
need to determine the protocol family of the inner packet (skb) before
it gets encapsulated.

In xfrm_dev_offload_ok, the code checked x->inner_mode.family. This is
unreliable because, for states handling both IPv4 and IPv6, the
relevant inner family could be either x->inner_mode.family or
x->inner_mode_iaf.family. Checking only the former can lead to a
mismatch with the actual packet being processed.

In xfrm_get_inner_ipproto, the code checked x->outer_mode.family. This
is also incorrect for tunnel mode, as the inner packet's family can be
different from the outer header's family.

At both of these call sites, the skb variable holds the original inner
packet. The most direct and reliable source of truth for its protocol
family is its destination entry. This patch fixes the issue by using
skb_dst(skb)->ops->family to ensure protocol-specific headers are only
accessed for the correct packet type.

Fixes: 91d8a53db219 ("xfrm: fix offloading of cross-family tunnels")
Fixes: 45a98ef4922d ("net/xfrm: IPsec tunnel mode fix inner_ipproto setting in sec_path")
Signed-off-by: Jianbo Liu <jianbol@nvidia.com>
Reviewed-by: Cosmin Ratiu <cratiu@nvidia.com>
Reviewed-by: Zhu Yanjun <yanjun.zhu@linux.dev>
Reviewed-by: Sabrina Dubroca <sd@queasysnail.net>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
net/xfrm/xfrm_device.c
net/xfrm/xfrm_output.c

index 44b9de6e4e7788ca9788c775e7c0c173193727f6..52ae0e034d29e265af5eeaf03df8fd973d8dbf9f 100644 (file)
@@ -438,7 +438,7 @@ ok:
 
        check_tunnel_size = x->xso.type == XFRM_DEV_OFFLOAD_PACKET &&
                            x->props.mode == XFRM_MODE_TUNNEL;
-       switch (x->inner_mode.family) {
+       switch (skb_dst(skb)->ops->family) {
        case AF_INET:
                /* Check for IPv4 options */
                if (ip_hdr(skb)->ihl != 5)
index 9077730ff7d0ea5bfd66e1c900b7910f245a33b1..a98b5bf55ac31a7116531cb89c60d505116ae5d0 100644 (file)
@@ -698,7 +698,7 @@ static void xfrm_get_inner_ipproto(struct sk_buff *skb, struct xfrm_state *x)
                return;
 
        if (x->outer_mode.encap == XFRM_MODE_TUNNEL) {
-               switch (x->outer_mode.family) {
+               switch (skb_dst(skb)->ops->family) {
                case AF_INET:
                        xo->inner_ipproto = ip_hdr(skb)->protocol;
                        break;