Subject: [PATCH AUTOSEL 7.0-5.10] net: rose: reject truncated CLEAR_REQUEST frames in state machines

From: Sasha Levin <[email-masked]>
Date: Mon, 20 Apr 2026 09:17:05 -0400

From: Mashiro Chen <[email-masked]>

[ Upstream commit 2835750dd6475a5ddc116be0b4c81fee8ce1a902 ]

All five ROSE state machines (states 1-5) handle ROSE_CLEAR_REQUEST
by reading the cause and diagnostic bytes directly from skb->data[3]
and skb->data[4] without verifying that the frame is long enough:

  rose_disconnect(sk, ..., skb->data[3], skb->data[4]);

The entry-point check in rose_route_frame() only enforces
ROSE_MIN_LEN (3 bytes), so a remote peer on a ROSE network can
send a syntactically valid but truncated CLEAR_REQUEST (3 or 4
bytes) while a connection is open in any state.  Processing such a
frame causes a one- or two-byte out-of-bounds read past the skb
data, leaking uninitialized heap content as the cause/diagnostic
values returned to user space via getsockopt(ROSE_GETCAUSE).

Add a single length check at the rose_process_rx_frame() dispatch
point, before any state machine is entered, to drop frames that
carry the CLEAR_REQUEST type code but are too short to contain the
required cause and diagnostic fields.

Signed-off-by: Mashiro Chen <[email-masked]>
Link: https://patch.msgid.link/[email-masked]
Signed-off-by: Jakub Kicinski <[email-masked]>
Signed-off-by: Sasha Levin <[email-masked]>
---

LLM Generated explanations, may be completely bogus:

I now have all the information needed for a complete analysis.

---

## PHASE 1: COMMIT MESSAGE FORENSICS

**Step 1.1: PARSE THE SUBJECT LINE**
- Subsystem: `net: rose:`
- Action verb: "reject" (implies adding a safety check / validation — a
  bug fix)
- Summary: Reject truncated CLEAR_REQUEST frames to prevent out-of-
  bounds read

Record: [net: rose] [reject] [Add length validation for CLEAR_REQUEST
frames to prevent OOB read]

**Step 1.2: PARSE ALL COMMIT MESSAGE TAGS**
- `Signed-off-by: Mashiro Chen <[email-masked]>` — author
- `Link: https://patch.msgid.link/20260408172551.281486-1-
  [email-masked]` — original patch submission
- `Signed-off-by: Jakub Kicinski <[email-masked]>` — network maintainer
  (committed the patch)
- No Fixes: tag (expected for this review pipeline)
- No Reported-by: tag
- No Cc: stable tag

Record: Patch accepted by Jakub Kicinski (net maintainer). Single
standalone patch (not part of a series).

**Step 1.3: ANALYZE THE COMMIT BODY TEXT**
The commit body clearly describes:
- **Bug**: All five ROSE state machines (states 1-5) handle
  ROSE_CLEAR_REQUEST by reading `skb->data[3]` and `skb->data[4]`
  without verifying the frame is long enough.
- **Root cause**: `rose_route_frame()` only enforces `ROSE_MIN_LEN` (3
  bytes), but `data[3]` and `data[4]` need at least 5 bytes.
- **Trigger**: A remote peer on a ROSE network can send a 3- or 4-byte
  CLEAR_REQUEST.
- **Consequence**: 1-2 byte out-of-bounds read past skb data, leaking
  uninitialized heap content as cause/diagnostic values returned to
  userspace via `getsockopt(ROSE_GETCAUSE)`.

Record: OOB read vulnerability. Remote trigger. Info leak to userspace.
Clear mechanism explained.

**Step 1.4: DETECT HIDDEN BUG FIXES**
This is not hidden — it's an explicit security/memory safety bug fix.
The word "reject" means "add missing input validation."

Record: Explicit bug fix, not disguised.

---

## PHASE 2: DIFF ANALYSIS

**Step 2.1: INVENTORY THE CHANGES**
- 1 file changed: `net/rose/rose_in.c`
- +7 lines added (5 lines comment + 2 lines of code)
- Function modified: `rose_process_rx_frame()`
- Scope: Single-file surgical fix

Record: [net/rose/rose_in.c +7/-0] [rose_process_rx_frame] [Single-file
surgical fix]

**Step 2.2: UNDERSTAND THE CODE FLOW CHANGE**
- **Before**: After `rose_decode()` returns the frametype, the code
  dispatches directly to state machines. If `frametype ==
  ROSE_CLEAR_REQUEST` and `skb->len < 5`, the state machines would read
  `skb->data[3]` and `skb->data[4]` beyond the buffer.
- **After**: A length check drops CLEAR_REQUEST frames shorter than 5
  bytes before any state machine is entered. This prevents the OOB
  access in all 5 state machines with one check.

Record: [Before: no length validation for CLEAR_REQUEST → OOB read |
After: reject truncated frames early]

**Step 2.3: IDENTIFY THE BUG MECHANISM**
Category: **Memory safety fix — out-of-bounds read**
- The frame minimum is 3 bytes (`ROSE_MIN_LEN = 3`)
- `ROSE_CLEAR_REQUEST` needs bytes at offsets 3 and 4 (requiring 5
  bytes)
- All five state machines access `skb->data[3]` and `skb->data[4]` when
  handling CLEAR_REQUEST
- The OOB-read values are stored in `rose->cause` and
  `rose->diagnostic`, which are exposed to userspace via `SIOCRSGCAUSE`
  ioctl

Record: [OOB read, 1-2 bytes past skb data] [Remote trigger via
malformed ROSE frame] [Info leak to userspace via ioctl]

**Step 2.4: ASSESS THE FIX QUALITY**
- Obviously correct: The check is trivially verifiable — CLEAR_REQUEST
  needs bytes at index 3 and 4, so minimum length must be 5.
- Minimal/surgical: 2 lines of actual code + comment, at a single
  dispatch point that covers all 5 state machines.
- Regression risk: Near zero. It only drops malformed frames that would
  cause OOB access anyway.
- No side effects: Returns 0 (drops the frame silently), which is the
  standard behavior for invalid frames.

Record: [Obviously correct, minimal, near-zero regression risk]

---

## PHASE 3: GIT HISTORY INVESTIGATION

**Step 3.1: BLAME THE CHANGED LINES**
Git blame shows the vulnerable `skb->data[3]` / `skb->data[4]` accesses
originate from commit `1da177e4c3f41` — **Linux 2.6.12-rc2 (April
2005)**. This is the initial import of the Linux kernel into git. The
bug has existed since the very beginning of the ROSE protocol
implementation.

Record: [Buggy code from Linux 2.6.12-rc2 (2005)] [Present in ALL stable
trees]

**Step 3.2: FOLLOW THE FIXES TAG**
No Fixes: tag present (expected). Based on blame, the theoretical Fixes:
target would be `1da177e4c3f41 ("Linux-2.6.12-rc2")`.

Record: [Bug exists since initial kernel git import, affects all stable
trees]

**Step 3.3: CHECK FILE HISTORY FOR RELATED CHANGES**
Recent changes to `rose_in.c` are minimal: `d860d1faa6b2c` (refcount
conversion), `a6f190630d070` (drop reason tracking), `b6459415b384c`
(include fix). None conflict with this fix. The fix applies cleanly with
no dependencies.

Record: [No conflicting changes, standalone fix, no dependencies]

**Step 3.4: CHECK THE AUTHOR**
Mashiro Chen has other ROSE/hamradio-related patches (visible in the
.mbx files in the workspace: `v2_20260409_mashiro_chen_net_hamradio_fix_
missing_input_validation_in_bpqether_and_scc.mbx`). The patch was
accepted by Jakub Kicinski, the network subsystem maintainer.

Record: [Author contributes to amateur radio subsystem, patch accepted
by net maintainer]

**Step 3.5: CHECK FOR DEPENDENT/PREREQUISITE COMMITS**
The fix only uses `frametype`, `ROSE_CLEAR_REQUEST`, and `skb->len` —
all of which have existed since the file's creation. No dependencies.

Record: [No dependencies. Applies standalone to any kernel version.]

---

## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH

**Step 4.1-4.2: FIND ORIGINAL PATCH DISCUSSION**
b4 dig could not find the exact match (possibly too recent or the commit
hash `028ef9c96e961` is the Linux 7.0 tag, not the fix commit). However,
the Link tag points to
`patch.msgid.link/[email-masked]`, and
the patch was signed off by Jakub Kicinski, confirming acceptance by the
net maintainer.

Record: [b4 dig could not match (HEAD is Linux 7.0 tag)] [Patch accepted
by Jakub Kicinski (net maintainer)]

**Step 4.3-4.5**: Lore is behind Anubis protection, preventing direct
fetching. But the commit message is detailed enough to fully understand
the bug.

Record: [Lore inaccessible due to bot protection] [Commit message
provides complete technical detail]

---

## PHASE 5: CODE SEMANTIC ANALYSIS

**Step 5.1: KEY FUNCTIONS**
Modified function: `rose_process_rx_frame()`

**Step 5.2: CALLERS**
`rose_process_rx_frame()` is called from:
1. `rose_route_frame()` in `rose_route.c:944` — the main frame routing
   entry point from AX.25
2. `rose_loopback_dequeue()` in `rose_loopback.c:93` — the loopback
   queue processor

Both callers only enforce `ROSE_MIN_LEN` (3 bytes) before calling,
confirming the vulnerability.

**Step 5.3: CALLEES**
The state machine functions (`rose_state1_machine` through
`rose_state5_machine`) are callees. All five access `skb->data[3]` and
`skb->data[4]` for CLEAR_REQUEST, making the single check at the
dispatch point the optimal fix location.

**Step 5.4: CALL CHAIN / REACHABILITY**
- `rose_route_frame()` is the AX.25 protocol handler for ROSE
  (`rose_pid.func = rose_route_frame`), registered at module load via
  `ax25_protocol_register()`. This is directly reachable from network
  input — a remote peer on a ROSE network can send malformed frames.
- `rose_loopback_dequeue()` processes locally-queued frames. Also
  reachable.

Record: [Remotely triggerable via ROSE network frames. Both entry paths
affected.]

**Step 5.5: USER DATA LEAK PATH**
Verified: `rose_disconnect()` stores the OOB-read values in
`rose->cause` and `rose->diagnostic`. The `SIOCRSGCAUSE` ioctl in
`af_rose.c:1389-1393` copies these to userspace via `copy_to_user()`.
This completes the info leak chain from OOB kernel heap read to
userspace.

Record: [Complete info leak chain verified: OOB read →
rose->cause/diagnostic → ioctl → userspace]

---

## PHASE 6: CROSS-REFERENCING AND STABLE TREE ANALYSIS

**Step 6.1: DOES THE BUGGY CODE EXIST IN STABLE TREES?**
The buggy code dates from Linux 2.6.12-rc2 (2005). Very few changes have
been made to `rose_in.c` across kernel versions. Since v5.15, only 3
unrelated commits touched this file (include changes, pfmemalloc
tracking, refcount conversion). The vulnerable
`skb->data[3]`/`skb->data[4]` accesses are present in ALL active stable
trees.

Record: [Bug present in all stable trees: 5.4.y, 5.10.y, 5.15.y, 6.1.y,
6.6.y, 6.12.y]

**Step 6.2: BACKPORT COMPLICATIONS**
The fix patches the `rose_process_rx_frame()` function which has been
nearly unchanged since 2005. The recent `d860d1faa6b2c` (refcount_t
conversion) doesn't affect the patch point. This will apply cleanly to
all stable trees.

Record: [Clean apply expected for all stable trees]

**Step 6.3: RELATED FIXES IN STABLE**
No related fix for this specific OOB read issue exists in any stable
tree.

Record: [No prior fix for this bug]

---

## PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT

**Step 7.1: SUBSYSTEM CRITICALITY**
- Subsystem: `net/rose/` — ROSE (Radio Over Serial Ethernet) amateur
  radio protocol
- Criticality: PERIPHERAL (niche protocol used by amateur radio
  operators)
- However: This is a network protocol reachable from external input,
  making it security-relevant despite limited user base.

Record: [net/rose — peripheral subsystem but remotely triggerable,
security-relevant]

**Step 7.2: SUBSYSTEM ACTIVITY**
The ROSE subsystem is mature/stable — minimal development activity. The
file has only had trivial/treewide changes since 2005. This means the
bug has been present for ~21 years.

Record: [Very mature code, minimal activity, bug present for 21 years]

---

## PHASE 8: IMPACT AND RISK ASSESSMENT

**Step 8.1: WHO IS AFFECTED**
Users with `CONFIG_ROSE` enabled who have ROSE sockets open. This is
primarily amateur radio operators using AX.25/ROSE networking.

Record: [Affected: systems with CONFIG_ROSE enabled and active ROSE
connections]

**Step 8.2: TRIGGER CONDITIONS**
- **Remote trigger**: A peer on a ROSE network sends a 3- or 4-byte
  frame with frametype byte 0x13 (CLEAR_REQUEST)
- **No authentication needed**: Any ROSE peer can send this
- **Deterministic**: Not a race condition — always triggers on receipt
  of truncated frame
- **Any connection state**: All 5 state machines are vulnerable

Record: [Remotely triggerable, no authentication, deterministic, any
connection state]

**Step 8.3: FAILURE MODE SEVERITY**
- **OOB read**: 1-2 bytes read past allocated skb data — reads
  uninitialized heap memory
- **Info leak to userspace**: The leaked bytes are stored in
  `rose->cause`/`rose->diagnostic` and returned via `SIOCRSGCAUSE` ioctl
- Severity: **HIGH** — kernel heap info leak reachable from network
  input

Record: [Severity: HIGH — remotely-triggered kernel heap info leak]

**Step 8.4: RISK-BENEFIT RATIO**
- **Benefit**: Fixes a remotely-triggered OOB read / kernel info leak in
  a 21-year-old bug
- **Risk**: 2 lines of code, obviously correct bounds check, zero
  regression potential
- **Ratio**: Extremely favorable — maximum benefit, minimum risk

Record: [Benefit: HIGH (security fix) | Risk: VERY LOW (2 lines,
trivially correct) | Ratio: Strongly favorable]

---

## PHASE 9: FINAL SYNTHESIS

**Step 9.1: COMPILE THE EVIDENCE**

Evidence FOR backporting:
- Fixes a remotely-triggerable out-of-bounds read (security
  vulnerability)
- Kernel heap info leak to userspace via ioctl (complete exploit chain
  verified)
- Bug present since Linux 2.6.12 (2005) — affects ALL stable trees
- Fix is 2 lines of code, obviously correct
- No dependencies, applies cleanly to all stable trees
- Accepted by net maintainer Jakub Kicinski
- Single centralized check covers all 5 vulnerable state machines

Evidence AGAINST backporting:
- ROSE is a niche protocol (limited user base)
- No Fixes: tag (expected)

Unresolved:
- Could not access lore discussion (Anubis protection)

**Step 9.2: STABLE RULES CHECKLIST**
1. Obviously correct and tested? **YES** — trivial bounds check,
   accepted by net maintainer
2. Fixes a real bug? **YES** — OOB read with info leak to userspace
3. Important issue? **YES** — security vulnerability (remotely-triggered
   kernel info leak)
4. Small and contained? **YES** — 7 lines added (2 code + 5 comment),
   single file
5. No new features or APIs? **YES** — only adds validation
6. Can apply to stable trees? **YES** — no conflicting changes, code
   unchanged since 2005

**Step 9.3: EXCEPTION CATEGORIES**
Not an exception category — this is a standard security bug fix, which
is core stable material.

**Step 9.4: DECISION**
This is a textbook stable backport candidate: a small, obvious security
fix for a remotely-triggerable OOB read that has been present for 21
years in all kernel versions.

---

## Verification

- [Phase 1] Parsed tags: Signed-off-by Jakub Kicinski (net maintainer),
  Link to original patch
- [Phase 2] Diff analysis: +7 lines (2 code + 5 comment) in
  rose_process_rx_frame(), adds `skb->len < 5` check for CLEAR_REQUEST
- [Phase 2] Verified all 5 state machines access `skb->data[3]` and
  `skb->data[4]` for CLEAR_REQUEST (lines 58, 81, 123, 236, 256 of
  rose_in.c)
- [Phase 3] git blame: buggy code from `1da177e4c3f41` (Linux
  2.6.12-rc2, April 2005), present in all stable trees
- [Phase 3] git log: only 3 unrelated changes to rose_in.c since v5.15,
  fix applies cleanly
- [Phase 4] b4 dig: could not match (HEAD is Linux 7.0 tag, not the fix
  commit)
- [Phase 4] UNVERIFIED: Full lore discussion (Anubis protection blocked
  access)
- [Phase 5] Verified callers: rose_route_frame() and
  rose_loopback_dequeue() both only check ROSE_MIN_LEN (3 bytes)
- [Phase 5] Verified info leak chain: OOB values →
  rose->cause/diagnostic → SIOCRSGCAUSE ioctl → copy_to_user
- [Phase 5] Verified ROSE_MIN_LEN = 3 and ROSE_CLEAR_REQUEST = 0x13 in
  include/net/rose.h
- [Phase 6] Code exists unchanged in all active stable trees (v5.4+)
- [Phase 7] net/rose is peripheral but network-reachable (security-
  relevant)
- [Phase 8] Failure mode: remotely-triggered kernel heap OOB read with
  info leak to userspace, severity HIGH

**YES**

 net/rose/rose_in.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/net/rose/rose_in.c b/net/rose/rose_in.c
index 0276b393f0e53..e268005819627 100644
--- a/net/rose/rose_in.c
+++ b/net/rose/rose_in.c
@@ -271,6 +271,13 @@ int rose_process_rx_frame(struct sock *sk, struct sk_buff *skb)
 
 	frametype = rose_decode(skb, &ns, &nr, &q, &d, &m);
 
+	/*
+	 * ROSE_CLEAR_REQUEST carries cause and diagnostic in bytes 3..4.
+	 * Reject a malformed frame that is too short to contain them.
+	 */
+	if (frametype == ROSE_CLEAR_REQUEST && skb->len < 5)
+		return 0;
+
 	switch (rose->state) {
 	case ROSE_STATE_1:
 		queued = rose_state1_machine(sk, skb, frametype);
-- 
2.53.0