From: Paolo Abeni <pabeni@redhat.com>
To: lucien.xin@gmail.com
Cc: netdev@vger.kernel.org, quic@lists.linux.dev,
davem@davemloft.net, kuba@kernel.org, edumazet@google.com,
pabeni@redhat.com, horms@kernel.org, metze@samba.org,
mbuhl@openbsd.org, tfanelli@redhat.com, hepengtao@xiaomi.com,
dreibh@simula.no, linux-cifs@vger.kernel.org, smfrench@gmail.com,
linkinjeon@kernel.org, tom@talpey.com,
kernel-tls-handshake@lists.linux.dev, chuck.lever@oracle.com,
jlayton@kernel.org, steved@redhat.com, hare@suse.de,
aahringo@redhat.com, dhowells@redhat.com, matttbe@kernel.org,
mail@johnericson.me, xiyou.wangcong@gmail.com,
alibuda@linux.alibaba.com, jbaron@akamai.com,
illiliti@protonmail.com, sd@queasysnail.net,
marcelo.leitner@gmail.com, daniel@haxx.se,
andrew.gospodarek@broadcom.com, mef@scarletmail.rutgers.edu,
paul@jakma.org
Subject: Re: [PATCH net-next v13 07/15] quic: add connection id management
Date: Thu, 11 Jun 2026 10:19:28 +0200 [thread overview]
Message-ID: <20260611081928.137149-1-pabeni@redhat.com> (raw)
In-Reply-To: <0565988e6b54dac937fa00cdb3b09adef9650be6.1780855297.git.lucien.xin@gmail.com>
From: AI Reviewer <ai@example.com>
This is an AI-generated review of your patch. The human sending this
email has considered the AI review valid, or at least plausible.
Full review at: https://netdev-ai.bots.linux.dev/sashiko/
---
Now I have enough information to produce the report.
commit e00266d0eea858a744fd827548eb8ebc6868f92c
Author: Xin Long <lucien.xin@gmail.com>
quic: add connection id management
This commit introduces struct quic_conn_id_set for managing QUIC
Connection IDs along with helpers to add, remove, and look up source
and destination CIDs, including a global hash table for source CID
lookup on the RX path.
> diff --git a/net/quic/connid.c b/net/quic/connid.c
> new file mode 100644
> index 000000000000..b1a39feb827e
> --- /dev/null
> +++ b/net/quic/connid.c
> @@ -0,0 +1,256 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/* QUIC kernel implementation
> + * (C) Copyright Red Hat Corp. 2023
> + *
> + * This file is part of the QUIC kernel implementation
> + *
> + * Initialization/cleanup for QUIC protocol support.
> + *
> + * Written or modified by:
> + * Xin Long <lucien.xin@gmail.com>
> + */
> +
> +#include <linux/quic.h>
> +#include <net/sock.h>
> +
> +#include "common.h"
> +#include "connid.h"
> +
> +/* Lookup a source connection ID (scid) in the global source connection ID hash
> + * table.
> + */
> +struct quic_conn_id *quic_conn_id_lookup(struct net *net, u8 *scid, u32 len)
> +{
> + struct quic_shash_head *head = quic_source_conn_id_head(net, scid, len);
> + struct quic_source_conn_id *s_conn_id;
> + struct quic_conn_id *conn_id = NULL;
> + struct hlist_nulls_node *node;
> +
> + hlist_nulls_for_each_entry_rcu(s_conn_id, node, &head->head, node) {
> + if (net != sock_net(s_conn_id->sk))
> + continue;
> + if (s_conn_id->common.id.len != len ||
> + memcmp(scid, &s_conn_id->common.id.data, len))
> + continue;
> + if (likely(refcount_inc_not_zero(&s_conn_id->sk->sk_refcnt)))
> + conn_id = &s_conn_id->common.id;
> + break;
> + }
[Critical]
Can s_conn_id->sk be freed while this RCU walk is running? The
s_conn_id itself is freed via call_rcu() in quic_source_conn_id_free(),
but the struct sock it points to does not appear to be RCU-protected.
A grep across this series for SOCK_RCU_FREE and SLAB_TYPESAFE_BY_RCU
under net/quic returns no matches, and quic_init_sock() does not call
sock_set_flag(sk, SOCK_RCU_FREE), so sk_destruct() will free the sock
synchronously rather than after a grace period.
Consider this sequence:
CPU0 (RX path, rcu_read_lock held) CPU1 (close path)
hlist_nulls_for_each_entry_rcu(..)
/* sees s_conn_id still linked */
sk_destruct()
quic_destroy_sock()
quic_conn_id_set_free()
/* unhash + call_rcu
defers s_conn_id
free, but not sk */
sk_prot_free() /* sk gone */
sock_net(s_conn_id->sk) /* UAF read of freed sock */
refcount_inc_not_zero(
&s_conn_id->sk->sk_refcnt) /* UAF refcount op */
Once quic_packet_get_sock() (in the later 'quic: add packet parser
base' patch) wires this lookup into every short- and long-header
packet, an incoming packet racing with close() on the matching socket
would dereference freed sock memory.
Would setting SOCK_RCU_FREE on the QUIC sockets, switching the proto
slabs to SLAB_TYPESAFE_BY_RCU, taking sock_hold() when the sk pointer
is stored in s_conn_id, or otherwise gating the sk free behind an RCU
grace period address this?
> +
> +/* Check if a given stateless reset token exists in any connection ID in the
> + * connection ID set.
> + */
> +bool quic_conn_id_token_exists(struct quic_conn_id_set *id_set, u8 *token)
> +{
> + struct quic_common_conn_id *common;
> + struct quic_dest_conn_id *dcid;
> +
> + dcid = (struct quic_dest_conn_id *)id_set->active;
> + if (memchr_inv(dcid->token, 0, QUIC_CONN_ID_TOKEN_LEN) &&
> + !memcmp(dcid->token, token, QUIC_CONN_ID_TOKEN_LEN))
> + return true; /* Fast path. */
> +
> + list_for_each_entry(common, &id_set->head, list) {
> + dcid = (struct quic_dest_conn_id *)common;
> + if (common == id_set->active)
> + continue;
> + if (memchr_inv(dcid->token, 0, QUIC_CONN_ID_TOKEN_LEN) &&
> + !memcmp(dcid->token, token, QUIC_CONN_ID_TOKEN_LEN))
> + return true;
> + }
> + return false;
> +}
[Medium]
Is memcmp() the right comparison primitive for the stateless reset
token here? RFC 9000 section 10.3 treats the token as a secret that
authorises tearing down a connection, and the commit message states
this helper is used during stateless reset processing on incoming
packets.
lib/string.c's memcmp() returns at the first differing byte (and
performs unaligned word-sized loads on architectures that allow it),
so the time taken to return false leaks how many leading bytes of the
supplied token match a stored token. Would crypto_memneq() from
<crypto/algapi.h>, which is constant-time, be more appropriate for
comparing the token bytes?
> +
[ ... ]
> +/* Add a connection ID with sequence number and associated private data to the
> + * connection ID set.
> + */
> +int quic_conn_id_add(struct quic_conn_id_set *id_set,
> + struct quic_conn_id *conn_id, u32 number, void *data)
> +{
[ ... ]
> + /* Locate insertion point to keep list ordered by number. */
> + list = &id_set->head;
> + list_for_each_entry(common, list, list) {
> + if (number == common->number)
> + return 0; /* Ignore if it already exists on the list. */
> + if (number < common->number) {
> + list = &common->list;
> + break;
> + }
> + }
[ ... ]
> + list_add_tail(&common->list, list);
> +
> + if (number == quic_conn_id_last_number(id_set) + 1) {
> + if (!id_set->active)
> + id_set->active = common;
> + id_set->count++;
> +
> + /* Increment count for consecutive following IDs. */
> + list_for_each_entry_continue(common, &id_set->head, list) {
> + if (common->number != ++number)
> + break;
> + id_set->count++;
> + }
> + }
> + return 0;
> +}
[Medium]
Does this function correctly maintain id_set->count when a CID is
inserted before all existing entries? The loop above explicitly
handles the "number < common->number" case, suggesting out-of-order
insertion is intended to be supported.
Consider starting from list=[5], count=1 (so first=5, last=5) and
calling quic_conn_id_add(..., number=3, ...):
- The location loop sets list = &common(5)->list and breaks.
- list_add_tail() inserts common(3) before common(5),
yielding list=[3, 5].
- The post-insert check evaluates:
quic_conn_id_last_number(id_set)
= quic_conn_id_first_number(id_set) + count - 1
= 3 + 1 - 1
= 3
so the test "number == last + 1" becomes "3 == 4" and the count
update branch is skipped.
The end state is list=[3, 5] with count still 1, so entry 5 is
silently uncounted. A subsequent quic_conn_id_remove(id_set, 3)
then trips the WARN_ON_ONCE(number >= last_number) because
last_number reads as 3.
Should the count adjustment also handle the case where the inserted
CID lowers first_number?
> +
> +/* Remove consecutive connection IDs from the set with sequence numbers less
> + * than or equal to a number.
> + */
> +void quic_conn_id_remove(struct quic_conn_id_set *id_set, u32 number)
[ ... ]
--
This is an AI-generated review.
next prev parent reply other threads:[~2026-06-11 8:20 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-07 18:01 [PATCH net-next v13 00/15] net: introduce QUIC infrastructure and core subcomponents Xin Long
2026-06-07 18:01 ` [PATCH net-next v13 01/15] net: define IPPROTO_QUIC and SOL_QUIC constants Xin Long
2026-06-07 18:01 ` [PATCH net-next v13 02/15] net: build socket infrastructure for QUIC protocol Xin Long
2026-06-07 18:01 ` [PATCH net-next v13 03/15] quic: provide common utilities and data structures Xin Long
2026-06-07 18:01 ` [PATCH net-next v13 04/15] quic: provide family ops for address and protocol Xin Long
2026-06-07 18:01 ` [PATCH net-next v13 05/15] quic: provide quic.h header files for kernel and userspace Xin Long
2026-06-07 18:01 ` [PATCH net-next v13 06/15] quic: add stream management Xin Long
2026-06-07 18:01 ` [PATCH net-next v13 07/15] quic: add connection id management Xin Long
2026-06-11 8:19 ` Paolo Abeni [this message]
2026-06-07 18:01 ` [PATCH net-next v13 08/15] quic: add path management Xin Long
2026-06-07 18:01 ` [PATCH net-next v13 09/15] quic: add congestion control Xin Long
2026-06-07 18:01 ` [PATCH net-next v13 10/15] quic: add packet number space Xin Long
2026-06-07 18:01 ` [PATCH net-next v13 11/15] quic: add crypto key derivation and installation Xin Long
2026-06-07 18:01 ` [PATCH net-next v13 12/15] quic: add crypto packet encryption and decryption Xin Long
2026-06-11 8:19 ` Paolo Abeni
2026-06-07 18:01 ` [PATCH net-next v13 13/15] quic: add timer management Xin Long
2026-06-07 18:01 ` [PATCH net-next v13 14/15] quic: add packet builder base Xin Long
2026-06-07 18:01 ` [PATCH net-next v13 15/15] quic: add packet parser base Xin Long
2026-06-11 8:20 ` Paolo Abeni
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=20260611081928.137149-1-pabeni@redhat.com \
--to=pabeni@redhat.com \
--cc=aahringo@redhat.com \
--cc=alibuda@linux.alibaba.com \
--cc=andrew.gospodarek@broadcom.com \
--cc=chuck.lever@oracle.com \
--cc=daniel@haxx.se \
--cc=davem@davemloft.net \
--cc=dhowells@redhat.com \
--cc=dreibh@simula.no \
--cc=edumazet@google.com \
--cc=hare@suse.de \
--cc=hepengtao@xiaomi.com \
--cc=horms@kernel.org \
--cc=illiliti@protonmail.com \
--cc=jbaron@akamai.com \
--cc=jlayton@kernel.org \
--cc=kernel-tls-handshake@lists.linux.dev \
--cc=kuba@kernel.org \
--cc=linkinjeon@kernel.org \
--cc=linux-cifs@vger.kernel.org \
--cc=lucien.xin@gmail.com \
--cc=mail@johnericson.me \
--cc=marcelo.leitner@gmail.com \
--cc=matttbe@kernel.org \
--cc=mbuhl@openbsd.org \
--cc=mef@scarletmail.rutgers.edu \
--cc=metze@samba.org \
--cc=netdev@vger.kernel.org \
--cc=paul@jakma.org \
--cc=quic@lists.linux.dev \
--cc=sd@queasysnail.net \
--cc=smfrench@gmail.com \
--cc=steved@redhat.com \
--cc=tfanelli@redhat.com \
--cc=tom@talpey.com \
--cc=xiyou.wangcong@gmail.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