public inbox for netdev@vger.kernel.org
 help / color / mirror / Atom feed
From: Antony Antony <antony.antony@secunet.com>
To: Yan Yan <evitayan@google.com>
Cc: Nathan Harold <nharold@google.com>,
	Tobias Brunner <tobias@strongswan.org>,
	<antony.antony@secunet.com>,
	Steffen Klassert <steffen.klassert@secunet.com>, <paul@nohats.ca>,
	<netdev@vger.kernel.org>,
	Herbert Xu <herbert@gondor.apana.org.au>,
	"David S . Miller" <davem@davemloft.net>,
	Eric Dumazet <edumazet@google.com>,
	Jakub Kicinski <kuba@kernel.org>, <pabeni@redhat.com>,
	<horms@kernel.org>, <saakashkumar@marvell.com>,
	<akamluddin@marvell.com>, <greg@kroah.com>
Subject: Re: [REGRESSION] Discussion on "xfrm: Duplicate SPI Handling"
Date: Mon, 30 Mar 2026 18:54:12 +0200	[thread overview]
Message-ID: <acqqpAHmKnduKxRp@moon.secunet.de> (raw)
In-Reply-To: <CADHa2dBA=MpBz3_j2kbLr-wb2nsmnYBhyhWb6pjWekEzurBr9w@mail.gmail.com>

[-- Attachment #1: Type: text/plain, Size: 8761 bytes --]

Hi,
I looked into this. I feel a simple solution is use x->dir as Nathan
proposed.
When dir is not set we get  pre
commit 94f39804d891 ("xfrm: Duplicate SPI Handling") behaviour.

When XFRM_SA_DIR is set alloc_spi() returns per direction unique spi. 

Another benfit is, this would also keep PF_KEY use case as it was before that comit.
Here is simple RFC patch attached.

How does this look?

strongswan 6.0.0, from Dec 2024, sets x->dir. 
Aakash would this work for for marvell? 

regads,
-antony

On Fri, Mar 27, 2026 at 17:05:13 -0700, Yan Yan wrote:
>    Hi all,
>    I wanted to send a friendly ping to see if we are aligning on making
>    the strict global SPI uniqueness requirement optional, perhaps via a
>    toggle or by leveraging the XFRM_SA_DIR attribute as previously
>    discussed.
>    Are there any other questions or concerns regarding this approach, or
>    anything else we should clarify to ensure backward compatibility while
>    meeting the needs of modern standards?
>    Best,
>    Yan
> 
>    On Tue, Feb 24, 2026 at 3:53 PM Nathan Harold <[1]nharold@google.com>
>    wrote:
> 
>      > That should still be allowed when using the intended APIs (i.e.
>      ALLOCSPI
>      > for the inbound and NEWSA for the outbound SA).  ALLOCSPI might
>      enforce
>      > a unique SPI without considering the address, as that's intended
>      for
>      > local, inbound SAs, where the kernel has full control (looking at
>      the
>      > the patch, it's certainly not ideal, as it goes through all
>      installed
>      > SAs to find a duplicate and it prevents an inbound SPI that
>      matches an
>      > existing outbound SPI - I guess that could be resolved by using
>      separate
>      > tables for in- and outbound SAs).  But that must not prevent
>      installing
>      > outbound SAs with the same SPI to another peer using NEWSA, which
>      still
>      > uses a hash that includes the destination address (that must
>      always be
>      > the case because peers are free to allocate whatever SPI they
>      want).
>      Agreed that there are some unfortunate limitations with the current
>      patch. Keying off the inclusion of XFRM_SA_DIR would resolve the
>      issue
>      you noted (conflating inbound and outbound SPIs) and function as an
>      opt-in for this enforcement. Whatever the mechanism though, the new
>      behavior should be opt-in rather than opt-out in order to maintain
>      backwards compatibility.
>      > In my opinion, you are using the API incorrectly...  I also
>      > don't think there are any benefits in that "consistent larval
>      lifecycle"
>      > (if you found any, please let us know).
>      The Android architecture is multi-tenant and allows userspace apps
>      to
>      establish SAs. At the time we designed it, this felt like the
>      cleanest
>      way to facilitate leak-free resource management because the chain of
>      associations between kernel resources could be symmetrical (and
>      managing them was already quite complicated). Mea culpa (Nathan).
>      But,
>      correctly or not, it has/had worked for many years.
>      > By the way, are you using the min/max option for inbound SAs as
>      well,
>      > with an SPI generated in userland?  That would seem like a
>      violation of
>      > the intention of the API as well (i.e. letting the kernel control
>      the
>      > local SPIs).
>      We provide following two Android APIs for app developers:
>      [2]https://developer.android.com/reference/android/net/IpSecManager#
>      allocateSecurityParameterIndex(java.net.InetAddress)
>      [3]https://developer.android.com/reference/android/net/IpSecManager#
>      allocateSecurityParameterIndex(java.net.InetAddress,%20int)
>      Indeed, allocateSecurityParameterIndex is direction-agnostic; both
>      overloads are implemented internally by including the min and max
>      values in ALLOCSPI. For the variant where app developers provide a
>      specific SPI (which is also useful in testing), Android simply sets
>      both the min and max parameters to that exact value. Our
>      understanding
>      of #xfrm_alloc_spi  is that min/max are required for ALLOCSPI, and
>      otherwise ENOENT will be returned.
>      Note that we also use the DADDR as a mandatory part of the tuple
>      because of the issue mentioned above: SPIs are only unique in
>      conjunction with a DADDR, regardless of direction, and accordingly,
>      that’s how Android is expecting the uniqueness requirement be
>      enforced. In this way, 5 duplicate SPIs can be used on 5 unique IP
>      addresses on the same machine; therefore, a strict "SPI only"
>      interpretation for ALLOCSPI (or SPI handling in general) is curious.
>      We feel that ALLOCSPI should really enforce the same uniqueness
>      requirements as the SAD.
>      Best,
>      Nathan and Yan
>      -Nathan
>      On Wed, Feb 18, 2026 at 12:42 AM Tobias Brunner
>      <[4]tobias@strongswan.org> wrote:
>      >
>      > Hi Yan,
>      >
>      > > For every inbound SA, we allocate SPIs before negotiation. For
>      > > outbound SAs, we allocate SPIs once requested by the peer. We
>      only
>      > > require the (SPI, destination address) combo to be unique. Thus,
>      we
>      > > may have an inbound and outbound SA sharing an SPI with
>      different
>      > > destinations, or multiple outbound SAs to different peers
>      sharing an
>      > > SPI.
>      >
>      > That should still be allowed when using the intended APIs (i.e.
>      ALLOCSPI
>      > for the inbound and NEWSA for the outbound SA).  ALLOCSPI might
>      enforce
>      > a unique SPI without considering the address, as that's intended
>      for
>      > local, inbound SAs, where the kernel has full control (looking at
>      the
>      > the patch, it's certainly not ideal, as it goes through all
>      installed
>      > SAs to find a duplicate and it prevents an inbound SPI that
>      matches an
>      > existing outbound SPI - I guess that could be resolved by using
>      separate
>      > tables for in- and outbound SAs).  But that must not prevent
>      installing
>      > outbound SAs with the same SPI to another peer using NEWSA, which
>      still
>      > uses a hash that includes the destination address (that must
>      always be
>      > the case because peers are free to allocate whatever SPI they
>      want).
>      >
>      > >> If so, why would you use ALLOCSPI and not just install the
>      outbound SA? Is it to avoid differences for in- and outbound SAs
>      (ALLOCSPI+UPDSA vs. NEWSA)?"
>      > >
>      > > Exactly—it is primarily for code symmetry. By using ALLOCSPI +
>      UPDSA
>      > > for both directions, we maintain a consistent larval lifecycle
>      and
>      > > make it easier to maintain.
>      >
>      > In my opinion, you are using the API incorrectly.  ALLOCSPI is
>      intended
>      > to allocate a free local SPI for an inbound SA.  That is, reserve
>      it
>      > before and while the details of the SA are negotiated with the
>      peer
>      > using IKE.  This step isn't necessary for outbound SAs and forcing
>      such
>      > an allocation, after all the details are known, to the responder's
>      SPI
>      > (which I assume you do via min/max option) doesn't feel right.  I
>      also
>      > don't think there are any benefits in that "consistent larval
>      lifecycle"
>      > (if you found any, please let us know).  And the difference
>      between
>      > UPDSA and NEWSA is the nlmsg_type (there are some attributes that
>      are
>      > different for in- and outbound SAs, especially if you set the
>      direction
>      > in newer kernels, but that's the case regardless of the message
>      type).
>      >
>      > By the way, are you using the min/max option for inbound SAs as
>      well,
>      > with an SPI generated in userland?  That would seem like a
>      violation of
>      > the intention of the API as well (i.e. letting the kernel control
>      the
>      > local SPIs).
>      >
>      > As the XFRM API basically mirrors PF_KEYv2 here, you can find more
>      about
>      > the two ways to install SAs in RFC 2367 (SADB_GETSPI/UPDATE vs.
>      SADB_ADD).
>      >
>      > Regards,
>      > Tobias
>      >
> 
>    --
> 
>    --
>    Best,
>    Yan
> 
> References
> 
>    1. mailto:nharold@google.com
>    2. https://developer.android.com/reference/android/net/IpSecManager#allocateSecurityParameterIndex(java.net.InetAddress)
>    3. https://developer.android.com/reference/android/net/IpSecManager#allocateSecurityParameterIndex(java.net.InetAddress, int)
>    4. mailto:tobias@strongswan.org

[-- Attachment #2: 0001-xfrm-allow-same-SPI-value-for-inbound-and-outbound-S.patch --]
[-- Type: text/x-diff, Size: 3548 bytes --]

From b712c3ff7d586c8ed62005e6a37ae01c4a771ce8 Mon Sep 17 00:00:00 2001
From: Antony Antony <antony.antony@secunet.com>
Date: Wed, 25 Mar 2026 06:02:07 +0100
Subject: [PATCH] xfrm: allow same SPI value for inbound and outbound SAs

Commit 94f39804d891 ("xfrm: Duplicate SPI Handling") introduced
xfrm_state_lookup_spi_proto() to fix duplicate SPI allocation for
inbound SAs with different destination addresses.  It enforces global
uniqueness by (spi, proto) across all states regardless of direction.

When x->dir is set, use xfrm_state_lookup_spi_proto() with a strict
per-direction match so that IN and OUT SAs can share a SPI value.

When x->dir is not set, also legacy states created via PF_KEY or without
direction, restore pre-94f39804d891 behavior and check uniqueness by
(daddr, spi, proto) via xfrm_state_lookup(). Extract the mark from
x->mark as required by xfrm_state_lookup().

Move the x->dir assignment in xfrm_alloc_userspi() to before
xfrm_alloc_spi() lookup using dir when it is set.

Signed-off-by: Antony Antony <antony.antony@secunet.com>
---
 net/xfrm/xfrm_state.c | 14 ++++++++++++--
 net/xfrm/xfrm_user.c  |  6 +++---
 2 files changed, 15 insertions(+), 5 deletions(-)

diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 98b362d51836..1cc4a06f9163 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -1698,7 +1698,9 @@ 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_spi_proto(struct net *net,
+						      __be32 spi, u8 proto,
+						      u8 dir)
 {
 	struct xfrm_state *x;
 	unsigned int i;
@@ -1707,6 +1709,8 @@ static struct xfrm_state *xfrm_state_lookup_spi_proto(struct net *net, __be32 sp
 	for (i = 0; i <= net->xfrm.state_hmask; i++) {
 		hlist_for_each_entry_rcu(x, &net->xfrm.state_byspi[i], byspi) {
 			if (x->id.spi == spi && x->id.proto == proto) {
+				if (x->dir != dir)
+					continue;
 				if (!xfrm_state_hold_rcu(x))
 					continue;
 				rcu_read_unlock();
@@ -2577,6 +2581,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);
@@ -2598,7 +2603,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)
+			x0 = xfrm_state_lookup_spi_proto(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 403b5ecac2c5..98b90c747aad 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -1873,13 +1873,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);
-- 
2.39.5


  parent reply	other threads:[~2026-03-30 16:54 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-01-28  8:43 [REGRESSION] Discussion on "xfrm: Duplicate SPI Handling" Yan Yan
2026-02-02  9:44 ` Steffen Klassert
2026-02-02 14:27 ` Antony Antony
2026-02-09  3:03   ` Yan Yan
2026-02-09 19:05     ` Nathan Harold
2026-02-10 10:17     ` Tobias Brunner
2026-02-18  4:36       ` Yan Yan
2026-02-18  8:41         ` Tobias Brunner
2026-02-24 23:53           ` Nathan Harold
     [not found]             ` <CADHa2dBA=MpBz3_j2kbLr-wb2nsmnYBhyhWb6pjWekEzurBr9w@mail.gmail.com>
2026-03-30 16:54               ` Antony Antony [this message]
     [not found]                 ` <BL1PPF236BDCF3E1BDA74118AE2A6ECFAFFDA52A@BL1PPF236BDCF3E.namprd18.prod.outlook.com>
2026-03-31 10:47                   ` [EXTERNAL] " Antony Antony

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=acqqpAHmKnduKxRp@moon.secunet.de \
    --to=antony.antony@secunet.com \
    --cc=akamluddin@marvell.com \
    --cc=davem@davemloft.net \
    --cc=edumazet@google.com \
    --cc=evitayan@google.com \
    --cc=greg@kroah.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=paul@nohats.ca \
    --cc=saakashkumar@marvell.com \
    --cc=steffen.klassert@secunet.com \
    --cc=tobias@strongswan.org \
    /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