From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5AF7F3DA7E4; Mon, 20 Apr 2026 13:24:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776691444; cv=none; b=Epv75XlBfx9wIWe1RoHPi0C1jAmFbGDIY+Wn2wblmpOThr7wYNLIIBKOo1XTeoLwspzdlJiwYiYfvX1Ww+u6z+6c1DUZdQ6VYqmAkwmk3VaMhxiFw3M0dJuhVqvSWv93p02eLgWmXeyP0TvP8BU60qQeEnkUO0nWr2YLKVgs3ao= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776691444; c=relaxed/simple; bh=AVw5mg88bSgQp4g6+0kb881zHx4zkaRGuN4cEpWXJ+E=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=kmRDB86I12lx2KD1SYkg38AslJAnB2fTwqz2G6nMJNP+VtKXbK3RI045wNoVbB6iIRHcMCKReAa7j9arU+PvYrgUymP37U1fTh+EyI2OHcUq1y9f2YPsIOeGaIyxYXEpoTTPMdkfa48td4rQr0Lo3hwHdIDgBrwQqpAJBmZkMEo= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=kUCoZJqp; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="kUCoZJqp" Received: by smtp.kernel.org (Postfix) with ESMTPSA id CFA08C2BCB4; Mon, 20 Apr 2026 13:24:02 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1776691444; bh=AVw5mg88bSgQp4g6+0kb881zHx4zkaRGuN4cEpWXJ+E=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=kUCoZJqpCwY4sZ+HgPDMBjGYBjkEpY/Ng4DFYeEpBQLh76F1HXWsn2FCyxB6nMLYu cHqgOpu/XLCe9N70VQm2s8FRnNZeA7fG1QZ67XJtMGZ/O1L9LJj+ZW4chtbZ06vX8C twruYrmoa/d9qgMkRZszewsuruI4ktsJac9uuPYiMOAVZowkGj+V/Ba+QyuY9CKuRu F16WO1gKnmErZYZx+w5BqFSnP+aVGshWzipTTfD69BFe1Pihq8c1tMpfuLjVgWIfYz T2ee1AJ5ESiWgCJ17fdrJQFGtCnXqGQRShemSyoRfRHCKgqQae9Ee4aizXnxoOz0X8 iheYqb7SS4e4w== From: Sasha Levin To: patches@lists.linux.dev, stable@vger.kernel.org Cc: Mashiro Chen , Jakub Kicinski , Sasha Levin , davem@davemloft.net, edumazet@google.com, pabeni@redhat.com, linux-hams@vger.kernel.org, netdev@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH AUTOSEL 7.0-5.10] net: rose: reject truncated CLEAR_REQUEST frames in state machines Date: Mon, 20 Apr 2026 09:17:05 -0400 Message-ID: <20260420132314.1023554-31-sashal@kernel.org> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260420132314.1023554-1-sashal@kernel.org> References: <20260420132314.1023554-1-sashal@kernel.org> Precedence: bulk X-Mailing-List: patches@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-stable: review X-Patchwork-Hint: Ignore X-stable-base: Linux 7.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From: Mashiro Chen [ 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 Link: https://patch.msgid.link/20260408172551.281486-1-mashiro.chen@mailbox.org Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- 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 ` — author - `Link: https://patch.msgid.link/20260408172551.281486-1- mashiro.chen@mailbox.org` — original patch submission - `Signed-off-by: Jakub Kicinski ` — 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/20260408172551.281486-1-mashiro.chen@mailbox.org`, 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