From: Jeffrey E Altman <jaltman@auristor.com>
To: Michael Bommarito <michael.bommarito@gmail.com>,
David Howells <dhowells@redhat.com>,
Marc Dionne <marc.dionne@auristor.com>,
"David S . Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@google.com>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>
Cc: Simon Horman <horms@kernel.org>,
linux-afs@lists.infradead.org, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org, stable@vger.kernel.org
Subject: Re: [PATCH] rxrpc: Fix read+write past skb_headlen in soft-ACK parser
Date: Fri, 15 May 2026 09:49:58 -0400 [thread overview]
Message-ID: <140786c6-e788-4860-95fc-7dbaf30eb51f@auristor.com> (raw)
In-Reply-To: <20260513180907.2061972-1-michael.bommarito@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 4637 bytes --]
On 5/13/2026 2:09 PM, Michael Bommarito wrote:
> rxrpc_input_soft_acks() builds a raw `u8 *acks = skb->data + ...`
> pointer and walks it for `sp->ack.nr_acks` iterations, performing a
> read-modify-write (shiftr_adv_rotr) on each byte.
>
> The caller rxrpc_input_ack() only validates that the bytes exist
> somewhere in the skb (`offset > skb->len - nr_acks`) and best-effort
> linearises the head with skb_condense(). skb_condense() returns
> without pulling when the skb is cloned, when paged data exceeds the
> linear-head tailroom, or when frags are unreadable. On a nonlinear
> skb that survives the condense step (cloned by AF_PACKET capture,
> frag_list-style after IP-fragment reassembly, or paged-frag receive
> on real NICs), skb->data covers only the linear head. The parser
> then walks past skb_headlen(skb) into skb tailroom, skb_shared_info,
> or the next slab object, doing in-place 1-byte shifts on up to 255
> attacker-controlled offsets per ACK packet.
>
> Sibling parsers in the same file already use the safe pattern:
> rxrpc_extract_header(), rxrpc_extract_abort(), rxrpc_input_split_jumbo(),
> and the rxrpc_input_ack_trailer() call site all use skb_copy_bits()
> with explicit length checks. The soft-ACK call path is the lone
> direct-deref site.
>
> Add an explicit pskb_may_pull() check before invoking the parser so
> that the linear head is guaranteed to cover the SACK bitmap. On
> allocation failure return rxrpc_proto_abort() with the same
> eproto_ackr_short_sack disposition the existing length check uses.
> skb_condense() is retained on the path; its truesize-accounting side
> effect is independent of the linearisation guarantee that
> pskb_may_pull() now provides.
>
> The bug shape was reproduced under UML+KASAN in two complementary
> harnesses:
>
> (1) A kmod that lifts the parser's inner shift loop verbatim and
> exercises it against a kmalloc(47) buffer. KASAN reports a
> slab-out-of-bounds read on the first byte past the allocation:
>
> BUG: KASAN: slab-out-of-bounds in run_rxrpc_soft_acks_loop+0x52/0x74
> Read of size 1 at addr 63a7032f by task insmod/37
> which belongs to the cache kmalloc-64 of size 64
> allocated 47-byte region [63a70300, 63a7032f)
>
> (2) A second kmod uses the in-kernel rxrpc API to allocate a real
> rxrpc_call, builds a nonlinear hostile ACK skb (linear head=46,
> paged frag=79, skb->cloned=1, nr_acks=60) and drives the
> upstream rxrpc_input_call_packet() -> rxrpc_input_ack() ->
> rxrpc_input_soft_acks() chain directly. Sixty 0xAA sentinel
> bytes placed in the linear-head tailroom are all right-shifted
> to 0x55 by the unmodified upstream rxrpc_input_soft_acks() on
> a stock kernel. On the patched kernel, zero of sixty shift --
> pskb_may_pull aborts the call before the parser runs.
>
> Note: the real-path demonstration does NOT produce a literal
> KASAN slab-out-of-bounds splat, because the on-wire nAcks field
> is a u8 (max 255) and the OOB shift stays within the same kmalloc
> slab object that holds skb_shared_info. Per-byte corruption of
> skb_shared_info and the linear-head tailroom is the actual
> production effect.
>
> A regression check on a fully-linear ACK skb confirms pskb_may_pull
> is a no-op on that path; the parser continues to read in-bounds.
>
> Fixes: d57a3a151660 ("rxrpc: Save last ACK's SACK table rather than marking txbufs")
> Cc: stable@vger.kernel.org
> Reported via internal source-audit pipeline on 2026-04-21.
> Assisted-by: Claude:claude-opus-4-7
> Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
> ---
> net/rxrpc/input.c | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/net/rxrpc/input.c b/net/rxrpc/input.c
> index 24aceb183c2c..52ace0f98d06 100644
> --- a/net/rxrpc/input.c
> +++ b/net/rxrpc/input.c
> @@ -1173,6 +1173,8 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb)
> if (nr_acks > 0) {
> if (offset > (int)skb->len - nr_acks)
> return rxrpc_proto_abort(call, 0, rxrpc_eproto_ackr_short_sack);
> + if (!pskb_may_pull(skb, offset + nr_acks))
> + return rxrpc_proto_abort(call, 0, rxrpc_eproto_ackr_short_sack);
> rxrpc_input_soft_acks(call, &summary, skb);
> }
>
Aborting the call because skb_condense() was unable to consolidate the
rx ack packet data is an unfriendly thing to do.
As suggested by the commit message, copying the data before processing
would be a friendlier solution to the identified problem.
Jeffrey Altman
[-- Attachment #2: S/MIME Cryptographic Signature --]
[-- Type: application/pkcs7-signature, Size: 4467 bytes --]
prev parent reply other threads:[~2026-05-15 13:50 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-13 18:09 [PATCH] rxrpc: Fix read+write past skb_headlen in soft-ACK parser Michael Bommarito
2026-05-15 13:49 ` Jeffrey E Altman [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=140786c6-e788-4860-95fc-7dbaf30eb51f@auristor.com \
--to=jaltman@auristor.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=michael.bommarito@gmail.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=stable@vger.kernel.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