[PATCH AUTOSEL 7.0-6.12] greybus: beagleplay: bound bootloader RX buffer copy

Sasha Levin
2026-04-28T10:42:40Z

From: Pengpeng Hou <pengpeng@iscas.ac.cn>

[ Upstream commit cbc96a916b1a3be7039b0166c0fc56ec1632ba01 ]

When `flashing_mode` is set, `gb_tty_receive()` routes incoming bytes to
`cc1352_bootloader_rx()`. That helper appends the new bytes to the shared
`rx_buffer` with `memcpy()` but does not check that the chunk fits in the
remaining space first. The normal HDLC receive path already enforces
`MAX_RX_HDLC`, so do the same here before appending bootloader data.

If a packet would overflow the receive buffer, drop it and reset the
bootloader receive state instead of copying past the end of `rx_buffer`.

Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
Link: https://patch.msgid.link/20260322031923.58013-1-pengpeng@iscas.ac.cn
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---

LLM Generated explanations, may be completely bogus:

I have enough information to write the full analysis.

# Analysis: greybus: beagleplay: bound bootloader RX buffer copy

## PHASE 1: COMMIT MESSAGE FORENSICS

**Step 1.1 - Subject parsing**
Record: subsystem=`greybus/beagleplay`, action=`bound` (i.e. add bounds
check), summary=add a bounds check to bootloader RX path before `memcpy`
into a fixed-size buffer.

**Step 1.2 - Tags**
Record:
- `Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>` (author)
- `Link:
https://patch.msgid.link/20260322031923.58013-1-pengpeng@iscas.ac.cn`
- `Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>`
(greybus maintainer)
- No `Fixes:`, no `Cc: stable`, no `Reported-by:`, no `Reviewed-by:`.
Absence is expected.

**Step 1.3 - Body analysis**
Record: Bug = `cc1352_bootloader_rx()` does `memcpy(rx_buffer +
rx_buffer_len, data, count)` without verifying `count` fits the
remaining space; the HDLC sibling path already enforces `MAX_RX_HDLC`.
Failure mode = write past end of `rx_buffer` (heap buffer overflow).

**Step 1.4 - Hidden bug fix detection**
Record: Subject says "bound" rather than "fix", but body explicitly
describes a buffer-overflow gap and the fix mirrors a guard that already
exists on the parallel HDLC path. This is unambiguously a bug fix.

## PHASE 2: DIFF ANALYSIS

**Step 2.1 - Inventory**
Record: 1 file (`drivers/greybus/gb-beagleplay.c`), +6/-0 lines, 1 hunk,
single function `cc1352_bootloader_rx()`. Surgical single-file fix.

**Step 2.2 - Code flow change**
Record: Before — copy unconditionally into `bg->rx_buffer +
bg->rx_buffer_len`. After — if `count > sizeof(rx_buffer) -
rx_buffer_len`, log a rate-limited error, reset `rx_buffer_len`, return
`count` (consume the chunk). Otherwise the original path runs.

**Step 2.3 - Bug mechanism**
Record: Category = memory-safety / out-of-bounds write. Mechanism:
`rx_buffer` is `u8 rx_buffer[MAX_RX_HDLC]` (1 + 256 + 2 = 259 bytes)
embedded in `struct gb_beagleplay`. Without the check, an inbound serdev
chunk plus stale `rx_buffer_len` could write past 259 bytes into heap
memory adjacent to subsequent fields (`fwl`, `flashing_mode`,
completions, etc.).

**Step 2.4 - Fix quality**
Record: 5 lines, mirrors the existing `MAX_RX_HDLC` guard in
`hdlc_rx()`. Resetting `rx_buffer_len` on overflow drops staged data,
which is acceptable here because the fix path is being exercised under
fault conditions; bootloader sync/transfers will retry. No new
regression vectors. Returning `count` correctly tells the serdev core
that the bytes were consumed.

## PHASE 3: GIT HISTORY INVESTIGATION

**Step 3.1 - Blame**
Record: `git log -S "cc1352_bootloader_rx" -- drivers/greybus/gb-
beagleplay.c` shows the function (and bug) was introduced by
`0cf7befa3ea2e` ("greybus: gb-beagleplay: Add firmware upload API").

**Step 3.2 - Fixes target**
Record: No explicit `Fixes:` tag here, but the introducing commit
`0cf7befa3ea2e` is in `v6.12-rc1` (`git describe --contains` =
`v6.12-rc1~39^2`), so the bug exists in v6.12 and later.

**Step 3.3 - File history & related changes**
Record: A near-identical follow-up patch `1214bf28965ce` ("greybus: gb-
beagleplay: bound bootloader receive buffering") by the same author,
dated 2026-04-02, was applied later to the same function with explicit
`Fixes: 0cf7befa3ea2` and `Cc: stable@kernel.org`. It adds a second,
redundant copy of the same bound check; in current `origin/master` both
checks exist back-to-back. The second commit confirms the
maintainer/author both view this as a real, stable-worthy bug.

**Step 3.4 - Author**
Record: Pengpeng Hou — submitter, not subsystem maintainer. Patch was
applied directly by Greg KH (greybus maintainer). The same author
followed up with a stable-tagged version when the first lacked tags.

**Step 3.5 - Dependencies**
Record: Self-contained. Does not depend on any other unmerged work. The
function and `rx_buffer` field have been unchanged since `0cf7befa3ea2e`
was merged in v6.12.

## PHASE 4: MAILING LIST RESEARCH

**Step 4.1 - Lore discussion**
Record: `b4 dig -c cbc96a916b1a3` matched by patch-id, returned `https:/
/lore.kernel.org/all/20260322031923.58013-1-pengpeng@iscas.ac.cn/`. `b4
dig -a` shows v1 only — no other revisions.

**Step 4.2 - Reviewers**
Record: Cc list (per the mbox): Ayush Singh (driver author), Johan
Hovold, Alex Elder, Greg KH, plus greybus-dev. No replies in the thread;
Greg merged it as v1.

**Step 4.3 - Bug report**
Record: No `Reported-by:` or external bug-tracker link. Bug found by
code inspection. No syzbot or sanitizer reference.

**Step 4.4 - Related patches**
Record: The same author submitted a duplicate fix
`20260402054016.38587-1-pengpeng@iscas.ac.cn` ("greybus: gb-beagleplay:
bound bootloader receive buffering") containing `Fixes: 0cf7befa3ea2`
and `Cc: stable@vger.kernel.org`. That confirms the author's intent that
the fix go to stable.

**Step 4.5 - Stable list**
Record: Not applicable — checked recent file history, the explicit
stable nomination is in the duplicate follow-up rather than this commit.

## PHASE 5: CODE SEMANTIC ANALYSIS

**Step 5.1 - Modified function**
Record: `cc1352_bootloader_rx()`.

**Step 5.2 - Callers**
Record: Single caller — `gb_tty_receive()`, which is the `.receive_buf`
member of `gb_beagleplay_ops` registered with the serdev framework
(`drivers/greybus/gb-beagleplay.c:556-578`). The serdev core invokes it
whenever the underlying UART (cc1352p7) hands up received bytes. The
branch into `cc1352_bootloader_rx` triggers when `bg->flashing_mode` is
true.

**Step 5.3 - Callees**
Record: `memcpy`, `memmove`, and `cc1352_bootloader_pkt_rx()`. The buggy
line is the `memcpy` — pre-fix, the destination pointer can advance past
the 259-byte array.

**Step 5.4 - Reachability**
Record: `flashing_mode` is set in `cc1352_prepare()`
(`drivers/greybus/gb-beagleplay.c:882`), invoked through the kernel
firmware-upload framework (sysfs `/sys/class/firmware/...`). A
privileged user-space firmware update on a BeaglePlay board makes the
buggy path reachable. The attacker/triggerer is therefore root-
equivalent, but the consequence (heap corruption from data the cc1352
sends back, batched by the UART driver into chunks > 259 bytes) is
severe.

**Step 5.5 - Similar patterns**
Record: The HDLC receive path (`hdlc_rx()` at line 399) already guards
with `bg->rx_buffer_len < MAX_RX_HDLC`. The patch makes the bootloader
path consistent with this established sibling.

## PHASE 6: STABLE TREE ANALYSIS

**Step 6.1 - Buggy code in stable**
Record: Verified via `git merge-base --is-ancestor 0cf7befa3ea2e
<stable-branch>`:
- 5.10.y / 5.15.y / 6.1.y / 6.6.y → bug NOT present (driver predates
`cc1352_bootloader_rx`).
- 6.12.y / 6.17.y / 6.18.y / 6.19.y → bug PRESENT.

**Step 6.2 - Backport difficulty**
Record: The hunk lands in `cc1352_bootloader_rx()` whose body has been
unchanged since v6.12. Patch should apply cleanly to all affected stable
trees. (The duplicate follow-up `1214bf28965ce` was generated against
the same parent, confirming this.)

**Step 6.3 - Related fixes already in stable**
Record: Verified via `git show <branch>:drivers/greybus/gb-beagleplay.c
| rg "count > sizeof|overflow|oversized"` — neither the current commit
nor the duplicate is present in any stable branch yet. No prior fix
exists for this bug in stable.

## PHASE 7: SUBSYSTEM CONTEXT

**Step 7.1 - Subsystem & criticality**
Record: `drivers/greybus` — niche subsystem, but this driver supports a
real shipped product (BeaglePlay). PERIPHERAL criticality (only affects
users of that specific board).

**Step 7.2 - Subsystem activity**
Record: Low churn — `git log` on the file shows ~10 changes since 2024.
The function being fixed has been unchanged since its introduction in
v6.12.

## PHASE 8: IMPACT AND RISK ASSESSMENT

**Step 8.1 - Affected population**
Record: Users of the BeaglePlay board running v6.12+ kernels who
exercise the cc1352p7 firmware-update path.

**Step 8.2 - Trigger conditions**
Record: Requires `flashing_mode` true (firmware upload in progress;
needs root) AND `count` (size of a single serdev receive chunk plus
already-staged bytes) exceeding 259 bytes. UART subsystems can batch
incoming bytes, so this is realistic during a firmware flash, not just
under attacker control.

**Step 8.3 - Failure mode severity**
Record: Heap out-of-bounds write inside `struct gb_beagleplay`. Likely
outcomes: kernel oops/panic, slab corruption, KASAN splat, potential
local privilege/info leak. Severity = HIGH.

**Step 8.4 - Risk-benefit**
Record: Benefit = closes a kernel heap OOB write reachable during a
normal product workflow. Risk = very low — 5 lines, mirror of existing
guard, only consequence is dropping a malformed/oversized chunk during
firmware flash (already an error condition). Strong net positive.

## PHASE 9: SYNTHESIS

**Step 9.1 - Evidence**
For:
- Real out-of-bounds write in `cc1352_bootloader_rx()` confirmed by
reading current code.
- Buggy code present in v6.12.y, v6.17.y, v6.18.y, v6.19.y.
- Tiny, surgical fix (5 lines), mirrors an existing guard.
- Same author submitted a follow-up explicitly tagged `Fixes:` + `Cc:
stable@vger.kernel.org` for the same bug — strong confirmation of
stable-worthiness.
- Applies cleanly to affected stable trees.

Against:
- Niche driver (limited user population).
- No `Reported-by:` / `Cc: stable` on this specific commit (expected per
instructions).
- Trigger requires root (firmware upload).
- Cosmetic concern: if both this and `1214bf28965ce` reach stable, you
get a duplicate bound check (still functionally correct).

**Step 9.2 - Stable rules checklist**
1. Obviously correct & tested? Yes — minimal logic, mirrors existing
pattern; merged to mainline.
2. Real bug? Yes — reachable kernel-heap OOB write.
3. Important? Yes — heap corruption.
4. Small & contained? Yes — 6 lines, one file, one function.
5. No new features/APIs? Correct.
6. Applies to stable? Yes — file unchanged since the bug was introduced.

**Step 9.3 - Exception category**
Memory safety / OOB write fix.

**Step 9.4 - Decision**
Backport.

## Verification
- [Phase 1] Read full commit message; tags inventoried — no
`Fixes:`/`Cc: stable` (expected).
- [Phase 2] Read current `cc1352_bootloader_rx()` (lines 532–554) and
confirmed `rx_buffer` is `u8[MAX_RX_HDLC]=259`.
- [Phase 2] Confirmed sibling `hdlc_rx()` already enforces `MAX_RX_HDLC`
(line 399).
- [Phase 3] `git log -S "cc1352_bootloader_rx" -- drivers/greybus/gb-
beagleplay.c` → introduced by `0cf7befa3ea2e`.
- [Phase 3] `git describe --contains 0cf7befa3ea2e` → `v6.12-rc1~39^2`.
- [Phase 3] `git log origin/master --oneline -- drivers/greybus/gb-
beagleplay.c` revealed duplicate follow-up `1214bf28965ce` with
`Fixes:` + `Cc: stable`.
- [Phase 3] `git show origin/master:drivers/greybus/gb-beagleplay.c`
shows two consecutive bound-check blocks at lines 620 and 626 in
master (cosmetic duplication after both commits).
- [Phase 4] `b4 dig -c cbc96a916b1a3` returned the lore thread (v1 only,
no replies).
- [Phase 4] `b4 dig -c 1214bf28965ce -m` confirmed the follow-up patch
carries `Fixes: 0cf7befa3ea2` and `Cc: stable@vger.kernel.org`.
- [Phase 5] Read `gb_tty_receive` and `gb_beagleplay_ops` to confirm the
call path: serdev `.receive_buf` → `gb_tty_receive` →
`cc1352_bootloader_rx` when `flashing_mode` is set.
- [Phase 5] Read `cc1352_prepare()` (lines 860–929) to confirm
`flashing_mode` is set during user-initiated firmware upload via the
fw_upload framework.
- [Phase 6] `git merge-base --is-ancestor 0cf7befa3ea2e` against each
stable-push branch — bug present in 6.12.y, 6.17.y, 6.18.y, 6.19.y;
absent in 6.6.y and earlier.
- [Phase 6] Searched stable branches for the bound-check string — not
present anywhere yet.
- [Phase 8] `rx_buffer` size = `1 + 256 + 2 = 259` (`MAX_RX_HDLC`);
confirmed by reading the macro definitions at lines 23–25.
- UNVERIFIED: I did not measure how often a real BeaglePlay UART chunk
exceeds 259 bytes during firmware flash; treating this as a defense-
in-depth fix even if the trigger is rare. Doesn't change the YES
decision because the OOB write itself is real.

This commit is a small, contained memory-safety fix for a real kernel-
heap OOB write that exists in 6.12.y/6.17.y/6.18.y/6.19.y. The same
author already submitted a duplicate version explicitly tagged `Cc:
stable`, which directly corroborates that the bug is stable-material. It
applies cleanly and meets every stable-kernel rule.

**YES**

drivers/greybus/gb-beagleplay.c | 6 ++++++
1 file changed, 6 insertions(+)

diff --git a/drivers/greybus/gb-beagleplay.c b/drivers/greybus/gb-beagleplay.c
index 87186f891a6ac..bca3132adacde 100644
--- a/drivers/greybus/gb-beagleplay.c
+++ b/drivers/greybus/gb-beagleplay.c
@@ -535,6 +535,12 @@ static size_t cc1352_bootloader_rx(struct gb_beagleplay *bg, const u8 *data,
int ret;
size_t off = 0;

+ if (count > sizeof(bg->rx_buffer) - bg->rx_buffer_len) {
+ dev_err_ratelimited(&bg->sd->dev, "Bootloader RX buffer overflow");
+ bg->rx_buffer_len = 0;
+ return count;
+ }
+
memcpy(bg->rx_buffer + bg->rx_buffer_len, data, count);
bg->rx_buffer_len += count;

--
2.53.0