From: Antony Antony <antony.antony@secunet.com>
To: Steffen Klassert <steffen.klassert@secunet.com>,
Herbert Xu <herbert@gondor.apana.org.au>,
Eric Dumazet <edumazet@google.com>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
Simon Horman <horms@kernel.org>,
Aakash Kumar S <saakashkumar@marvell.com>,
Yan Yan <evitayan@google.com>
Cc: Abed Mohammad Kamaluddin <akamluddin@marvell.com>,
Nathan Harold <nharold@google.com>, <netdev@vger.kernel.org>,
<devel@linux-ipsec.org>,
Antony Antony <antony.antony@secunet.com>
Subject: [PATCH RFC] xfrm: enforce SPI uniqueness for inbound SAs only
Date: Thu, 16 Apr 2026 07:44:56 +0200 [thread overview]
Message-ID: <20260416-alloc-spi-dir-v1-1-145e16477480@secunet.com> (raw)
Per RFC 4301 section 4.4.2.1, the SPI is selected by the receiving
end, which is interpreted as making SPI uniqueness an inbound-only
requirement.
Commit 94f39804d891 ("xfrm: Duplicate SPI Handling") introduced
xfrm_state_lookup_spi_proto() to fix duplicate SPI allocation for
inbound SAs with different destination addresses. However, it enforces
global uniqueness by (spi, proto) across all states regardless of
direction, which causes SPI allocation to fail for outbound SAs when
the same (spi, proto) is already in use by an inbound SA.
When x->dir == XFRM_DIR_IN, enforce SPI uniqueness via
xfrm_state_lookup_spi_proto() scoped to inbound SAs. SAs created via
PF_KEY, without direction, or with XFRM_DIR_OUT restore the
pre 94f39804d891, RFC 2401 lookup by (daddr, spi, proto).
Reported-by: Yan Yan <evitayan@google.com>
Fixes: 94f39804d891 ("xfrm: Duplicate SPI Handling")
Signed-off-by: Antony Antony <antony.antony@secunet.com>
---
net/xfrm/xfrm_state.c | 16 ++++++++++++++--
net/xfrm/xfrm_user.c | 6 +++---
2 files changed, 17 insertions(+), 5 deletions(-)
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 1748d374abca..b1ec95141512 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -1698,15 +1698,21 @@ struct xfrm_state *xfrm_state_lookup_byspi(struct net *net, __be32 spi,
}
EXPORT_SYMBOL(xfrm_state_lookup_byspi);
-static struct xfrm_state *xfrm_state_lookup_spi_proto(struct net *net, __be32 spi, u8 proto)
+static struct xfrm_state *xfrm_state_lookup_input_spi(struct net *net,
+ __be32 spi, u8 proto,
+ u8 dir)
{
struct xfrm_state *x;
unsigned int i;
for (i = 0; i <= net->xfrm.state_hmask; i++) {
hlist_for_each_entry(x, xfrm_state_deref_prot(net->xfrm.state_byspi, net) + i, byspi) {
+ if (x->dir != dir)
+ continue;
+
if (x->id.spi == spi && x->id.proto == proto)
return x;
+
}
}
return NULL;
@@ -2578,6 +2584,7 @@ int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high,
struct xfrm_state *x0;
int err = -ENOENT;
u32 range = high - low + 1;
+ u32 mark = x->mark.v & x->mark.m;
__be32 newspi = 0;
spin_lock_bh(&x->lock);
@@ -2599,7 +2606,12 @@ int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high,
newspi = htonl(spi);
spin_lock_bh(&net->xfrm.xfrm_state_lock);
- x0 = xfrm_state_lookup_spi_proto(net, newspi, x->id.proto);
+ if (x->dir == XFRM_SA_DIR_IN)
+ x0 = xfrm_state_lookup_input_spi(net, newspi,
+ x->id.proto, x->dir);
+ else
+ x0 = xfrm_state_lookup(net, mark, &x->id.daddr, newspi,
+ x->id.proto, x->props.family);
if (!x0) {
x->id.spi = newspi;
h = xfrm_spi_hash(net, &x->id.daddr, newspi, x->id.proto, x->props.family);
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index d56450f61669..f9db2d2c392b 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -1883,13 +1883,13 @@ static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh,
goto out_noput;
}
+ if (attrs[XFRMA_SA_DIR])
+ x->dir = nla_get_u8(attrs[XFRMA_SA_DIR]);
+
err = xfrm_alloc_spi(x, p->min, p->max, extack);
if (err)
goto out;
- if (attrs[XFRMA_SA_DIR])
- x->dir = nla_get_u8(attrs[XFRMA_SA_DIR]);
-
resp_skb = xfrm_state_netlink(skb, x, nlh->nlmsg_seq);
if (IS_ERR(resp_skb)) {
err = PTR_ERR(resp_skb);
---
base-commit: 426c355742f02cf743b347d9d7dbdc1bfbfa31ef
change-id: 20260330-alloc-spi-dir-3b6e2f4b34e9
Best regards,
--
Antony Antony <antony.antony@secunet.com>
reply other threads:[~2026-04-16 5:45 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260416-alloc-spi-dir-v1-1-145e16477480@secunet.com \
--to=antony.antony@secunet.com \
--cc=akamluddin@marvell.com \
--cc=devel@linux-ipsec.org \
--cc=edumazet@google.com \
--cc=evitayan@google.com \
--cc=herbert@gondor.apana.org.au \
--cc=horms@kernel.org \
--cc=kuba@kernel.org \
--cc=netdev@vger.kernel.org \
--cc=nharold@google.com \
--cc=pabeni@redhat.com \
--cc=saakashkumar@marvell.com \
--cc=steffen.klassert@secunet.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox