* [PATCH v2 0/2] Fix issues in xfrm_migrate
@ 2022-01-19 0:00 Yan Yan
2022-01-19 0:00 ` [PATCH v2 1/2] xfrm: Check if_id " Yan Yan
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Yan Yan @ 2022-01-19 0:00 UTC (permalink / raw)
To: Steffen Klassert
Cc: netdev, Herbert Xu, David S . Miller, Jakub Kicinski, lorenzo,
maze, nharold, benedictwong, Yan Yan
This patch series include two patches to fix two issues in xfrm_migrate.
PATCH 1/2 enables distinguishing SAs and SPs based on if_id during the
xfrm_migrate flow. It fixes the problem that when there are multiple
existing SPs with the same direction, the same xfrm_selector and
different endpoint addresses, xfrm_migrate might fail.
PATCH 2/2 enables xfrm_migrate to handle address family change by
breaking the original xfrm_state_clone method into two steps so as to
update the props.family before running xfrm_init_state.
V1 -> V2:
- Move xfrm_init_state() out of xfrm_state_clone()
and called it after updating the address family
Yan Yan (2):
xfrm: Check if_id in xfrm_migrate
xfrm: Fix xfrm migrate issues when address family changes
include/net/xfrm.h | 5 +++--
net/key/af_key.c | 2 +-
net/xfrm/xfrm_policy.c | 14 ++++++++------
net/xfrm/xfrm_state.c | 15 +++++++++++----
net/xfrm/xfrm_user.c | 6 +++++-
5 files changed, 28 insertions(+), 14 deletions(-)
base-commit: fe8152b38d3a994c4c6fdbc0cd6551d569a5715a
--
2.34.1.703.g22d0c6ccf7-goog
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH v2 1/2] xfrm: Check if_id in xfrm_migrate
2022-01-19 0:00 [PATCH v2 0/2] Fix issues in xfrm_migrate Yan Yan
@ 2022-01-19 0:00 ` Yan Yan
2022-01-19 0:00 ` [PATCH v2 2/2] xfrm: Fix xfrm migrate issues when address family changes Yan Yan
2022-01-27 6:20 ` [PATCH v2 0/2] Fix issues in xfrm_migrate Steffen Klassert
2 siblings, 0 replies; 4+ messages in thread
From: Yan Yan @ 2022-01-19 0:00 UTC (permalink / raw)
To: Steffen Klassert
Cc: netdev, Herbert Xu, David S . Miller, Jakub Kicinski, lorenzo,
maze, nharold, benedictwong, Yan Yan
This patch enables distinguishing SAs and SPs based on if_id during
the xfrm_migrate flow. This ensures support for xfrm interfaces
throughout the SA/SP lifecycle.
When there are multiple existing SPs with the same direction,
the same xfrm_selector and different endpoint addresses,
xfrm_migrate might fail with ENODATA.
Specifically, the code path for performing xfrm_migrate is:
Stage 1: find policy to migrate with
xfrm_migrate_policy_find(sel, dir, type, net)
Stage 2: find and update state(s) with
xfrm_migrate_state_find(mp, net)
Stage 3: update endpoint address(es) of template(s) with
xfrm_policy_migrate(pol, m, num_migrate)
Currently "Stage 1" always returns the first xfrm_policy that
matches, and "Stage 3" looks for the xfrm_tmpl that matches the
old endpoint address. Thus if there are multiple xfrm_policy
with same selector, direction, type and net, "Stage 1" might
rertun a wrong xfrm_policy and "Stage 3" will fail with ENODATA
because it cannot find a xfrm_tmpl with the matching endpoint
address.
The fix is to allow userspace to pass an if_id and add if_id
to the matching rule in Stage 1 and Stage 2 since if_id is a
unique ID for xfrm_policy and xfrm_state. For compatibility,
if_id will only be checked if the attribute is set.
Tested with additions to Android's kernel unit test suite:
https://android-review.googlesource.com/c/kernel/tests/+/1668886
Signed-off-by: Yan Yan <evitayan@google.com>
---
V1->V2:
- No change (change of this commit serie is not in this commit)
---
include/net/xfrm.h | 5 +++--
net/key/af_key.c | 2 +-
net/xfrm/xfrm_policy.c | 14 ++++++++------
net/xfrm/xfrm_state.c | 7 ++++++-
net/xfrm/xfrm_user.c | 6 +++++-
5 files changed, 23 insertions(+), 11 deletions(-)
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index fdb41e8bb626..743dd1da506e 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -1681,14 +1681,15 @@ int km_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
const struct xfrm_migrate *m, int num_bundles,
const struct xfrm_kmaddress *k,
const struct xfrm_encap_tmpl *encap);
-struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *net);
+struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *net,
+ u32 if_id);
struct xfrm_state *xfrm_state_migrate(struct xfrm_state *x,
struct xfrm_migrate *m,
struct xfrm_encap_tmpl *encap);
int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
struct xfrm_migrate *m, int num_bundles,
struct xfrm_kmaddress *k, struct net *net,
- struct xfrm_encap_tmpl *encap);
+ struct xfrm_encap_tmpl *encap, u32 if_id);
#endif
int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport);
diff --git a/net/key/af_key.c b/net/key/af_key.c
index de24a7d474df..9bf52a09b5ff 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -2623,7 +2623,7 @@ static int pfkey_migrate(struct sock *sk, struct sk_buff *skb,
}
return xfrm_migrate(&sel, dir, XFRM_POLICY_TYPE_MAIN, m, i,
- kma ? &k : NULL, net, NULL);
+ kma ? &k : NULL, net, NULL, 0);
out:
return err;
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index dccb8f3318ef..b4ccad50d94f 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -4255,7 +4255,7 @@ static bool xfrm_migrate_selector_match(const struct xfrm_selector *sel_cmp,
}
static struct xfrm_policy *xfrm_migrate_policy_find(const struct xfrm_selector *sel,
- u8 dir, u8 type, struct net *net)
+ u8 dir, u8 type, struct net *net, u32 if_id)
{
struct xfrm_policy *pol, *ret = NULL;
struct hlist_head *chain;
@@ -4264,7 +4264,8 @@ static struct xfrm_policy *xfrm_migrate_policy_find(const struct xfrm_selector *
spin_lock_bh(&net->xfrm.xfrm_policy_lock);
chain = policy_hash_direct(net, &sel->daddr, &sel->saddr, sel->family, dir);
hlist_for_each_entry(pol, chain, bydst) {
- if (xfrm_migrate_selector_match(sel, &pol->selector) &&
+ if ((if_id == 0 || pol->if_id == if_id) &&
+ xfrm_migrate_selector_match(sel, &pol->selector) &&
pol->type == type) {
ret = pol;
priority = ret->priority;
@@ -4276,7 +4277,8 @@ static struct xfrm_policy *xfrm_migrate_policy_find(const struct xfrm_selector *
if ((pol->priority >= priority) && ret)
break;
- if (xfrm_migrate_selector_match(sel, &pol->selector) &&
+ if ((if_id == 0 || pol->if_id == if_id) &&
+ xfrm_migrate_selector_match(sel, &pol->selector) &&
pol->type == type) {
ret = pol;
break;
@@ -4392,7 +4394,7 @@ static int xfrm_migrate_check(const struct xfrm_migrate *m, int num_migrate)
int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
struct xfrm_migrate *m, int num_migrate,
struct xfrm_kmaddress *k, struct net *net,
- struct xfrm_encap_tmpl *encap)
+ struct xfrm_encap_tmpl *encap, u32 if_id)
{
int i, err, nx_cur = 0, nx_new = 0;
struct xfrm_policy *pol = NULL;
@@ -4411,14 +4413,14 @@ int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
}
/* Stage 1 - find policy */
- if ((pol = xfrm_migrate_policy_find(sel, dir, type, net)) == NULL) {
+ if ((pol = xfrm_migrate_policy_find(sel, dir, type, net, if_id)) == NULL) {
err = -ENOENT;
goto out;
}
/* Stage 2 - find and update state(s) */
for (i = 0, mp = m; i < num_migrate; i++, mp++) {
- if ((x = xfrm_migrate_state_find(mp, net))) {
+ if ((x = xfrm_migrate_state_find(mp, net, if_id))) {
x_cur[nx_cur] = x;
nx_cur++;
xc = xfrm_state_migrate(x, mp, encap);
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index ca6bee18346d..b0eeb0aef493 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -1606,7 +1606,8 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig,
return NULL;
}
-struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *net)
+struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *net,
+ u32 if_id)
{
unsigned int h;
struct xfrm_state *x = NULL;
@@ -1622,6 +1623,8 @@ struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *n
continue;
if (m->reqid && x->props.reqid != m->reqid)
continue;
+ if (if_id != 0 && x->if_id != if_id)
+ continue;
if (!xfrm_addr_equal(&x->id.daddr, &m->old_daddr,
m->old_family) ||
!xfrm_addr_equal(&x->props.saddr, &m->old_saddr,
@@ -1637,6 +1640,8 @@ struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *n
if (x->props.mode != m->mode ||
x->id.proto != m->proto)
continue;
+ if (if_id != 0 && x->if_id != if_id)
+ continue;
if (!xfrm_addr_equal(&x->id.daddr, &m->old_daddr,
m->old_family) ||
!xfrm_addr_equal(&x->props.saddr, &m->old_saddr,
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index 8cd6c8129004..a4fb596e87af 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -2608,6 +2608,7 @@ static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh,
int n = 0;
struct net *net = sock_net(skb->sk);
struct xfrm_encap_tmpl *encap = NULL;
+ u32 if_id = 0;
if (attrs[XFRMA_MIGRATE] == NULL)
return -EINVAL;
@@ -2632,7 +2633,10 @@ static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh,
return -ENOMEM;
}
- err = xfrm_migrate(&pi->sel, pi->dir, type, m, n, kmp, net, encap);
+ if (attrs[XFRMA_IF_ID])
+ if_id = nla_get_u32(attrs[XFRMA_IF_ID]);
+
+ err = xfrm_migrate(&pi->sel, pi->dir, type, m, n, kmp, net, encap, if_id);
kfree(encap);
--
2.34.1.703.g22d0c6ccf7-goog
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH v2 2/2] xfrm: Fix xfrm migrate issues when address family changes
2022-01-19 0:00 [PATCH v2 0/2] Fix issues in xfrm_migrate Yan Yan
2022-01-19 0:00 ` [PATCH v2 1/2] xfrm: Check if_id " Yan Yan
@ 2022-01-19 0:00 ` Yan Yan
2022-01-27 6:20 ` [PATCH v2 0/2] Fix issues in xfrm_migrate Steffen Klassert
2 siblings, 0 replies; 4+ messages in thread
From: Yan Yan @ 2022-01-19 0:00 UTC (permalink / raw)
To: Steffen Klassert
Cc: netdev, Herbert Xu, David S . Miller, Jakub Kicinski, lorenzo,
maze, nharold, benedictwong, Yan Yan
xfrm_migrate cannot handle address family change of an xfrm_state.
The symptons are the xfrm_state will be migrated to a wrong address,
and sending as well as receiving packets wil be broken.
This commit fixes it by breaking the original xfrm_state_clone
method into two steps so as to update the props.family before
running xfrm_init_state. As the result, xfrm_state's inner mode,
outer mode, type and IP header length in xfrm_state_migrate can
be updated with the new address family.
Tested with additions to Android's kernel unit test suite:
https://android-review.googlesource.com/c/kernel/tests/+/1885354
Signed-off-by: Yan Yan <evitayan@google.com>
---
V1->V2:
- Moved xfrm_init_state() out of xfrm_state_clone()
and called it after updating the address family
---
net/xfrm/xfrm_state.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index b0eeb0aef493..1ba6fbfe8cdb 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -1579,9 +1579,6 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig,
memcpy(&x->mark, &orig->mark, sizeof(x->mark));
memcpy(&x->props.smark, &orig->props.smark, sizeof(x->props.smark));
- if (xfrm_init_state(x) < 0)
- goto error;
-
x->props.flags = orig->props.flags;
x->props.extra_flags = orig->props.extra_flags;
@@ -1668,6 +1665,11 @@ struct xfrm_state *xfrm_state_migrate(struct xfrm_state *x,
if (!xc)
return NULL;
+ xc->props.family = m->new_family;
+
+ if (xfrm_init_state(xc) < 0)
+ goto error;
+
memcpy(&xc->id.daddr, &m->new_daddr, sizeof(xc->id.daddr));
memcpy(&xc->props.saddr, &m->new_saddr, sizeof(xc->props.saddr));
--
2.34.1.703.g22d0c6ccf7-goog
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH v2 0/2] Fix issues in xfrm_migrate
2022-01-19 0:00 [PATCH v2 0/2] Fix issues in xfrm_migrate Yan Yan
2022-01-19 0:00 ` [PATCH v2 1/2] xfrm: Check if_id " Yan Yan
2022-01-19 0:00 ` [PATCH v2 2/2] xfrm: Fix xfrm migrate issues when address family changes Yan Yan
@ 2022-01-27 6:20 ` Steffen Klassert
2 siblings, 0 replies; 4+ messages in thread
From: Steffen Klassert @ 2022-01-27 6:20 UTC (permalink / raw)
To: Yan Yan
Cc: netdev, Herbert Xu, David S . Miller, Jakub Kicinski, lorenzo,
maze, nharold, benedictwong
On Tue, Jan 18, 2022 at 04:00:12PM -0800, Yan Yan wrote:
> This patch series include two patches to fix two issues in xfrm_migrate.
>
> PATCH 1/2 enables distinguishing SAs and SPs based on if_id during the
> xfrm_migrate flow. It fixes the problem that when there are multiple
> existing SPs with the same direction, the same xfrm_selector and
> different endpoint addresses, xfrm_migrate might fail.
>
> PATCH 2/2 enables xfrm_migrate to handle address family change by
> breaking the original xfrm_state_clone method into two steps so as to
> update the props.family before running xfrm_init_state.
>
> V1 -> V2:
> - Move xfrm_init_state() out of xfrm_state_clone()
> and called it after updating the address family
>
> Yan Yan (2):
> xfrm: Check if_id in xfrm_migrate
> xfrm: Fix xfrm migrate issues when address family changes
Applied, thanks a lot Yan!
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2022-01-27 6:20 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-01-19 0:00 [PATCH v2 0/2] Fix issues in xfrm_migrate Yan Yan
2022-01-19 0:00 ` [PATCH v2 1/2] xfrm: Check if_id " Yan Yan
2022-01-19 0:00 ` [PATCH v2 2/2] xfrm: Fix xfrm migrate issues when address family changes Yan Yan
2022-01-27 6:20 ` [PATCH v2 0/2] Fix issues in xfrm_migrate Steffen Klassert
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).