From: Jeffrey E Altman <jaltman@auristor.com>
To: David Howells <dhowells@redhat.com>, netdev@vger.kernel.org
Cc: Marc Dionne <marc.dionne@auristor.com>,
Jakub Kicinski <kuba@kernel.org>,
"David S. Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@google.com>,
Paolo Abeni <pabeni@redhat.com>, Simon Horman <horms@kernel.org>,
linux-afs@lists.infradead.org, linux-kernel@vger.kernel.org,
Wyatt Feng <bronzed_45_vested@icloud.com>,
Yuan Tan <yuantan098@gmail.com>, Yifan Wu <yifanwucs@gmail.com>,
Juefei Pu <tomapufckgml@gmail.com>,
Zhengchuan Liang <zcliangcn@gmail.com>, Xin Liu <bird@lzu.edu.cn>,
Ren Wei <n05ec@lzu.edu.cn>,
stable@vger.kernel.org
Subject: Re: [PATCH net v3 01/11] rxrpc: Fix ACKALL packet handling
Date: Wed, 24 Jun 2026 23:31:32 -0400 [thread overview]
Message-ID: <4dc5ae26-ef2d-494b-afdd-c723de8bd059@auristor.com> (raw)
In-Reply-To: <20260624163819.3017002-2-dhowells@redhat.com>
On 6/24/2026 12:38 PM, David Howells wrote:
> From: Wyatt Feng <bronzed_45_vested@icloud.com>
>
> rxrpc_input_ackall() accepts ACKALL packets without checking whether the
> call is in a state that can legitimately have outstanding transmit buffers.
> A forged ACKALL can therefore reach a new service call in
> RXRPC_CALL_SERVER_RECV_REQUEST before any reply packets have been queued.
>
> In that state call->tx_top is zero and call->tx_queue is NULL, so
> rxrpc_rotate_tx_window() dereferences a NULL txqueue and triggers a
> null-pointer dereference.
>
> Fix the handling of ACKALL packets by the following means:
>
> (1) Add two new call states: RXRPC_CALL_CLIENT_PRE_SEND which indicates
> that the client call is connected, but nothing has been transmitted as
> yet; and RXRPC_CALL_CLIENT_AWAIT_ACK, which indicates that everything
> has been transmitted at least once, but we're now waiting for the
> stuff remaining in the Tx buffer to be ACK'd (retransmissions may
> still happen).
>
> The RXRPC_CALL_CLIENT_PRE_SEND state is set when the call is assigned
> a channel and transitions to RXRPC_CALL_CLIENT_SEND_REQUEST when the
> first packet is transmitted.
>
> RXRPC_CALL_CLIENT_AWAIT_REPLY is then narrowed in scope to indicate
> that all Tx packets have been ACK'd and we're now waiting for the
> reply to be received.
>
> (2) As per Wyatt Feng's original patch[1], the ACKALL handler then checks
> that the call state is one in which there might be stuff in the Tx
> buffer to ACK, but now this includes AWAIT_ACK rather than
> AWAIT_REPLY. ACKALL packets are ignored if received in the wrong
> state.
>
> Note that unlike Wyatt Feng's patch, it's no longer necessary to check
> to see if the Tx buffer exists as this the state set now covers this.
>
> (3) Make the ACKALL handler use call->tx_transmitted rather than
> call->tx_top as the former is explicitly the highest packet seq number
> transmitted, whereas the latter has a looser definition.
>
> Thanks to Jeffrey Altman for a description of the history of the ACKALL
> packet[1].
The Link reference should be [2] instead of [1].
> Fixes: b341a0263b1b ("rxrpc: Implement progressive transmission queue struct")
> Reported-by: Yuan Tan <yuantan098@gmail.com>
> Reported-by: Yifan Wu <yifanwucs@gmail.com>
> Reported-by: Juefei Pu <tomapufckgml@gmail.com>
> Reported-by: Zhengchuan Liang <zcliangcn@gmail.com>
> Reported-by: Xin Liu <bird@lzu.edu.cn>
> Signed-off-by: Wyatt Feng <bronzed_45_vested@icloud.com>
> Co-developed-by: David Howells <dhowells@redhat.com>
> Signed-off-by: David Howells <dhowells@redhat.com>
> cc: Ren Wei <n05ec@lzu.edu.cn>
> cc: Marc Dionne <marc.dionne@auristor.com>
> cc: linux-afs@lists.infradead.org
> Cc: stable@vger.kernel.org
> Link: https://lore.kernel.org/r/20260616155749.2125907-2-dhowells@redhat.com/ [1]
> Link: https://lore.kernel.org/r/c0fd4fec-1576-4070-b31e-a37d5506f5ed@auristor.com/ [2]
> ---
> net/rxrpc/ar-internal.h | 2 ++
> net/rxrpc/call_event.c | 5 ++++-
> net/rxrpc/call_object.c | 2 ++
> net/rxrpc/conn_client.c | 2 +-
> net/rxrpc/input.c | 23 +++++++++++++++++++----
> net/rxrpc/sendmsg.c | 3 ++-
> 6 files changed, 30 insertions(+), 7 deletions(-)
>
> diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h
> index 98f2165159d7..b6ccd8a8199b 100644
> --- a/net/rxrpc/ar-internal.h
> +++ b/net/rxrpc/ar-internal.h
> @@ -650,7 +650,9 @@ enum rxrpc_call_event {
> enum rxrpc_call_state {
> RXRPC_CALL_UNINITIALISED,
> RXRPC_CALL_CLIENT_AWAIT_CONN, /* - client waiting for connection to become available */
> + RXRPC_CALL_CLIENT_PRE_SEND, /* - client is connected, but hasn't sent anything yet */
> RXRPC_CALL_CLIENT_SEND_REQUEST, /* - client sending request phase */
> + RXRPC_CALL_CLIENT_AWAIT_ACK, /* - client awaiting ACKs of request */
> RXRPC_CALL_CLIENT_AWAIT_REPLY, /* - client awaiting reply */
> RXRPC_CALL_CLIENT_RECV_REPLY, /* - client receiving reply phase */
> RXRPC_CALL_SERVER_PREALLOC, /* - service preallocation */
> diff --git a/net/rxrpc/call_event.c b/net/rxrpc/call_event.c
> index fec59d9338b9..21be9c86d7a7 100644
> --- a/net/rxrpc/call_event.c
> +++ b/net/rxrpc/call_event.c
> @@ -178,7 +178,7 @@ static void rxrpc_close_tx_phase(struct rxrpc_call *call)
>
> switch (__rxrpc_call_state(call)) {
> case RXRPC_CALL_CLIENT_SEND_REQUEST:
> - rxrpc_set_call_state(call, RXRPC_CALL_CLIENT_AWAIT_REPLY);
> + rxrpc_set_call_state(call, RXRPC_CALL_CLIENT_AWAIT_ACK);
> break;
> case RXRPC_CALL_SERVER_SEND_REPLY:
> rxrpc_set_call_state(call, RXRPC_CALL_SERVER_AWAIT_ACK);
> @@ -244,6 +244,8 @@ static void rxrpc_transmit_fresh_data(struct rxrpc_call *call, unsigned int limi
> break;
> } while (req.n < limit && before(seq, send_top));
>
> + if (__rxrpc_call_state(call) == RXRPC_CALL_CLIENT_PRE_SEND)
> + rxrpc_set_call_state(call, RXRPC_CALL_CLIENT_SEND_REQUEST);
> if (txb->flags & RXRPC_LAST_PACKET) {
> rxrpc_close_tx_phase(call);
> tq = NULL;
> @@ -267,6 +269,7 @@ void rxrpc_transmit_some_data(struct rxrpc_call *call, unsigned int limit,
> fallthrough;
>
> case RXRPC_CALL_SERVER_SEND_REPLY:
> + case RXRPC_CALL_CLIENT_PRE_SEND:
> case RXRPC_CALL_CLIENT_SEND_REQUEST:
> if (!rxrpc_tx_window_space(call))
> return;
> diff --git a/net/rxrpc/call_object.c b/net/rxrpc/call_object.c
> index fcb9d38bb521..817ed9acb91e 100644
> --- a/net/rxrpc/call_object.c
> +++ b/net/rxrpc/call_object.c
> @@ -18,7 +18,9 @@
> const char *const rxrpc_call_states[NR__RXRPC_CALL_STATES] = {
> [RXRPC_CALL_UNINITIALISED] = "Uninit ",
> [RXRPC_CALL_CLIENT_AWAIT_CONN] = "ClWtConn",
> + [RXRPC_CALL_CLIENT_PRE_SEND] = "ClPreSnd",
> [RXRPC_CALL_CLIENT_SEND_REQUEST] = "ClSndReq",
> + [RXRPC_CALL_CLIENT_AWAIT_ACK] = "ClAwtAck",
> [RXRPC_CALL_CLIENT_AWAIT_REPLY] = "ClAwtRpl",
> [RXRPC_CALL_CLIENT_RECV_REPLY] = "ClRcvRpl",
> [RXRPC_CALL_SERVER_PREALLOC] = "SvPrealc",
> diff --git a/net/rxrpc/conn_client.c b/net/rxrpc/conn_client.c
> index 9b757798dedd..48519f0de185 100644
> --- a/net/rxrpc/conn_client.c
> +++ b/net/rxrpc/conn_client.c
> @@ -449,7 +449,7 @@ static void rxrpc_activate_one_channel(struct rxrpc_connection *conn,
> trace_rxrpc_connect_call(call);
> call->tx_last_sent = ktime_get_real();
> rxrpc_start_call_timer(call);
> - rxrpc_set_call_state(call, RXRPC_CALL_CLIENT_SEND_REQUEST);
> + rxrpc_set_call_state(call, RXRPC_CALL_CLIENT_PRE_SEND);
> wake_up(&call->waitq);
> }
>
> diff --git a/net/rxrpc/input.c b/net/rxrpc/input.c
> index ce761466b02d..2eedab1b0919 100644
> --- a/net/rxrpc/input.c
> +++ b/net/rxrpc/input.c
> @@ -181,7 +181,8 @@ void rxrpc_congestion_degrade(struct rxrpc_call *call)
> if (call->cong_ca_state != RXRPC_CA_SLOW_START &&
> call->cong_ca_state != RXRPC_CA_CONGEST_AVOIDANCE)
> return;
> - if (__rxrpc_call_state(call) == RXRPC_CALL_CLIENT_AWAIT_REPLY)
> + if (__rxrpc_call_state(call) == RXRPC_CALL_CLIENT_AWAIT_ACK ||
> + __rxrpc_call_state(call) == RXRPC_CALL_CLIENT_AWAIT_REPLY)
> return;
>
> rtt = ns_to_ktime(call->srtt_us * (NSEC_PER_USEC / 8));
> @@ -356,6 +357,7 @@ static void rxrpc_end_tx_phase(struct rxrpc_call *call, bool reply_begun,
>
> switch (__rxrpc_call_state(call)) {
> case RXRPC_CALL_CLIENT_SEND_REQUEST:
> + case RXRPC_CALL_CLIENT_AWAIT_ACK:
> case RXRPC_CALL_CLIENT_AWAIT_REPLY:
> if (reply_begun) {
> rxrpc_set_call_state(call, RXRPC_CALL_CLIENT_RECV_REPLY);
> @@ -694,6 +696,7 @@ static void rxrpc_input_data(struct rxrpc_call *call, struct sk_buff *skb)
>
> switch (__rxrpc_call_state(call)) {
> case RXRPC_CALL_CLIENT_SEND_REQUEST:
> + case RXRPC_CALL_CLIENT_AWAIT_ACK:
> case RXRPC_CALL_CLIENT_AWAIT_REPLY:
> /* Received data implicitly ACKs all of the request
> * packets we sent when we're acting as a client.
> @@ -1154,10 +1157,12 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb)
> if (hard_ack + 1 == 0)
> return rxrpc_proto_abort(call, 0, rxrpc_eproto_ackr_zero);
>
> - /* Ignore ACKs unless we are or have just been transmitting. */
> + /* Ignore ACKs unless we are transmitting or are waiting for
> + * acknowledgement of the packets we've just been transmitting.
> + */
> switch (__rxrpc_call_state(call)) {
> case RXRPC_CALL_CLIENT_SEND_REQUEST:
> - case RXRPC_CALL_CLIENT_AWAIT_REPLY:
> + case RXRPC_CALL_CLIENT_AWAIT_ACK:
> case RXRPC_CALL_SERVER_SEND_REPLY:
> case RXRPC_CALL_SERVER_AWAIT_ACK:
> break;
> @@ -1215,7 +1220,17 @@ static void rxrpc_input_ackall(struct rxrpc_call *call, struct sk_buff *skb)
> {
> struct rxrpc_ack_summary summary = { 0 };
>
> - if (rxrpc_rotate_tx_window(call, call->tx_top, &summary))
> + switch (__rxrpc_call_state(call)) {
> + case RXRPC_CALL_CLIENT_SEND_REQUEST:
> + case RXRPC_CALL_CLIENT_AWAIT_ACK:
> + case RXRPC_CALL_SERVER_SEND_REPLY:
> + case RXRPC_CALL_SERVER_AWAIT_ACK:
> + break;
> + default:
> + return;
> + }
> +
> + if (rxrpc_rotate_tx_window(call, call->tx_transmitted, &summary))
> rxrpc_end_tx_phase(call, false, rxrpc_eproto_unexpected_ackall);
> }
>
> diff --git a/net/rxrpc/sendmsg.c b/net/rxrpc/sendmsg.c
> index c35de4fd75e3..ed2c9a51005a 100644
> --- a/net/rxrpc/sendmsg.c
> +++ b/net/rxrpc/sendmsg.c
> @@ -366,7 +366,8 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
> if (state >= RXRPC_CALL_COMPLETE)
> goto maybe_error;
> ret = -EPROTO;
> - if (state != RXRPC_CALL_CLIENT_SEND_REQUEST &&
> + if (state != RXRPC_CALL_CLIENT_PRE_SEND &&
> + state != RXRPC_CALL_CLIENT_SEND_REQUEST &&
> state != RXRPC_CALL_SERVER_ACK_REQUEST &&
> state != RXRPC_CALL_SERVER_SEND_REPLY) {
> /* Request phase complete for this client call */
>
Thanks for the update patch.
Reviewed-by: Jeffrey Altman <jaltman@auristor.com>
next prev parent reply other threads:[~2026-06-25 3:31 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-24 16:38 [PATCH net v3 00/11] rxrpc: Miscellaneous fixes David Howells
2026-06-24 16:38 ` [PATCH net v3 01/11] rxrpc: Fix ACKALL packet handling David Howells
2026-06-25 3:31 ` Jeffrey E Altman [this message]
2026-06-24 16:38 ` [PATCH net v3 02/11] rxrpc: Fix leak of connection from OOB challenge David Howells
2026-06-24 16:38 ` [PATCH net v3 03/11] rxrpc: Fix double unlock in rxrpc_recvmsg() David Howells
2026-06-24 16:38 ` [PATCH net v3 04/11] afs: Fix further netns teardown to cancel the preallocation charger David Howells
2026-06-24 16:38 ` [PATCH net v3 05/11] afs: Fix uncancelled rxrpc OOB message handler David Howells
2026-06-24 16:38 ` [PATCH net v3 06/11] rxrpc: Fix the reception of a reply packet before data transmission David Howells
2026-06-24 16:38 ` [PATCH net v3 07/11] rxrpc: Fix oob challenge leak in cleanup after notification failure David Howells
2026-06-24 16:38 ` [PATCH net v3 08/11] rxrpc: Fix potential infinite loop in rxrpc_recvmsg() David Howells
2026-06-24 16:38 ` [PATCH net v3 09/11] rxrpc: Fix socket notification race David Howells
2026-06-24 16:38 ` [PATCH net v3 10/11] rxrpc: Fix leak of released call in recvmsg(MSG_PEEK) David Howells
2026-06-24 16:38 ` [PATCH net v3 11/11] rxrpc: Fix rxrpc_rotate_tx_rotate() to check there's something to rotate David Howells
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=4dc5ae26-ef2d-494b-afdd-c723de8bd059@auristor.com \
--to=jaltman@auristor.com \
--cc=bird@lzu.edu.cn \
--cc=bronzed_45_vested@icloud.com \
--cc=davem@davemloft.net \
--cc=dhowells@redhat.com \
--cc=edumazet@google.com \
--cc=horms@kernel.org \
--cc=kuba@kernel.org \
--cc=linux-afs@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=marc.dionne@auristor.com \
--cc=n05ec@lzu.edu.cn \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=stable@vger.kernel.org \
--cc=tomapufckgml@gmail.com \
--cc=yifanwucs@gmail.com \
--cc=yuantan098@gmail.com \
--cc=zcliangcn@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