]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
xfrm: Sanitize marks before insert
authorPaul Chaignon <paul.chaignon@gmail.com>
Wed, 7 May 2025 11:31:58 +0000 (13:31 +0200)
committerSteffen Klassert <steffen.klassert@secunet.com>
Wed, 14 May 2025 05:18:58 +0000 (07:18 +0200)
Prior to this patch, the mark is sanitized (applying the state's mask to
the state's value) only on inserts when checking if a conflicting XFRM
state or policy exists.

We discovered in Cilium that this same sanitization does not occur
in the hot-path __xfrm_state_lookup. In the hot-path, the sk_buff's mark
is simply compared to the state's value:

    if ((mark & x->mark.m) != x->mark.v)
        continue;

Therefore, users can define unsanitized marks (ex. 0xf42/0xf00) which will
never match any packet.

This commit updates __xfrm_state_insert and xfrm_policy_insert to store
the sanitized marks, thus removing this footgun.

This has the side effect of changing the ip output, as the
returned mark will have the mask applied to it when printed.

Fixes: 3d6acfa7641f ("xfrm: SA lookups with mark")
Signed-off-by: Paul Chaignon <paul.chaignon@gmail.com>
Signed-off-by: Louis DeLosSantos <louis.delos.devel@gmail.com>
Co-developed-by: Louis DeLosSantos <louis.delos.devel@gmail.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
net/xfrm/xfrm_policy.c
net/xfrm/xfrm_state.c

index 143ac3aa75374605fa707d63e2122ff6831a93b2..f4bad8c895d668e5baedcf4110d22507f691d64c 100644 (file)
@@ -1581,6 +1581,9 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
        struct xfrm_policy *delpol;
        struct hlist_head *chain;
 
+       /* Sanitize mark before store */
+       policy->mark.v &= policy->mark.m;
+
        spin_lock_bh(&net->xfrm.xfrm_policy_lock);
        chain = policy_hash_bysel(net, &policy->selector, policy->family, dir);
        if (chain)
index 2f57dabcc70b65e30d9a65de512437735189a7c0..07fe8e5daa32b0ebdd950457e6ea41a002637464 100644 (file)
@@ -1718,6 +1718,9 @@ static void __xfrm_state_insert(struct xfrm_state *x)
 
        list_add(&x->km.all, &net->xfrm.state_all);
 
+       /* Sanitize mark before store */
+       x->mark.v &= x->mark.m;
+
        h = xfrm_dst_hash(net, &x->id.daddr, &x->props.saddr,
                          x->props.reqid, x->props.family);
        XFRM_STATE_INSERT(bydst, &x->bydst, net->xfrm.state_bydst + h,