]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.14-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 14 Apr 2022 10:46:41 +0000 (12:46 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 14 Apr 2022 10:46:41 +0000 (12:46 +0200)
added patches:
xfrm-policy-match-with-both-mark-and-mask-on-user-interfaces.patch

queue-4.14/series
queue-4.14/xfrm-policy-match-with-both-mark-and-mask-on-user-interfaces.patch [new file with mode: 0644]

index f66ad98dacd0dd042a2b49bdb2f3c1dd3498f54a..a6e688fd993d1fec80e44baa81648cc7a80b1d08 100644 (file)
@@ -260,3 +260,4 @@ mm-sparsemem-fix-mem_section-will-never-be-null-gcc-12-warning.patch
 cgroup-use-open-time-credentials-for-process-migraton-perm-checks.patch
 cgroup-allocate-cgroup_file_ctx-for-kernfs_open_file-priv.patch
 cgroup-use-open-time-cgroup-namespace-for-process-migration-perm-checks.patch
+xfrm-policy-match-with-both-mark-and-mask-on-user-interfaces.patch
diff --git a/queue-4.14/xfrm-policy-match-with-both-mark-and-mask-on-user-interfaces.patch b/queue-4.14/xfrm-policy-match-with-both-mark-and-mask-on-user-interfaces.patch
new file mode 100644 (file)
index 0000000..cc2df83
--- /dev/null
@@ -0,0 +1,218 @@
+From 4f47e8ab6ab796b5380f74866fa5287aca4dcc58 Mon Sep 17 00:00:00 2001
+From: Xin Long <lucien.xin@gmail.com>
+Date: Mon, 22 Jun 2020 16:40:29 +0800
+Subject: xfrm: policy: match with both mark and mask on user interfaces
+
+From: Xin Long <lucien.xin@gmail.com>
+
+commit 4f47e8ab6ab796b5380f74866fa5287aca4dcc58 upstream.
+
+In commit ed17b8d377ea ("xfrm: fix a warning in xfrm_policy_insert_list"),
+it would take 'priority' to make a policy unique, and allow duplicated
+policies with different 'priority' to be added, which is not expected
+by userland, as Tobias reported in strongswan.
+
+To fix this duplicated policies issue, and also fix the issue in
+commit ed17b8d377ea ("xfrm: fix a warning in xfrm_policy_insert_list"),
+when doing add/del/get/update on user interfaces, this patch is to change
+to look up a policy with both mark and mask by doing:
+
+  mark.v == pol->mark.v && mark.m == pol->mark.m
+
+and leave the check:
+
+  (mark & pol->mark.m) == pol->mark.v
+
+for tx/rx path only.
+
+As the userland expects an exact mark and mask match to manage policies.
+
+v1->v2:
+  - make xfrm_policy_mark_match inline and fix the changelog as
+    Tobias suggested.
+
+Fixes: 295fae568885 ("xfrm: Allow user space manipulation of SPD mark")
+Fixes: ed17b8d377ea ("xfrm: fix a warning in xfrm_policy_insert_list")
+Reported-by: Tobias Brunner <tobias@strongswan.org>
+Tested-by: Tobias Brunner <tobias@strongswan.org>
+Signed-off-by: Xin Long <lucien.xin@gmail.com>
+Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/net/xfrm.h     |    9 ++++++---
+ net/key/af_key.c       |    4 ++--
+ net/xfrm/xfrm_policy.c |   24 ++++++++++--------------
+ net/xfrm/xfrm_user.c   |   14 ++++++++------
+ 4 files changed, 26 insertions(+), 25 deletions(-)
+
+--- a/include/net/xfrm.h
++++ b/include/net/xfrm.h
+@@ -1674,13 +1674,16 @@ int xfrm_policy_walk(struct net *net, st
+                    void *);
+ void xfrm_policy_walk_done(struct xfrm_policy_walk *walk, struct net *net);
+ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl);
+-struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark,
++struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net,
++                                        const struct xfrm_mark *mark,
+                                         u8 type, int dir,
+                                         struct xfrm_selector *sel,
+                                         struct xfrm_sec_ctx *ctx, int delete,
+                                         int *err);
+-struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8, int dir,
+-                                   u32 id, int delete, int *err);
++struct xfrm_policy *xfrm_policy_byid(struct net *net,
++                                   const struct xfrm_mark *mark,
++                                   u8 type, int dir, u32 id, int delete,
++                                   int *err);
+ int xfrm_policy_flush(struct net *net, u8 type, bool task_valid);
+ void xfrm_policy_hash_rebuild(struct net *net);
+ u32 xfrm_get_acqseq(void);
+--- a/net/key/af_key.c
++++ b/net/key/af_key.c
+@@ -2411,7 +2411,7 @@ static int pfkey_spddelete(struct sock *
+                       return err;
+       }
+-      xp = xfrm_policy_bysel_ctx(net, DUMMY_MARK, XFRM_POLICY_TYPE_MAIN,
++      xp = xfrm_policy_bysel_ctx(net, &dummy_mark, XFRM_POLICY_TYPE_MAIN,
+                                  pol->sadb_x_policy_dir - 1, &sel, pol_ctx,
+                                  1, &err);
+       security_xfrm_policy_free(pol_ctx);
+@@ -2662,7 +2662,7 @@ static int pfkey_spdget(struct sock *sk,
+               return -EINVAL;
+       delete = (hdr->sadb_msg_type == SADB_X_SPDDELETE2);
+-      xp = xfrm_policy_byid(net, DUMMY_MARK, XFRM_POLICY_TYPE_MAIN,
++      xp = xfrm_policy_byid(net, &dummy_mark, XFRM_POLICY_TYPE_MAIN,
+                             dir, pol->sadb_x_policy_id, delete, &err);
+       if (xp == NULL)
+               return -ENOENT;
+--- a/net/xfrm/xfrm_policy.c
++++ b/net/xfrm/xfrm_policy.c
+@@ -719,14 +719,10 @@ static void xfrm_policy_requeue(struct x
+       spin_unlock_bh(&pq->hold_queue.lock);
+ }
+-static bool xfrm_policy_mark_match(struct xfrm_policy *policy,
+-                                 struct xfrm_policy *pol)
++static inline bool xfrm_policy_mark_match(const struct xfrm_mark *mark,
++                                        struct xfrm_policy *pol)
+ {
+-      if (policy->mark.v == pol->mark.v &&
+-          policy->priority == pol->priority)
+-              return true;
+-
+-      return false;
++      return mark->v == pol->mark.v && mark->m == pol->mark.m;
+ }
+ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
+@@ -744,7 +740,7 @@ int xfrm_policy_insert(int dir, struct x
+       hlist_for_each_entry(pol, chain, bydst) {
+               if (pol->type == policy->type &&
+                   !selector_cmp(&pol->selector, &policy->selector) &&
+-                  xfrm_policy_mark_match(policy, pol) &&
++                  xfrm_policy_mark_match(&policy->mark, pol) &&
+                   xfrm_sec_ctx_match(pol->security, policy->security) &&
+                   !WARN_ON(delpol)) {
+                       if (excl) {
+@@ -794,8 +790,8 @@ int xfrm_policy_insert(int dir, struct x
+ }
+ EXPORT_SYMBOL(xfrm_policy_insert);
+-struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, u8 type,
+-                                        int dir, struct xfrm_selector *sel,
++struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, const struct xfrm_mark *mark,
++                                        u8 type, int dir, struct xfrm_selector *sel,
+                                         struct xfrm_sec_ctx *ctx, int delete,
+                                         int *err)
+ {
+@@ -808,7 +804,7 @@ struct xfrm_policy *xfrm_policy_bysel_ct
+       ret = NULL;
+       hlist_for_each_entry(pol, chain, bydst) {
+               if (pol->type == type &&
+-                  (mark & pol->mark.m) == pol->mark.v &&
++                  xfrm_policy_mark_match(mark, pol) &&
+                   !selector_cmp(sel, &pol->selector) &&
+                   xfrm_sec_ctx_match(ctx, pol->security)) {
+                       xfrm_pol_hold(pol);
+@@ -833,8 +829,8 @@ struct xfrm_policy *xfrm_policy_bysel_ct
+ }
+ EXPORT_SYMBOL(xfrm_policy_bysel_ctx);
+-struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8 type,
+-                                   int dir, u32 id, int delete, int *err)
++struct xfrm_policy *xfrm_policy_byid(struct net *net, const struct xfrm_mark *mark,
++                                       u8 type, int dir, u32 id, int delete, int *err)
+ {
+       struct xfrm_policy *pol, *ret;
+       struct hlist_head *chain;
+@@ -849,7 +845,7 @@ struct xfrm_policy *xfrm_policy_byid(str
+       ret = NULL;
+       hlist_for_each_entry(pol, chain, byidx) {
+               if (pol->type == type && pol->index == id &&
+-                  (mark & pol->mark.m) == pol->mark.v) {
++                  xfrm_policy_mark_match(mark, pol)) {
+                       xfrm_pol_hold(pol);
+                       if (delete) {
+                               *err = security_xfrm_policy_delete(
+--- a/net/xfrm/xfrm_user.c
++++ b/net/xfrm/xfrm_user.c
+@@ -1814,7 +1814,6 @@ static int xfrm_get_policy(struct sk_buf
+       struct km_event c;
+       int delete;
+       struct xfrm_mark m;
+-      u32 mark = xfrm_mark_get(attrs, &m);
+       p = nlmsg_data(nlh);
+       delete = nlh->nlmsg_type == XFRM_MSG_DELPOLICY;
+@@ -1827,8 +1826,10 @@ static int xfrm_get_policy(struct sk_buf
+       if (err)
+               return err;
++      xfrm_mark_get(attrs, &m);
++
+       if (p->index)
+-              xp = xfrm_policy_byid(net, mark, type, p->dir, p->index, delete, &err);
++              xp = xfrm_policy_byid(net, &m, type, p->dir, p->index, delete, &err);
+       else {
+               struct nlattr *rt = attrs[XFRMA_SEC_CTX];
+               struct xfrm_sec_ctx *ctx;
+@@ -1845,7 +1846,7 @@ static int xfrm_get_policy(struct sk_buf
+                       if (err)
+                               return err;
+               }
+-              xp = xfrm_policy_bysel_ctx(net, mark, type, p->dir, &p->sel,
++              xp = xfrm_policy_bysel_ctx(net, &m, type, p->dir, &p->sel,
+                                          ctx, delete, &err);
+               security_xfrm_policy_free(ctx);
+       }
+@@ -2108,7 +2109,6 @@ static int xfrm_add_pol_expire(struct sk
+       u8 type = XFRM_POLICY_TYPE_MAIN;
+       int err = -ENOENT;
+       struct xfrm_mark m;
+-      u32 mark = xfrm_mark_get(attrs, &m);
+       err = copy_from_user_policy_type(&type, attrs);
+       if (err)
+@@ -2118,8 +2118,10 @@ static int xfrm_add_pol_expire(struct sk
+       if (err)
+               return err;
++      xfrm_mark_get(attrs, &m);
++
+       if (p->index)
+-              xp = xfrm_policy_byid(net, mark, type, p->dir, p->index, 0, &err);
++              xp = xfrm_policy_byid(net, &m, type, p->dir, p->index, 0, &err);
+       else {
+               struct nlattr *rt = attrs[XFRMA_SEC_CTX];
+               struct xfrm_sec_ctx *ctx;
+@@ -2136,7 +2138,7 @@ static int xfrm_add_pol_expire(struct sk
+                       if (err)
+                               return err;
+               }
+-              xp = xfrm_policy_bysel_ctx(net, mark, type, p->dir,
++              xp = xfrm_policy_bysel_ctx(net, &m, type, p->dir,
+                                          &p->sel, ctx, 0, &err);
+               security_xfrm_policy_free(ctx);
+       }