]> git.proxmox.com Git - mirror_ubuntu-kernels.git/commitdiff
xfrm: Treat already-verified secpath entries as optional
authorBenedict Wong <benedictwong@google.com>
Wed, 10 May 2023 01:30:21 +0000 (01:30 +0000)
committerRoxana Nicolescu <roxana.nicolescu@canonical.com>
Mon, 2 Oct 2023 15:19:20 +0000 (17:19 +0200)
BugLink: https://bugs.launchpad.net/bugs/2033931
[ Upstream commit 1f8b6df6a997a430b0c48b504638154b520781ad ]

This change allows inbound traffic through nested IPsec tunnels to
successfully match policies and templates, while retaining the secpath
stack trace as necessary for netfilter policies.

Specifically, this patch marks secpath entries that have already matched
against a relevant policy as having been verified, allowing it to be
treated as optional and skipped after a tunnel decapsulation (during
which the src/dst/proto/etc may have changed, and the correct policy
chain no long be resolvable).

This approach is taken as opposed to the iteration in b0355dbbf13c,
where the secpath was cleared, since that breaks subsequent validations
that rely on the existence of the secpath entries (netfilter policies, or
transport-in-tunnel mode, where policies remain resolvable).

Fixes: b0355dbbf13c ("Fix XFRM-I support for nested ESP tunnels")
Test: Tested against Android Kernel Unit Tests
Test: Tested against Android CTS
Signed-off-by: Benedict Wong <benedictwong@google.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Kamal Mostafa <kamal@canonical.com>
Signed-off-by: Stefan Bader <stefan.bader@canonical.com>
include/net/xfrm.h
net/xfrm/xfrm_input.c
net/xfrm/xfrm_policy.c

index 3e1f70e8e42479c9babadb97967d0dd43e9c6a90..47ecf1d4719b069119b3487912f0536c9732febd 100644 (file)
@@ -1049,6 +1049,7 @@ struct xfrm_offload {
 struct sec_path {
        int                     len;
        int                     olen;
+       int                     verified_cnt;
 
        struct xfrm_state       *xvec[XFRM_MAX_DEPTH];
        struct xfrm_offload     ovec[XFRM_MAX_OFFLOAD_DEPTH];
index 436d29640ac2cf3a48a2602c7f16e966ed7ab928..9f294a20dcece718c089664bfd75ad6dc4db1ca1 100644 (file)
@@ -131,6 +131,7 @@ struct sec_path *secpath_set(struct sk_buff *skb)
        memset(sp->ovec, 0, sizeof(sp->ovec));
        sp->olen = 0;
        sp->len = 0;
+       sp->verified_cnt = 0;
 
        return sp;
 }
index 6d15788b512315f030899998354a7c8f4edc4e8c..ff58ce6c030cada39e93e342031404b4861c75e0 100644 (file)
@@ -3349,6 +3349,13 @@ xfrm_policy_ok(const struct xfrm_tmpl *tmpl, const struct sec_path *sp, int star
                if (xfrm_state_ok(tmpl, sp->xvec[idx], family, if_id))
                        return ++idx;
                if (sp->xvec[idx]->props.mode != XFRM_MODE_TRANSPORT) {
+                       if (idx < sp->verified_cnt) {
+                               /* Secpath entry previously verified, consider optional and
+                                * continue searching
+                                */
+                               continue;
+                       }
+
                        if (start == -1)
                                start = -2-idx;
                        break;
@@ -3723,6 +3730,9 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
                 * Order is _important_. Later we will implement
                 * some barriers, but at the moment barriers
                 * are implied between each two transformations.
+                * Upon success, marks secpath entries as having been
+                * verified to allow them to be skipped in future policy
+                * checks (e.g. nested tunnels).
                 */
                for (i = xfrm_nr-1, k = 0; i >= 0; i--) {
                        k = xfrm_policy_ok(tpp[i], sp, k, family, if_id);
@@ -3741,6 +3751,8 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
                }
 
                xfrm_pols_put(pols, npols);
+               sp->verified_cnt = k;
+
                return 1;
        }
        XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLBLOCK);