Linux RDMA and InfiniBand development
 help / color / mirror / Atom feed
From: Allison Henderson <achender@kernel.org>
To: netdev-bot+sashiko@kernel.org
Cc: netdev@vger.kernel.org, linux-rdma@vger.kernel.org,
	pabeni@redhat.com,  edumazet@google.com, kuba@kernel.org,
	horms@kernel.org
Subject: Re: [PATCH net] net/rds: include the scope id in the sendmsg connection cache check
Date: Sat, 26 Sep 2026 23:52:40 -0700	[thread overview]
Message-ID: <12c79c59ff1e55fd82ce2af0b8fd1c8feff66767.camel@kernel.org> (raw)
In-Reply-To: <179029759642.2160803.15910900914007089694@kernel.org>

On Fri, 2026-09-25 at 00:53 +0000, netdev-bot+sashiko@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 1 potential
> issue(s) to consider.
> 
> Critical: 0 · High: 0 · Medium: 1 (1) · Low: 0
> 
> If you believe none of the issues are legitimate, please reply to each
> issue of Medium severity or higher and explain why the AI is wrong.
> If any of them are legitimate and you plan to respin, please let patchwork
> know by including "pw-bot: cr" as a separate line at the end of your reply
> (one such reply per series is enough).
> 
> - [Medium] New regression for connected (destination-less) sends: the
>   added `rs->rs_conn->c_dev_if == scope_id` test in rds_sendmsg()…
> 
> Pre-existing issues:
> - [Medium] rds_sendmsg() validates the cached connection with plain,
>   unsynchronized loads of rs->rs_conn (`rs->rs_conn &&`, `->c_faddr`,…
> 
> --
> 
> net/rds: include the scope id in the sendmsg connection cache check
> 
> The patch adds the interface index to the cached-connection test in
> rds_sendmsg(), so that a send to a link-local peer through a different
> interface no longer reuses the connection created for the first
> interface.  Two questions below about the destination-less send case and
> about the locking around the cache test.
> 
> > diff --git a/net/rds/send.c b/net/rds/send.c
> > index 1afa981e5c06d..38b9cc9e0d20b 100644
> > --- a/net/rds/send.c
> > +++ b/net/rds/send.c
> > @@ -1342,7 +1342,8 @@ int rds_sendmsg(struct socket *sock, struct msghdr *msg, size_t payload_len)
> >  	/* rds_conn_create has a spinlock that runs with IRQ off.
> >  	 * Caching the conn in the socket helps a lot. */
> >  	if (rs->rs_conn && ipv6_addr_equal(&rs->rs_conn->c_faddr, &daddr) &&
> > -	    rs->rs_tos == rs->rs_conn->c_tos) {
> > +	    rs->rs_tos == rs->rs_conn->c_tos &&
> > +	    rs->rs_conn->c_dev_if == scope_id) {
> 
> [Severity: Medium]
> Should the new comparison treat scope_id == 0 as "unspecified" rather
> than as a mismatch?
Yes, the analysis is right, I've sent a V2 that keeps the cached connection when
the request names no interface and only checks c_dev_if when it does.
> 
> For a send with msg_namelen == 0, rds_sendmsg() takes the scope from the
> bound scope id:
> 
> net/rds/send.c:rds_sendmsg() {
> 	} else {
> 		/* We only care about consistency with ->connect() */
> 		lock_sock(sk);
> 		daddr = rs->rs_conn_addr;
> 		dport = rs->rs_conn_port;
> 		scope_id = rs->rs_bound_scope_id;
> 		release_sock(sk);
> 	}
> 
> and the namelen != 0 repair branch that would fill in a zero scope from
> rs_bound_scope_id is skipped in that case.
> 
> rs_bound_scope_id can be 0 while rs_conn_addr is a link-local peer.
> rds_connect() records the peer scope there for an unbound socket:
> 
> net/rds/af_rds.c:rds_connect() {
> 		if (addr_type & IPV6_ADDR_LINKLOCAL) {
> 			...
> 			rs->rs_bound_scope_id = sin6->sin6_scope_id;
> 		}
> 		rs->rs_conn_addr = sin6->sin6_addr;
> 
> and a later bind() to a non-link-local address overwrites it
> unconditionally:
> 
> net/rds/bind.c:rds_add_bound() {
> 			*port = rs->rs_bound_port;
> 			rs->rs_bound_scope_id = scope_id;	/* 0 here */
> 
> With the sequence connect(fe80::x%ifA) -> bind(global address) ->
> sendto(fe80::x%ifA) -> send() with no destination, the last send now
> computes scope_id == 0, misses the cached ifA connection, and goes down
> the else branch:
> 
> >  		conn = rs->rs_conn;
> >  	} else {
> >  		conn = rds_conn_create_outgoing(sock_net(sock->sk),
> > 						&rs->rs_bound_addr, &daddr,
> > 						rs->rs_transport, rs->rs_tos,
> > 						sock->sk->sk_allocation,
> > 						scope_id);
> 
> Since rds_conn_lookup() compares c_dev_if, this creates a new connection
> with c_dev_if == 0 for a link-local destination.  Can that connection
> ever come up?  rds_tcp_conn_path_connect() passes it on as the scope:
> 
> net/rds/tcp_connect.c:rds_tcp_conn_path_connect() {
> 		sin6.sin6_scope_id = conn->c_dev_if;
> 
> and tcp_v6_connect() rejects a link-local destination with no scope and
> no sk_bound_dev_if:
> 
> net/ipv6/tcp_ipv6.c:tcp_v6_connect() {
> 		/* Connect to link-local address requires an interface */
> 		if (!sk->sk_bound_dev_if)
> 			return -EINVAL;
> 
> So the message looks like it gets queued on a connection that can never
> be established, where before the patch it went out over ifA, and
> rs->rs_conn is left pointing at the new connection.  Would skipping the
> comparison when scope_id == 0, or keeping the connected peer's scope
> separately from rs_bound_scope_id, avoid this?
> 
> [Severity: Medium]
> This isn't a bug introduced by this patch, but the cache test reads
> rs->rs_conn several times without any synchronization, and the new
> c_dev_if comparison is one more such read.

Yes, but I'm handling that in the larger connection lifetime series 
("net/rds: make connection lifetime reference-counted").  It moves
rs_conn cache under rs_lock and gives the cache a real reference.  If 
we did the READ_ONCE() here would still leave the pointer unreferenced
across the test, so I'd rather not let this patch feature creep into
something the ref counting series is already handling.

Thanks!
Allison

pw-bot: cr
> 
> The validation loads and thpw-bot: crpw-bot: cr
> e load used for the assignment are separate:
> 
> net/rds/send.c:rds_sendmsg() {
> 	if (rs->rs_conn && ipv6_addr_equal(&rs->rs_conn->c_faddr, &daddr) &&
> 	    rs->rs_tos == rs->rs_conn->c_tos &&
> 	    rs->rs_conn->c_dev_if == scope_id) {
> 		conn = rs->rs_conn;
> 
> The socket lock covering the earlier scope-id checks has already been
> dropped by the release_sock(sk) before rds_rdma_bytes(), and
> rds_sock_lock, which the RDS_TOS ioctl path takes when it inspects
> rs->rs_conn, is not held here either.  The publishing store in the else
> branch is equally unsynchronized:
> 
> 		rs->rs_conn = conn;
> 
> For two concurrent sendmsg() calls on the same AF_RDS socket (threads or
> a shared fd), can one thread validate the connection for fe80::x%ifA and
> then reload rs->rs_conn and pick up the fe80::x%ifB connection the other
> thread just stored, so that rm->m_conn_path ends up on the unvalidated
> connection?  That would be the same misrouting the changelog describes.
> 
> Would it be worth folding in a single snapshot of the pointer, for
> example conn = READ_ONCE(rs->rs_conn); if (conn && ...), with a matching
> WRITE_ONCE() on the store, or holding the socket lock across the cache
> test?
> 


      reply	other threads:[~2026-09-27  6:52 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-21 21:50 [PATCH net] net/rds: include the scope id in the sendmsg connection cache check Allison Henderson
2026-09-21 22:00 ` sashiko-bot
2026-09-25  0:53 ` netdev-bot+sashiko
2026-09-27  6:52   ` Allison Henderson [this message]

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=12c79c59ff1e55fd82ce2af0b8fd1c8feff66767.camel@kernel.org \
    --to=achender@kernel.org \
    --cc=edumazet@google.com \
    --cc=horms@kernel.org \
    --cc=kuba@kernel.org \
    --cc=linux-rdma@vger.kernel.org \
    --cc=netdev-bot+sashiko@kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.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