* [PATCH AUTOSEL 6.18-5.10] ACPICA: Prevent adding invalid references
[not found] <20260831133314.4125787-1-sashal@kernel.org>
@ 2026-08-31 13:20 ` Sasha Levin
2026-08-31 13:21 ` [PATCH AUTOSEL 6.18-5.10] ACPICA: Improve argument parsing in acpi_ps_get_next_simple_arg() Sasha Levin
` (22 subsequent siblings)
23 siblings, 0 replies; 26+ messages in thread
From: Sasha Levin @ 2026-08-31 13:20 UTC (permalink / raw)
To: patches, stable
Cc: ikaros, Rafael J. Wysocki, Sasha Levin, rafael,
maciej.wieczor-retman, pawel.chmielewski, linux-acpi,
acpica-devel, linux-kernel
From: ikaros <void0red@gmail.com>
[ Upstream commit 6e8c55e13a5e3a9f38921d62924f18ceba3330eb ]
Prevent adding references for local, argument, and debug objects
in acpi_ut_copy_simple_object().
Link: https://github.com/acpica/acpica/commit/f576898d7814
Signed-off-by: ikaros <void0red@gmail.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Link: https://patch.msgid.link/4511989.ejJDZkT8p0@rafael.j.wysocki
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
# Stable Backport Analysis: ACPICA: Prevent adding invalid references
## Tree Context
Local checkout: **v6.18.44** (6.18.44). The fix is **not** present in
this tree; the buggy code remains at `drivers/acpi/acpica/utcopy.c:734`.
---
## PHASE 1: COMMIT MESSAGE FORENSICS
### Step 1.1: Subject Line
**Record:** `[ACPICA] [prevent] — Prevent adding invalid references in
acpi_ut_copy_simple_object() when copying LOCAL/ARG/DEBUG reference
objects.`
### Step 1.2: Tags
**Record:**
- **Link:** https://github.com/acpica/acpica/commit/f576898d7814
(upstream ACPICA commit)
- **Link:** https://patch.msgid.link/4511989.ejJDZkT8p0@rafael.j.wysocki
(kernel submission; fetch blocked by bot protection)
- **Signed-off-by:** ikaros <void0red@gmail.com> (author)
- **Signed-off-by:** Rafael J. Wysocki <rafael.j.wysocki@intel.com>
(ACPI maintainer)
- No Fixes:, Reported-by:, Tested-by:, Reviewed-by:, Cc: stable@
- Notable: Submitted as **[PATCH v1 15/27] ACPI: ACPICA 20260408**
series (May 27, 2026)
### Step 1.3: Body Analysis
**Record:**
- **Bug:** `acpi_ut_copy_simple_object()` unconditionally calls
`acpi_ut_add_reference(source_desc->reference.object)` for all
reference classes except `ACPI_REFCLASS_TABLE`.
- **Problem:** LOCAL, ARG, and DEBUG references do not have a valid
operand-object pointer in `reference.object`.
- **Symptom:** Use-after-free when `acpi_ut_add_reference()` →
`acpi_ut_valid_internal_object()` reads freed memory (confirmed in
ACPICA issue #1127 with ASAN stack trace).
- **Root cause:** LOCAL/ARG use `reference.value` (and may store a
namespace-node pointer in `object` via cast); DEBUG sets only
`reference.class` with no valid `object`. Calling
`acpi_ut_add_reference()` on these is semantically wrong and can
dereference stale/freed pointers.
### Step 1.4: Hidden Bug Fix Detection
**Record:** Yes — despite the neutral "prevent" wording, this is a real
memory-safety bug fix (UAF), not cleanup. It extends the existing 2008
`ACPI_REFCLASS_TABLE` exemption pattern to the three other reference
classes that similarly lack a valid operand-object pointer.
---
## PHASE 2: DIFF ANALYSIS
### Step 2.1: Inventory
**Record:**
- **Files:** `drivers/acpi/acpica/utcopy.c` (+9, -1)
- **Function:** `acpi_ut_copy_simple_object()`
- **Scope:** Single-file, surgical fix in one `case
ACPI_TYPE_LOCAL_REFERENCE:` block
### Step 2.2: Code Flow Change
**Record:**
- **Before:** After exempting `ACPI_REFCLASS_TABLE`, always call
`acpi_ut_add_reference(source_desc->reference.object)`.
- **After:** Also skip `acpi_ut_add_reference()` for
`ACPI_REFCLASS_LOCAL`, `ACPI_REFCLASS_ARG`, and `ACPI_REFCLASS_DEBUG`.
- **Path affected:** Object-copy path used when duplicating ACPI
internal objects (packages, CopyObject opcode, store operations).
### Step 2.3: Bug Mechanism
**Record:**
- **Category:** Use-after-free / invalid pointer dereference
- **Mechanism:** For LOCAL/ARG/DEBUG references, `reference.object` is
not a valid `union acpi_operand_object *`. `acpi_ut_add_reference()`
calls `acpi_ut_valid_internal_object()` which reads
`ACPI_GET_DESCRIPTOR_TYPE(object)` from that pointer — triggering UAF
when the pointer is stale (e.g., freed walk-state memory per ACPICA
issue #1127 ASAN report).
### Step 2.4: Fix Quality
**Record:**
- Obviously correct: mirrors the existing TABLE exemption and matches
how `exresolv.c` treats these classes ("do not dereference").
- Minimal, no unrelated changes.
- Low regression risk: only skips refcount increment that should never
have happened for these three classes.
---
## PHASE 3: GIT HISTORY INVESTIGATION
### Step 3.1: Blame
**Record:**
- Reference-handling case dates to **2005** (initial ACPICA import).
- `acpi_ut_add_reference()` call: **2005** (Len Brown).
- `ACPI_REFCLASS_TABLE` exemption: **2008** (Bob Moore, commit
`1044f1f65b7df2`) — LOCAL/ARG/DEBUG were never added.
- Bug has been present since ~2005; TABLE partial fix since 2008.
### Step 3.2: Fixes: Tag
**Record:** N/A — no Fixes: tag. Upstream ACPICA issue #1127 references
commit f576898.
### Step 3.3: Related File History
**Record:**
- `470188b09e92d` (2022): Fixed a separate UAF in
`acpi_ut_copy_ipackage_to_ipackage()` in the same file — shows this
code path is security-relevant and prior UAF fixes were backported.
- `b6a163875935c` (2008): Warn on invalid package references — related
defensive work in ACPI reference handling.
- This fix is **standalone** (patch 15/27 of ACPICA bulk update, but
functionally independent).
### Step 3.4: Author Context
**Record:** ikaros reported the bug to ACPICA upstream. Rafael J.
Wysocki (ACPI maintainer) signed off and submitted to linux-acpi. Author
has prior kernel commits (null-check fixes).
### Step 3.5: Dependencies
**Record:** No dependencies. Self-contained 8-line conditional. All
referenced symbols (`ACPI_REFCLASS_LOCAL/ARG/DEBUG`) exist in this
tree's `acobject.h`.
---
## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
### Step 4.1: Original Discussion
**Record:**
- `b4 dig -c f576898d7814`: Failed (ACPICA upstream SHA, not in Linux
git).
- Web search found submission: **[PATCH v1 15/27] ACPICA: Prevent adding
invalid references** at lkml.iu.edu (May 27, 2026), part of ACPI:
ACPICA 20260408 series by Rafael J. Wysocki.
- ACPICA GitHub issue #1127: ASAN heap-use-after-free in
`AcpiUtValidInternalObject` via `AcpiUtAddReference` →
`AcpiUtCopySimpleObject`, reproduced with `acpiexec -m issue11.aml`.
### Step 4.2: Reviewers
**Record:** Rafael J. Wysocki submitted and signed off — ACPI subsystem
maintainer endorsement. Full recipient list unavailable (b4 dig failed;
lore blocked).
### Step 4.3: Bug Report
**Record:**
- ACPICA issue #1127: **heap-use-after-free**, READ of size 1 in
`acpi_ut_valid_internal_object`.
- Call chain: `acpi_ut_copy_simple_object` → `acpi_ut_add_reference` →
`acpi_ut_valid_internal_object`.
- Triggered during AML parsing/execution (`acpi_ps_parse_aml`, table
load).
- Severity: memory safety, potential crash/corruption.
### Step 4.4: Series Context
**Record:** Part of 27-patch ACPICA 20260408 update. This patch is
standalone; does not require other series patches.
### Step 4.5: Stable List History
**Record:** UNVERIFIED — could not search lore.kernel.org/stable (bot
protection). No evidence against stable nomination.
---
## PHASE 5: CODE SEMANTIC ANALYSIS
### Step 5.1: Key Functions
**Record:** `acpi_ut_copy_simple_object()` (modified); callers:
`acpi_ut_copy_ielement_to_ielement()`,
`acpi_ut_copy_iobject_to_iobject()`.
### Step 5.2: Callers
**Record:**
- `acpi_ut_copy_iobject_to_iobject()` called from:
- `exoparg1.c` — `AML_COPY_OBJECT_OP`
- `exstore.c`, `exstoren.c` — store operations
- `dsutils.c`, `dsmthdat.c` — dispatcher/method data
- All are core ACPI AML execution paths, active during boot and runtime
ACPI method evaluation.
### Step 5.3: Callees
**Record:** `acpi_ut_add_reference()` →
`acpi_ut_valid_internal_object()` → reads descriptor type from pointer.
For invalid `reference.object`, this is the UAF site.
### Step 5.4: Reachability
**Record:**
- Triggered when copying packages or objects containing LOCAL/ARG/DEBUG
references.
- ASAN reproducer uses AML table execution during namespace load.
- Reachable on every ACPI-enabled system during DSDT/SSDT evaluation and
method execution. Not limited to obscure configs.
### Step 5.5: Similar Patterns
**Record:**
- `utcopy.c:730`: `ACPI_REFCLASS_TABLE` already exempted (same
rationale).
- `exresolv.c:208-212`: DEBUG/TABLE/REFOF — "Just leave the object as-
is, do not dereference."
- `dsobject.c:471-522`: LOCAL/ARG set `reference.value`; DEBUG sets only
`reference.class` — confirms `object` is not a refcountable operand
object.
---
## PHASE 6: CROSS-REFERENCE WITH LOCAL TREE (v6.18.44)
### Step 6.1: Buggy Code Present?
**Record:** **YES.** At `drivers/acpi/acpica/utcopy.c:721-735`,
unconditional `acpi_ut_add_reference(source_desc->reference.object)`
after only TABLE exemption. Fix text not found via grep.
### Step 6.2: Backport Complications
**Record:** **Clean apply expected.** Index context matches submitted
patch (line ~731). No conflicting recent changes to this hunk. Only
copyright-year churn in file history.
### Step 6.3: Related Fixes Already Present?
**Record:** `470188b09e92d` (UAF in `acpi_ut_copy_ipackage_to_ipackage`)
is present. No duplicate fix for LOCAL/ARG/DEBUG reference handling.
---
## PHASE 7: SUBSYSTEM CONTEXT
### Step 7.1: Subsystem
**Record:** **ACPI/ACPICA** — **CORE** subsystem. Affects all x86
systems and ARM64 systems using ACPI.
### Step 7.2: Activity
**Record:** Actively maintained; recent ACPICA fixes in this tree
include UAF, NULL deref, and AML safety patches.
---
## PHASE 8: IMPACT AND RISK
### Step 8.1: Who Is Affected
**Record:** All users with ACPI enabled (essentially all PCs, servers,
many ARM laptops). Driver-specific? No — core ACPI interpreter.
### Step 8.2: Trigger Conditions
**Record:** Copying ACPI internal objects (packages, CopyObject) that
contain LOCAL, ARG, or DEBUG reference elements. Can be triggered by
ACPI AML in firmware tables. Timing-dependent UAF when
`reference.object` holds stale pointer. Unprivileged users cannot
directly trigger, but firmware/ACPI tables are the attack surface.
### Step 8.3: Failure Mode
**Record:** **Heap use-after-free** in `acpi_ut_valid_internal_object`.
Severity: **HIGH** (crash, potential memory corruption). Could manifest
as oops during boot, suspend/resume, or device hotplug ACPI methods.
### Step 8.4: Risk-Benefit
**Record:**
- **Benefit:** HIGH — prevents UAF in core ACPI object-copy path on all
ACPI systems.
- **Risk:** VERY LOW — 8-line conditional extending an established
pattern; no API/behavior change for valid reference types (REFOF,
INDEX, NAME still get refcounted).
- **Ratio:** Strongly favors backport.
---
## PHASE 9: FINAL SYNTHESIS
### Step 9.1: Evidence Summary
**FOR backport:**
- Confirmed UAF (ASAN report in ACPICA #1127)
- Long-standing bug (since 2005; TABLE partial fix since 2008)
- Buggy code present in v6.18.44
- Core ACPI path (boot, AML execution)
- Small, surgical, obviously correct fix
- Matches existing TABLE exemption and exresolv.c semantics
- ACPI maintainer (Rafael Wysocki) signed off and submitted
- Prior UAF fix in same file was backported to stable
**AGAINST backport:**
- No kernel runtime reproducer in commit message (only acpiexec/AML test
case)
- Part of larger ACPICA bulk update (but this patch is standalone)
- Not yet merged into this 6.18.44 tree (candidate evaluation)
**Unresolved:**
- Lore stable-list discussion (site blocked)
- Exact frequency in production firmware (unverified, but bug mechanism
is clear)
### Step 9.2: Stable Rules Checklist
1. Obviously correct and tested? **PASS** — logic mirrors TABLE
exemption; ASAN-verified upstream; maintainer SOB.
2. Fixes a real bug? **PASS** — UAF in object copy.
3. Important issue? **PASS** — UAF/memory corruption in core ACPI,
severity HIGH.
4. Small and contained? **PASS** — 9 lines, one file, one function.
5. No new features/APIs? **PASS** — defensive guard only.
6. Can apply to local tree? **PASS** — buggy code present, clean apply
expected.
### Step 9.3: Exception Categories
**Record:** N/A (not device ID, quirk, DT, build, or docs — standard bug
fix).
### Step 9.4: Decision Rationale
This commit fixes a verified use-after-free in the ACPICA object-copy
path that has existed since the code was written. LOCAL, ARG, and DEBUG
references never had valid operand-object pointers in `reference.object`
— the 2008 TABLE exemption proves the developers knew some reference
classes must skip `acpi_ut_add_reference()`. The fix is minimal, follows
established patterns in the same file and in `exresolv.c`, and protects
all ACPI-enabled systems during AML execution. For v6.18.44, the buggy
code is present and the fix applies cleanly.
---
## Verification
- [Phase 1] Parsed subject, tags, body; identified UAF bug from ACPICA
issue #1127
- [Phase 1] Web search: found [PATCH v1 15/27] on lkml (May 27, 2026),
Rafael Wysocki submission
- [Phase 2] Read diff: +9/-1 in `acpi_ut_copy_simple_object()`,
LOCAL/ARG/DEBUG guard added
- [Phase 2] Read `acobject.h:340-365`: LOCAL/ARG use `value`, DEBUG has
no valid `object`
- [Phase 2] Read `dsobject.c:462-522`: LOCAL/ARG/DEBUG creation confirms
no operand-object in `reference.object`
- [Phase 2] Read `utdelete.c:677-696`: `acpi_ut_add_reference()` calls
`acpi_ut_valid_internal_object()`
- [Phase 2] Read `utobject.c:305-335`: `acpi_ut_valid_internal_object()`
reads descriptor type (UAF site)
- [Phase 3] `git blame -L 721,735`: buggy code from 2005; TABLE
exemption from 2008 (`1044f1f65b7df2`)
- [Phase 3] `git log -20 -- utcopy.c`: related UAF fix `470188b09e92d`
present in tree
- [Phase 3] `git show 1044f1f65b7df2`: TABLE exemption rationale
documented
- [Phase 3] `git show 470188b09e92d`: prior UAF in same file, backported
class of bug
- [Phase 4] `b4 dig -c f576898d7814`: failed (ACPICA SHA not in Linux
git) — used web search instead
- [Phase 4] ACPICA GitHub issue #1127: ASAN UAF stack trace, acpiexec
reproducer
- [Phase 4] ACPICA GitHub commit f576898: confirms fix details
- [Phase 4] UNVERIFIED: lore.kernel.org and patch.msgid.link blocked by
bot protection
- [Phase 5] `grep acpi_ut_copy_simple_object`: callers in utcopy.c,
exoparg1.c, exstore.c, dsutils.c, dsmthdat.c
- [Phase 5] Read `exresolv.c:208-212`: DEBUG/TABLE/REFOF not
dereferenced — consistent with fix
- [Phase 5] Read `exoparg1.c:465-469`: CopyObject opcode uses
`acpi_ut_copy_iobject_to_iobject`
- [Phase 6] `git describe HEAD`: v6.18.44
- [Phase 6] Read `utcopy.c:721-735`: buggy unconditional
`acpi_ut_add_reference` confirmed
- [Phase 6] `grep "Local/Arg/Debug references"`: fix NOT in tree
- [Phase 8] ACPICA #1127 ASAN: heap-use-after-free, severity HIGH
**YES**The background `git log --grep` check finished: it found **no
commit** matching “Prevent adding invalid” or “invalid references” in
this tree. That matches what we already saw in `utcopy.c` — the
LOCAL/ARG/DEBUG guard is still missing, so the backport analysis stands
as **YES** for v6.18.44.
drivers/acpi/acpica/utcopy.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/drivers/acpi/acpica/utcopy.c b/drivers/acpi/acpica/utcopy.c
index 80458e70ac2bf..9ecf5c3f49ba6 100644
--- a/drivers/acpi/acpica/utcopy.c
+++ b/drivers/acpi/acpica/utcopy.c
@@ -731,7 +731,15 @@ acpi_ut_copy_simple_object(union acpi_operand_object *source_desc,
break;
}
- acpi_ut_add_reference(source_desc->reference.object);
+ /*
+ * Local/Arg/Debug references do not have a valid Object pointer
+ * that can be referenced
+ */
+ if ((source_desc->reference.class != ACPI_REFCLASS_LOCAL) &&
+ (source_desc->reference.class != ACPI_REFCLASS_ARG) &&
+ (source_desc->reference.class != ACPI_REFCLASS_DEBUG)) {
+ acpi_ut_add_reference(source_desc->reference.object);
+ }
break;
case ACPI_TYPE_REGION:
--
2.53.0
^ permalink raw reply related [flat|nested] 26+ messages in thread* [PATCH AUTOSEL 6.18-5.10] ACPICA: Improve argument parsing in acpi_ps_get_next_simple_arg()
[not found] <20260831133314.4125787-1-sashal@kernel.org>
2026-08-31 13:20 ` [PATCH AUTOSEL 6.18-5.10] ACPICA: Prevent adding invalid references Sasha Levin
@ 2026-08-31 13:21 ` Sasha Levin
2026-08-31 13:21 ` [PATCH AUTOSEL 6.18-5.10] ACPICA: Fix NULL pointer dereference in acpi_ns_custom_package() Sasha Levin
` (21 subsequent siblings)
23 siblings, 0 replies; 26+ messages in thread
From: Sasha Levin @ 2026-08-31 13:21 UTC (permalink / raw)
To: patches, stable
Cc: ikaros, Rafael J. Wysocki, Sasha Levin, rafael,
maciej.wieczor-retman, pawel.chmielewski, linux-acpi,
acpica-devel, linux-kernel
From: ikaros <void0red@gmail.com>
[ Upstream commit 27d27e75ecb752a0b4da848c440bb3a88396ecba ]
Improve argument parsing in acpi_ps_get_next_simple_arg() to handle
remaining AML data safely.
Link: https://github.com/acpica/acpica/commit/ecbb8bcfe301
Signed-off-by: ikaros <void0red@gmail.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Link: https://patch.msgid.link/2008043.taCxCBeP46@rafael.j.wysocki
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
## Phase 1: Commit Message Forensics
**Step 1.1 — Subject line**
Record: **[ACPICA] [Improve] argument parsing in
`acpi_ps_get_next_simple_arg()` to handle remaining AML data safely**
**Step 1.2 — Tags**
Record:
- **Link:** https://github.com/acpica/acpica/commit/ecbb8bcfe301
- **Link:** https://patch.msgid.link/2008043.taCxCBeP46@rafael.j.wysocki
(blocked by bot protection; lkml.iu.edu mirror used instead)
- **Signed-off-by:** ikaros \<void0red@gmail.com\> (author)
- **Signed-off-by:** Rafael J. Wysocki \<rafael.j.wysocki@intel.com\>
(ACPI maintainer)
- No **Fixes:**, **Reported-by:**, **Cc: stable**, **Tested-by:**, or
**Reviewed-by:** tags in the message
- Notable: patch is **[PATCH v1 17/27]** in Rafael’s ACPICA sync series
(May 2026); upstream ACPICA commit fixes GitHub issues **#1073** and
**#1131**
**Step 1.3 — Body analysis**
Record:
- **Bug:** `acpi_ps_get_next_simple_arg()` reads integer and string AML
arguments without checking how many bytes remain before
`parser_state->aml_end`.
- **Symptoms:** Out-of-bounds reads when AML is truncated or a string
lacks a null terminator within the buffer; downstream code (e.g.
`strlen()` on the string pointer) can also OOB-read.
- **Root cause:** Unbounded `*aml` / `ACPI_MOVE_*` reads and unbounded
`while (aml[length])` loop.
- **Fix approach:** Compute `remaining = aml_end - aml`, bounds-check
all reads, bound the string scan, warn and force a null terminator at
the buffer edge when needed.
**Step 1.4 — Hidden bug fix?**
Record: **Yes.** “Improve argument parsing” is defensive hardening
against real memory-safety bugs (heap-buffer-overflow confirmed in
upstream ACPICA via ASAN).
---
## Phase 2: Diff Analysis
**Step 2.1 — Inventory**
Record:
- **File:** `drivers/acpi/acpica/psargs.c` (+68 / −10 per lkml; net ~58
lines)
- **Function:** `acpi_ps_get_next_simple_arg()` only
- **Scope:** Single-file, single-function surgical fix
**Step 2.2 — Code flow per hunk**
Record:
- **ARGP_BYTEDATA:** Before: always read 1 byte. After: read only if
`remaining >= 1`, else return 0 with `length = 0`.
- **ARGP_WORD/DWORD/QWORDDATA:** Before: always read 2/4/8 bytes. After:
full read if enough bytes; else zero-init and `memcpy()` partial bytes
if any remain.
- **ARGP_CHARLIST:** Before: unbounded scan for `'\0'`. After: scan only
within `remaining`; if no terminator, `ACPI_WARNING`, write `'\0'` at
`aml[remaining-1]`, set `length = remaining`.
- **Normal path:** `parser_state->aml += length` unchanged.
**Step 2.3 — Bug mechanism**
Record: **Memory safety / buffer overflow (OOB read).** Integer cases
read past `aml_end`; string case can scan past `aml_end` and pass a non-
terminated pointer to later `strlen()`-based code (upstream issue
#1131).
**Step 2.4 — Fix quality**
Record: Fix is minimal, uses existing `aml_end` and `ACPI_PTR_DIFF`
(already used elsewhere in ACPICA). Low regression risk on valid AML.
Minor concern: in-place mutation of AML bytes for malformed strings
(`aml[remaining-1] = 0`), but this only triggers on invalid AML and is
the upstream-chosen mitigation to prevent downstream OOB.
---
## Phase 3: Git History Investigation
**Step 3.1 — Blame**
Record: Buggy logic dates to original ACPICA import (~2005, Bob Moore /
Len Brown). Present in this tree at lines 364–443 of `psargs.c`. Not a
recently introduced regression.
**Step 3.2 — Fixes: tag**
Record: N/A — no `Fixes:` tag in commit message.
**Step 3.3 — Related file history**
Record: Recent `psargs.c` changes in v6.18.44 are copyright updates and
separate memory-leak fixes (`acpi_ps_get_next_field`,
`acpi_ps_get_next_namepath`). No prior fix for this bounds-check issue.
**Step 3.4 — Author commits**
Record: Author ikaros/void0red is an ACPICA contributor (fuzzing-driven
fixes). Rafael Wysocki is ACPI subsystem maintainer; patch submitted as
part of ACPICA v1 27-patch series.
**Step 3.5 — Dependencies**
Record: Listed as patch 17/27 in an ACPICA bulk sync, but the diff is
self-contained — uses only existing `struct acpi_parse_state` fields
(`aml`, `aml_end`, `aml_start`) and `ACPI_PTR_DIFF`. No structural
prerequisites from other series patches identified. **Can apply
standalone.**
---
## Phase 4: Mailing List and External Research
**Step 4.1 — Original discussion**
Record:
- **b4 dig -c ecbb8bcfe301:** Failed (ACPICA SHA not in Linux git)
- **lkml mirror:** https://lkml.iu.edu/2605.3/06252.html — Rafael’s
[PATCH v1 17/27], May 27 2026
- **Series revisions:** Part of v1 27-patch ACPICA update; no evidence
of a newer conflicting version for this hunk
- **Stable nomination in thread:** Not found in available sources
- **NAKs:** None found
**Step 4.2 — Reviewers**
Record: Rafael J. Wysocki (maintainer) signed off and submitted. Full
recipient list unavailable (b4/lore blocked).
**Step 4.3 — Bug reports**
Record:
- **GitHub acpica#1073:** ASAN heap-buffer-overflow in
`AcpiPsGetNextSimpleArg` at integer read (iasl fuzzing)
- **GitHub acpica#1131:** ASAN heap-buffer-overflow via `strlen()` on
malformed AML string without null terminator (acpiexec); fixed by this
commit
- Both closed after ecbb8bc
**Step 4.4 — Series context**
Record: One patch in a 27-patch ACPICA sync; this hunk is independent
and does not require the other 26 patches.
**Step 4.5 — Stable list**
Record: Could not search lore stable list (bot protection). No stable-
specific discussion found via web search.
---
## Phase 5: Code Semantic Analysis
**Step 5.1 — Key functions**
Record: `acpi_ps_get_next_simple_arg()` modified.
**Step 5.2 — Callers**
Record:
- `acpi_ps_get_arguments()` in `psloop.c` (constant/string opcode
arguments during parse loop)
- `acpi_ps_get_next_arg()` in `psargs.c` (general argument fetching)
Both are on the ACPI AML parse path used during table load and method
execution.
**Step 5.3 — Callees**
Record: `acpi_ps_init_op()`, `acpi_ps_get_next_namestring()` (unchanged
paths), `ACPI_MOVE_*` macros, `memcpy()`, `ACPI_WARNING()`.
**Step 5.4 — Reachability**
Record:
- Boot: `acpi_ns_one_complete_parse()` →
`acpi_ds_init_aml_walk(aml_start, aml_length)` → `acpi_ps_parse_aml()`
→ parse loop → `acpi_ps_get_next_simple_arg()`
- Runtime: ACPI method evaluation uses the same walk/parse path via
`acpi_ds_init_aml_walk()`
- **Reachable on every ACPI-enabled system** when parsing tables or
evaluating methods. Trigger requires malformed/truncated AML (buggy
firmware, corrupted tables, or injected SSDT).
**Step 5.5 — Similar patterns**
Record: No existing bounds-check pattern for this function in v6.18.44.
`parser_state->aml_end` is set in `acpi_ds_init_aml_walk()`
(`dswstate.c:578-586`) for all AML walks. `psloop.c` already uses
`parser_state->aml < parser_state->aml_end` at the loop level, but
individual argument parsing lacked per-field bounds checks.
---
## Phase 6: Cross-Reference Against Local Tree (v6.18.44)
**Step 6.1 — Buggy code present?**
Record: **Yes.** Local tree is `v6.18.44` (Makefile 6.18.44).
`acpi_ps_get_next_simple_arg()` at `psargs.c:364-443` has the unbounded
reads. Commit ecbb8bc is **not** in this tree.
**Step 6.2 — Backport complications**
Record: **Clean apply expected.** lkml diff index (`3526ea109414`)
matches current file structure; only line-offset difference. `aml_end`
field exists in `aclocal.h:912`. `ACPI_PTR_DIFF` used elsewhere in
ACPICA.
**Step 6.3 — Related fixes already present?**
Record: **No.** `git log --grep` found no prior fix for this function’s
bounds checking in `psargs.c`.
---
## Phase 7: Subsystem Context
**Step 7.1 — Subsystem / criticality**
Record: **ACPI / ACPICA parser** — **CORE** for all `CONFIG_ACPI`
systems (essentially all x86 PCs and many ARM servers).
**Step 7.2 — Activity**
Record: ACPICA receives regular maintenance; this is a targeted safety
fix within a periodic upstream sync.
---
## Phase 8: Impact and Risk Assessment
**Step 8.1 — Who is affected**
Record: All ACPI-enabled systems parsing AML at boot or during method
evaluation. Driver-specific only in the sense that it requires ACPI,
which is near-universal on supported platforms.
**Step 8.2 — Trigger conditions**
Record: Malformed or truncated AML bytecode (truncated integer args,
string without `'\0'` within buffer). Uncommon in practice from
legitimate firmware, but confirmed reproducible with fuzzed AML. ACPI
table override/SSDT loading requires elevated privileges; primary
production risk is buggy OEM firmware.
**Step 8.3 — Failure mode severity**
Record: **OOB read** → potential kernel oops, info leak, or further
cascading OOB in `strlen()`. **Severity: HIGH** (boot-time or runtime
crash on ACPI parse path).
**Step 8.4 — Risk vs benefit**
Record:
- **Benefit: HIGH** — prevents memory-safety bug on a core boot path
- **Risk: LOW** — single function, defensive checks, no API change;
valid AML behavior unchanged
- **Ratio:** Strong benefit, low risk → backport warranted
---
## Phase 9: Final Synthesis
**Evidence FOR backport:**
- Confirmed heap-buffer-overflow (ASAN) in upstream ACPICA for this
exact function
- Same vulnerable code present in v6.18.44 since ~2005
- `aml_end` infrastructure already exists and is set on all parse paths
- Small, self-contained, maintainer-signed fix
- Prevents OOB reads during ACPI table parsing and method evaluation
- Fits stable criteria: real bug, important (crash/security-class memory
safety), no new APIs
**Evidence AGAINST backport:**
- Part of a 27-patch ACPICA series (cosmetic concern only; patch is
standalone)
- In-place AML mutation for malformed strings (edge case; upstream-
accepted)
- Bugs found via iasl/acpiexec fuzzing, not a field user report (but
kernel shares the code)
**Stable rules checklist:**
1. Obviously correct and tested? **PASS** — straightforward bounds
checks; ASAN-verified upstream
2. Fixes a real bug affecting users? **PASS** — OOB read on ACPI parse
path
3. Important issue? **PASS** — HIGH severity (memory safety / potential
crash)
4. Small and contained? **PASS** — one function, ~58 net lines
5. No new features or APIs? **PASS** — defensive parsing only
6. Can apply to local tree? **PASS** — buggy code present, dependencies
satisfied
**Exception category:** N/A (not device ID, quirk, DT, build, or docs)
**Conclusion:** This commit fixes a long-standing memory-safety hole in
core ACPI AML parsing that is present in the v6.18.44 tree. The fix is
surgical, uses existing parser state, and prevents out-of-bounds reads
that can crash the kernel when malformed AML is encountered.
---
## Verification
- [Phase 1] Parsed subject, tags, body from user-provided commit message
and lkml mirror
- [Phase 1] Confirmed upstream fixes acpica#1073 and #1131 via GitHub
issue pages
- [Phase 2] Diff analysis: single-function bounds-check fix in
`acpi_ps_get_next_simple_arg()`
- [Phase 3] `git describe HEAD`: v6.18.44
- [Phase 3] `git blame -L 364,443 drivers/acpi/acpica/psargs.c`: code
from ~2005
- [Phase 3] `git log --oneline -20 -- drivers/acpi/acpica/psargs.c`: no
prior bounds-check fix
- [Phase 3] `git log -1 ecbb8bcfe301`: commit not in local tree
- [Phase 4] `b4 dig -c ecbb8bcfe301`: no match (ACPICA-only SHA)
- [Phase 4] lkml.iu.edu/2605.3/06252.html: found [PATCH v1 17/27] with
identical diff
- [Phase 4] GitHub acpica#1073: ASAN heap-buffer-overflow at integer
read
- [Phase 4] GitHub acpica#1131: ASAN heap-buffer-overflow via strlen on
malformed string
- [Phase 5] `grep acpi_ps_get_next_simple_arg`: callers in
`psloop.c:71`, `psargs.c:769`
- [Phase 5] Read `nsparse.c:173-198`: table parse sets
`aml_start`/`aml_length` via `acpi_ds_init_aml_walk()`
- [Phase 5] Read `dswstate.c:578-586`: `aml_end` set from `aml_start +
aml_length`
- [Phase 6] Read `psargs.c:364-443`: confirmed vulnerable code in
v6.18.44
- [Phase 6] Read `aclocal.h:909-920`: `aml_end` field exists in `struct
acpi_parse_state`
- [Phase 8] Assessed severity as HIGH based on verified OOB read
mechanism
- [UNVERIFIED] Full lore.kernel.org review thread (Anubis bot blocked
direct fetch)
- [UNVERIFIED] Whether any reviewer explicitly nominated for stable (not
needed for decision)
**YES**The background history searches finished and matched what the
main analysis already used.
**Task 264644** (`git log` on `psargs.c`): Recent changes are copyright
updates and separate leak fixes in `acpi_ps_get_next_field()` /
`acpi_ps_get_next_namepath()`. Nothing related to bounds checking in
`acpi_ps_get_next_simple_arg()`.
**Task 264645** (author/search): No Linux-kernel commits from
ikaros/void0red on this fix; the patch came through Rafael Wysocki’s
ACPICA sync. Recent ACPI work in this tree includes other parser/safety
fixes, but not this one.
That confirms the vulnerable code is still present in **v6.18.44** and
this fix isn’t already here. Verdict remains **YES** for stable
backport.
drivers/acpi/acpica/psargs.c | 78 +++++++++++++++++++++++++++++++-----
1 file changed, 68 insertions(+), 10 deletions(-)
diff --git a/drivers/acpi/acpica/psargs.c b/drivers/acpi/acpica/psargs.c
index 3526ea1094146..064652d11d9aa 100644
--- a/drivers/acpi/acpica/psargs.c
+++ b/drivers/acpi/acpica/psargs.c
@@ -384,6 +384,8 @@ acpi_ps_get_next_simple_arg(struct acpi_parse_state *parser_state,
u32 length;
u16 opcode;
u8 *aml = parser_state->aml;
+ u32 remaining = (u32)ACPI_PTR_DIFF(parser_state->aml_end, aml);
+ u64 partial_value;
ACPI_FUNCTION_TRACE_U32(ps_get_next_simple_arg, arg_type);
@@ -393,8 +395,13 @@ acpi_ps_get_next_simple_arg(struct acpi_parse_state *parser_state,
/* Get 1 byte from the AML stream */
opcode = AML_BYTE_OP;
- arg->common.value.integer = (u64) *aml;
- length = 1;
+ if (remaining >= 1) {
+ arg->common.value.integer = (u64)*aml;
+ length = 1;
+ } else {
+ arg->common.value.integer = 0;
+ length = 0;
+ }
break;
case ARGP_WORDDATA:
@@ -402,8 +409,19 @@ acpi_ps_get_next_simple_arg(struct acpi_parse_state *parser_state,
/* Get 2 bytes from the AML stream */
opcode = AML_WORD_OP;
- ACPI_MOVE_16_TO_64(&arg->common.value.integer, aml);
- length = 2;
+ if (remaining >= 2) {
+ ACPI_MOVE_16_TO_64(&arg->common.value.integer, aml);
+ length = 2;
+ } else {
+ arg->common.value.integer = 0;
+ length = 0;
+ if (remaining > 0) {
+ partial_value = 0;
+ memcpy(&partial_value, aml, remaining);
+ arg->common.value.integer = partial_value;
+ length = remaining;
+ }
+ }
break;
case ARGP_DWORDDATA:
@@ -411,8 +429,19 @@ acpi_ps_get_next_simple_arg(struct acpi_parse_state *parser_state,
/* Get 4 bytes from the AML stream */
opcode = AML_DWORD_OP;
- ACPI_MOVE_32_TO_64(&arg->common.value.integer, aml);
- length = 4;
+ if (remaining >= 4) {
+ ACPI_MOVE_32_TO_64(&arg->common.value.integer, aml);
+ length = 4;
+ } else {
+ arg->common.value.integer = 0;
+ length = 0;
+ if (remaining > 0) {
+ partial_value = 0;
+ memcpy(&partial_value, aml, remaining);
+ arg->common.value.integer = partial_value;
+ length = remaining;
+ }
+ }
break;
case ARGP_QWORDDATA:
@@ -420,8 +449,19 @@ acpi_ps_get_next_simple_arg(struct acpi_parse_state *parser_state,
/* Get 8 bytes from the AML stream */
opcode = AML_QWORD_OP;
- ACPI_MOVE_64_TO_64(&arg->common.value.integer, aml);
- length = 8;
+ if (remaining >= 8) {
+ ACPI_MOVE_64_TO_64(&arg->common.value.integer, aml);
+ length = 8;
+ } else {
+ arg->common.value.integer = 0;
+ length = 0;
+ if (remaining > 0) {
+ partial_value = 0;
+ memcpy(&partial_value, aml, remaining);
+ arg->common.value.integer = partial_value;
+ length = remaining;
+ }
+ }
break;
case ARGP_CHARLIST:
@@ -434,10 +474,28 @@ acpi_ps_get_next_simple_arg(struct acpi_parse_state *parser_state,
/* Find the null terminator */
length = 0;
- while (aml[length]) {
+ while ((length < remaining) && aml[length]) {
+ length++;
+ }
+ if (length < remaining) {
+
+ /* Account for the terminating null */
length++;
+ } else {
+ /*
+ * No terminator found - add null at buffer boundary
+ * and report a warning
+ */
+ ACPI_WARNING((AE_INFO,
+ "Invalid AML string: no null terminator, truncating at offset %u",
+ (u32)(aml - parser_state->aml)));
+
+ /* Add null terminator at the boundary */
+ if (remaining > 0) {
+ aml[remaining - 1] = 0;
+ length = remaining;
+ }
}
- length++;
break;
case ARGP_NAME:
--
2.53.0
^ permalink raw reply related [flat|nested] 26+ messages in thread* [PATCH AUTOSEL 6.18-5.10] ACPICA: Fix NULL pointer dereference in acpi_ns_custom_package()
[not found] <20260831133314.4125787-1-sashal@kernel.org>
2026-08-31 13:20 ` [PATCH AUTOSEL 6.18-5.10] ACPICA: Prevent adding invalid references Sasha Levin
2026-08-31 13:21 ` [PATCH AUTOSEL 6.18-5.10] ACPICA: Improve argument parsing in acpi_ps_get_next_simple_arg() Sasha Levin
@ 2026-08-31 13:21 ` Sasha Levin
2026-08-31 13:23 ` [PATCH AUTOSEL 6.18-5.10] ACPICA: Fix condition check in acpi_ps_parse_loop() Sasha Levin
` (20 subsequent siblings)
23 siblings, 0 replies; 26+ messages in thread
From: Sasha Levin @ 2026-08-31 13:21 UTC (permalink / raw)
To: patches, stable
Cc: Weiming Shi, Xiang Mei, Rafael J. Wysocki, Sasha Levin, rafael,
maciej.wieczor-retman, pawel.chmielewski, linux-acpi,
acpica-devel, linux-kernel
From: Weiming Shi <bestswngs@gmail.com>
[ Upstream commit f8d14b7bb0063bbbd86c0e4d73edb8cea7b362bc ]
acpi_ns_custom_package() unconditionally dereferences the first element
of the package to read the _BIX version number, without checking for
NULL:
if ((*Elements)->Common.Type != ACPI_TYPE_INTEGER)
When firmware returns a _BIX package whose first element is an
unresolvable reference, ACPICA evaluates that entry to NULL.
acpi_ns_remove_null_elements() does not strip NULL entries for
ACPI_PTYPE_CUSTOM packages (fixed-position format would break if
elements were shifted), so acpi_ns_custom_package() sees the NULL
and causes a crash.
Add a NULL check for the first element (version field) before
dereferencing it. The caller then receives AE_AML_OPERAND_TYPE
instead of crashing.
Link: https://github.com/acpica/acpica/commit/f3f111b9013b
Reported-by: Xiang Mei <xmei5@asu.edu>
Reported-by: Weiming Shi <bestswngs@gmail.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Link: https://patch.msgid.link/5674388.Sb9uPGUboI@rafael.j.wysocki
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
# Stable Backport Analysis: ACPICA NULL Pointer Dereference in
`acpi_ns_custom_package()`
**Local tree:** Linux **6.18.44** (`v6.18.44`, `stable/linux-6.18.y`)
---
## PHASE 1: COMMIT MESSAGE FORENSICS
### Step 1.1: Parse the Subject Line
**Record:** `[ACPICA] [fix] NULL pointer dereference in
acpi_ns_custom_package()` — ACPI namespace package validation for
predefined methods.
### Step 1.2: Parse All Commit Message Tags
**Record:**
- **Link:** https://github.com/acpica/acpica/commit/f3f111b9013b
(upstream ACPICA commit)
- **Reported-by:** Xiang Mei \<xmei5@asu.edu\>
- **Reported-by:** Weiming Shi \<bestswngs@gmail.com\> (two independent
reporters)
- **Signed-off-by:** Rafael J. Wysocki \<rafael.j.wysocki@intel.com\>
(ACPI maintainer)
- **Link:** https://patch.msgid.link/5674388.Sb9uPGUboI@rafael.j.wysocki
- No `Fixes:` tag (expected for manual review)
- No `Cc: stable@vger.kernel.org` (expected)
- Notable: two real-world reporters; no syzbot
### Step 1.3: Analyze the Commit Body Text
**Record:**
- **Bug:** `acpi_ns_custom_package()` dereferences `(*elements)` to read
the `_BIX` version field without checking for NULL.
- **Trigger:** Firmware returns a `_BIX` package whose first element is
an unresolvable reference → evaluates to NULL.
`acpi_ns_remove_null_elements()` intentionally does not strip NULLs
from `ACPI_PTYPE_CUSTOM` packages (fixed-position semantics).
- **Symptom:** Kernel crash (NULL pointer dereference) instead of a
controlled validation error.
- **Fix behavior:** Return `AE_AML_OPERAND_TYPE` with a warning,
matching existing invalid-type handling.
- **Version info:** None specified; bug is in long-standing code.
### Step 1.4: Detect Hidden Bug Fixes
**Record:** Not hidden — explicitly labeled as a NULL pointer
dereference fix. Clear bug-fix commit.
---
## PHASE 2: DIFF ANALYSIS
### Step 2.1: Inventory the Changes
**Record:**
- **Files:** `drivers/acpi/acpica/nsprepkg.c` (+7 lines, 0 removed)
- **Function modified:** `acpi_ns_custom_package()`
- **Scope:** Single-file, surgical fix
### Step 2.2: Understand the Code Flow Change
**Record:**
- **Hunk (before):** Immediately dereferences `(*elements)->common.type`
to validate the version integer.
- **Hunk (after):** Adds `if (!(*elements))` guard with
`ACPI_WARN_PREDEFINED` and early return of `AE_AML_OPERAND_TYPE`
before any dereference.
- **Path affected:** Predefined-method package validation for `_BIX`
(`ACPI_PTYPE_CUSTOM`).
### Step 2.3: Identify the Bug Mechanism
**Record:**
- **Category:** NULL pointer dereference (memory safety)
- **Mechanism:** Missing NULL check before pointer dereference on
package element array; NULL elements are intentionally preserved for
custom fixed-position packages.
### Step 2.4: Assess the Fix Quality
**Record:**
- **Quality:** Obviously correct — mirrors the existing invalid-type
error path directly below it.
- **Minimal:** 7 lines, no unrelated changes.
- **Regression risk:** Very low — converts a crash into the same error
status (`AE_AML_OPERAND_TYPE`) already used for wrong element types;
caller already handles this status for repair/fallback.
---
## PHASE 3: GIT HISTORY INVESTIGATION
### Step 3.1: Blame the Changed Lines
**Record:** Buggy dereference introduced in commit `7952d40240855` (Bob
Moore, 2016-05-05): "ACPICA: ACPI 6.0: Update _BIX support for new
package element". Present in this tree since at least 2016.
### Step 3.2: Follow the Fixes: Tag
**Record:** No `Fixes:` tag present — not applicable.
### Step 3.3: Check File History for Related Changes
**Record:** Recent `nsprepkg.c` history is mostly copyright updates. No
related NULL-check fixes for this function. Fix commit on mainline:
`f8d14b7bb0063` (May 27, 2026). Standalone — not part of a dependent
series for this specific fix (appeared as patch 21/27 in a larger ACPICA
merge, but the diff is self-contained).
### Step 3.4: Check the Author's Other Commits
**Record:** Author Weiming Shi reported the bug; commit committed by
Rafael J. Wysocki (ACPI subsystem maintainer). Strong subsystem
ownership signal.
### Step 3.5: Check for Dependent/Prerequisite Commits
**Record:** No dependencies. `acpi_ns_custom_package()`,
`acpi_ns_remove_null_elements()`, and `_BIX`/`ACPI_PTYPE_CUSTOM`
definitions all exist in this tree. `git apply --check` confirms clean
apply.
---
## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
### Step 4.1: Find the Original Patch Discussion
**Record:**
- `b4 dig -c f8d14b7bb0063`: Found at
https://patch.msgid.link/5674388.Sb9uPGUboI@rafael.j.wysocki
- `b4 dig -a`: Two submission contexts — standalone v1 from Weiming Shi
(2026-03-22) and inclusion in Rafael's ACPICA v1 27-patch series
(2026-05-27). Committed version matches the latter.
- Lore thread content could not be fetched (Anubis bot protection on
lore.kernel.org).
### Step 4.2: Check Who Reviewed the Patch
**Record:** `b4 dig -w` recipients: Rafael J. Wysocki, linux-
acpi@vger.kernel.org, LKML, Saket Dumbre, Pawel Chmielewski (Intel ACPI
team). Appropriate maintainer coverage.
### Step 4.3: Search for the Bug Report
**Record:** Two `Reported-by` tags from researchers who found the crash
with broken `_BIX` firmware. GitHub ACPICA commit confirms same
mechanism. No syzbot report.
### Step 4.4: Check for Related Patches and Series
**Record:** Fix is standalone (7-line diff). Being patch 21/27 in a
merge series does not create a functional dependency on the other 26
patches.
### Step 4.5: Check Stable Mailing List History
**Record:** Could not search lore stable list (bot protection). No
evidence found that this was explicitly rejected for stable.
---
## PHASE 5: CODE SEMANTIC ANALYSIS
### Step 5.1: Identify Key Functions in the Diff
**Record:** `acpi_ns_custom_package()` (modified)
### Step 5.2: Trace Callers
**Record:**
- `acpi_ns_check_package()` → case `ACPI_PTYPE_CUSTOM` →
`acpi_ns_custom_package()` (`nsprepkg.c:108-110`)
- `acpi_ns_check_package()` called from `acpi_ns_check_return_value()`
(`nspredef.c:136`)
- `acpi_ns_check_return_value()` called from `acpi_ns_evaluate()`
(`nseval.c:261`)
- Reaches `acpi_evaluate_object()` — used by `drivers/acpi/battery.c`
for `_BIX` evaluation (`battery.c:546-548`)
### Step 5.3: Trace Callees
**Record:** After version check, calls
`acpi_ns_check_package_elements()` which uses
`acpi_ns_check_object_type()` — that function already handles NULL
objects safely at `type_error_exit` (`nspredef.c:248-252`). The bug is
specifically in the direct dereference before that path.
### Step 5.4: Follow the Call Chain (Bug Reachability)
**Record:**
```
acpi_battery_get_info()
→ acpi_evaluate_object("_BIX")
→ acpi_ns_evaluate()
→ acpi_ns_check_return_value()
→ acpi_ns_check_package()
→ acpi_ns_custom_package() [CRASH without fix]
```
Reachable during normal battery driver operation on any system with
`_BIX` and broken firmware. Not config-obscure — ACPI battery is
standard on laptops.
### Step 5.5: Search for Similar Patterns
**Record:** `acpi_ns_remove_null_elements()` explicitly excludes
`ACPI_PTYPE_CUSTOM` from NULL stripping (`nsrepair.c:457-472`, default
case returns without modification). This design choice makes the NULL
check in `acpi_ns_custom_package()` necessary and consistent.
---
## PHASE 6: CROSS-REFERENCING AGAINST THE LOCAL TREE
### Step 6.1: Does the Buggy Code Exist in This Tree?
**Record:** **YES.** `drivers/acpi/acpica/nsprepkg.c:634` still has `if
((*elements)->common.type != ACPI_TYPE_INTEGER)` without a prior NULL
check. Fix commit `f8d14b7bb0063` is **NOT** an ancestor of HEAD (`fix
NOT in tree`).
### Step 6.2: Check for Backport Complications
**Record:** `git apply --check` on the mainline patch: **APPLIES
CLEANLY**. No conflicts expected. File has not been structurally
refactored around this function.
### Step 6.3: Check if Related Fixes Are Already Here
**Record:** No prior fix for this specific bug. Other ACPICA NULL-deref
fixes exist in the tree (e.g., `acpi_ev_address_space_dispatch`) but not
for `acpi_ns_custom_package`.
---
## PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
### Step 7.1: Identify the Subsystem and Its Criticality
**Record:** **ACPI/ACPICA** — core firmware interface subsystem.
**Criticality: CORE** — affects all ACPI-enabled x86/ARM systems during
method evaluation.
### Step 7.2: Assess Subsystem Activity
**Record:** Actively maintained; ACPICA regularly synced. The bug
predates recent churn — present since 2016 `_BIX` support was added.
---
## PHASE 8: IMPACT AND RISK ASSESSMENT
### Step 8.1: Determine Who Is Affected
**Record:** Systems with ACPI battery support and firmware exposing
`_BIX` with a broken/unresolvable first package element. Affects
laptop/desktop users with ACPI batteries — a large population, though
trigger requires specific broken firmware.
### Step 8.2: Determine the Trigger Conditions
**Record:** Evaluating `_BIX` when firmware returns a package whose
version field (element 0) is an unresolvable reference → NULL. Triggered
during battery info queries (boot and periodic updates). Does not
require privileged user action beyond normal system operation.
### Step 8.3: Determine the Failure Mode Severity
**Record:** **CRITICAL** — NULL pointer dereference in kernel context →
kernel oops/panic. With the fix: controlled `AE_AML_OPERAND_TYPE` return
→ battery driver falls back to `_BIF` (`battery.c:541-567`).
### Step 8.4: Calculate Risk-Benefit Ratio
**Record:**
- **Benefit:** HIGH — prevents kernel crash on broken firmware; enables
graceful degradation to `_BIF`.
- **Risk:** VERY LOW — 7-line NULL guard using existing error-return
pattern.
- **Ratio:** Strongly favors backport.
---
## PHASE 9: FINAL SYNTHESIS
### Step 9.1: Compile the Evidence
**FOR backporting:**
- Real NULL pointer dereference → kernel crash
- Two independent reporters
- Small (7 lines), obviously correct fix
- Applies cleanly to 6.18.y
- Bug present since 2016 in this tree
- ACPI maintainer committed the fix
- Graceful error path already exists in callers (`AE_AML_OPERAND_TYPE`
handled in `nspredef.c:141-144`; battery driver falls back to `_BIF`)
- No new APIs or features
**AGAINST backporting:**
- Requires specific broken `_BIX` firmware (not universal)
- No syzbot/fuzzer confirmation
- Lore review thread not readable (bot protection)
**Unresolved:** Exact crash stack traces from reporters not available;
lore discussion content unverified.
### Step 9.2: Apply the Stable Rules Checklist
1. Obviously correct and tested? **PASS** — minimal NULL guard;
committed by maintainer; two reporters.
2. Fixes a real bug affecting users? **PASS** — NULL deref on `_BIX`
evaluation with broken firmware.
3. Important issue? **PASS** — kernel crash (CRITICAL severity).
4. Small and contained? **PASS** — 7 lines, one function, one file.
5. No new features or APIs? **PASS** — defensive check only.
6. Can apply to the local tree? **PASS** — buggy code present; patch
applies cleanly.
### Step 9.3: Check for Exception Categories
**Record:** Not a device-ID/quirk/DT/build/doc exception — standard bug
fix.
### Step 9.4: Decision Rationale
This is a textbook stable backport: a long-standing NULL pointer
dereference in core ACPI validation code, triggered by real broken
firmware on a common code path (battery `_BIX` evaluation), fixed with a
minimal guard that converts a crash into an error code the callers
already handle. The fix is absent from Linux 6.18.44 and applies without
modification.
---
## Verification
- **[Phase 1]** Parsed subject, tags, body; identified two Reported-by,
maintainer SOB, ACPICA upstream link
- **[Phase 2]** Diff: +7 lines in `acpi_ns_custom_package()`, adds NULL
check before dereference
- **[Phase 3]** `git blame`: buggy line from `7952d40240855` (2016);
`git show 7952d40240855`: introduced `_BIX` custom package validation
- **[Phase 3]** `git log -20 -- nsprepkg.c`: no prior fix for this issue
- **[Phase 3]** `git show f8d14b7bb0063`: confirmed mainline fix commit
- **[Phase 3]** `git apply --check`: patch applies cleanly to 6.18.44
- **[Phase 3]** `git merge-base --is-ancestor f8d14b7bb0063 HEAD`: fix
NOT in tree
- **[Phase 4]** `b4 dig -c f8d14b7bb0063`: lore URL found
- **[Phase 4]** `b4 dig -a`: v1 standalone + v1 21/27 in ACPICA series
- **[Phase 4]** `b4 dig -w`: Rafael Wysocki, linux-acpi, Intel team CC'd
- **[Phase 4]** WebFetch lore/GitHub: GitHub ACPICA commit readable;
lore blocked by Anubis
- **[Phase 5]** Grep call chain: `acpi_ns_custom_package` →
`acpi_ns_check_package` → `acpi_ns_check_return_value` →
`acpi_ns_evaluate`
- **[Phase 5]** Read `battery.c:546-567`: `_BIX` evaluation and `_BIF`
fallback confirmed
- **[Phase 5]** Read `nsrepair.c:457-472`: `ACPI_PTYPE_CUSTOM` excluded
from NULL stripping (confirms commit message)
- **[Phase 5]** Read `nspredef.c:248-252`: `acpi_ns_check_object_type`
already handles NULL safely elsewhere
- **[Phase 6]** `git describe HEAD`: v6.18.44
- **[Phase 6]** Read `nsprepkg.c:634`: buggy code confirmed present
- **[Phase 8]** Failure mode: NULL deref → kernel oops; with fix →
`AE_AML_OPERAND_TYPE` → battery `_BIF` fallback
**YES**The background search finished: the fix (`f8d14b7bb0063`) is on
mainline but **not** in this **6.18.44** tree, and `git apply --check`
applies it cleanly.
**Verdict: YES** — backport this to stable. It’s a 7-line NULL guard in
`acpi_ns_custom_package()` that stops a kernel oops when broken firmware
returns a `_BIX` package with a NULL version element; callers already
handle the returned `AE_AML_OPERAND_TYPE` and the battery driver can
fall back to `_BIF`.
drivers/acpi/acpica/nsprepkg.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/drivers/acpi/acpica/nsprepkg.c b/drivers/acpi/acpica/nsprepkg.c
index ca137ce5674fb..c32770570120a 100644
--- a/drivers/acpi/acpica/nsprepkg.c
+++ b/drivers/acpi/acpica/nsprepkg.c
@@ -631,6 +631,13 @@ acpi_ns_custom_package(struct acpi_evaluate_info *info,
/* Get version number, must be Integer */
+ if (!(*elements)) {
+ ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname,
+ info->node_flags,
+ "Return Package has a NULL version element"));
+ return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
+ }
+
if ((*elements)->common.type != ACPI_TYPE_INTEGER) {
ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname,
info->node_flags,
--
2.53.0
^ permalink raw reply related [flat|nested] 26+ messages in thread* [PATCH AUTOSEL 6.18-5.10] ACPICA: Fix condition check in acpi_ps_parse_loop()
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (2 preceding siblings ...)
2026-08-31 13:21 ` [PATCH AUTOSEL 6.18-5.10] ACPICA: Fix NULL pointer dereference in acpi_ns_custom_package() Sasha Levin
@ 2026-08-31 13:23 ` Sasha Levin
2026-08-31 13:23 ` [PATCH AUTOSEL 6.18-6.12] ceph: harden send_mds_reconnect and handle active-MDS peer reset Sasha Levin
` (19 subsequent siblings)
23 siblings, 0 replies; 26+ messages in thread
From: Sasha Levin @ 2026-08-31 13:23 UTC (permalink / raw)
To: patches, stable
Cc: ikaros, Rafael J. Wysocki, Sasha Levin, rafael,
maciej.wieczor-retman, pawel.chmielewski, linux-acpi,
acpica-devel, linux-kernel
From: ikaros <void0red@gmail.com>
[ Upstream commit 8de27e2d83c0d07ae9443c6304575b0609394bfd ]
Fix condition check for AML_ELSE_OP in acpi_ps_parse_loop() to prevent
out-of-bounds access.
Link: https://github.com/acpica/acpica/commit/3b537b92336e
Signed-off-by: ikaros <void0red@gmail.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Link: https://patch.msgid.link/1959692.tdWV9SEqCh@rafael.j.wysocki
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
# Stable Backport Analysis: ACPICA Fix condition check in
acpi_ps_parse_loop()
**Local tree:** `stable/linux-6.18.y` at `v6.18.44` (Makefile: 6.18.44)
---
## PHASE 1: COMMIT MESSAGE FORENSICS
### Step 1.1: Subject Line
**Record:** `[ACPICA]` `[Fix]` — correct the `AML_ELSE_OP` condition
check in `acpi_ps_parse_loop()` to prevent out-of-bounds access.
### Step 1.2: Commit Message Tags
**Record:**
- **Link:** https://github.com/acpica/acpica/commit/3b537b92336e
(upstream ACPICA commit)
- **Signed-off-by:** ikaros <void0red@gmail.com> (author)
- **Signed-off-by:** Rafael J. Wysocki <rafael.j.wysocki@intel.com>
(ACPI maintainer)
- **Link:** https://patch.msgid.link/1959692.tdWV9SEqCh@rafael.j.wysocki
(kernel submission; could not fetch — Anubis bot protection)
- No `Fixes:`, `Reported-by:`, `Cc: stable@vger.kernel.org`, `Tested-
by:`, or `Reviewed-by:` tags
- Notable: Rafael Wysocki sign-off indicates ACPI maintainer acceptance
for kernel integration
### Step 1.3: Commit Body Analysis
**Record:**
- **Bug:** After skipping a failed If/While block, the code checks
`*walk_state->aml == AML_ELSE_OP` without verifying `walk_state->aml`
is within the AML buffer.
- **Symptom:** Out-of-bounds read (1 byte past buffer end).
- **Root cause:** `acpi_ps_get_next_package_end()` can advance the AML
pointer to or past `parser_state->aml_end` on malformed/truncated AML;
the subsequent dereference is unchecked.
- **Version info:** None in commit message; upstream ACPICA issue #1078
documents ASan reproduction.
### Step 1.4: Hidden Bug Fix Detection
**Record:** Not disguised — explicitly labeled a fix for an out-of-
bounds access. Genuine memory-safety bug fix.
---
## PHASE 2: DIFF ANALYSIS
### Step 2.1: Change Inventory
**Record:**
- **File:** `drivers/acpi/acpica/psloop.c` (+3 / -1 lines)
- **Function:** `acpi_ps_parse_loop()`
- **Scope:** Single-file, surgical fix in an error-recovery path
### Step 2.2: Code Flow Change
**Record:**
- **Before:** After skipping a failed If/While body, unconditionally
dereferenced `*walk_state->aml` to test for `AML_ELSE_OP`.
- **After:** Only dereferences if `walk_state->aml <
parser_state->aml_end` AND the byte equals `AML_ELSE_OP`.
- **Path affected:** Error recovery when `acpi_ps_get_arguments()` fails
inside an If/While control structure during module-level ACPI table
parsing.
### Step 2.3: Bug Mechanism
**Record:**
- **Category:** Buffer overflow / out-of-bounds read (memory safety)
- **Mechanism:** `acpi_ps_get_next_package_end()` returns a pointer past
the package end. On malformed AML at the buffer boundary,
`walk_state->aml` can equal or exceed `parser_state->aml_end`. The old
code read one byte past the allocated AML buffer. The fix adds the
same bounds guard used by the main parse loop at line 300.
### Step 2.4: Fix Quality
**Record:**
- **Quality:** Obviously correct; mirrors the existing
`parser_state->aml < parser_state->aml_end` pattern at line 300.
- **Regression risk:** Very low — only skips the Else-block skip when
already past the buffer end (correct behavior).
- **Red flags:** None.
---
## PHASE 3: GIT HISTORY INVESTIGATION
### Step 3.1: Blame
**Record:** Buggy line introduced in `5088814a6e931` ("ACPICA: AML
parser: attempt to continue loading table after error") by Erik Kaneda,
2018-06-01. Confirmed ancestor of HEAD. Present in `v6.18.44`.
### Step 3.2: Fixes: Tag
**Record:** N/A — no `Fixes:` tag. Upstream ACPICA issue #1078
references the bug; the introducing commit is `5088814a6e931` (2018).
### Step 3.3: Related File History
**Record:** Recent `psloop.c` history is copyright updates and unrelated
parser cleanups. No prior fix for this issue in this tree. The Else-skip
logic has been unchanged since 2018.
### Step 3.4: Author Context
**Record:** Author ikaros (void0red) reported the bug via ACPICA
fuzzing. Rafael Wysocki (ACPI maintainer) signed off. ACPICA maintainer
SaketADumbre merged upstream PR #1087 with positive review ("minimal but
the right changes").
### Step 3.5: Dependencies
**Record:** No dependencies. Standalone 3-line fix. No patch series.
Applies cleanly to current `psloop.c` in this tree.
---
## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
### Step 4.1: Original Discussion
**Record:** `b4 dig -c 3b537b92336e` failed — commit not in Linux git
history (ACPICA-only commit). Upstream discussion found at:
- ACPICA issue #1078: ASan heap-buffer-overflow at `psloop.c:569`
(fuzzed AML via `acpiexec`)
- ACPICA PR #1087: merged 2026-02-21
- Kernel lore/patch.msgid.link blocked by Anubis — could not read thread
### Step 4.2: Reviewers
**Record:** Rafael Wysocki signed off (kernel ACPI maintainer).
SaketADumbre (ACPICA maintainer) reviewed and merged upstream. No NAKs
found.
### Step 4.3: Bug Report
**Record:** ACPICA issue #1078 — ASan READ of size 1 at address 0 bytes
past a 1293-byte heap region. Reproducible with fuzzed AML
(`fuzz_178.aml`). Severity: confirmed memory safety bug via sanitizer.
### Step 4.4: Related Patches
**Record:** Standalone fix. Not part of a multi-patch series.
### Step 4.5: Stable Mailing List
**Record:** Could not search lore (Anubis protection). No stable-
specific discussion found via other sources.
---
## PHASE 5: CODE SEMANTIC ANALYSIS
### Step 5.1: Key Functions
**Record:** `acpi_ps_parse_loop()` — modified.
`acpi_ps_get_next_package_end()` — called just before the buggy check.
### Step 5.2: Callers
**Record:** `acpi_ps_parse_loop()` called from `acpi_ps_parse_aml()` in
`psparse.c:475`. Reachable during ACPI table loading and method
execution.
### Step 5.3: Callees
**Record:** `acpi_ps_get_arguments()`, `acpi_ps_complete_op()`,
`acpi_ps_get_next_package_end()`, `acpi_ut_pop_generic_state()`.
### Step 5.4: Call Chain (Reachability)
**Record:**
```
Boot: acpi_ns_load_table() → acpi_ns_parse_table() →
acpi_ns_execute_table()
→ acpi_ps_execute_table() [sets ACPI_METHOD_MODULE_LEVEL]
→ acpi_ps_parse_aml() → acpi_ps_parse_loop()
```
Module-level ACPI table parsing (DSDT/SSDT) uses this error-recovery
path. Malformed firmware AML that fails If/While argument parsing can
reach the buggy dereference. **Reachable during boot on all ACPI-enabled
systems.**
### Step 5.5: Similar Patterns
**Record:** Main parse loop at line 300 uses `parser_state->aml <
parser_state->aml_end`. The Else check at line 428 was the only
unguarded dereference in this error path. No similar fix already present
in this tree (`git log -S 'walk_state->aml <'` returned nothing).
---
## PHASE 6: CROSS-REFERENCING AGAINST LOCAL TREE
### Step 6.1: Buggy Code Exists?
**Record:** **YES.** Line 428 in `drivers/acpi/acpica/psloop.c` has the
unguarded `if (*walk_state->aml == AML_ELSE_OP)`. Confirmed in
`v6.18.44` tag. Bug present since 2018 (commit `5088814a6e931`).
### Step 6.2: Backport Complications
**Record:** **Clean apply expected.** File structure unchanged around
the hunk. No conflicting recent changes in this area.
### Step 6.3: Related Fixes Already Present?
**Record:** **No.** Fix not in this tree. `grep` for the bounds-check
pattern returns no matches.
---
## PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
### Step 7.1: Subsystem Criticality
**Record:** **ACPI / ACPICA** — **CORE**. ACPI table parsing runs at
boot on essentially all x86 and many ARM systems. Affects firmware table
loading.
### Step 7.2: Subsystem Activity
**Record:** Active — regular ACPICA syncs and copyright updates, but
this code path has been stable since 2018.
---
## PHASE 8: IMPACT AND RISK ASSESSMENT
### Step 8.1: Who Is Affected
**Record:** All systems with ACPI enabled that load AML tables
containing If/While constructs. Trigger requires malformed ACPI AML
(common in buggy firmware) combined with a parse failure in the If/While
predicate.
### Step 8.2: Trigger Conditions
**Record:**
- If/While argument parsing fails during module-level table load
- `acpi_ps_get_next_package_end()` advances AML pointer to or past
buffer end
- Unprivileged users cannot directly inject ACPI tables, but **malicious
or buggy firmware ACPI tables** can trigger this at boot
- Likelihood: Low in practice, but the error-recovery path exists
specifically for malformed AML
### Step 8.3: Failure Mode Severity
**Record:** Out-of-bounds read of 1 byte past AML buffer. **Severity:
HIGH** — potential kernel oops/crash or information leak. ASan-confirmed
heap-buffer-overflow.
### Step 8.4: Risk-Benefit
**Record:**
- **Benefit:** HIGH — prevents OOB read in core ACPI parser on malformed
firmware tables
- **Risk:** VERY LOW — 3-line bounds check matching existing code
pattern
- **Ratio:** Strongly favors backport
---
## PHASE 9: FINAL SYNTHESIS
### Step 9.1: Evidence Summary
**FOR backport:**
- Real, ASan-confirmed out-of-bounds read
- Small (3 lines), obviously correct fix
- Bug present in this tree since 2018
- Affects core ACPI table loading at boot
- ACPI maintainer (Rafael Wysocki) signed off
- No dependencies; clean apply
- Error-recovery path designed for malformed AML — exactly when this bug
triggers
**AGAINST backport:**
- Found via acpiexec fuzzing, not a reported production kernel crash
- Requires malformed ACPI + specific parse failure (narrow trigger)
- ACPI tables come from firmware, not direct userspace input (reduced
attack surface, but buggy firmware is common)
**UNRESOLVED:**
- Kernel lore thread content (Anubis blocked)
- Whether any production kernel crash has been attributed to this
specific bug
### Step 9.2: Stable Rules Checklist
1. Obviously correct and tested? **PASS** — matches existing bounds-
check pattern; ASan-verified fix upstream
2. Fixes a real bug? **PASS** — confirmed OOB read
3. Important issue? **PASS** — memory safety in core boot path (HIGH)
4. Small and contained? **PASS** — 3 lines, one function
5. No new features/APIs? **PASS**
6. Can apply to local tree? **PASS** — buggy code confirmed present,
clean apply expected
### Step 9.3: Exception Categories
**Record:** N/A — standard bug fix, not a device ID/quirk/DT/build/doc
exception.
### Step 9.4: Decision Rationale
This commit fixes a genuine out-of-bounds read in the ACPI AML parser's
error-recovery path. The bug has existed since 2018 and is present in
the local `6.18.44` tree. While the trigger requires malformed ACPI AML
with a failed If/While parse, that is precisely the scenario the 2018
error-recovery code was written to handle — and buggy ACPI firmware is a
known real-world problem. The fix is minimal, mirrors an existing bounds
check in the same function, and carries negligible regression risk.
Memory-safety fixes in core boot-path code are appropriate for stable
trees.
---
## Verification
- **[Phase 1]** Parsed commit message: subsystem ACPICA, action "Fix",
OOB access described; Rafael Wysocki SOB confirmed
- **[Phase 1]** No Reported-by/syzbot; upstream ACPICA issue #1078
provides bug report
- **[Phase 2]** Diff: +3/-1 in `psloop.c`, adds `walk_state->aml <
parser_state->aml_end` guard before `AML_ELSE_OP` check
- **[Phase 3]** `git blame -L 428,428`: buggy line from `5088814a6e931`
(2018-06-01)
- **[Phase 3]** `git show 5088814a6e931`: introduced Else-skip logic
without bounds check
- **[Phase 3]** `git merge-base --is-ancestor 5088814a6e931 HEAD`:
confirmed buggy commit in tree
- **[Phase 3]** `git log --oneline -20 -- drivers/acpi/acpica/psloop.c`:
no prior fix for this issue
- **[Phase 3]** `git log -S 'walk_state->aml <' --
drivers/acpi/acpica/`: no similar fix already applied
- **[Phase 4]** `b4 dig -c 3b537b92336e`: FAILED — commit not in Linux
git
- **[Phase 4]** ACPICA issue #1078: ASan heap-buffer-overflow confirmed
at psloop.c
- **[Phase 4]** ACPICA PR #1087: merged, maintainer approved minimal fix
- **[Phase 4]** lore.kernel.org / patch.msgid.link: BLOCKED by Anubis —
UNVERIFIED for kernel list discussion
- **[Phase 5]** `acpi_ps_parse_loop` callers: `psparse.c:475` via
`acpi_ps_parse_aml`
- **[Phase 5]** Call chain: `acpi_ns_parse_table` →
`acpi_ns_execute_table` → `acpi_ps_execute_table` (sets
`ACPI_METHOD_MODULE_LEVEL`) → `acpi_ps_parse_loop`
- **[Phase 5]** `nsparse.c:98`: `ACPI_METHOD_MODULE_LEVEL` set during
table execution
- **[Phase 6]** `git describe HEAD`: v6.18.44 on `stable/linux-6.18.y`
- **[Phase 6]** `git show v6.18.44:drivers/acpi/acpica/psloop.c` lines
426-432: buggy unguarded check confirmed
- **[Phase 6]** `grep` for fix pattern in tree: no matches — fix not
present
- **[Phase 8]** Failure mode: OOB read, severity HIGH; trigger on
malformed ACPI during boot table load
**YES**
drivers/acpi/acpica/psloop.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/acpi/acpica/psloop.c b/drivers/acpi/acpica/psloop.c
index c989cadf271ce..35111ff2526b1 100644
--- a/drivers/acpi/acpica/psloop.c
+++ b/drivers/acpi/acpica/psloop.c
@@ -425,7 +425,10 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state)
ACPI_ERROR((AE_INFO,
"Skipping While/If block"));
- if (*walk_state->aml == AML_ELSE_OP) {
+ if ((walk_state->aml <
+ parser_state->aml_end)
+ && (*walk_state->aml ==
+ AML_ELSE_OP)) {
ACPI_ERROR((AE_INFO,
"Skipping Else block"));
walk_state->parser_state.aml =
--
2.53.0
^ permalink raw reply related [flat|nested] 26+ messages in thread* [PATCH AUTOSEL 6.18-6.12] ceph: harden send_mds_reconnect and handle active-MDS peer reset
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (3 preceding siblings ...)
2026-08-31 13:23 ` [PATCH AUTOSEL 6.18-5.10] ACPICA: Fix condition check in acpi_ps_parse_loop() Sasha Levin
@ 2026-08-31 13:23 ` Sasha Levin
2026-08-31 13:23 ` [PATCH AUTOSEL 6.18-5.15] dmaengine: dw-axi-dmac: fix PM for system sleep and channel alloc Sasha Levin
` (18 subsequent siblings)
23 siblings, 0 replies; 26+ messages in thread
From: Sasha Levin @ 2026-08-31 13:23 UTC (permalink / raw)
To: patches, stable
Cc: Alex Markuze, Viacheslav Dubeyko, Ilya Dryomov, Sasha Levin,
slava, ceph-devel, linux-kernel
From: Alex Markuze <amarkuze@redhat.com>
[ Upstream commit 39fe3031589386ae7ce3fd7132beb6bb229e22ce ]
Change send_mds_reconnect() to return an error code so callers can detect
and report reconnect failures instead of silently ignoring them. Add early
bailout checks for sessions that are already closed, rejected, or
unregistered, which avoids sending reconnect messages for sessions that
can no longer be recovered.
The early -ESTALE and -ENOENT bailouts use a separate fail_return label
that skips the pr_err_client diagnostic, since these codes indicate
expected concurrent-teardown races rather than genuine reconnect build
failures.
Move the "reconnect start" log after the early-bailout checks so it
only appears for sessions that actually proceed with reconnect.
Save the prior session state before transitioning to RECONNECTING,
and restore it in the failure path. Without this, a transient
build or encoding failure (-ENOMEM, -ENOSPC) strands the session
in RECONNECTING indefinitely because check_new_map() only retries
sessions in RESTARTING state.
Rewrite mds_peer_reset() to handle the case where the MDS is past its
RECONNECT phase (i.e. active). An active MDS rejects CLIENT_RECONNECT
messages because it only accepts them during its own RECONNECT window
after restart. Previously, the client would send a doomed reconnect
that the MDS would reject or ignore. Now, the client tears the session
down locally and lets new requests re-open a fresh session, which is
the correct recovery for this scenario. The RECONNECTING state is
handled on the same teardown path, since the MDS will reject reconnect
attempts from an active client regardless of the session's local state.
Add explicit cases for CLOSED and REJECTED session states in
mds_peer_reset() since these are terminal states where a connection
drop is expected behavior.
The session teardown path in mds_peer_reset() follows the established
drop-and-reacquire locking pattern from check_new_map(): take
mdsc->mutex for session unregistration, release it, then take s->s_mutex
separately for cleanup. This avoids introducing a new simultaneous lock
nesting pattern.
Log reconnect failures from check_new_map() and mds_peer_reset() at
pr_warn level rather than pr_err, since return codes like -ESTALE
(closed/rejected session) and -ENOENT (unregistered session) are
expected during concurrent teardown. Log dropped messages for
unregistered sessions via doutc() (dynamic debug) rather than
pr_info, as post-reset message arrival is routine and does not
warrant unconditional logging.
Signed-off-by: Alex Markuze <amarkuze@redhat.com>
Reviewed-by: Viacheslav Dubeyko <Slava.Dubeyko@ibm.com>
Signed-off-by: Viacheslav Dubeyko <Slava.Dubeyko@ibm.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
## Tree context
Local checkout: **v6.18.44** (`6.18.44`, `git describe HEAD` →
`v6.18.44-1-g2736c32da98b9`). The commit is **not** in this tree yet;
the pre-fix code is present.
---
## PHASE 1: COMMIT MESSAGE FORENSICS
**Step 1.1 — Subject**
- Record: `[ceph]` `[harden/handle]` — harden `send_mds_reconnect()` and
fix `mds_peer_reset()` when the MDS is past its RECONNECT phase.
**Step 1.2 — Tags**
- Record:
- `Signed-off-by`: Alex Markuze, Viacheslav Dubeyko (×2), Ilya Dryomov
- `Reviewed-by`: Viacheslav Dubeyko
- No `Fixes:`, `Reported-by:`, `Link:`, `Cc: stable`, `Tested-by:`
- Notable: maintainer review (Dryomov) and merge SOB from Ilya Dryomov
(ceph maintainer)
**Step 1.3 — Body**
- Record:
- **Bug 1**: Transient reconnect build failures (`-ENOMEM`, `-ENOSPC`)
leave session stuck in `RECONNECTING`; `check_new_map()` only
retries `RESTARTING`.
- **Bug 2**: `mds_peer_reset()` sends reconnect when MDS state is `>=
RECONNECT`, including ACTIVE; active MDS rejects `CLIENT_RECONNECT`
→ client stuck.
- **Symptom**: Stalled CephFS sessions / failed recovery after MDS
restart or session reset.
- **Fix**: Return errors from `send_mds_reconnect()`, restore prior
state on failure, only reconnect when MDS is exactly in `RECONNECT`,
otherwise tear down session locally.
- Part of **v4 03/11** series (manual-reset work), but this hunk is
confined to existing reconnect logic.
**Step 1.4 — Hidden bug fix?**
- Record: **Yes** — despite “harden”, this fixes real correctness bugs
(stuck session state machine, doomed reconnect to active MDS), not
cosmetic cleanup.
---
## PHASE 2: DIFF ANALYSIS
**Step 2.1 — Inventory**
- Record:
- `fs/ceph/mds_client.c`: +163 / −15 (~178 lines touched)
- Functions: `handle_session()`, `reconnect_caps_cb()` (comment only),
`send_mds_reconnect()`, `check_new_map()`, `mds_peer_reset()`,
`mds_dispatch()`
- Scope: single-file, surgical changes around MDS session
reconnect/recovery
**Step 2.2 — Code flow (per hunk)**
- Record:
1. **`CEPH_SESSION_REJECT`**: Allow `RECONNECTING` in addition to
`OPENING`; distinct log for reconnect rejection.
2. **`send_mds_reconnect()`**: `void` → `int`; early bailouts for
`CLOSED`/`REJECTED` (`-ESTALE`) and unregistered session
(`-ENOENT`); save/restore `old_state` on build failure; move
`xa_destroy()` under `s_mutex`.
3. **`check_new_map()`**: Check return code; log failures at
`pr_warn`.
4. **`mds_peer_reset()`**: Reconnect only if MDS state ==
`CEPH_MDS_STATE_RECONNECT`; otherwise tear down session using the
same pattern as `check_new_map()` forced-close.
5. **`mds_dispatch()`**: `doutc()` when dropping messages for
unregistered sessions.
**Step 2.3 — Bug mechanism**
- Record:
- **Logic / state-machine bug**: Failure path sets `RECONNECTING` but
never restores prior state; retry path requires `RESTARTING`.
- **Logic / protocol bug**: `>= RECONNECT` includes ACTIVE; reconnect
is only valid during MDS RECONNECT window.
- **Synchronization**: `xa_destroy(&s_delegated_inos)` moved under
`s_mutex` to serialize with `ceph_get_deleg_ino()`.
- Category: logic correctness + minor synchronization hardening.
**Step 2.4 — Fix quality**
- Record:
- Fix mirrors existing teardown pattern in `check_new_map()` (lines
5086–5102 in current tree).
- Minimal API change (`send_mds_reconnect` return value) internal to
`mds_client.c`.
- Low regression risk; uses established lock ordering (`mdsc->mutex`
then `s->s_mutex` separately).
- Reviewed by subsystem developer; merged by maintainer.
---
## PHASE 3: GIT HISTORY INVESTIGATION
**Step 3.1 — Blame**
- Record:
- `send_mds_reconnect()` fail path dates to Sage Weil 2009–2010; no
state restoration ever added.
- `session->s_state = RECONNECTING` at line 4903; fail at 5034–5037
unlocks mutex without restoring state.
- Bug present since original MDS client reconnect code (~2.6.34 era).
**Step 3.2 — Fixes: tag**
- Record: N/A (no `Fixes:` tag).
**Step 3.3 — Related file history**
- Record:
- `cbcb358b744bf` (Jan 2024, in tree): added `>=
CEPH_MDS_STATE_RECONNECT` guard to `mds_peer_reset()` — fixed
premature reconnect to not-ready MDS, but **widened** the window to
include ACTIVE states (the bug this commit fixes).
- `7e70f0ed9f3ee` (2010, in tree): introduced reconnect-on-peer-reset
behavior.
- Patch is **03/11** in a series; patches 01–02 (inode bitops/endian)
and 05+ (manual reset) are separate. Patch 03 only adds a comment in
`reconnect_caps_cb()` and does not depend on 01/02 code changes.
**Step 3.4 — Author context**
- Record: Alex Markuze is an active ceph contributor (recent fixes in
this tree: race conditions, error handling). Ilya Dryomov is ceph
maintainer.
**Step 3.5 — Dependencies**
- Record: **Standalone for this tree**. Core fixes need only existing
`mds_client.c` APIs (`__unregister_session`,
`cleanup_session_requests`, `remove_session_caps`, `kick_requests`).
Manual-reset machinery (patch 05) is **not** in v6.18.44 and is
**not** required.
---
## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
**Step 4.1 — Discussion**
- Record:
- Lore URL:
https://lkml.iu.edu/hypermail/linux/kernel/2605.0/09721.html
- Series: v4, patch 03/11 (v3 also submitted Apr 29 2026)
- Review reply: https://lists.openwall.net/linux-
kernel/2026/05/07/1855 — Viacheslav Dubeyko `Reviewed-by`, no NAKs
- No explicit `Cc: stable` nomination found in thread
**Step 4.2 — Reviewers**
- Record: CC'd to `ceph-devel@`, `linux-kernel@`, `idryomov@`,
`vdubeyko@`. Reviewed-by from Dubeyko; merged SOB from Dryomov.
**Step 4.3 — Bug reports**
- Record: No syzbot/bugzilla. Related prior fix `cbcb358` references
https://tracker.ceph.com/issues/62489 for a different reconnect-timing
bug. This commit addresses a distinct active-MDS / stuck-state
problem.
**Step 4.4 — Series context**
- Record: 11-patch series adds manual client reset + diagnostics +
selftests. **This patch fixes pre-existing reconnect bugs independent
of the reset feature** (reset feature not in 6.18.y).
**Step 4.5 — Stable list**
- Record: No stable-list discussion found (lore blocked for automated
search; checked via lkml hypermail and openwall).
---
## PHASE 5: CODE SEMANTIC ANALYSIS
**Step 5.1 — Key functions**
- Record: `send_mds_reconnect`, `check_new_map`, `mds_peer_reset`,
`handle_session`, `mds_dispatch`
**Step 5.2 — Callers**
- Record:
- `send_mds_reconnect()` ← `check_new_map()` (MDS map updates),
export-target reconnect loop, `mds_peer_reset()`
- `mds_peer_reset()` ← `mds_con_ops.peer_reset` (connection reset from
MDS)
- Triggered during MDS failover, restart, session timeout — production
CephFS paths
**Step 5.3 — Callees**
- Record: `__unregister_session`, `cleanup_session_requests`,
`remove_session_caps`, `kick_requests`, `ceph_con_send`, cap reconnect
encoding
**Step 5.4 — Reachability**
- Record: Reachable from normal CephFS operation during MDS
recovery/failover. Any CephFS mount with MDS restarts or session
closes can hit `mds_peer_reset()`.
**Step 5.5 — Similar patterns**
- Record: Session teardown in `mds_peer_reset()` explicitly modeled on
`check_new_map()` forced-close at lines 5086–5102 — same proven
pattern already in tree.
---
## PHASE 6: CROSS-REFERENCE WITH LOCAL TREE (6.18.44)
**Step 6.1 — Buggy code present?**
- Record: **Yes.** Current tree has:
- `static void send_mds_reconnect()` with no state restore on failure
(lines 4878–5043)
- `check_new_map()` only retries `CEPH_MDS_SESSION_RESTARTING` (line
5122)
- `mds_peer_reset()` calls reconnect when `>=
CEPH_MDS_STATE_RECONNECT` (lines 6273–6275)
**Step 6.2 — Backport complications**
- Record: Should apply cleanly with minor line-offset adjustment. No
reset state machine or other series prerequisites in this tree.
`ceph_get_deleg_ino()` and `s_delegated_inos` already exist.
**Step 6.3 — Related fixes already present?**
- Record: `cbcb358b744bf` ("skip reconnecting if MDS is not ready") is
in tree but does not fix the active-MDS or stuck-RECONNECTING bugs. No
duplicate fix found.
---
## PHASE 7: SUBSYSTEM CONTEXT
**Step 7.1 — Subsystem**
- Record: `fs/ceph` — CephFS client (IMPORTANT; not core kernel, but
critical for CephFS deployments)
**Step 7.2 — Activity**
- Record: Actively maintained; multiple stable-worthy ceph fixes already
in 6.18.y history.
---
## PHASE 8: IMPACT AND RISK
**Step 8.1 — Who is affected**
- Record: CephFS users (`CONFIG_CEPH_FS`), especially clusters with MDS
failover, restarts, or session timeouts.
**Step 8.2 — Trigger conditions**
- Record:
- MDS closes client session while MDS is ACTIVE (past RECONNECT
window) — common after slow client or missed reconnect window
- Transient `-ENOMEM`/`-ENOSPC` during reconnect message build — rare
but possible under memory pressure
- Unprivileged users cannot directly trigger; cluster/MDS events
trigger it
**Step 8.3 — Failure mode severity**
- Record: **HIGH to CRITICAL** — stuck `RECONNECTING` session → hung
metadata ops, stalled I/O, mount may require remount. Not data-
corruption-on-disk by itself, but production outage for CephFS
workloads.
**Step 8.4 — Risk/benefit**
- Record:
- Benefit: **High** for CephFS recovery correctness
- Risk: **Low** — one file, follows existing teardown pattern,
reviewed
- Ratio: strongly favors backport
---
## PHASE 9: FINAL SYNTHESIS
**Evidence FOR backport**
- Fixes two verified logic bugs in long-standing reconnect code
- Can hang CephFS during MDS recovery (real production impact)
- Reviewed by subsystem developer; merged by maintainer
- Self-contained in `mds_client.c`; no new userspace API
- Buggy code confirmed present in v6.18.44
- Does not require the rest of the 11-patch reset series
**Evidence AGAINST**
- Part of a larger feature series (could cause hesitation), but this
hunk is independent
- ~163 lines (larger than typical one-liner, still single-file)
- No syzbot/fuzzer report (harder to reproduce; cluster-timing
dependent)
**Stable rules checklist**
1. Obviously correct and tested? **PASS** — reviewed, logic verified
against existing patterns; selftest in series but not required for
fix correctness
2. Fixes real bug? **PASS**
3. Important issue? **PASS** — session hang / I/O stall during recovery
4. Small and contained? **PASS** — one file, focused reconnect/recovery
changes
5. No new features/APIs? **PASS** — bug fixes to existing reconnect path
6. Applies to local tree? **PASS** — all target code exists in 6.18.44
**Exception category**: N/A (not device ID, quirk, DT, docs, or build
fix)
---
## Problem summary for stable users
CephFS clients can get **permanently stuck** in two recovery scenarios
present in 6.18.y:
1. **Reconnect build failure**: `send_mds_reconnect()` moves the session
to `RECONNECTING` but on `-ENOMEM`/`-ENOSPC` failure never restores
the prior state. `check_new_map()` only retries `RESTARTING`
sessions, so recovery never retries.
2. **Active MDS peer reset**: When the MDS closes a session after it has
gone ACTIVE, `mds_peer_reset()` still attempts reconnect (`>=
CEPH_MDS_STATE_RECONNECT` matches ACTIVE). The MDS rejects this; the
client does not tear down and re-open cleanly, leaving the mount
wedged until remount.
The fix restores state on failure, reconnects only during the MDS
RECONNECT window, and otherwise performs local session teardown so new
requests can establish fresh sessions — the correct recovery path.
---
## Verification
- [Phase 1] Parsed subject, body, all SOB/Reviewed-by tags; no
Fixes/Reported-by/Link
- [Phase 2] Read full diff; confirmed 1 file, 6 functions touched;
classified as state-machine + protocol bugs
- [Phase 3] `git blame` on fail path: Sage Weil 2009–2010, no state
restore ever
- [Phase 3] `git log -S`: `7e70f0ed9f3ee` introduced peer-reset
reconnect (in tree); `cbcb358b744bf` added `>= RECONNECT` guard (in
tree)
- [Phase 3] `git merge-base --is-ancestor`: both `7e70f0` and `cbcb358`
confirmed in HEAD
- [Phase 3] Series 01/02/05 reviewed via lkml; patch 03 is independent
of reset state machine
- [Phase 4] Fetched
https://lkml.iu.edu/hypermail/linux/kernel/2605.0/09721.html — full
patch text
- [Phase 4] Fetched https://lists.openwall.net/linux-
kernel/2026/05/07/1855 — Reviewed-by Dubeyko, no objections
- [Phase 4] b4 dig unavailable for commit (not in tree); used lkml
message-ID search instead
- [Phase 5] Verified callers: `send_mds_reconnect` at lines 5126, 5190,
6275; `mds_peer_reset` via `mds_con_ops.peer_reset` at line 6504
- [Phase 5] Verified teardown pattern matches `check_new_map()` lines
5086–5102
- [Phase 6] `git describe HEAD` → v6.18.44; buggy `void
send_mds_reconnect` and `>= RECONNECT` guard confirmed at lines 4878,
6273–6275
- [Phase 6] No `reset/trigger` debugfs or reset state machine in tree —
series patch 05 not present
- [Phase 6] `ceph_get_deleg_ino` and `s_delegated_inos` exist (lines
613–628, 4900)
- [Phase 8] Failure mode: stuck RECONNECTING / failed recovery → CephFS
hang; severity HIGH
**YES**The background history lookups finished and match the earlier
analysis.
**Reconnect logic history** (`619755`): `send_mds_reconnect` goes back
to the original MDS client (`2f2dc053404fe`, 2009). Later related fixes
in this tree include the NPD fix (`c0bd50e2eeddf`) and the deadlock fix
around `mdsc->mutex`/`s->s_mutex` nesting (`ea8412b284c09`).
**Author context** (`619756`): Alex Markuze has recent ceph commits in
this 6.18.y tree (race fixes in `r_parent` handling, read error-path
hardening), which fits this being a targeted reconnect/recovery fix
rather than new subsystem work.
That supports the **YES** backport verdict: the bugs sit in long-
standing reconnect code, the author is an active ceph contributor, and
the patch is standalone in `mds_client.c` without needing the manual-
reset series.
fs/ceph/mds_client.c | 178 +++++++++++++++++++++++++++++++++++++++----
1 file changed, 163 insertions(+), 15 deletions(-)
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c
index af7137661c8fc..48d622cd8b1e2 100644
--- a/fs/ceph/mds_client.c
+++ b/fs/ceph/mds_client.c
@@ -4401,9 +4401,14 @@ static void handle_session(struct ceph_mds_session *session,
break;
case CEPH_SESSION_REJECT:
- WARN_ON(session->s_state != CEPH_MDS_SESSION_OPENING);
- pr_info_client(cl, "mds%d rejected session\n",
- session->s_mds);
+ WARN_ON(session->s_state != CEPH_MDS_SESSION_OPENING &&
+ session->s_state != CEPH_MDS_SESSION_RECONNECTING);
+ if (session->s_state == CEPH_MDS_SESSION_RECONNECTING)
+ pr_info_client(cl, "mds%d reconnect rejected\n",
+ session->s_mds);
+ else
+ pr_info_client(cl, "mds%d rejected session\n",
+ session->s_mds);
session->s_state = CEPH_MDS_SESSION_REJECTED;
cleanup_session_requests(mdsc, session);
remove_session_caps(session);
@@ -4663,6 +4668,14 @@ static int reconnect_caps_cb(struct inode *inode, int mds, void *arg)
cap->mseq = 0; /* and migrate_seq */
cap->cap_gen = atomic_read(&cap->session->s_cap_gen);
+ /*
+ * Note: CEPH_I_ERROR_FILELOCK is not set during reconnect.
+ * Instead, locks are submitted for best-effort MDS reclaim
+ * via the flock_len field below. If reclaim fails (e.g.,
+ * another client grabbed a conflicting lock), future lock
+ * operations will fail and set the error flag at that point.
+ */
+
/* These are lost when the session goes away */
if (S_ISDIR(inode->i_mode)) {
if (cap->issued & CEPH_CAP_DIR_CREATE) {
@@ -4876,20 +4889,19 @@ static int encode_snap_realms(struct ceph_mds_client *mdsc,
*
* This is a relatively heavyweight operation, but it's rare.
*/
-static void send_mds_reconnect(struct ceph_mds_client *mdsc,
- struct ceph_mds_session *session)
+static int send_mds_reconnect(struct ceph_mds_client *mdsc,
+ struct ceph_mds_session *session)
{
struct ceph_client *cl = mdsc->fsc->client;
struct ceph_msg *reply;
int mds = session->s_mds;
int err = -ENOMEM;
+ int old_state;
struct ceph_reconnect_state recon_state = {
.session = session,
};
LIST_HEAD(dispose);
- pr_info_client(cl, "mds%d reconnect start\n", mds);
-
recon_state.pagelist = ceph_pagelist_alloc(GFP_NOFS);
if (!recon_state.pagelist)
goto fail_nopagelist;
@@ -4898,9 +4910,37 @@ static void send_mds_reconnect(struct ceph_mds_client *mdsc,
if (!reply)
goto fail_nomsg;
+ mutex_lock(&session->s_mutex);
+
+ /* Serialized by s_mutex against concurrent ceph_get_deleg_ino(). */
xa_destroy(&session->s_delegated_inos);
+ if (session->s_state == CEPH_MDS_SESSION_CLOSED ||
+ session->s_state == CEPH_MDS_SESSION_REJECTED) {
+ pr_info_client(cl, "mds%d skipping reconnect, session %s\n",
+ mds,
+ ceph_session_state_name(session->s_state));
+ mutex_unlock(&session->s_mutex);
+ ceph_msg_put(reply);
+ err = -ESTALE;
+ goto fail_return;
+ }
- mutex_lock(&session->s_mutex);
+ /* s_mutex -> mdsc->mutex matches cleanup_session_requests() order. */
+ mutex_lock(&mdsc->mutex);
+ if (mds >= mdsc->max_sessions || mdsc->sessions[mds] != session) {
+ mutex_unlock(&mdsc->mutex);
+ pr_info_client(cl,
+ "mds%d skipping reconnect, session unregistered\n",
+ mds);
+ mutex_unlock(&session->s_mutex);
+ ceph_msg_put(reply);
+ err = -ENOENT;
+ goto fail_return;
+ }
+ mutex_unlock(&mdsc->mutex);
+
+ pr_info_client(cl, "mds%d reconnect start\n", mds);
+ old_state = session->s_state;
session->s_state = CEPH_MDS_SESSION_RECONNECTING;
session->s_seq = 0;
@@ -5030,18 +5070,34 @@ static void send_mds_reconnect(struct ceph_mds_client *mdsc,
up_read(&mdsc->snap_rwsem);
ceph_pagelist_release(recon_state.pagelist);
- return;
+ return 0;
fail:
ceph_msg_put(reply);
up_read(&mdsc->snap_rwsem);
+ /*
+ * Restore prior session state so map-driven reconnect logic
+ * (check_new_map) can retry. Without this, a transient build
+ * failure strands the session in RECONNECTING indefinitely.
+ */
+ session->s_state = old_state;
mutex_unlock(&session->s_mutex);
fail_nomsg:
ceph_pagelist_release(recon_state.pagelist);
fail_nopagelist:
pr_err_client(cl, "error %d preparing reconnect for mds%d\n",
err, mds);
- return;
+ return err;
+
+fail_return:
+ /*
+ * Early-exit path for expected concurrent-teardown races
+ * (-ESTALE for closed/rejected sessions, -ENOENT for
+ * unregistered sessions). Skip the pr_err_client diagnostic
+ * since these are not genuine reconnect build failures.
+ */
+ ceph_pagelist_release(recon_state.pagelist);
+ return err;
}
@@ -5122,9 +5178,15 @@ static void check_new_map(struct ceph_mds_client *mdsc,
*/
if (s->s_state == CEPH_MDS_SESSION_RESTARTING &&
newstate >= CEPH_MDS_STATE_RECONNECT) {
+ int rc;
+
mutex_unlock(&mdsc->mutex);
clear_bit(i, targets);
- send_mds_reconnect(mdsc, s);
+ rc = send_mds_reconnect(mdsc, s);
+ if (rc)
+ pr_warn_client(cl,
+ "mds%d reconnect failed: %d\n",
+ i, rc);
mutex_lock(&mdsc->mutex);
}
@@ -5188,7 +5250,11 @@ static void check_new_map(struct ceph_mds_client *mdsc,
}
doutc(cl, "send reconnect to export target mds.%d\n", i);
mutex_unlock(&mdsc->mutex);
- send_mds_reconnect(mdsc, s);
+ err = send_mds_reconnect(mdsc, s);
+ if (err)
+ pr_warn_client(cl,
+ "mds%d export target reconnect failed: %d\n",
+ i, err);
ceph_put_mds_session(s);
mutex_lock(&mdsc->mutex);
}
@@ -6268,12 +6334,92 @@ static void mds_peer_reset(struct ceph_connection *con)
{
struct ceph_mds_session *s = con->private;
struct ceph_mds_client *mdsc = s->s_mdsc;
+ int session_state;
pr_warn_client(mdsc->fsc->client, "mds%d closed our session\n",
s->s_mds);
- if (READ_ONCE(mdsc->fsc->mount_state) != CEPH_MOUNT_FENCE_IO &&
- ceph_mdsmap_get_state(mdsc->mdsmap, s->s_mds) >= CEPH_MDS_STATE_RECONNECT)
- send_mds_reconnect(mdsc, s);
+
+ if (READ_ONCE(mdsc->fsc->mount_state) == CEPH_MOUNT_FENCE_IO ||
+ ceph_mdsmap_get_state(mdsc->mdsmap, s->s_mds) < CEPH_MDS_STATE_RECONNECT)
+ return;
+
+ /*
+ * Only reconnect if MDS is in its RECONNECT phase. An MDS past
+ * RECONNECT (REJOIN, CLIENTREPLAY, ACTIVE) will reject reconnect
+ * attempts, so those states fall through to session teardown below.
+ */
+ if (ceph_mdsmap_get_state(mdsc->mdsmap, s->s_mds) == CEPH_MDS_STATE_RECONNECT) {
+ int rc = send_mds_reconnect(mdsc, s);
+
+ if (rc)
+ pr_warn_client(mdsc->fsc->client,
+ "mds%d reconnect failed: %d\n",
+ s->s_mds, rc);
+ return;
+ }
+
+ /*
+ * MDS is active (past RECONNECT). It will not accept a
+ * CLIENT_RECONNECT from us, so tear the session down locally
+ * and let new requests re-open a fresh session.
+ *
+ * Snapshot session state with READ_ONCE, then revalidate under
+ * mdsc->mutex before acting. The subsequent mdsc->mutex
+ * section rechecks s_state to catch concurrent transitions, so
+ * the lockless snapshot here is safe. s->s_mutex is taken
+ * separately for cleanup after unregistration, which avoids
+ * introducing a new s->s_mutex + mdsc->mutex nesting.
+ */
+ session_state = READ_ONCE(s->s_state);
+
+ switch (session_state) {
+ case CEPH_MDS_SESSION_RESTARTING:
+ case CEPH_MDS_SESSION_RECONNECTING:
+ case CEPH_MDS_SESSION_CLOSING:
+ case CEPH_MDS_SESSION_OPEN:
+ case CEPH_MDS_SESSION_HUNG:
+ case CEPH_MDS_SESSION_OPENING:
+ mutex_lock(&mdsc->mutex);
+ if (s->s_mds >= mdsc->max_sessions ||
+ mdsc->sessions[s->s_mds] != s ||
+ s->s_state != session_state) {
+ pr_info_client(mdsc->fsc->client,
+ "mds%d state changed to %s during peer reset\n",
+ s->s_mds,
+ ceph_session_state_name(s->s_state));
+ mutex_unlock(&mdsc->mutex);
+ return;
+ }
+
+ ceph_get_mds_session(s);
+ s->s_state = CEPH_MDS_SESSION_CLOSED;
+ __unregister_session(mdsc, s);
+ __wake_requests(mdsc, &s->s_waiting);
+ mutex_unlock(&mdsc->mutex);
+
+ mutex_lock(&s->s_mutex);
+ cleanup_session_requests(mdsc, s);
+ remove_session_caps(s);
+ mutex_unlock(&s->s_mutex);
+
+ wake_up_all(&mdsc->session_close_wq);
+
+ mutex_lock(&mdsc->mutex);
+ kick_requests(mdsc, s->s_mds);
+ mutex_unlock(&mdsc->mutex);
+
+ ceph_put_mds_session(s);
+ break;
+ case CEPH_MDS_SESSION_CLOSED:
+ case CEPH_MDS_SESSION_REJECTED:
+ break;
+ default:
+ pr_warn_client(mdsc->fsc->client,
+ "mds%d peer reset in unexpected state %s\n",
+ s->s_mds,
+ ceph_session_state_name(session_state));
+ break;
+ }
}
static void mds_dispatch(struct ceph_connection *con, struct ceph_msg *msg)
@@ -6285,6 +6431,8 @@ static void mds_dispatch(struct ceph_connection *con, struct ceph_msg *msg)
mutex_lock(&mdsc->mutex);
if (__verify_registered_session(mdsc, s) < 0) {
+ doutc(cl, "dropping tid %llu from unregistered session %d\n",
+ le64_to_cpu(msg->hdr.tid), s->s_mds);
mutex_unlock(&mdsc->mutex);
goto out;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 26+ messages in thread* [PATCH AUTOSEL 6.18-5.15] dmaengine: dw-axi-dmac: fix PM for system sleep and channel alloc
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (4 preceding siblings ...)
2026-08-31 13:23 ` [PATCH AUTOSEL 6.18-6.12] ceph: harden send_mds_reconnect and handle active-MDS peer reset Sasha Levin
@ 2026-08-31 13:23 ` Sasha Levin
2026-08-31 14:58 ` sashiko-bot
2026-08-31 13:24 ` [PATCH AUTOSEL 6.18-5.10] ACPICA: validate handler object type in two places Sasha Levin
` (17 subsequent siblings)
23 siblings, 1 reply; 26+ messages in thread
From: Sasha Levin @ 2026-08-31 13:23 UTC (permalink / raw)
To: patches, stable
Cc: Tze Yee Ng, Vinod Koul, Sasha Levin, Eugeniy.Paltsev, dmaengine,
linux-kernel
From: Tze Yee Ng <tze.yee.ng@altera.com>
[ Upstream commit df0c2dc68770cf43f15df40b184df030b850ea05 ]
The driver only had runtime PM callbacks. If a channel stayed allocated
across system suspend/resume, the runtime usage count could remain
non-zero while hardware state (DMAC_CFG, clocks) was lost, and
axi_dma_runtime_resume() would not run to restore it.
Add system-sleep PM ops that use pm_runtime_force_suspend() and
pm_runtime_force_resume() so suspend/resume reuses the existing
axi_dma_suspend() and axi_dma_resume() paths.
Replace pm_runtime_get() with pm_runtime_resume_and_get() in
dma_chan_alloc_chan_resources() so clocks are enabled before a client
can immediately submit a transfer and touch MMIO.
Signed-off-by: Tze Yee Ng <tze.yee.ng@altera.com>
Link: https://patch.msgid.link/18bf778a3a1cc2f377ef8eb0d1508d8ac6371896.1779688569.git.tze.yee.ng@altera.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
# Stable Backport Analysis: `dmaengine: dw-axi-dmac: fix PM for system
sleep and channel alloc`
**Local tree:** `v6.18.44` (`stable/linux-6.18.y`, detached HEAD)
**Mainline commit:** `df0c2dc68770c` (merged by Vinod Koul, 2026-06-11)
**Status in this tree:** Buggy code is present; fix is **not** yet
applied (`NOT_IN_TREE`)
---
## PHASE 1: COMMIT MESSAGE FORENSICS
### Step 1.1: Parse the subject line
**Record:** `[dmaengine: dw-axi-dmac]` `[fix]` — Correct power-
management handling for system sleep and DMA channel allocation.
### Step 1.2: Parse all commit message tags
**Record:**
- **Fixes:** — absent (expected for manual review)
- **Reported-by:** — absent
- **Tested-by:** — absent
- **Reviewed-by / Acked-by:** — absent in commit message
- **Link:** https://patch.msgid.link/18bf778a3a1cc2f377ef8eb0d1508d8ac63
71896.1779688569.git.tze.yee.ng@altera.com
- **Cc: stable:** — absent (not a negative signal)
- **Signed-off-by:** Tze Yee Ng (author), Vinod Koul (subsystem
maintainer, committer)
- **Notable:** Merged by dmaengine maintainer; patch 2/2 in a reviewed
series
### Step 1.3: Analyze commit body
**Record:**
- **Bug:** Driver registered only runtime PM callbacks. With a channel
allocated across system suspend/resume, runtime usage count can stay
non-zero while hardware state (DMAC_CFG, clocks) is lost;
`axi_dma_runtime_resume()` is then skipped.
- **Symptom:** DMA controller left with clocks off and/or DMAC_CFG not
restored after resume; subsequent DMA/MMIO can fail or hang.
- **Second bug:** `pm_runtime_get()` in
`dma_chan_alloc_chan_resources()` bumps the usage counter without
resuming; a client can submit a transfer immediately and touch MMIO
before clocks are enabled.
- **Root cause:** Missing system-sleep PM ops; incorrect runtime PM API
usage on channel allocation.
- **Version info:** None stated; driver has had this pattern since 2018.
### Step 1.4: Detect hidden bug fixes
**Record:** Not disguised — explicitly described as a PM bug fix. The
`pm_runtime_resume_and_get()` change also adds missing
`pm_runtime_put()` on error paths (refcount balance), which is proper
error-path cleanup tied to the fix.
---
## PHASE 2: DIFF ANALYSIS
### Step 2.1: Inventory the changes
**Record:**
- **File:** `drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c` (+9 / -2)
- **Functions modified:** `dma_chan_alloc_chan_resources()`,
`dw_axi_dma_pm_ops`
- **Scope:** Single-file, surgical fix
### Step 2.2: Code flow change per hunk
**Hunk 1 — `dma_chan_alloc_chan_resources()`:**
- **Before:** Check idle → allocate descriptor pool → `pm_runtime_get()`
(counter only, no resume) → return 0. Error paths did not balance
runtime PM.
- **After:** `pm_runtime_resume_and_get()` first (resume + increment);
on `-EBUSY` / `-ENOMEM`, `pm_runtime_put()` before return.
- **Path affected:** Normal DMA client channel allocation (common
client-driver path).
**Hunk 2 — `dw_axi_dma_pm_ops`:**
- **Before:** Only `SET_RUNTIME_PM_OPS(axi_dma_runtime_suspend,
axi_dma_runtime_resume, NULL)`.
- **After:** Adds `SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
pm_runtime_force_resume)`.
- **Path affected:** System suspend/resume (S3/hibernate on affected
SoCs).
### Step 2.3: Bug mechanism
**Record:**
- **Category (a):** Error-path refcount fix — `pm_runtime_put()` on
allocation failure after `resume_and_get`.
- **Category (b):** PM / suspend-resume correctness — system sleep now
forces runtime suspend/resume regardless of usage count.
- **Category (c):** Reference-counting / PM API misuse —
`pm_runtime_get()` does not resume; `pm_runtime_resume_and_get()`
does.
- **Specific mechanism:** After system sleep, hardware is reset but
software refcount says device is "active," so runtime resume is
skipped and `axi_dma_resume()` (clocks + DMAC enable) never runs.
### Step 2.4: Fix quality
**Record:**
- **Quality:** High. Uses the standard kernel pattern documented in
`DEFINE_RUNTIME_DEV_PM_OPS()` / `pm_runtime.h` comments.
- **Minimal:** 9 lines, no API changes.
- **Regression risk:** Very low. `pm_runtime_force_suspend/resume` are
well-tested core PM helpers; error-path `pm_runtime_put()` is correct
pairing.
- **Red flags:** None.
---
## PHASE 3: GIT HISTORY INVESTIGATION
### Step 3.1: Blame changed lines
**Record:**
- `dma_chan_alloc_chan_resources()` and `pm_runtime_get()`: introduced
in `1fe20f1b84548` (2018-03-06, "Introduce DW AXI DMAC driver").
- `dw_axi_dma_pm_ops` with runtime-only ops: same commit, 2018.
- Bug has been present since driver introduction in this tree.
### Step 3.2: Follow Fixes: tag
**Record:** No `Fixes:` tag. N/A.
### Step 3.3: File history for related changes
**Record:**
- Recent stable-tree changes: StarFive JH8100/JH7110 support, per-
channel IRQ, array overrun fix.
- Patch 1 of series (`dc6d681e1571c` — "drop redundant DMAC enable in
block start") is **not** in this tree (`PATCH1_NOT_IN_TREE`).
- This commit (patch 2) is **standalone**; it does not depend on patch
1. Patch 1 without patch 2 would expose the PM gap more; patch 2 alone
is sufficient and correct for 6.18.y.
### Step 3.4: Author's other commits
**Record:** Tze Yee Ng — Altera/Intel contributor; author of
stratix10-svc fixes. Vinod Koul committed and is dmaengine maintainer.
### Step 3.5: Prerequisites
**Record:** No prerequisites. `pm_runtime_force_suspend`,
`pm_runtime_force_resume`, and `pm_runtime_resume_and_get` all exist in
this tree's `include/linux/pm_runtime.h`. Patch applies cleanly (`git
apply --check` exit 0).
---
## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
### Step 4.1: Original patch discussion
**Record:**
- **b4 dig URL:** https://patch.msgid.link/18bf778a3a1cc2f377ef8eb0d1508
d8ac6371896.1779688569.git.tze.yee.ng@altera.com
- **Series:** v2 0/2 "clean up DMAC enable and PM" (2026-05-25)
- **Revisions:** v2 only found by b4 dig `-a`
- **Key feedback:** Patch 2 added per review feedback from Sashiko
Watanabe (AI review bot flagged issues; patch 2 addresses PM gap
identified in review)
- **Maintainer:** Vinod Koul replied "Applied, thanks!" applying both
patches
- **Stable nomination in thread:** None found
- **NAKs:** None found
### Step 4.2: Reviewers from b4 dig -w
**Record:** CC'd: Eugeniy Paltsev (Synopsys, original driver author),
Vinod Koul, Frank Li, dmaengine@vger.kernel.org, linux-
kernel@vger.kernel.org.
### Step 4.3: Bug report
**Record:** No external bug report or syzbot link. Bug identified
through code review / PM analysis during series review.
### Step 4.4: Related patches / series
**Record:** 2-patch series. Only patch 2 is needed for this backport
decision. Patch 1 is optional cleanup not present in 6.18.y.
### Step 4.5: Stable mailing list
**Record:** Not searched separately; no stable discussion found in
downloaded thread.
---
## PHASE 5: CODE SEMANTIC ANALYSIS
### Step 5.1: Key functions
**Record:** `dma_chan_alloc_chan_resources()`,
`dma_chan_free_chan_resources()` (unchanged, has matching
`pm_runtime_put`), `axi_dma_suspend()`, `axi_dma_resume()`,
`axi_dma_runtime_suspend/resume()`, `dw_axi_dma_pm_ops`.
### Step 5.2: Callers
**Record:** `dma_chan_alloc_chan_resources` is registered as
`device_alloc_chan_resources` in the dmaengine device ops (line 1565).
Called by any DMA client requesting a channel — SDHCI, SPI, audio, etc.
on affected SoCs.
### Step 5.3: Callees
**Record:** `pm_runtime_resume_and_get()` → `pm_runtime_get_active()` →
`__pm_runtime_resume()`; system sleep uses
`pm_runtime_force_suspend/resume` → existing `axi_dma_suspend/resume`
(clock disable/enable, `axi_dma_disable/enable`).
### Step 5.4: Call chain / reachability
**Record:**
1. **Suspend/resume:** Platform system sleep → driver
`.suspend`/`.resume` → force runtime suspend/resume → restore clocks
and DMAC.
2. **Channel alloc:** Userspace/driver → `dma_request_channel()` →
`alloc_chan_resources()` → must have clocks before any transfer.
- **Userspace reachable:** Yes, indirectly via drivers using DMA on
StarFive, Intel KMB, Altera/Intel FPGA platforms.
### Step 5.5: Similar patterns
**Record:** Other DMA drivers in this tree already use
`pm_runtime_resume_and_get()` in alloc paths (e.g. `zynqmp_dma.c`,
`tegra20-apb-dma.c`, `stm32-dma.c`) and/or
`SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
pm_runtime_force_resume)` (e.g. `dw_mmc-pltfm.c`, `idma64.c`). This fix
aligns dw-axi-dmac with established practice.
---
## PHASE 6: CROSS-REFERENCE AGAINST LOCAL TREE
### Step 6.1: Does buggy code exist?
**Record:** **Yes.** Current tree at `v6.18.44` has:
- `pm_runtime_get()` at line 538 in `dma_chan_alloc_chan_resources()`
- Runtime-only `dw_axi_dma_pm_ops` at lines 1654–1656
- Affected platforms in OF table: `snps,axi-dma-1.01a`, `intel,kmb-axi-
dma`, `starfive,jh7110-axi-dma`, `starfive,jh8100-axi-dma`
### Step 6.2: Backport complications
**Record:** Clean apply expected. `git apply --check` on mainline patch
succeeded. No structural divergence in the changed regions.
### Step 6.3: Related fixes already present?
**Record:** No equivalent fix found. `git merge-base --is-ancestor
df0c2dc68770c HEAD` → `NOT_IN_TREE`.
---
## PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
### Step 7.1: Subsystem criticality
**Record:** `drivers/dma/dw-axi-dmac` — **IMPORTANT** (DMA engine for
multiple embedded SoC platforms; suspend/resume and DMA are core to I/O
on those systems).
### Step 7.2: Subsystem activity
**Record:** Actively maintained in 6.18.y (StarFive JH8100, per-channel
IRQ, overrun fix in recent history).
---
## PHASE 8: IMPACT AND RISK ASSESSMENT
### Step 8.1: Who is affected
**Record:** Users of dw-axi-dmac on Intel KMB, StarFive JH7110/JH8100,
and Synopsys/Altera AXI DMA platforms — embedded boards, FPGA SoCs.
Config: `CONFIG_DW_AXI_DMAC` (or built-in on those platforms).
### Step 8.2: Trigger conditions
**Record:**
1. DMA channel allocated, system enters suspend (S3/hibernate), then
resumes — **common** on laptops/embedded devices.
2. Device runtime-suspended, client allocates channel and immediately
submits transfer — **plausible** under autosuspend.
- **Unprivileged trigger:** Indirectly yes (e.g., triggering suspend or
I/O that uses DMA).
### Step 8.3: Failure mode severity
**Record:**
- DMA failures after resume (broken I/O: storage, network, audio)
- MMIO with clocks disabled → bus hang, timeout, or oops
- **Severity: HIGH** (system-level I/O breakage; potential hang)
### Step 8.4: Risk-benefit
**Record:**
- **Benefit:** HIGH — fixes real suspend/resume breakage on shipping
hardware
- **Risk:** LOW — 9-line, standard PM pattern, maintainer-merged
- **Ratio:** Strongly favors backport
---
## PHASE 9: FINAL SYNTHESIS
### Step 9.1: Evidence summary
**FOR backport:**
- Fixes real PM bug present since driver introduction (2018)
- Affects multiple platforms in this stable tree
- Can break DMA and cause hangs after suspend/resume
- Small, obviously correct, maintainer-merged fix
- Applies cleanly to v6.18.44
- Uses established kernel PM APIs/patterns
- Standalone — does not require patch 1 of the series
**AGAINST backport:**
- No syzbot/user crash report (review-found bug)
- Driver-specific, not core kernel (but suspend/resume is critical for
affected users)
**Unresolved:** No explicit `Tested-by` on hardware; no `Cc: stable`
nomination in thread.
### Step 9.2: Stable rules checklist
1. Obviously correct and tested? **PASS** — standard PM pattern; merged
by maintainer after review
2. Fixes a real bug? **PASS** — suspend/resume state desync and alloc-
without-resume
3. Important issue? **PASS** — HIGH: post-resume DMA failure / potential
hang
4. Small and contained? **PASS** — 9 lines, one file
5. No new features/APIs? **PASS** — only PM ops wiring and correct API
usage
6. Can apply to local tree? **PASS** — verified clean apply
### Step 9.3: Exception categories
**Record:** None (not a quirk/ID/DT/docs fix) — qualifies on straight
bug-fix merits.
### Step 9.4: Decision rationale
For **linux-6.18.y (v6.18.44)**, the buggy code is present and the fix
is absent. The commit addresses a longstanding power-management defect:
without system-sleep PM ops, suspend/resume can leave the DMAC with
clocks off and hardware unconfigured while the runtime PM counter
indicates the device is still active. The `pm_runtime_resume_and_get()`
change fixes a second, independently valid bug where channel allocation
does not ensure the device is resumed before clients can use it. The
change is minimal, follows patterns already used elsewhere in
`drivers/dma/`, and applies cleanly. This is appropriate stable
material.
---
## Verification
- **[Phase 1]** `git describe HEAD` → `v6.18.44`; parsed commit message
from user query and `git show df0c2dc68770c`
- **[Phase 2]** Read current `dw-axi-dmac-platform.c` lines 516–564,
1315–1356, 1654–1656; confirmed diff matches missing fix
- **[Phase 3]** `git blame` lines 516–540, 1654–1656 → `1fe20f1b84548`
(2018); `git merge-base --is-ancestor df0c2dc68770c HEAD` →
`NOT_IN_TREE`; patch 1 also `NOT_IN_TREE`
- **[Phase 3]** `git apply --check` on `df0c2dc68770c` patch → exit 0
(clean apply)
- **[Phase 4]** `b4 dig -c df0c2dc68770c` → lore URL; `b4 dig -a` → v2
series; `b4 dig -w` → maintainers CC'd; mbox → Vinod "Applied,
thanks!"
- **[Phase 4]** WebFetch lkml.iu.edu cover letter → patch 2 addresses
Sashiko Watanabe review feedback
- **[Phase 5]** `grep pm_runtime_resume_and_get drivers/dma/` → pattern
used in peer drivers; read `axi_dma_enable/suspend/resume` code
- **[Phase 6]** Confirmed buggy `pm_runtime_get` and runtime-only PM ops
in tree; OF compatibles present
- **[Phase 7]** `git log --oneline -20 -- drivers/dma/dw-axi-dmac/` →
active maintenance
- **[Phase 8]** Failure mode derived from verified code paths
(`axi_dma_suspend` disables clocks; `pm_runtime_get` does not resume
per `pm_runtime.h` docs)
**YES**
drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
index b0e689f48bb67..ea4e47ee0d710 100644
--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
+++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
@@ -516,11 +516,17 @@ static void dw_axi_dma_synchronize(struct dma_chan *dchan)
static int dma_chan_alloc_chan_resources(struct dma_chan *dchan)
{
struct axi_dma_chan *chan = dchan_to_axi_dma_chan(dchan);
+ int ret;
+
+ ret = pm_runtime_resume_and_get(chan->chip->dev);
+ if (ret < 0)
+ return ret;
/* ASSERT: channel is idle */
if (axi_chan_is_hw_enable(chan)) {
dev_err(chan2dev(chan), "%s is non-idle!\n",
axi_chan_name(chan));
+ pm_runtime_put(chan->chip->dev);
return -EBUSY;
}
@@ -531,12 +537,11 @@ static int dma_chan_alloc_chan_resources(struct dma_chan *dchan)
64, 0);
if (!chan->desc_pool) {
dev_err(chan2dev(chan), "No memory for descriptors\n");
+ pm_runtime_put(chan->chip->dev);
return -ENOMEM;
}
dev_vdbg(dchan2dev(dchan), "%s: allocating\n", axi_chan_name(chan));
- pm_runtime_get(chan->chip->dev);
-
return 0;
}
@@ -1652,6 +1657,8 @@ static void dw_remove(struct platform_device *pdev)
}
static const struct dev_pm_ops dw_axi_dma_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
SET_RUNTIME_PM_OPS(axi_dma_runtime_suspend, axi_dma_runtime_resume, NULL)
};
--
2.53.0
^ permalink raw reply related [flat|nested] 26+ messages in thread* Re: [PATCH AUTOSEL 6.18-5.15] dmaengine: dw-axi-dmac: fix PM for system sleep and channel alloc
2026-08-31 13:23 ` [PATCH AUTOSEL 6.18-5.15] dmaengine: dw-axi-dmac: fix PM for system sleep and channel alloc Sasha Levin
@ 2026-08-31 14:58 ` sashiko-bot
0 siblings, 0 replies; 26+ messages in thread
From: sashiko-bot @ 2026-08-31 14:58 UTC (permalink / raw)
To: Sasha Levin; +Cc: dmaengine, Frank.Li, vkoul
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] The shared interrupt handler accesses hardware registers without checking if the device is active, and the suspend callback fails to synchronize IRQs.
--
commit 11e86e3a3829f6e35823522311eef18dacb1afef
Author: Tze Yee Ng <tze.yee.ng@altera.com>
dmaengine: dw-axi-dmac: fix PM for system sleep and channel alloc
The driver only had runtime PM callbacks. If a channel stayed allocated
across system suspend/resume, the runtime usage count could remain
non-zero while hardware state (DMAC_CFG, clocks) was lost, and
axi_dma_runtime_resume() would not run to restore it.
Add system-sleep PM ops that use pm_runtime_force_suspend() and
pm_runtime_force_resume() so suspend/resume reuses the existing
axi_dma_suspend() and axi_dma_resume() paths.
Link: https://patch.msgid.link/18bf778a3a1cc2f377ef8eb0d1508d8ac6371896.1779688569.git.tze.yee.ng@altera.com
> diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
> index b23536645ff7c..4fd77f5b67c47 100644
> --- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
> +++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
[ ... ]
> @@ -1654,6 +1659,8 @@ static void dw_remove(struct platform_device *pdev)
> }
>
> static const struct dev_pm_ops dw_axi_dma_pm_ops = {
> + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
> + pm_runtime_force_resume)
> SET_RUNTIME_PM_OPS(axi_dma_runtime_suspend, axi_dma_runtime_resume, NULL)
> };
[Severity: High]
This is a pre-existing issue, but does the shared interrupt handler have a
potential race condition with device suspend?
The driver requests a shared interrupt:
drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c:axi_req_irqs() {
...
ret = devm_request_irq(chip->dev, chip->irq[i], dw_axi_dma_interrupt,
IRQF_SHARED, KBUILD_MODNAME, chip);
...
}
However, the interrupt handler accesses hardware registers unconditionally:
drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c:dw_axi_dma_interrupt() {
...
axi_dma_irq_disable(chip);
...
}
If another device on the same shared IRQ line triggers an interrupt while this
DMA controller is runtime suspended (with clocks disabled), could this cause a
bus hang or system crash when accessing unclocked registers?
Additionally, the suspend routine cuts clocks without synchronizing IRQs:
drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c:axi_dma_suspend() {
...
clk_disable_unprepare(chip->core_clk);
clk_disable_unprepare(chip->cfgr_clk);
...
}
Could an in-flight IRQ handler crash when the clocks are cut mid-execution?
Should the interrupt handler use pm_runtime_get_if_active() to check if the
device is active before proceeding, and should the suspend callback call
synchronize_irq() to ensure no handler is executing before disabling the clocks?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260831133314.4125787-209-sashal@kernel.org?part=1
^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH AUTOSEL 6.18-5.10] ACPICA: validate handler object type in two places
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (5 preceding siblings ...)
2026-08-31 13:23 ` [PATCH AUTOSEL 6.18-5.15] dmaengine: dw-axi-dmac: fix PM for system sleep and channel alloc Sasha Levin
@ 2026-08-31 13:24 ` Sasha Levin
2026-08-31 13:24 ` [PATCH AUTOSEL 6.18-5.10] ACPICA: add boundary checks " Sasha Levin
` (16 subsequent siblings)
23 siblings, 0 replies; 26+ messages in thread
From: Sasha Levin @ 2026-08-31 13:24 UTC (permalink / raw)
To: patches, stable
Cc: ikaros, Rafael J. Wysocki, Sasha Levin, rafael,
maciej.wieczor-retman, pawel.chmielewski, linux-acpi,
acpica-devel, linux-kernel
From: ikaros <void0red@gmail.com>
[ Upstream commit c5296da2d516707862f8a2dbb4b515f777e5294f ]
ACPICA: validate handler object type in acpi_ev_has_default_handler()
and acpi_ev_find_region_handler().
Link: https://github.com/acpica/acpica/commit/f6fc648a1389
Signed-off-by: ikaros <void0red@gmail.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Link: https://patch.msgid.link/48111441.fMDQidcC6G@rafael.j.wysocki
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
# Stable Backport Analysis: ACPICA handler object type validation
**Local tree:** `v6.18.44` (`stable/linux-6.18.y`, `make kernelversion`
= 6.18.44)
**Candidate commit (mainline):** `c5296da2d5167` — same diff as upstream
ACPICA `f6fc648a1389`
**Status in this tree:** Fix is **not** present; vulnerable code is
present.
---
## PHASE 1: COMMIT MESSAGE FORENSICS
### Step 1.1: Subject line
**Record:** `[ACPICA] [validate] validate handler object type in
acpi_ev_has_default_handler() and acpi_ev_find_region_handler()`
### Step 1.2: Tags
**Record:**
- **Link:** https://github.com/acpica/acpica/commit/f6fc648a1389
- **Link:**
https://patch.msgid.link/48111441.fMDQidcC6G@rafael.j.wysocki
- **Signed-off-by:** ikaros \<void0red@gmail.com\>
- **Signed-off-by:** Rafael J. Wysocki \<rafael.j.wysocki@intel.com\>
- No `Fixes:`, `Reported-by:`, `Cc: stable@vger.kernel.org`, `Reviewed-
by:`, `Tested-by:`, or `Acked-by:` tags in the commit message
- Notable: upstream ACPICA issue #1132 documents an ASAN global-buffer-
overflow; author is the issue reporter
### Step 1.3: Body text
**Record:**
- **Bug:** Handler linked lists walked via `common_notify.handler`
assume every node is `ACPI_TYPE_LOCAL_ADDRESS_HANDLER`, but the list
can contain objects of another type (corrupt/crafted ACPI state).
- **Symptom:** Out-of-bounds read when accessing
`address_space.space_id` or `address_space.next` on a non-address-
handler object (ASAN: global-buffer-overflow, 8-byte read in
`AcpiEvFindRegionHandler`).
- **Root cause:** Missing type check before interpreting union members
as `address_space` fields.
- **Version info:** None in commit message; upstream ACPICA fix dated
2026-03-20.
### Step 1.4: Hidden bug fix?
**Record:** Yes — although the subject says “validate,” this is a
memory-safety fix preventing buffer overflow on handler-list traversal,
not cosmetic cleanup.
---
## PHASE 2: DIFF ANALYSIS
### Step 2.1: Inventory
**Record:**
- **Files:** `drivers/acpi/acpica/evhandler.c` (+11 lines, 0 removed)
- **Functions modified:** `acpi_ev_has_default_handler()`,
`acpi_ev_find_region_handler()`
- **Scope:** Single-file, surgical fix
### Step 2.2: Code flow change
**Record:**
- **Hunk 1 (`acpi_ev_has_default_handler`):** Before — walked handler
list unconditionally using `address_space` fields. After — breaks loop
if `handler_obj->common.type != ACPI_TYPE_LOCAL_ADDRESS_HANDLER`.
- **Hunk 2 (`acpi_ev_find_region_handler`):** Same type check added
before `space_id` comparison and `next` pointer chase.
- **Paths affected:** Normal ACPI handler lookup during region
initialization, handler installation, and namespace walks.
### Step 2.3: Bug mechanism
**Record:**
- **Category:** Memory safety / buffer overflow (out-of-bounds read)
- **Mechanism:** `union acpi_operand_object` is accessed as
`address_space` without verifying `common.type`. Wrong type → wrong
union layout → read past valid object memory via
`address_space.space_id` (1 byte + padding) or `address_space.next`
(8-byte pointer read per ASAN report).
### Step 2.4: Fix quality
**Record:**
- Fix is minimal and obviously correct: `common_notify.handler` is
documented as the address-space handler list; only
`ACPI_TYPE_LOCAL_ADDRESS_HANDLER` objects belong there.
- **Regression risk:** Very low. On type mismatch, loop terminates (same
as list end). Worst case: handler not found where list was already
corrupt — far safer than OOB read.
- No API changes, no locking changes.
---
## PHASE 3: GIT HISTORY INVESTIGATION
### Step 3.1: Blame
**Record:**
- `acpi_ev_has_default_handler` walk loop: `42f8fb75c43cc6` (Bob Moore,
2013-01-11) — long-standing code
- `acpi_ev_find_region_handler`: `7b73806485ada` (Bob Moore,
2015-12-29), introduced by `f31a99cefd05f` “Deploys
acpi_ev_find_region_handler()”
- Bug predates 6.18.y branch by many years
### Step 3.2: Fixes: tag
**Record:** N/A — no `Fixes:` tag. Upstream ACPICA references GitHub
issue #1132 (ASAN global-buffer-overflow in `AcpiEvFindRegionHandler`).
### Step 3.3: Related file history
**Record:**
- Recent `evhandler.c` changes in this tree are copyright updates and
unrelated fixes (e.g. `c27f3d011b085` I2C/GPIO race).
- `aa6abd2be1cc7` (2015) moved address handlers to
`common_notify.handler` — architectural context, not the bug
introducer.
- Fix is **standalone**; patch 18/27 in the ACPICA sync series but does
not depend on patches 1–17.
### Step 3.4: Author context
**Record:** ikaros reported the upstream ACPICA bug and authored 14
hardening patches in the same series. Rafael J. Wysocki (ACPI
maintainer) signed off and committed to mainline.
### Step 3.5: Dependencies
**Record:** None. Uses `ACPI_TYPE_LOCAL_ADDRESS_HANDLER` (defined in
`include/acpi/actypes.h` as `0x18` in this tree). No prerequisite
commits required.
---
## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
### Step 4.1: Original discussion
**Record:**
- **URL:** https://patch.msgid.link/48111441.fMDQidcC6G@rafael.j.wysocki
- **Series:** `[PATCH v1 18/27]` in “ACPI: ACPICA 20260408” series by
Rafael Wysocki
- **Revisions:** v1 only found via `b4 dig -a`
- No explicit stable nomination or NAK found in thread grep
- Cover letter groups this with other ikaros buffer-overflow / memory-
safety hardening patches
### Step 4.2: Reviewers
**Record:** CC’d: Rafael J. Wysocki, linux-acpi, LKML, Saket Dumbre,
Pawel Chmielewski (Intel ACPICA maintainers). Signed-off-by from Rafael
J. Wysocki.
### Step 4.3: Bug report
**Record:**
- **GitHub issue #1132:** ASAN global-buffer-overflow, READ of 8 bytes
in `AcpiEvFindRegionHandler`
- **Reproducer:** `./acpiexec -m issue26.aml` (crafted AML)
- **Severity:** Memory safety bug with concrete ASAN proof
### Step 4.4: Related patches
**Record:** Part of 27-patch ACPICA sync; 13 other ikaros hardening
patches in same series. This patch is independently applicable.
### Step 4.5: Stable list discussion
**Record:** No stable@vger.kernel.org discussion found for this specific
patch (lore blocked for web fetch; mbox grep found no “Cc: stable”).
---
## PHASE 5: CODE SEMANTIC ANALYSIS
### Step 5.1: Key functions
**Record:** `acpi_ev_has_default_handler()`,
`acpi_ev_find_region_handler()`
### Step 5.2: Callers
**Record:**
- `acpi_ev_has_default_handler()` ← `acpi_ev_initialize_op_regions()` in
`evregion.c` (boot-time `_REG` method execution)
- `acpi_ev_find_region_handler()` ←
- `acpi_ev_install_handler()` (namespace walk during handler install)
- `acpi_ev_install_space_handler()` (handler installation)
- `acpi_ev_region_init()` path in `evrgnini.c` (region attachment
during init)
- `dbdisply.c` (debug only, `CONFIG_ACPI_DEBUG`)
### Step 5.3: Callees
**Record:** Functions read `obj_desc->common_notify.handler`, then walk
list accessing `address_space.space_id`, `handler_flags`, `next`. No
allocation in the fixed loops.
### Step 5.4: Reachability
**Record:**
- **Boot path:** `tbxfload.c` → `acpi_ev_install_region_handlers()`;
`nsinit.c` → `acpi_ev_initialize_op_regions()`
- **Runtime:** `acpi_install_address_space_handler()` used by EC, GPIO,
I2C, PMIC, PCC, and platform drivers
- **Trigger:** Corrupt/crafted ACPI AML that leaves non-address-handler
objects on the handler list
- **Userspace:** Not directly syscall-reachable, but ACPI tables are
firmware-controlled; root can override tables on some systems
### Step 5.5: Similar patterns
**Record:** Other ACPICA code validates `common.type` before union
access (e.g. `exdump.c`, `utdecode.c`, `nsobject.c`). `evxfregn.c` and
`dbdisply.c` still walk handler lists without type checks — fix is
partial but addresses the two functions named in the ASAN stack trace.
---
## PHASE 6: CROSS-REFERENCE AGAINST LOCAL TREE (6.18.44)
### Step 6.1: Buggy code present?
**Record:** **Yes.** Current `evhandler.c` lines 132–141 and 294–305
lack type validation. Bug present since at least 2013/2015.
### Step 6.2: Backport complications
**Record:** **Clean apply expected.** Mainline diff applies identically
to this tree’s `evhandler.c` (verified via `git show c5296da2d5167`
against current file).
### Step 6.3: Related fixes already present?
**Record:** **No.** `git grep 'validate handler object type'` returns
nothing in this tree. Fix exists on `all-next` as `c5296da2d5167` but
not on `stable/linux-6.18.y` at `v6.18.44`.
---
## PHASE 7: SUBSYSTEM CONTEXT
### Step 7.1: Subsystem and criticality
**Record:** **ACPI / ACPICA events subsystem** — **CORE** (affects all
ACPI-enabled x86/ARM systems at boot and during device operation).
### Step 7.2: Activity
**Record:** Actively maintained; periodic ACPICA upstream syncs. Long-
standing handler-list code with recent hardening focus from fuzzing.
---
## PHASE 8: IMPACT AND RISK ASSESSMENT
### Step 8.1: Who is affected
**Record:** All systems with `CONFIG_ACPI` during ACPI table load,
operation-region initialization, and address-space handler installation.
### Step 8.2: Trigger conditions
**Record:** Handler list containing a
non-`ACPI_TYPE_LOCAL_ADDRESS_HANDLER` object — demonstrated with crafted
AML (`issue26.aml`). Uncommon in the field but plausible with
malicious/corrupt ACPI tables or interpreter bugs. Requires ACPI
processing context (boot or module load), not arbitrary unprivileged
syscall.
### Step 8.3: Failure mode severity
**Record:** Out-of-bounds **read** (8 bytes) → kernel oops/crash or
information leak. **Severity: HIGH** (memory safety in core boot path).
### Step 8.4: Risk-benefit
**Record:**
- **Benefit:** HIGH — prevents OOB read in widely used ACPI core code
- **Risk:** VERY LOW — 11-line defensive check, ACPI maintainer-reviewed
- **Ratio:** Strong benefit, minimal risk
---
## PHASE 9: FINAL SYNTHESIS
### Step 9.1: Evidence summary
**FOR backport:**
- ASAN-confirmed global-buffer-overflow (upstream issue #1132)
- Buggy code present in 6.18.44 since 2013/2015
- Small, surgical, standalone fix (+11 lines, one file)
- ACPI maintainer signed off
- Affects boot-time and runtime ACPI handler paths
- Consistent with ACPICA hardening pattern (type check before union
access)
**AGAINST backport:**
- Reproducer uses crafted AML via `acpiexec` — field trigger frequency
uncertain
- Fix does not cover all similar walks (`evxfregn.c`, `dbdisply.c`) —
incomplete hardening
- Part of larger 27-patch series (though this patch is independent)
**Unresolved:**
- No kernel-runtime reproducer confirmed (only upstream `acpiexec` tool)
- No explicit stable nomination in mailing list thread
### Step 9.2: Stable rules checklist
1. Obviously correct and tested? **PASS** — logic is straightforward;
ASAN-tested upstream; maintainer SOB
2. Fixes a real bug affecting users? **PASS** — ASAN OOB read with
concrete reproducer
3. Important issue? **PASS** — memory safety in ACPI core (HIGH
severity)
4. Small and contained? **PASS** — 11 lines, one file, two functions
5. No new features or APIs? **PASS** — defensive validation only
6. Can apply to local tree? **PASS** — clean apply to 6.18.44
### Step 9.3: Exception categories
**Record:** None (not device ID, quirk, DT, build, or docs). Qualifies
as a core memory-safety bug fix.
### Step 9.4: Decision rationale
For **this** 6.18.y tree, the vulnerable handler-list walk code exists
and is reachable during ACPI initialization and handler management. The
fix prevents a demonstrated out-of-bounds read with negligible
regression risk. Incomplete coverage of similar walks elsewhere does not
diminish the value of fixing the two functions implicated in the ASAN
report.
---
## Verification
- **[Phase 1]** Parsed subject, tags, body from commit `c5296da2d5167`
and user-provided message
- **[Phase 1]** Fetched upstream ACPICA commit and issue #1132 from
GitHub — confirmed ASAN global-buffer-overflow
- **[Phase 2]** Analyzed diff: +11 lines in `evhandler.c`, two type-
check hunks
- **[Phase 3]** `git blame`: buggy loops from 2013 and 2015
- **[Phase 3]** `git show aa6abd2be1cc7`: `common_notify.handler` used
for address-space handlers since 2015
- **[Phase 3]** No `Fixes:` tag to follow
- **[Phase 3]** Fix not in stable tree; present on `all-next` as
`c5296da2d5167`
- **[Phase 4]** `b4 dig -c c5296da2d5167`: found lore thread at
patch.msgid.link
- **[Phase 4]** `b4 dig -a`: v1, patch 18/27 in ACPICA 20260408 series
- **[Phase 4]** `b4 dig -w`: Rafael Wysocki, linux-acpi, Intel
maintainers CC’d
- **[Phase 4]** Downloaded mbox; grep found no stable nomination or NAK
for this patch
- **[Phase 5]** `grep` callers: `evregion.c`, `evrgnini.c`,
`evhandler.c`, `dbdisply.c`
- **[Phase 5]** Traced boot path: `tbxfload.c` →
`acpi_ev_install_region_handlers()`, `nsinit.c` →
`acpi_ev_initialize_op_regions()`
- **[Phase 5]** `grep acpi_install_address_space_handler`: used by EC,
GPIO, I2C, PMIC, platform drivers
- **[Phase 6]** `git describe HEAD`: v6.18.44 on `stable/linux-6.18.y`
- **[Phase 6]** Read current `evhandler.c`: vulnerable code confirmed at
lines 132–141, 294–305
- **[Phase 6]** `git show c5296da2d5167`: diff applies cleanly to
current file
- **[Phase 6]** `grep 'validate handler object type'`: no match in tree
- **[Phase 8]** GitHub issue #1132: ASAN READ 8 bytes, reproducer
`acpiexec -m issue26.aml`
---
**YES**The background `git log --grep` search timed out on this repo, so
I killed it and used targeted lookups instead (`b4 dig`, `git show
c5296da2d5167`, direct file reads). That was enough to finish the
analysis.
**Verdict for 6.18.44:** backport **YES** — the fix prevents an ASAN-
confirmed out-of-bounds read when walking ACPI address-space handler
lists, and it applies cleanly as an 11-line change to `evhandler.c`.
drivers/acpi/acpica/evhandler.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/drivers/acpi/acpica/evhandler.c b/drivers/acpi/acpica/evhandler.c
index 5a35dae945e20..f16c1148e602e 100644
--- a/drivers/acpi/acpica/evhandler.c
+++ b/drivers/acpi/acpica/evhandler.c
@@ -130,6 +130,14 @@ acpi_ev_has_default_handler(struct acpi_namespace_node *node,
/* Walk the linked list of handlers for this object */
while (handler_obj) {
+
+ /* Validate handler object type before accessing fields */
+
+ if (handler_obj->common.type !=
+ ACPI_TYPE_LOCAL_ADDRESS_HANDLER) {
+ break;
+ }
+
if (handler_obj->address_space.space_id == space_id) {
if (handler_obj->address_space.handler_flags &
ACPI_ADDR_HANDLER_DEFAULT_INSTALLED) {
@@ -292,6 +300,9 @@ union acpi_operand_object *acpi_ev_find_region_handler(acpi_adr_space_type
/* Walk the handler list for this device */
while (handler_obj) {
+ if (handler_obj->common.type != ACPI_TYPE_LOCAL_ADDRESS_HANDLER) {
+ break;
+ }
/* Same space_id indicates a handler is installed */
--
2.53.0
^ permalink raw reply related [flat|nested] 26+ messages in thread* [PATCH AUTOSEL 6.18-5.10] ACPICA: add boundary checks in two places
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (6 preceding siblings ...)
2026-08-31 13:24 ` [PATCH AUTOSEL 6.18-5.10] ACPICA: validate handler object type in two places Sasha Levin
@ 2026-08-31 13:24 ` Sasha Levin
2026-08-31 13:25 ` [PATCH AUTOSEL 6.18-5.10] blk-cgroup: fix leaks and online flag on radix_tree_insert failure Sasha Levin
` (15 subsequent siblings)
23 siblings, 0 replies; 26+ messages in thread
From: Sasha Levin @ 2026-08-31 13:24 UTC (permalink / raw)
To: patches, stable
Cc: ikaros, Rafael J. Wysocki, Sasha Levin, rafael,
maciej.wieczor-retman, pawel.chmielewski, linux-acpi,
acpica-devel, linux-kernel
From: ikaros <void0red@gmail.com>
[ Upstream commit bdc35754012906dbf094be104b103ca3adfef6f7 ]
Add boundary checks in acpi_ps_get_next_namestring() and
acpi_ps_peek_opcode() to prevent out-of-bounds access.
Link: https://github.com/acpica/acpica/commit/cfdc96896d8d
Signed-off-by: ikaros <void0red@gmail.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Link: https://patch.msgid.link/5180044.0VBMTVartN@rafael.j.wysocki
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
The background searches finished and matched what we already found:
- **Author/grep search on stable** — No hits in linux-6.18.y; the fix
isn’t in this tree yet.
- **linux-pm web search** — Confirmed the commit lives on Rafael’s
linux-pm `master` branch; we already identified it as `bdc3575401290`.
The earlier analysis stands: this is a small, self-contained ACPI parser
OOB-read fix that applies cleanly to 6.18.44 and should be backported.
**YES**
drivers/acpi/acpica/psargs.c | 18 +++++++++++++++++-
drivers/acpi/acpica/psparse.c | 6 ++++++
2 files changed, 23 insertions(+), 1 deletion(-)
diff --git a/drivers/acpi/acpica/psargs.c b/drivers/acpi/acpica/psargs.c
index 34d887e2211ac..a7293332197aa 100644
--- a/drivers/acpi/acpica/psargs.c
+++ b/drivers/acpi/acpica/psargs.c
@@ -148,10 +148,16 @@ char *acpi_ps_get_next_namestring(struct acpi_parse_state *parser_state)
/* Point past any namestring prefix characters (backslash or carat) */
- while (ACPI_IS_ROOT_PREFIX(*end) || ACPI_IS_PARENT_PREFIX(*end)) {
+ while (end < parser_state->aml_end &&
+ (ACPI_IS_ROOT_PREFIX(*end) || ACPI_IS_PARENT_PREFIX(*end))) {
end++;
}
+ if (end >= parser_state->aml_end) {
+ parser_state->aml = parser_state->aml_end;
+ return_PTR(NULL);
+ }
+
/* Decode the path prefix character */
switch (*end) {
@@ -176,6 +182,11 @@ char *acpi_ps_get_next_namestring(struct acpi_parse_state *parser_state)
/* Multiple name segments, 4 chars each, count in next byte */
+ if ((end + 1) >= parser_state->aml_end) {
+ parser_state->aml = parser_state->aml_end;
+ return_PTR(NULL);
+ }
+
end += 2 + (*(end + 1) * ACPI_NAMESEG_SIZE);
break;
@@ -187,6 +198,11 @@ char *acpi_ps_get_next_namestring(struct acpi_parse_state *parser_state)
break;
}
+ if (end > parser_state->aml_end) {
+ parser_state->aml = parser_state->aml_end;
+ return_PTR(NULL);
+ }
+
parser_state->aml = end;
return_PTR((char *)start);
}
diff --git a/drivers/acpi/acpica/psparse.c b/drivers/acpi/acpica/psparse.c
index b4f21a8988795..41587ee0a9c78 100644
--- a/drivers/acpi/acpica/psparse.c
+++ b/drivers/acpi/acpica/psparse.c
@@ -70,6 +70,9 @@ u16 acpi_ps_peek_opcode(struct acpi_parse_state * parser_state)
u16 opcode;
aml = parser_state->aml;
+ if (aml >= parser_state->aml_end) {
+ return (0xFFFF);
+ }
opcode = (u16) ACPI_GET8(aml);
if (opcode == AML_EXTENDED_PREFIX) {
@@ -77,6 +80,9 @@ u16 acpi_ps_peek_opcode(struct acpi_parse_state * parser_state)
/* Extended opcode, get the second opcode byte */
aml++;
+ if (aml >= parser_state->aml_end) {
+ return (0xFFFF);
+ }
opcode = (u16) ((opcode << 8) | ACPI_GET8(aml));
}
--
2.53.0
^ permalink raw reply related [flat|nested] 26+ messages in thread* [PATCH AUTOSEL 6.18-5.10] blk-cgroup: fix leaks and online flag on radix_tree_insert failure
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (7 preceding siblings ...)
2026-08-31 13:24 ` [PATCH AUTOSEL 6.18-5.10] ACPICA: add boundary checks " Sasha Levin
@ 2026-08-31 13:25 ` Sasha Levin
2026-08-31 13:25 ` [PATCH AUTOSEL 6.18-6.12] dmaengine: altera-msgdma: Use memcpy_toio for descriptor FIFO writes Sasha Levin
` (14 subsequent siblings)
23 siblings, 0 replies; 26+ messages in thread
From: Sasha Levin @ 2026-08-31 13:25 UTC (permalink / raw)
To: patches, stable
Cc: Tao Cui, Tejun Heo, Jens Axboe, Sasha Levin, josef, cgroups,
linux-block, linux-kernel
From: Tao Cui <cuitao@kylinos.cn>
[ Upstream commit dbbca20764382b4d411ec2918f4e278ffe547acc ]
When radix_tree_insert() fails in blkg_create(), the error path has two
issues:
1. blkg->online is set to true unconditionally, even when the blkg was
never fully inserted. Move the assignment inside the success block.
2. The error path calls blkg_put() without first calling
percpu_ref_kill(). Because the refcount is still in percpu mode,
percpu_ref_put() only does this_cpu_sub() without checking for zero,
so blkg_release() is never triggered. This permanently leaks the
blkg memory, its percpu iostat, policy data, the parent blkg
reference, and the cgroup css reference — the latter preventing the
cgroup from ever being destroyed.
Fix by replacing blkg_put() with percpu_ref_kill(), matching the pattern
used in blkg_destroy().
Acked-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Tao Cui <cuitao@kylinos.cn>
Link: https://patch.msgid.link/20260715132407.1469777-1-cui.tao@linux.dev
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
# Stable Backport Analysis: `blk-cgroup: fix leaks and online flag on
radix_tree_insert failure`
**Local tree:** `v6.18.44` (Linux 6.18.44 stable)
---
## PHASE 1: COMMIT MESSAGE FORENSICS
**Step 1.1 — Subject line**
Record: `[blk-cgroup]` `[fix]` — fixes resource leaks and incorrect
`online` flag when `radix_tree_insert()` fails in `blkg_create()`.
**Step 1.2 — Tags**
Record:
- **Acked-by:** Tejun Heo `<tj@kernel.org>` (cgroup/block-cgroup
maintainer)
- **Signed-off-by:** Tao Cui `<cuitao@kylinos.cn>` (author)
- **Signed-off-by:** Jens Axboe `<axboe@kernel.dk>` (block layer
maintainer)
- **Link:**
https://patch.msgid.link/20260715132407.1469777-1-cui.tao@linux.dev
- No Fixes:, Reported-by:, Tested-by:, Reviewed-by:, or Cc: stable tags
- (Ignoring pipeline-added Signed-off-by: Sasha Levin per instructions)
**Step 1.3 — Body analysis**
Record:
- **Bug:** When `radix_tree_insert()` fails in `blkg_create()`, two
errors occur:
1. `blkg->online = true` is set even though the blkg was never
inserted into the tree.
2. Error path calls `blkg_put()` without `percpu_ref_kill()`. While
the refcount is still in percpu mode, `percpu_ref_put()` only
decrements a per-CPU counter and never checks for zero, so
`blkg_release()` is never called.
- **Symptom/failure mode:** Permanent leak of blkg memory, percpu
iostat, policy data, parent blkg reference, and cgroup css reference —
the css leak prevents the cgroup from ever being destroyed.
- **Root cause:** Wrong teardown primitive on the error path;
`blkg_destroy()` correctly uses `percpu_ref_kill()`.
**Step 1.4 — Hidden bug fix?**
Record: No — this is an explicit bug fix, not disguised cleanup.
---
## PHASE 2: DIFF ANALYSIS
**Step 2.1 — Inventory**
Record:
- **Files:** `block/blk-cgroup.c` only (+2 / −2 lines, 4 lines touched)
- **Function:** `blkg_create()`
- **Scope:** Single-file, surgical fix
**Step 2.2 — Code flow change**
Record:
- **Hunk 1:** `blkg->online = true` moved inside the `if (likely(!ret))`
success block.
- Before: online set unconditionally after insert attempt.
- After: online only set when insert succeeds.
- **Hunk 2:** Error path changed from `blkg_put(blkg)` to
`percpu_ref_kill(&blkg->refcnt)`.
- Before: percpu-mode put never triggers release callback.
- After: switches to atomic mode and triggers `blkg_release()` →
`__blkg_release()` → `css_put()` + `blkg_free()`.
**Step 2.3 — Bug mechanism**
Record: **Reference counting / resource leak fix.** Category (a) error-
path leak + (g) logic correctness (online flag). The percpu_ref
lifecycle requires `percpu_ref_kill()` before the final drop can trigger
the release function — documented in `include/linux/percpu-refcount.h`
lines 19–24.
**Step 2.4 — Fix quality**
Record: Obviously correct — mirrors `blkg_destroy()` at line 568.
Minimal change. Very low regression risk; only affects the rare
`radix_tree_insert()` failure path.
---
## PHASE 3: GIT HISTORY INVESTIGATION
**Step 3.1 — Blame**
Record: Buggy lines in this tree all from `5d324e5159d9e` (v6.18 merge,
Nov 2025). Same pattern present in `v6.12` and `v6.17` per `git show`.
**Step 3.2 — Fixes: tag**
Record: Not applicable — no Fixes: tag in commit message.
**Step 3.3 — Related file history**
Record:
- `93383b6681074` — "wait for blkcg cleanup before initializing new
disk" — reduces `-EEXIST` from `radix_tree_insert()` during disk
rebind, but does not fix the broken error path when insert still
fails.
- `5e5b7f2ef8549` — UAF fix in `__blkcg_rstat_flush()` (related
subsystem, separate issue).
- Fix commit on master: `dbbca20764382` (Jul 15, 2026); **not** an
ancestor of current HEAD (`merge-base` exit 1).
**Step 3.4 — Author context**
Record: Tao Cui; Acked-by Tejun Heo (blk-cgroup/cgroup maintainer). No
other Tao Cui commits in this tree's `block/blk-cgroup.c` history.
**Step 3.5 — Dependencies**
Record: Standalone — no series dependencies, no prerequisite commits
required. Self-contained 4-line change.
---
## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
**Step 4.1 — Original discussion**
Record:
- `b4 dig -c dbbca20764382`:
https://patch.msgid.link/20260715132407.1469777-1-cui.tao@linux.dev
- Series: v4 only (no v1–v3 in b4 results; v4 is the applied version)
- No NAKs found in saved mbox
- No explicit Cc: stable nomination in thread headers
**Step 4.2 — Reviewers**
Record: `b4 dig -w` CC'd: tj@kernel.org, axboe@kernel.dk,
josef@toxicpanda.com, cgroups@vger.kernel.org, linux-
block@vger.kernel.org. Tejun Heo Acked-by.
**Step 4.3 — Bug report**
Record: No external bug report or syzbot link. Bug identified via code
review of percpu_ref lifecycle.
**Step 4.4 — Related patches**
Record: Complementary to `93383b6681074` (reduces trigger frequency) but
independently needed for correct error handling.
**Step 4.5 — Stable list**
Record: No stable@vger.kernel.org discussion found for this specific
fix.
---
## PHASE 5: CODE SEMANTIC ANALYSIS
**Step 5.1 — Key functions**
Record: `blkg_create()` modified; related: `blkg_destroy()`,
`blkg_release()`, `__blkg_release()`, `blkg_free()`.
**Step 5.2 — Callers**
Record: `blkg_create()` called from:
- `blkg_lookup_create()` — I/O hot path via `blkg_tryget_closest()` →
`bio_assoc_blkcg()` (line 2113)
- `blkg_conf_prep()` — cgroup sysfs configuration (uses
`radix_tree_preload`)
- `blkcg_init_disk()` — disk initialization (uses `radix_tree_preload`)
`blkg_lookup_create()` does **not** call `radix_tree_preload()`, so
`-ENOMEM` from `radix_tree_insert()` is reachable under memory pressure.
**Step 5.3 — Callees**
Record: On failure path after fix: `percpu_ref_kill()` →
`blkg_release()` → `__blkcg_rstat_flush()` + `call_rcu(__blkg_release)`
→ `css_put()` + `blkg_free()` → `blkg_free_workfn()` releases parent
ref, policy data, queue ref, percpu iostat.
**Step 5.4 — Reachability**
Record: Reachable from block I/O path when `CONFIG_BLK_CGROUP` is
enabled and a new blkg must be created for a cgroup/disk pair. Userspace
cgroup management can also trigger via `blkg_conf_prep()`. Unprivileged
users can trigger via I/O in their cgroup.
**Step 5.5 — Similar patterns**
Record: `blkg_destroy()` at line 568 already uses
`percpu_ref_kill(&blkg->refcnt)` — fix aligns error path with
established pattern. `include/linux/percpu-refcount.h` documents that
`percpu_ref_put()` does not check for zero before `percpu_ref_kill()`.
---
## PHASE 6: CROSS-REFERENCE WITH LOCAL TREE
**Step 6.1 — Buggy code present?**
Record: **YES.** Current tree at lines 436 and 443:
```436:444:block/blk-cgroup.c
blkg->online = true;
spin_unlock(&blkcg->lock);
if (!ret)
return blkg;
/* @blkg failed fully initialized, use the usual release path */
blkg_put(blkg);
return ERR_PTR(ret);
```
Bug present since at least v6.12 in this repository's history.
**Step 6.2 — Backport complications**
Record: Trivial change; `git apply --check` on upstream patch fails only
because stable has `err_put_css:` label that mainline parent lacks
(context line difference below the hunk). The three actual changed lines
apply without modification. Expected difficulty: **minor context
adjustment, not rework**.
**Step 6.3 — Related fixes already present?**
Record: `93383b6681074` is present (reduces `-EEXIST` trigger). This
specific leak fix is **not** present.
---
## PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
**Step 7.1 — Subsystem**
Record: **block/blk-cgroup** — CORE/IMPORTANT subsystem. Affects all
systems using cgroup v1/v2 block controller (`CONFIG_BLK_CGROUP`).
**Step 7.2 — Activity**
Record: Active maintenance in 6.18.y — recent fixes include UAF
(`5e5b7f2ef8549`), disk reference leak (`b3e005f16cd98`), blkcg cleanup
wait (`93383b6681074`).
---
## PHASE 8: IMPACT AND RISK ASSESSMENT
**Step 8.1 — Who is affected**
Record: Systems with `CONFIG_BLK_CGROUP` enabled — container hosts
(Kubernetes, Docker, systemd cgroups), cloud VMs, any workload using
block I/O cgroup controller.
**Step 8.2 — Trigger conditions**
Record:
- `radix_tree_insert()` returns error (`-ENOMEM` most likely in
`blkg_lookup_create()` without preload; `-EEXIST` possible in races
despite `93383b6681074`)
- Requires blkg creation for a new cgroup/disk pair
- Unprivileged cgroup users can trigger via I/O; cgroup admin via sysfs
- Not every boot — requires memory pressure or specific race — but
consequences are permanent
**Step 8.3 — Failure mode severity**
Record:
- **Permanent memory/resource leak** (blkg, iostat, policy data)
- **Cgroup css reference leak → cgroup cannot be destroyed** —
functional breakage for container lifecycle
- **Incorrect online flag** — minor (e.g., `blkcg_print_one_stat()` at
line 1190 may process a non-inserted blkg)
- Severity: **HIGH** (resource leak with cgroup destruction blocked; not
a crash but serious operational impact)
**Step 8.4 — Risk-benefit**
Record:
- **Benefit:** HIGH — prevents unrecoverable resource leaks and stuck
cgroups
- **Risk:** VERY LOW — 4-line change, matches existing `blkg_destroy()`
pattern, only affects error path
- **Ratio:** Strongly favors backport
---
## PHASE 9: FINAL SYNTHESIS
**Step 9.1 — Evidence summary**
**FOR:**
- Real, verifiable resource leak on error path
- Cgroup css leak prevents cgroup destruction — serious for production
container workloads
- Small, surgical, maintainer-acked fix
- Buggy code confirmed present in v6.18.44
- Matches documented percpu_ref semantics and existing `blkg_destroy()`
pattern
- Reachable from common I/O and cgroup configuration paths
**AGAINST:**
- Rare trigger (radix_tree_insert failure)
- No syzbot/user crash report
- Upstream patch needs trivial context adjustment for `err_put_css:`
label
**UNRESOLVED:**
- No quantitative data on how often `radix_tree_insert()` fails in
production
**Step 9.2 — Stable rules checklist**
1. Obviously correct and tested? **PASS** — mechanism verified against
`percpu-refcount.h` and `blkg_destroy()`; Acked-by cgroup maintainer
2. Fixes real bug affecting users? **PASS** — permanent leak + cgroup
destruction blocked
3. Important issue? **PASS** — HIGH severity resource leak affecting
cgroup lifecycle
4. Small and contained? **PASS** — 4 lines, one function, one file
5. No new features or APIs? **PASS**
6. Can apply to local tree? **PASS** — trivial manual apply (minor
context difference only)
**Step 9.3 — Exception categories**
Record: Not applicable (standard bug fix, not device ID/quirk/build/doc
exception).
**Step 9.4 — Decision rationale**
This commit fixes a genuine error-path bug in `blkg_create()` where
failed `radix_tree_insert()` leaves resources permanently leaked because
`blkg_put()` cannot trigger `blkg_release()` while the percpu refcount
is still in percpu mode. The css reference leak prevents cgroup
destruction — a significant operational issue for any system using block
cgroups. The fix is minimal, follows the established `blkg_destroy()`
pattern, is acked by the cgroup maintainer, and the buggy code is
present in this v6.18.44 tree without the fix.
---
## Verification
- [Phase 1] `git show dbbca20764382`: parsed subject, tags, body; Acked-
by Tejun Heo confirmed
- [Phase 2] Read `block/blk-cgroup.c` lines 371–452, 524–569, 1190; read
`include/linux/percpu-refcount.h` lines 19–24, 147–150, 326–352
- [Phase 2] Confirmed `blkg_put()` → `percpu_ref_put()` in `block/blk-
cgroup.h` line 336–338
- [Phase 3] `git describe HEAD`: v6.18.44; `git blame -L 419,452`: buggy
code from 5d324e5159d9e
- [Phase 3] `git merge-base --is-ancestor dbbca20764382 HEAD`: exit 1 —
fix NOT in tree
- [Phase 3] `git show v6.12/v6.17:v6.18:block/blk-cgroup.c`: same buggy
pattern back to v6.12
- [Phase 3] `93383b6681074` present in tree; complementary, not
substitute
- [Phase 4] `b4 dig -c dbbca20764382`: lore URL found; v4 series
- [Phase 4] `b4 dig -w`: maintainers CC'd; Tejun Heo Acked-by
- [Phase 4] `b4 dig -m /tmp/blkcg_fix.mbox`: no Cc: stable in thread
- [Phase 5] Grep callers: `blkg_create` at lines 510, 936, 1526;
`blkg_lookup_create` at 2113
- [Phase 5] Confirmed `blkg_lookup_create` does not use
`radix_tree_preload` (only `blkg_conf_prep` and `blkcg_init_disk` do)
- [Phase 6] Buggy code at lines 436, 443 confirmed in working tree
- [Phase 6] `git apply --check` fails on context below hunk
(`err_put_css:` vs `err_free_blkg:`); actual 3 changed lines are
identical — trivial backport
- [Phase 8] Failure mode: permanent leak + cgroup destruction blocked;
severity HIGH
**YES**
block/blk-cgroup.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c
index 812f60905a708..9aa3b6ae81ca8 100644
--- a/block/blk-cgroup.c
+++ b/block/blk-cgroup.c
@@ -432,15 +432,15 @@ static struct blkcg_gq *blkg_create(struct blkcg *blkcg, struct gendisk *disk,
blkg->pd[i]->online = true;
}
}
+ blkg->online = true;
}
- blkg->online = true;
spin_unlock(&blkcg->lock);
if (!ret)
return blkg;
/* @blkg failed fully initialized, use the usual release path */
- blkg_put(blkg);
+ percpu_ref_kill(&blkg->refcnt);
return ERR_PTR(ret);
err_put_css:
--
2.53.0
^ permalink raw reply related [flat|nested] 26+ messages in thread* [PATCH AUTOSEL 6.18-6.12] dmaengine: altera-msgdma: Use memcpy_toio for descriptor FIFO writes
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (8 preceding siblings ...)
2026-08-31 13:25 ` [PATCH AUTOSEL 6.18-5.10] blk-cgroup: fix leaks and online flag on radix_tree_insert failure Sasha Levin
@ 2026-08-31 13:25 ` Sasha Levin
2026-08-31 15:36 ` sashiko-bot
2026-08-31 13:25 ` [PATCH AUTOSEL 6.18] dm-raid: only requeue bios when dm is suspending Sasha Levin
` (13 subsequent siblings)
23 siblings, 1 reply; 26+ messages in thread
From: Sasha Levin @ 2026-08-31 13:25 UTC (permalink / raw)
To: patches, stable
Cc: Adrian Ng Ho Yin, Tze Yee Ng, Vinod Koul, Sasha Levin,
adrian.ho.yin.ng, dmaengine, linux-kernel
From: Adrian Ng Ho Yin <adrianhoyin.ng@altera.com>
[ Upstream commit 94963138cce29f85605d76c94fa1d43a0335ead9 ]
The descriptor FIFO requires that all words of a descriptor are written
in order, with the control word written last to flush it into the DMA
engine. Using memcpy() with __force to __iomem is not the correct API
and does not guarantee appropriate MMIO access on all architectures.
Replace the descriptor body copy with memcpy_toio(), using
offsetof(struct msgdma_extended_desc, control) to exclude the control
word. This matches the previous sizeof(desc->hw_desc) - sizeof(u32)
length only when control is the last struct member; add a static_assert
to enforce that layout so a future field after control cannot silently
break FIFO ordering.
Keep writing the control word separately with write barriers, so it
remains the final word pushed into the FIFO.
Signed-off-by: Adrian Ng Ho Yin <adrianhoyin.ng@altera.com>
Signed-off-by: Tze Yee Ng <tze.yee.ng@altera.com>
Link: https://patch.msgid.link/f6f3b4a2e2eb0eb1a51976de3f5d1ef5bab9bd76.1779697226.git.tze.yee.ng@altera.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
## Phase 1: Commit Message Forensics
**Step 1.1 – Subject line**
Record: `[dmaengine: altera-msgdma] [Use] Use memcpy_toio for descriptor
FIFO writes` — subsystem is Altera mSGDMA DMAengine driver; action is
replacing incorrect MMIO copy API.
**Step 1.2 – Tags**
Record:
- **Fixes:** none
- **Reported-by:** none
- **Tested-by:** none
- **Reviewed-by / Acked-by:** none
- **Link:** https://patch.msgid.link/f6f3b4a2e2eb0eb1a51976de3f5d1ef5bab
9bd76.1779697226.git.tze.yee.ng@altera.com
- **Signed-off-by:** Adrian Ng Ho Yin, Tze Yee Ng, Vinod Koul
(maintainer)
- **Cc: stable@vger.kernel.org:** absent (expected for manual review)
- Notable: no syzbot, no user bug report, no crash trace
**Step 1.3 – Body analysis**
Record:
- **Bug:** Descriptor FIFO hardware requires ordered 32-bit word writes;
control word must be written last to flush the descriptor. Using
`memcpy()` with `__force` cast to `__iomem` is not the correct MMIO
API and does not guarantee proper access on all architectures.
- **Symptom:** Malformed or partially written descriptors can cause DMA
to wrong addresses, transfer failures, or silent data corruption.
- **Root cause:** Body of descriptor copied via plain `memcpy()` to MMIO
instead of `memcpy_toio()`.
- **Version info:** none in message
**Step 1.4 – Hidden bug fix?**
Record: **Yes.** Although framed as an API correction, it fixes a real
hardware-interaction bug. The pre-existing comment in the driver already
acknowledged uncertainty about `memcpy()` write ordering; this commit
completes that fix by using the proper MMIO helper.
---
## Phase 2: Diff Analysis
**Step 2.1 – Inventory**
Record:
- **File:** `drivers/dma/altera-msgdma.c` (+15 / −9, 24 lines touched)
- **Function modified:** `msgdma_copy_one()` only
- **Scope:** single-file, surgical fix
**Step 2.2 – Code flow change**
Record:
- **Hunk 1 (before FIFO wait):** adds duplicate `static_assert`
verifying `control` is the last struct member.
- **Hunk 2 (before body copy):** adds second identical `static_assert`
(copy-paste error acknowledged by author on list).
- **Hunk 3 (body copy):** `memcpy((void __force *)hw_desc, ...)` →
`memcpy_toio(hw_desc, ..., offsetof(..., control))`; control word
still written separately via `iowrite32()` + `wmb()`.
- **Path affected:** every descriptor submission to hardware FIFO
(normal DMA operation path).
**Step 2.3 – Bug mechanism**
Record: **Memory safety / MMIO correctness fix.** Category: incorrect
MMIO access pattern. Plain `memcpy()` to `__iomem` may use CPU memory
copy optimizations (reordering, non-MMIO stores) that do not satisfy
hardware FIFO ordering requirements. `memcpy_toio()` uses architecture-
appropriate MMIO store sequences.
**Step 2.4 – Fix quality**
Record: Fix is logically correct and minimal. Regression risk is very
low — it replaces one copy primitive with the documented equivalent.
Minor quality blemish: duplicate `static_assert` blocks (author agreed
to fix in v3, but v2 was merged as-is). Pre-existing concerns (BE
endianness mix of `memcpy_toio` + `iowrite32`, `mdelay()` while holding
spinlock) are unchanged by this patch.
---
## Phase 3: Git History Investigation
**Step 3.1 – Blame**
Record: Buggy `memcpy()` path introduced in `6084fc2ec478d` (Aug 2017,
Stefan Roese, "Use macros instead of structs..."). Original driver added
in `a85c6f1b2921c` (Jul 2017). Bug has been present ~9 years.
**Step 3.2 – Fixes: tag**
Record: N/A — no Fixes: tag present.
**Step 3.3 – Related file history**
Record: Recent stable-tree changes to this file include descriptor
free/cleanup fixes (`54e4ada1a4206`, `d3ddfab0969b1`), spinlock IRQ
variant fix (`261d3a85d9598`). No related fix for MMIO copy already
present. Standalone patch (v2 of 1-patch series).
**Step 3.4 – Author context**
Record: Authors are Altera/Intel engineers (hardware vendor). Vinod Koul
(dmaengine maintainer) applied the patch. Authors are not regular
altera-msgdma maintainers but submitted from hardware expertise.
**Step 3.5 – Dependencies**
Record: No prerequisites. Uses `memcpy_toio()` and `static_assert`, both
available in Linux 6.18. Applies cleanly (`git apply --check` passed).
---
## Phase 4: Mailing List and External Research
**Step 4.1 – Original discussion**
Record:
- **URL:** https://patch.msgid.link/f6f3b4a2e2eb0eb1a51976de3f5d1ef5bab9
bd76.1779697226.git.tze.yee.ng@altera.com
- **Series:** v2 only (v1 not in thread); committed version matches v2
- **Maintainer response:** Vinod Koul — "Applied, thanks!"
- **No stable nomination** from reviewers
- **No NAKs** from human reviewers
**Step 4.2 – Reviewers**
Record: CC'd: Olivier Dautricourt, Stefan Roese (original driver
author), Vinod Koul, Frank Li, dmaengine@, linux-kernel@. Appropriate
maintainers included.
**Step 4.3 – Bug report**
Record: No external bug report. Sashiko AI review flagged duplicate
static_assert (Low) and pre-existing MMIO/endianness/spinlock+mdelay
issues (High, pre-existing). Author Tze Yee Ng agreed duplicate assert
was copy-paste error; offered v3 with single assert and optional
`iowrite32()` loop if Frank Li preferred. Frank Li asked author to
review Sashiko comments; no further human NAK before merge.
**Step 4.4 – Related patches**
Record: Standalone. Author indicated FIFO polling and stricter MMIO
access could be separate follow-ups.
**Step 4.5 – Stable list history**
Record: Not searched separately; no stable nomination found in patch
thread.
---
## Phase 5: Code Semantic Analysis
**Step 5.1 – Key functions**
Record: `msgdma_copy_one()` modified; callers unchanged.
**Step 5.2 – Callers**
Record:
- `msgdma_copy_desc_to_fifo()` → called from `msgdma_start_transfer()`
- `msgdma_start_transfer()` called from:
- `msgdma_issue_pending()` (under `spin_lock_irqsave`)
- `msgdma_irq_handler()` (under `spin_lock`)
- Reachable on every DMA transfer submission and from IRQ when
controller becomes idle.
**Step 5.3 – Callees**
Record: `ioread32()` (FIFO full check), `mdelay(1)` (wait loop),
`memcpy_toio()` (new), `wmb()`, `iowrite32()` (control word flush).
**Step 5.4 – Reachability**
Record: Triggered whenever userspace/kernel submits DMA operations
through the dmaengine API on Altera mSGDMA hardware
(`CONFIG_ALTERA_MSGDMA`). Common operational path, not init-only or
error-only.
**Step 5.5 – Similar patterns**
Record: Other dma drivers use `memcpy_toio()` for MMIO (e.g., edma). The
forced `memcpy()` to `__iomem` pattern is explicitly discouraged in
kernel MMIO documentation.
---
## Phase 6: Cross-Reference Against Local Tree
**Step 6.1 – Buggy code in this tree?**
Record: **Yes.** Local tree is **Linux 6.18.44** (`git describe HEAD` →
v6.18.44). Buggy `memcpy((void __force *)hw_desc, ...)` present at lines
518–519 of `drivers/dma/altera-msgdma.c`. Bug present since driver
introduction (2017).
**Step 6.2 – Backport complications**
Record: **Clean apply** confirmed via `git format-patch -1 94963138cce29
| git apply --check`. No conflicting recent changes to this function in
6.18.y.
**Step 6.3 – Related fixes already present?**
Record: Commit `94963138cce29` is **not** in `stable/linux-6.18.y` (`git
merge-base --is-ancestor` returned exit 1). No equivalent fix found via
grep for `memcpy_toio` in this file.
---
## Phase 7: Subsystem and Maintainer Context
**Step 7.1 – Subsystem criticality**
Record: **dmaengine / Altera mSGDMA driver** — **PERIPHERAL** (niche
FPGA/embedded hardware, `CONFIG_ALTERA_MSGDMA`). However, DMA descriptor
corruption affects memory integrity for users of that hardware.
**Step 7.2 – Subsystem activity**
Record: Driver receives occasional maintenance (descriptor lifecycle,
spinlock fixes in 2024–2025). Mature, low-churn code.
---
## Phase 8: Impact and Risk Assessment
**Step 8.1 – Who is affected**
Record: Users with `CONFIG_ALTERA_MSGDMA` on Altera/Intel FPGA platforms
(PCIe-connected Cyclone and similar, ARM and x86 per original driver
testing). Config-specific, platform-specific.
**Step 8.2 – Trigger conditions**
Record: Every DMA descriptor submission. Not timing-dependent race;
architecture-dependent MMIO behavior. Unprivileged users can trigger via
dmaengine consumers using this controller.
**Step 8.3 – Failure mode severity**
Record: Corrupted descriptor fields → DMA to/from wrong physical
addresses → **data corruption** (CRITICAL for affected users). Could
also cause transfer failure or hardware stall. No crash/oops required
for impact.
**Step 8.4 – Risk-benefit**
Record:
- **Benefit:** Prevents potential silent memory corruption on non-x86 or
strict MMIO architectures; uses correct kernel API; hardware vendor
fix.
- **Risk:** Very low — 1-line functional change plus compile-time
assert; applies cleanly.
- **Ratio:** Favorable for affected hardware users; limited broader
impact due to niche driver.
---
## Phase 9: Final Synthesis
**Step 9.1 – Evidence summary**
**FOR backport:**
- Real MMIO correctness bug present since 2017 in this tree
- Potential DMA data corruption (critical for affected users)
- Small, obviously correct, clean-apply fix
- Hardware vendor submitted with maintainer acceptance
- Original driver comment acknowledged memcpy ordering uncertainty
- Commit not yet in 6.18.y
**AGAINST backport:**
- No user bug report, crash, or syzbot finding
- Very niche driver (FPGA embedded)
- Driver has functioned with workaround since 2017 without reported
failures
- Duplicate `static_assert` in merged code (cosmetic)
- Does not address all MMIO concerns raised in AI review (pre-existing)
- No explicit stable nomination
**Unresolved:** No verified report of the bug manifesting in production;
impact inferred from API semantics and hardware requirements.
**Step 9.2 – Stable rules checklist**
1. Obviously correct and tested? **PASS** — API fix is standard; no
runtime Tested-by, but logically sound.
2. Fixes a real bug affecting users? **PASS** — incorrect MMIO access on
descriptor submission path.
3. Important issue? **PASS** — potential DMA data corruption.
4. Small and contained? **PASS** — 1 file, ~24 lines.
5. No new features/APIs? **PASS** — behavior correction only.
6. Can apply to local tree? **PASS** — clean apply verified.
**Step 9.3 – Exception categories**
Record: Not a device ID, quirk, DT, build, or docs fix. Standard driver
correctness bug fix.
**Step 9.4 – Decision rationale**
For Linux 6.18.y, the buggy code exists, the fix applies cleanly, and
the failure mode (DMA writing to wrong memory) is serious for the Altera
mSGDMA users this driver serves. While the driver is niche and lacks a
field bug report, the original code explicitly doubted `memcpy()`
ordering, the hardware vendor corrected the MMIO access pattern, and the
patch is minimal with negligible regression risk. Stable trees routinely
accept such hardware-interaction fixes when data corruption is the
consequence.
---
## Verification
- [Phase 1] Parsed commit `94963138cce29` on master; tags: Link, SOBs
only; no Reported-by/syzbot
- [Phase 2] Diff: 1 file, `msgdma_copy_one()` only; `memcpy` →
`memcpy_toio`; duplicate static_assert confirmed in `git show
94963138cce29`
- [Phase 3] `git blame`: buggy memcpy from `6084fc2ec478d` (2017);
driver from `a85c6f1b2921c` (2017)
- [Phase 3] `git log -20 -- drivers/dma/altera-msgdma.c`: no prior MMIO
fix
- [Phase 3] `git format-patch -1 94963138cce29 | git apply --check`:
clean apply
- [Phase 4] `b4 dig -c 94963138cce29`: lore URL found; v2 series
- [Phase 4] `b4 dig -c 94963138cce29 -w`: Vinod Koul, Frank Li, Stefan
Roese CC'd
- [Phase 4] `b4 dig -m /tmp/altera-msgdma.mbx`: Vinod applied; author
acknowledged duplicate assert; no stable nomination
- [Phase 5] Call chain verified in source:
`msgdma_issue_pending`/`msgdma_irq_handler` → `msgdma_start_transfer`
→ `msgdma_copy_desc_to_fifo` → `msgdma_copy_one`
- [Phase 6] `git describe HEAD`: v6.18.44; `make kernelversion`: 6.18.44
- [Phase 6] Buggy `memcpy((void __force *)hw_desc` confirmed at line 518
in local tree
- [Phase 6] `git merge-base --is-ancestor 94963138cce29
stable/linux-6.18.y`: NOT ancestor (exit 1)
- [Phase 6] `grep memcpy_toio drivers/dma/altera-msgdma.c`: no match in
local tree (fix absent)
- [Phase 7] `grep CONFIG_ALTERA_MSGDMA drivers/dma/Kconfig`: tristate,
depends on HAS_IOMEM
- [Phase 8] Struct layout verified: `control` is last field at offset 28
in 32-byte `msgdma_extended_desc`
**YES**
drivers/dma/altera-msgdma.c | 24 +++++++++++++++---------
1 file changed, 15 insertions(+), 9 deletions(-)
diff --git a/drivers/dma/altera-msgdma.c b/drivers/dma/altera-msgdma.c
index a203fdd84950e..e1811a9be0bbe 100644
--- a/drivers/dma/altera-msgdma.c
+++ b/drivers/dma/altera-msgdma.c
@@ -498,6 +498,11 @@ static void msgdma_copy_one(struct msgdma_device *mdev,
{
void __iomem *hw_desc = mdev->desc;
+ /* Ensure control is the last field — required for correct FIFO flush ordering */
+ static_assert(offsetof(struct msgdma_extended_desc, control) ==
+ sizeof(struct msgdma_extended_desc) - sizeof(u32),
+ "control must be the last field in msgdma_extended_desc");
+
/*
* Check if the DESC FIFO it not full. If its full, we need to wait
* for at least one entry to become free again
@@ -506,17 +511,18 @@ static void msgdma_copy_one(struct msgdma_device *mdev,
MSGDMA_CSR_STAT_DESC_BUF_FULL)
mdelay(1);
+ /* Ensure control is the last field — required for correct FIFO flush ordering */
+ static_assert(offsetof(struct msgdma_extended_desc, control) ==
+ sizeof(struct msgdma_extended_desc) - sizeof(u32),
+ "control must be the last field in msgdma_extended_desc");
+
/*
- * The descriptor needs to get copied into the descriptor FIFO
- * of the DMA controller. The descriptor will get flushed to the
- * FIFO, once the last word (control word) is written. Since we
- * are not 100% sure that memcpy() writes all word in the "correct"
- * order (address from low to high) on all architectures, we make
- * sure this control word is written last by single coding it and
- * adding some write-barriers here.
+ * Copy the descriptor into the descriptor FIFO of the DMA controller,
+ * excluding the control word. The FIFO is flushed and the descriptor
+ * becomes valid once the control word is written last.
*/
- memcpy((void __force *)hw_desc, &desc->hw_desc,
- sizeof(desc->hw_desc) - sizeof(u32));
+ memcpy_toio(hw_desc, &desc->hw_desc,
+ offsetof(struct msgdma_extended_desc, control));
/* Write control word last to flush this descriptor into the FIFO */
mdev->idle = false;
--
2.53.0
^ permalink raw reply related [flat|nested] 26+ messages in thread* Re: [PATCH AUTOSEL 6.18-6.12] dmaengine: altera-msgdma: Use memcpy_toio for descriptor FIFO writes
2026-08-31 13:25 ` [PATCH AUTOSEL 6.18-6.12] dmaengine: altera-msgdma: Use memcpy_toio for descriptor FIFO writes Sasha Levin
@ 2026-08-31 15:36 ` sashiko-bot
0 siblings, 0 replies; 26+ messages in thread
From: sashiko-bot @ 2026-08-31 15:36 UTC (permalink / raw)
To: Sasha Levin; +Cc: Frank.Li, vkoul, dmaengine
Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
New issues:
- [Low] Duplicate `static_assert` declaration.
Pre-existing issues:
- [Critical] Inconsistent MMIO accessor variants used for the same FIFO, causing data corruption on big-endian architectures.
- [Critical] Handling of zero-length transfers allocates a descriptor without accounting for it, causing out-of-bounds memory writes if the free list is empty.
- [High] Unbounded `mdelay(1)` loop while holding a spinlock with interrupts disabled.
- [High] Interrupt handler is registered before the spinlock and lists it relies on are initialized.
--
commit 53559846cb40149ec4edf05249c1dcd2c2956df1
Author: Adrian Ng Ho Yin <adrianhoyin.ng@altera.com>
dmaengine: altera-msgdma: Use memcpy_toio for descriptor FIFO writes
This commit fixes an issue where the descriptor body copy was using memcpy()
with a cast to __iomem, which does not guarantee proper MMIO access across
all architectures. It replaces the body copy with memcpy_toio(), excluding
the final control word which is still written separately.
Link: https://patch.msgid.link/f6f3b4a2e2eb0eb1a51976de3f5d1ef5bab9bd76.1779697226.git.tze.yee.ng@altera.com
> diff --git a/drivers/dma/altera-msgdma.c b/drivers/dma/altera-msgdma.c
> index a203fdd84950e..e1811a9be0bbe 100644
> --- a/drivers/dma/altera-msgdma.c
> +++ b/drivers/dma/altera-msgdma.c
> @@ -498,6 +498,11 @@ static void msgdma_copy_one(struct msgdma_device *mdev,
> {
> void __iomem *hw_desc = mdev->desc;
>
> + /* Ensure control is the last field — required for correct FIFO flush ordering */
> + static_assert(offsetof(struct msgdma_extended_desc, control) ==
> + sizeof(struct msgdma_extended_desc) - sizeof(u32),
> + "control must be the last field in msgdma_extended_desc");
> +
> /*
> * Check if the DESC FIFO it not full. If its full, we need to wait
> * for at least one entry to become free again
> */
> while (ioread32(mdev->csr + MSGDMA_CSR_STATUS) &
> MSGDMA_CSR_STAT_DESC_BUF_FULL)
> mdelay(1);
[Severity: High]
This is a pre-existing issue, but could this unbounded mdelay(1) loop cause a
hard lockup?
This function is called by msgdma_issue_pending() and msgdma_irq_handler()
which both hold mdev->lock and disable local interrupts. Busy-waiting for
milliseconds inside an IRQ-disabled atomic context will stall the CPU and
cause a hard lockup if the hardware stalls.
>
> + /* Ensure control is the last field — required for correct FIFO flush ordering */
> + static_assert(offsetof(struct msgdma_extended_desc, control) ==
> + sizeof(struct msgdma_extended_desc) - sizeof(u32),
> + "control must be the last field in msgdma_extended_desc");
> +
[Severity: Low]
this isn't a bug, but you've duplicated this static_assert statement from
a few lines above.
> /*
> - * The descriptor needs to get copied into the descriptor FIFO
> - * of the DMA controller. The descriptor will get flushed to the
> - * FIFO, once the last word (control word) is written. Since we
> - * are not 100% sure that memcpy() writes all word in the "correct"
> - * order (address from low to high) on all architectures, we make
> - * sure this control word is written last by single coding it and
> - * adding some write-barriers here.
> + * Copy the descriptor into the descriptor FIFO of the DMA controller,
> + * excluding the control word. The FIFO is flushed and the descriptor
> + * becomes valid once the control word is written last.
> */
> - memcpy((void __force *)hw_desc, &desc->hw_desc,
> - sizeof(desc->hw_desc) - sizeof(u32));
> + memcpy_toio(hw_desc, &desc->hw_desc,
> + offsetof(struct msgdma_extended_desc, control));
>
> /* Write control word last to flush this descriptor into the FIFO */
> mdev->idle = false;
> wmb();
> iowrite32(desc->hw_desc.control, hw_desc +
> offsetof(struct msgdma_extended_desc, control));
[Severity: Critical]
This is a pre-existing issue, but does mixing memcpy_toio() and iowrite32() on
the same hardware FIFO corrupt descriptor data on big-endian platforms?
The patch uses memcpy_toio() which preserves CPU byte order for the first 28
bytes of the descriptor, and iowrite32() which performs CPU-to-little-endian
byteswapping on big-endian architectures for the final 4-byte control word.
Writing to the same hardware FIFO with mixed accessor variants violates the
subsystem guidelines and ensures the descriptor will be malformed on
big-endian platforms.
[Severity: High]
This is a pre-existing issue, but is the interrupt handler registered before
the spinlock and lists it relies on are initialized?
drivers/dma/altera-msgdma.c:msgdma_probe() {
[ ... ]
ret = devm_request_irq(&pdev->dev, mdev->irq, msgdma_irq_handler,
0, dev_name(&pdev->dev), mdev);
if (ret)
return ret;
tasklet_setup(&mdev->irq_tasklet, msgdma_tasklet);
dma_cookie_init(&mdev->dmachan);
spin_lock_init(&mdev->lock);
[ ... ]
}
If a shared or spurious interrupt fires immediately during device probe,
msgdma_irq_handler() will attempt to lock the uninitialized mdev->lock and
access uninitialized list heads.
[Severity: Critical]
This is a pre-existing issue, but does a zero-length transfer bypass the free
list capacity check and cause out-of-bounds memory writes?
drivers/dma/altera-msgdma.c:msgdma_prep_memcpy() {
[ ... ]
desc_cnt = DIV_ROUND_UP(len, MSGDMA_MAX_TRANS_LEN);
spin_lock_irqsave(&mdev->lock, irqflags);
if (desc_cnt > mdev->desc_free_cnt) {
spin_unlock_irqrestore(&mdev->lock, irqflags);
dev_dbg(mdev->dev, "mdev %p descs are not available\n", mdev);
return NULL;
}
mdev->desc_free_cnt -= desc_cnt;
spin_unlock_irqrestore(&mdev->lock, irqflags);
do {
/* Allocate and populate the descriptor */
new = msgdma_get_descriptor(mdev);
[ ... ]
}
If len == 0, desc_cnt evaluates to 0. The bounds check passes even if
mdev->desc_free_cnt is 0. The function then unconditionally enters the do-while
loop and allocates a descriptor without accounting for it.
When msgdma_get_descriptor() calls list_first_entry() on the empty free_list,
it will return an invalid pointer aliasing the device struct. Subsequent
list_del() and hardware descriptor initialization will corrupt adjacent memory
inside mdev.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260831133314.4125787-290-sashal@kernel.org?part=1
^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH AUTOSEL 6.18] dm-raid: only requeue bios when dm is suspending
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (9 preceding siblings ...)
2026-08-31 13:25 ` [PATCH AUTOSEL 6.18-6.12] dmaengine: altera-msgdma: Use memcpy_toio for descriptor FIFO writes Sasha Levin
@ 2026-08-31 13:25 ` Sasha Levin
2026-08-31 13:25 ` [PATCH AUTOSEL 6.18-5.10] ACPICA: Fix integer overflow in acpi_ex_opcode_3A_1T_1R() (mid_op) Sasha Levin
` (12 subsequent siblings)
23 siblings, 0 replies; 26+ messages in thread
From: Sasha Levin @ 2026-08-31 13:25 UTC (permalink / raw)
To: patches, stable
Cc: Benjamin Marzinski, Mikulas Patocka, Sasha Levin, agk, snitzer,
song, yukuai, dm-devel, linux-kernel, linux-raid
From: Benjamin Marzinski <bmarzins@redhat.com>
[ Upstream commit 97cb8be0fd4c50d310988e0822f7e91d1711e6f8 ]
returning DM_MAPIO_REQUEUE from the target map() function only requeues
the bio during noflush suspends. During regular operations or during
flushing suspends, it fails the bio. Failing the bio during flushing
suspends is the correct behavior here. We cannot handle the bio, and we
cannot suspends while it is outstanding. But during normal operations,
we should not push the bio back to dm. Instead, wait for the reshape
to be resumed.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
# Stable Backport Analysis: `dm-raid: only requeue bios when dm is
suspending`
**Local tree:** Linux **6.18.43** (`v6.18.43-1-gc7f0dac02d232`)
---
## PHASE 1: COMMIT MESSAGE FORENSICS
### Step 1.1: Subject line
**Record:** `[dm-raid]` `[fix/implied]` — Only requeue bios when DM is
suspending (reshape-interrupted I/O path).
### Step 1.2: Tags
**Record:**
- **Fixes:** — none
- **Reported-by:** — none
- **Tested-by:** — none
- **Reviewed-by:** — none
- **Acked-by:** — none
- **Link:** — none
- **Cc: stable:** — none (expected for manual review)
- **Signed-off-by:** Benjamin Marzinski `<bmarzins@redhat.com>`, Mikulas
Patocka `<mpatocka@redhat.com>`
No syzbot, no user bug reports in the message. Authors are dm/md
maintainers.
### Step 1.3: Body analysis
**Record:**
- **Bug:** `STRIPE_WAIT_RESHAPE` in raid456 causes `raid_map()` to
return `DM_MAPIO_REQUEUE`. That only requeues during **noflush**
suspend; otherwise DM fails the bio with `BLK_STS_IOERR`.
- **Symptom:** Spurious I/O failures on dm-raid456 when reshape is
interrupted and I/O crosses the reshape position during **normal**
operation (not suspend).
- **Correct behavior:** During normal ops, wait on `wait_for_reshape`
for reshape to resume. During suspend, abort/wake I/O so suspend can
complete (deadlock avoidance).
- **Root cause:** `STRIPE_WAIT_RESHAPE` is returned unconditionally when
`reshape_interrupted()`, without distinguishing suspend vs. normal
operation.
### Step 1.4: Hidden bug fix?
**Record:** No — explicitly described as correcting when bios are
requeued vs. failed. Real I/O-path bug fix, not cosmetic cleanup.
---
## PHASE 2: DIFF ANALYSIS
### Step 2.1: Inventory
**Record:**
| File | Change |
|------|--------|
| `drivers/md/md.h` | +1 enum flag `MD_DM_SUSPENDING`, doc comment |
| `drivers/md/dm-raid.c` | Set/clear `MD_DM_SUSPENDING` in
presuspend/postsuspend (+12 lines) |
| `drivers/md/raid5.c` | Gate `STRIPE_WAIT_RESHAPE` on dm+suspending (+4
lines net) |
**Functions:** `raid_presuspend`, `raid_presuspend_undo`,
`raid_postsuspend`, `make_stripe_request`
**Scope:** Small, 3-file surgical fix.
### Step 2.2: Code flow (per hunk)
**Hunk 1 — `raid_presuspend`:** Before → only set `RT_FLAG_RS_FROZEN`.
After → also `set_bit(MD_DM_SUSPENDING)` so raid5 knows DM suspend is in
progress.
**Hunk 2 — `raid_presuspend_undo`:** Clears `MD_DM_SUSPENDING` if
presuspend is rolled back.
**Hunk 3 — `raid_postsuspend`:** Clears `MD_DM_SUSPENDING` after suspend
completes.
**Hunk 4 — `make_stripe_request` out path:** Before → always convert
`STRIPE_SCHEDULE_AND_RETRY` + `reshape_interrupted()` to
`STRIPE_WAIT_RESHAPE`. After → only convert when **not** dm-raid, **or**
dm-raid **and** `MD_DM_SUSPENDING` is set. Otherwise keep
`STRIPE_SCHEDULE_AND_RETRY` → caller waits on `wait_for_reshape`.
### Step 2.3: Bug mechanism
**Record:** **Logic/correctness fix** in dm-raid456 reshape I/O
handling.
Broken path (present in 6.18.43):
1. Reshape interrupted; I/O crosses reshape position.
2. `make_stripe_request` → `STRIPE_WAIT_RESHAPE`.
3. `raid5_make_request` → `md_free_cloned_bio`, returns `false`.
4. `md_handle_request` (no `gendisk`, has `prepare_suspend`) → returns
`false`.
5. `raid_map` → `DM_MAPIO_REQUEUE`.
6. `dm_handle_requeue` — not noflush suspending → `BLK_STS_IOERR` (bio
failed).
Fix: During normal dm-raid ops, stay in `STRIPE_SCHEDULE_AND_RETRY` wait
loop. Only take abort path during actual DM suspend.
### Step 2.4: Fix quality
**Record:** Obviously correct, minimal, matches existing
`prepare_suspend`/`wait_for_reshape` design. Low regression risk — only
narrows when `STRIPE_WAIT_RESHAPE` fires for dm-raid. Complements
`ff6b93410192b` ("md: wake raid456 reshape waiters before suspend")
already in this tree.
---
## PHASE 3: GIT HISTORY INVESTIGATION
### Step 3.1: Blame
**Record:** Buggy lines at `raid5.c:6056-6059` blame to `19eef1d98eeda`
(tree import point; granular upstream history not available in this
stable checkout). `STRIPE_WAIT_RESHAPE` and `reshape_interrupted`
handling are present in 6.18.43.
### Step 3.2: Fixes: tag
**Record:** N/A — no `Fixes:` tag.
### Step 3.3: Related file history
**Record:**
- `ff6b93410192b` — related suspend deadlock fix for native md (already
in 6.18.43).
- `raid_presuspend` + `prepare_suspend` infrastructure present in
current `dm-raid.c`.
- Commit under review **not** in this tree (`MD_DM_SUSPENDING` absent).
### Step 3.4: Author context
**Record:** Marzinski/Patocka are dm/md maintainers. Web search found
prior dm-raid456 reshape deadlock/requeue discussion in the v6.7
regression series (Benjamin Marzinski proposing dm-raid requeue during
suspend).
### Step 3.5: Dependencies
**Record:** Self-contained. Requires existing `STRIPE_WAIT_RESHAPE`,
`reshape_interrupted()`, `raid_presuspend`/`prepare_suspend` — all
present in 6.18.43. No series dependency.
---
## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
### Step 4.1: Original discussion
**Record:** `b4 dig -c <hash>` — **failed** (commit not in local git).
`b4 dig` with author email — **failed**. No matching `.mbx` in
workspace. lore.kernel.org — **blocked** (Anubis bot protection).
### Step 4.2: Reviewers
**Record:** UNVERIFIED — could not fetch mailing list thread.
### Step 4.3: Bug reports
**Record:** No `Reported-by`/`Link` in commit. Web search found related
dm-raid456 reshape test failures (`lvconvert-raid-reshape-stripes-load-
reload.sh`, `lvconvert-repair-raid.sh`) in the v6.7 regression thread —
contextual, not a direct report for this exact patch.
### Step 4.4: Series context
**Record:** Part of ongoing dm-raid456 reshape I/O fixes. Standalone;
does not require other unmerged patches.
### Step 4.5: Stable list
**Record:** UNVERIFIED — lore stable list inaccessible.
---
## PHASE 5: CODE SEMANTIC ANALYSIS
### Step 5.1: Key functions
**Record:** `make_stripe_request`, `raid5_make_request`,
`md_handle_request`, `raid_map`, `dm_handle_requeue`, `raid_presuspend`,
`raid5_prepare_suspend`.
### Step 5.2: Callers
**Record:**
- `raid_map` ← dm target map (all dm-raid I/O)
- `raid5_make_request` ← `md_handle_request` ← `raid_map`
- `raid_presuspend` ← dm suspend path
All common block-I/O and device-mapper admin paths.
### Step 5.3: Callees
**Record:** `wait_woken(&wait_for_reshape)`, `prepare_suspend` →
`wake_up(&conf->wait_for_reshape)`, `dm_handle_requeue` →
`__noflush_suspending()`.
### Step 5.4: Reachability
**Record:** Triggered when dm-raid456 reshape is interrupted and I/O
hits the reshape boundary — realistic during `lvconvert`, table reload,
reshape freeze. Userspace block I/O is the trigger. Not obscure or init-
only.
### Step 5.5: Similar patterns
**Record:** `mddev_is_dm()` checks exist elsewhere in raid5.c.
`DM_MAPIO_REQUEUE` only requeues under noflush suspend (`dm.c:929-939`).
Same pattern as other dm-raid reshape fixes.
---
## PHASE 6: CROSS-REFERENCE WITH LOCAL TREE (6.18.43)
### Step 6.1: Buggy code present?
**Record:** **YES.** Current tree at `raid5.c:6056-6059`:
```6056:6059:drivers/md/raid5.c
if (ret == STRIPE_SCHEDULE_AND_RETRY &&
reshape_interrupted(mddev)) {
bi->bi_status = BLK_STS_RESOURCE;
ret = STRIPE_WAIT_RESHAPE;
pr_err_ratelimited("dm-raid456: io across reshape
position while reshape can't make progress");
```
`MD_DM_SUSPENDING` **not** present. `raid_presuspend` has
`prepare_suspend` call but no suspending flag.
### Step 6.2: Backport difficulty
**Record:** **Clean apply** expected — small additive change, no
conflicting refactors in these functions.
### Step 6.3: Duplicate fix?
**Record:** **None.** `ff6b93410192b` fixes native-md suspend deadlock;
does not fix dm-raid normal-operation I/O failure.
---
## PHASE 7: SUBSYSTEM CONTEXT
### Step 7.1: Subsystem
**Record:** `drivers/md` — device-mapper / md RAID. **Criticality:
IMPORTANT** (storage stack, LVM dm-raid users).
### Step 7.2: Activity
**Record:** Actively maintained; multiple recent stable backports in
this tree (raid5 hang fixes, dm-raid NULL deref, reshape suspend fix).
---
## PHASE 8: IMPACT AND RISK
### Step 8.1: Who is affected
**Record:** dm-raid456 users (LVM `raid` target, reshaping arrays).
Config-specific, but affects production storage setups.
### Step 8.2: Trigger conditions
**Record:** Reshape interrupted/frozen **and** I/O crosses reshape
position **and** not in DM suspend. Moderately common during reshape
admin operations. Unprivileged users can trigger via normal filesystem
I/O on the dm device.
### Step 8.3: Failure severity
**Record:** Spurious `BLK_STS_IOERR` on in-flight I/O → application
errors, possible failed LVM operations. **Severity: HIGH** for affected
workloads (incorrect I/O failure, not kernel crash). Suspend deadlock is
a separate issue addressed by related patches.
### Step 8.4: Risk-benefit
**Record:**
- **Benefit:** HIGH for dm-raid reshape users — prevents incorrect I/O
failure.
- **Risk:** LOW — ~15 lines, internal flag, narrow condition change.
- **Ratio:** Strong benefit, minimal risk.
---
## PHASE 9: FINAL SYNTHESIS
### Step 9.1: Evidence summary
**FOR backport:**
- Real bug in 6.18.43 — verified in source
- Incorrect I/O failure on production storage path
- Small, surgical, maintainer-authored fix
- Complements existing reshape suspend fix already in tree
- Obviously correct logic: wait during normal ops, abort only during
suspend
- dm/md maintainers signed off
**AGAINST backport:**
- Affects dm-raid456 reshape edge case, not all kernel users
- No syzbot/user Reported-by in commit message
- Mailing list review not verified
**UNRESOLVED:**
- Original lore thread and explicit stable nomination not verified
- Exact upstream commit date/hash not in this checkout
### Step 9.2: Stable rules checklist
1. Obviously correct and tested? **PASS** — logic verified in code;
maintainer SOBs; no Tested-by
2. Fixes real bug affecting users? **PASS** — spurious I/O errors on dm-
raid456 reshape
3. Important issue? **PASS** — incorrect I/O failure on storage path
(HIGH)
4. Small and contained? **PASS** — ~15 lines, 3 files
5. No new features/APIs? **PASS** — internal `MD_DM_SUSPENDING` flag
only
6. Can apply to local tree? **PASS** — all prerequisite code present;
clean apply expected
### Step 9.3: Exception categories
**Record:** N/A — standard bug fix, not device-ID/quirk/build/doc
exception.
### Step 9.4: Decision rationale
This commit fixes a real regression in dm-raid456: I/O that should block
waiting for reshape resume is instead failed because `DM_MAPIO_REQUEUE`
does not requeue outside noflush suspend. The buggy code exists in Linux
6.18.43, the fix is minimal and self-contained, and the failure mode
(spurious I/O errors during reshape operations) matters to stable users
running LVM dm-raid.
---
## Verification
- **[Phase 1]** Parsed subject, tags, body from user-provided commit
message
- **[Phase 2]** Read current `raid5.c:6056-6060`, `dm-
raid.c:3341-3360,3824-3867`, `md.c:395-426`, `dm.c:872-939,1446-1454`
- **[Phase 2]** Traced `STRIPE_WAIT_RESHAPE` → `md_free_cloned_bio` →
`false` → `DM_MAPIO_REQUEUE` → `BLK_STS_IOERR` path
- **[Phase 3]** `git describe HEAD` → v6.18.43
- **[Phase 3]** `git blame -L 6056,6060 drivers/md/raid5.c` → lines at
tree base
- **[Phase 3]** `git log --grep='only requeue bios'` → not in tree
- **[Phase 3]** `grep MD_DM_SUSPENDING` → not in tree (fix not applied)
- **[Phase 3]** `git log --oneline ff6b93410192b` → related suspend fix
present
- **[Phase 4]** `b4 dig -c <hash>` → failed (commit not local)
- **[Phase 4]** lore.kernel.org → blocked by Anubis
- **[Phase 4]** Web search → related dm-raid456 reshape context (v6.7
regression thread)
- **[Phase 5]** `grep md_handle_request, STRIPE_WAIT_RESHAPE,
prepare_suspend` → call chain verified
- **[Phase 6]** Buggy unconditional `STRIPE_WAIT_RESHAPE` confirmed in
6.18.43
- **[Phase 6]** `raid_presuspend`/`prepare_suspend` infrastructure
confirmed present
- **[Phase 8]** `dm_handle_requeue` noflush-only requeue behavior
confirmed at `dm.c:929-939`
- **UNVERIFIED:** Mailing list review thread; explicit stable
nomination; upstream commit SHA
**YES**The background searches finished and match what the earlier
analysis already used:
- **Commit not in this tree** — no match for `MD_DM_SUSPENDING` or the
subject line; the fix is still a candidate, not applied.
- **History** — `STRIPE_WAIT_RESHAPE` traces to the tree import point
(`19eef1d98eeda`); no finer-grained upstream history in this 6.18.43
checkout.
- **kernel.org search** — no useful commit hit from the web grep.
**Verdict unchanged: YES** for backport to this 6.18.43 tree. The buggy
path is present, and the patch is a small, low-risk fix for spurious I/O
errors on dm-raid456 during interrupted reshape outside of suspend.
drivers/md/dm-raid.c | 6 ++++++
drivers/md/md.h | 2 ++
drivers/md/raid5.c | 7 +++++--
3 files changed, 13 insertions(+), 2 deletions(-)
diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c
index 4bacdc499984b..9eee490c029e7 100644
--- a/drivers/md/dm-raid.c
+++ b/drivers/md/dm-raid.c
@@ -3831,6 +3831,7 @@ static void raid_presuspend(struct dm_target *ti)
* resume, raid_postsuspend() is too late.
*/
set_bit(RT_FLAG_RS_FROZEN, &rs->runtime_flags);
+ set_bit(MD_DM_SUSPENDING, &mddev->flags);
if (!reshape_interrupted(mddev))
return;
@@ -3847,13 +3848,16 @@ static void raid_presuspend(struct dm_target *ti)
static void raid_presuspend_undo(struct dm_target *ti)
{
struct raid_set *rs = ti->private;
+ struct mddev *mddev = &rs->md;
+ clear_bit(MD_DM_SUSPENDING, &mddev->flags);
clear_bit(RT_FLAG_RS_FROZEN, &rs->runtime_flags);
}
static void raid_postsuspend(struct dm_target *ti)
{
struct raid_set *rs = ti->private;
+ struct mddev *mddev = &rs->md;
if (!test_and_set_bit(RT_FLAG_RS_SUSPENDED, &rs->runtime_flags)) {
/*
@@ -3864,6 +3868,8 @@ static void raid_postsuspend(struct dm_target *ti)
mddev_suspend(&rs->md, false);
rs->md.ro = MD_RDONLY;
}
+ clear_bit(MD_DM_SUSPENDING, &mddev->flags);
+
}
static void attempt_restore_of_faulty_devices(struct raid_set *rs)
diff --git a/drivers/md/md.h b/drivers/md/md.h
index 2960a98747607..2ece7788f9075 100644
--- a/drivers/md/md.h
+++ b/drivers/md/md.h
@@ -343,6 +343,7 @@ struct md_cluster_operations;
* @MD_HAS_SUPERBLOCK: There is persistence sb in member disks.
* @MD_FAILLAST_DEV: Allow last rdev to be removed.
* @MD_SERIALIZE_POLICY: Enforce write IO is not reordered, just used by raid1.
+ * @MD_DM_SUSPENDING: This DM raid device is suspending.
*
* change UNSUPPORTED_MDDEV_FLAGS for each array type if new flag is added
*/
@@ -362,6 +363,7 @@ enum mddev_flags {
MD_HAS_SUPERBLOCK,
MD_FAILLAST_DEV,
MD_SERIALIZE_POLICY,
+ MD_DM_SUSPENDING,
};
enum mddev_sb_flags {
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index b19d870e41719..0d83c4adf8e83 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -6054,8 +6054,11 @@ static enum stripe_result make_stripe_request(struct mddev *mddev,
raid5_release_stripe(sh);
out:
if (ret == STRIPE_SCHEDULE_AND_RETRY && reshape_interrupted(mddev)) {
- bi->bi_status = BLK_STS_RESOURCE;
- ret = STRIPE_WAIT_RESHAPE;
+ if (!mddev_is_dm(mddev) ||
+ test_bit(MD_DM_SUSPENDING, &mddev->flags)) {
+ bi->bi_status = BLK_STS_RESOURCE;
+ ret = STRIPE_WAIT_RESHAPE;
+ }
pr_err_ratelimited("dm-raid456: io across reshape position while reshape can't make progress");
}
return ret;
--
2.53.0
^ permalink raw reply related [flat|nested] 26+ messages in thread* [PATCH AUTOSEL 6.18-5.10] ACPICA: Fix integer overflow in acpi_ex_opcode_3A_1T_1R() (mid_op)
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (10 preceding siblings ...)
2026-08-31 13:25 ` [PATCH AUTOSEL 6.18] dm-raid: only requeue bios when dm is suspending Sasha Levin
@ 2026-08-31 13:25 ` Sasha Levin
2026-08-31 13:26 ` [PATCH AUTOSEL 6.18-5.10] ACPICA: Add package limit checks in parser functions Sasha Levin
` (11 subsequent siblings)
23 siblings, 0 replies; 26+ messages in thread
From: Sasha Levin @ 2026-08-31 13:25 UTC (permalink / raw)
To: patches, stable
Cc: ikaros, Rafael J. Wysocki, Sasha Levin, rafael,
maciej.wieczor-retman, pawel.chmielewski, linux-acpi,
acpica-devel, linux-kernel
From: ikaros <void0red@gmail.com>
[ Upstream commit 0e2021f49e64b3c8a9aa880d0c62a218bfe147ce ]
Add overflow check for Index + Length to prevent integer overflow
when calculating the truncation length. This prevents negative
size parameter being passed to memcpy().
Link: https://github.com/acpica/acpica/commit/d281ec1ac84e
Signed-off-by: ikaros <void0red@gmail.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Link: https://patch.msgid.link/3760974.R56niFO833@rafael.j.wysocki
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
The background author/search finished. A search for `ikaros`/`void0red`
in this tree only turned up unrelated error-path hardening commits
(hwmon, thermal, ACPICA debug checks, etc.) — not the MidOp overflow
fix. That fix exists only on master as `0e2021f49e64b` and is still
missing from `stable/linux-6.18.y` at v6.18.44.
That matches the earlier analysis: the vulnerable code is present, the
one-line patch applies cleanly, and the backport recommendation remains
**YES**.
drivers/acpi/acpica/exoparg3.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/acpi/acpica/exoparg3.c b/drivers/acpi/acpica/exoparg3.c
index c8c8c4e49563e..df770f36b4d08 100644
--- a/drivers/acpi/acpica/exoparg3.c
+++ b/drivers/acpi/acpica/exoparg3.c
@@ -152,7 +152,7 @@ acpi_status acpi_ex_opcode_3A_1T_1R(struct acpi_walk_state *walk_state)
/* Truncate request if larger than the actual String/Buffer */
- else if ((index + length) > operand[0]->string.length) {
+ else if ((index + length) > operand[0]->string.length || (index + length) < index) { /* Check for overflow */
length =
(acpi_size)operand[0]->string.length -
(acpi_size)index;
--
2.53.0
^ permalink raw reply related [flat|nested] 26+ messages in thread* [PATCH AUTOSEL 6.18-5.10] ACPICA: Add package limit checks in parser functions
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (11 preceding siblings ...)
2026-08-31 13:25 ` [PATCH AUTOSEL 6.18-5.10] ACPICA: Fix integer overflow in acpi_ex_opcode_3A_1T_1R() (mid_op) Sasha Levin
@ 2026-08-31 13:26 ` Sasha Levin
2026-08-31 13:26 ` [PATCH AUTOSEL 6.18-5.10] ACPICA: Fix use-after-free in acpi_ds_terminate_control_method() Sasha Levin
` (10 subsequent siblings)
23 siblings, 0 replies; 26+ messages in thread
From: Sasha Levin @ 2026-08-31 13:26 UTC (permalink / raw)
To: patches, stable
Cc: ikaros, Rafael J. Wysocki, Sasha Levin, rafael,
maciej.wieczor-retman, pawel.chmielewski, linux-acpi,
acpica-devel, linux-kernel
From: ikaros <void0red@gmail.com>
[ Upstream commit d27d48a528e437aed690f977e69a6fe73fe82ab5 ]
Add package limit checks in parser functions to prevent out-of-bounds
access.
Link: https://github.com/acpica/acpica/commit/b31b45af2122
Signed-off-by: ikaros <void0red@gmail.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Link: https://patch.msgid.link/3212937.CbtlEUcBR6@rafael.j.wysocki
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
The background git searches finished. Both came back empty:
- No commit matching **"Add package limit"** in this tree
- No commits from author **ikaros**
- No related fixes for **"Clamp PackageEnd"**, **"package limit"**, or
**"package end"**
That confirms the package-limit checks are not in **6.18.44** yet. The
earlier analysis stands: this is a small, maintainer-reviewed bounds-
check fix for a real ACPI parser OOB read, and it should be backported.
**YES**
drivers/acpi/acpica/nsxfname.c | 4 ++++
drivers/acpi/acpica/psargs.c | 4 ++++
drivers/acpi/acpica/psloop.c | 25 +++++++++++++++++++++++++
drivers/acpi/acpica/psparse.c | 8 ++++++++
4 files changed, 41 insertions(+)
diff --git a/drivers/acpi/acpica/nsxfname.c b/drivers/acpi/acpica/nsxfname.c
index 1db831545ec8c..821fb4930e9d8 100644
--- a/drivers/acpi/acpica/nsxfname.c
+++ b/drivers/acpi/acpica/nsxfname.c
@@ -512,6 +512,10 @@ acpi_status acpi_install_method(u8 *buffer)
parser_state.aml += acpi_ps_get_opcode_size(opcode);
parser_state.pkg_end = acpi_ps_get_next_package_end(&parser_state);
+ if ((parser_state.pkg_end > parser_state.aml_end) ||
+ (parser_state.pkg_end < parser_state.aml)) {
+ return (AE_AML_PACKAGE_LIMIT);
+ }
path = acpi_ps_get_next_namestring(&parser_state);
method_flags = *parser_state.aml++;
diff --git a/drivers/acpi/acpica/psargs.c b/drivers/acpi/acpica/psargs.c
index 064652d11d9aa..34d887e2211ac 100644
--- a/drivers/acpi/acpica/psargs.c
+++ b/drivers/acpi/acpica/psargs.c
@@ -867,6 +867,10 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state,
parser_state->pkg_end =
acpi_ps_get_next_package_end(parser_state);
+ if ((parser_state->pkg_end > parser_state->aml_end)
+ || (parser_state->pkg_end < parser_state->aml)) {
+ return_ACPI_STATUS(AE_AML_PACKAGE_LIMIT);
+ }
break;
case ARGP_FIELDLIST:
diff --git a/drivers/acpi/acpica/psloop.c b/drivers/acpi/acpica/psloop.c
index 35111ff2526b1..7c3caf0ccab62 100644
--- a/drivers/acpi/acpica/psloop.c
+++ b/drivers/acpi/acpica/psloop.c
@@ -361,6 +361,13 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state)
walk_state->parser_state.aml =
acpi_ps_get_next_package_end
(&walk_state->parser_state);
+ if ((walk_state->parser_state.aml >
+ walk_state->parser_state.aml_end)
+ || (walk_state->parser_state.aml <
+ walk_state->aml)) {
+ return_ACPI_STATUS
+ (AE_AML_PACKAGE_LIMIT);
+ }
walk_state->aml =
walk_state->parser_state.aml;
}
@@ -421,6 +428,14 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state)
parser_state->aml =
acpi_ps_get_next_package_end
(parser_state);
+ if ((parser_state->aml >
+ parser_state->aml_end)
+ || (parser_state->aml <
+ walk_state->control_state->
+ control.aml_predicate_start)) {
+ return_ACPI_STATUS
+ (AE_AML_PACKAGE_LIMIT);
+ }
walk_state->aml = parser_state->aml;
ACPI_ERROR((AE_INFO,
@@ -436,6 +451,16 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state)
walk_state->parser_state.aml =
acpi_ps_get_next_package_end
(parser_state);
+ if ((walk_state->parser_state.
+ aml >
+ walk_state->parser_state.
+ aml_end)
+ || (walk_state->
+ parser_state.aml <
+ walk_state->aml)) {
+ return_ACPI_STATUS
+ (AE_AML_PACKAGE_LIMIT);
+ }
walk_state->aml =
parser_state->aml;
}
diff --git a/drivers/acpi/acpica/psparse.c b/drivers/acpi/acpica/psparse.c
index 55a416e56fd83..b4f21a8988795 100644
--- a/drivers/acpi/acpica/psparse.c
+++ b/drivers/acpi/acpica/psparse.c
@@ -300,6 +300,7 @@ acpi_ps_next_parse_state(struct acpi_walk_state *walk_state,
{
struct acpi_parse_state *parser_state = &walk_state->parser_state;
acpi_status status = AE_CTRL_PENDING;
+ u8 *aml;
ACPI_FUNCTION_TRACE_PTR(ps_next_parse_state, op);
@@ -344,7 +345,14 @@ acpi_ps_next_parse_state(struct acpi_walk_state *walk_state,
* Predicate of an IF was true, and we are at the matching ELSE.
* Just close out this package
*/
+ aml = parser_state->aml;
+
parser_state->aml = acpi_ps_get_next_package_end(parser_state);
+ if ((parser_state->aml > parser_state->aml_end) ||
+ (parser_state->aml < aml)) {
+ status = AE_AML_PACKAGE_LIMIT;
+ break;
+ }
status = AE_CTRL_PENDING;
break;
--
2.53.0
^ permalink raw reply related [flat|nested] 26+ messages in thread* [PATCH AUTOSEL 6.18-5.10] ACPICA: Fix use-after-free in acpi_ds_terminate_control_method()
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (12 preceding siblings ...)
2026-08-31 13:26 ` [PATCH AUTOSEL 6.18-5.10] ACPICA: Add package limit checks in parser functions Sasha Levin
@ 2026-08-31 13:26 ` Sasha Levin
2026-08-31 13:27 ` [PATCH AUTOSEL 6.18-5.10] ACPICA: validate byte_count in acpi_ps_get_next_package_length() Sasha Levin
` (9 subsequent siblings)
23 siblings, 0 replies; 26+ messages in thread
From: Sasha Levin @ 2026-08-31 13:26 UTC (permalink / raw)
To: patches, stable
Cc: ikaros, Rafael J. Wysocki, Sasha Levin, rafael,
maciej.wieczor-retman, pawel.chmielewski, linux-acpi,
acpica-devel, linux-kernel
From: ikaros <void0red@gmail.com>
[ Upstream commit 945e87267cfd90937b3c637f87324cbb56998b72 ]
Fix use-after-free issue in acpi_ds_terminate_control_method() by
clearing references to method locals and arguments.
Link: https://github.com/acpica/acpica/commit/36f22a94cb1b
Signed-off-by: ikaros <void0red@gmail.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Link: https://patch.msgid.link/8730924.NyiUUSuA9g@rafael.j.wysocki
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
# Stable Backport Analysis: ACPICA UAF in
`acpi_ds_terminate_control_method()`
**Local tree:** Linux **6.18.44** (`git describe HEAD` → `v6.18.44`,
`make kernelversion` → `6.18.44`)
---
## PHASE 1: COMMIT MESSAGE FORENSICS
### Step 1.1: PARSE THE SUBJECT LINE
**Record:** `[ACPICA] [fix] use-after-free in
acpi_ds_terminate_control_method() when clearing references to method
locals/arguments`
### Step 1.2: PARSE ALL COMMIT MESSAGE TAGS
**Record:**
- **Link:** https://github.com/acpica/acpica/commit/36f22a94cb1b
(upstream ACPICA commit)
- **Link:** https://patch.msgid.link/8730924.NyiUUSuA9g@rafael.j.wysocki
(kernel submission; could not fetch)
- **Signed-off-by:** ikaros \<void0red@gmail.com\> (author)
- **Signed-off-by:** Rafael J. Wysocki \<rafael.j.wysocki@intel.com\>
(ACPI maintainer)
- **Fixes:** #1119 (ACPICA GitHub issue, in upstream commit message)
- No Reported-by, Tested-by, Reviewed-by, Acked-by, or Cc: stable in the
provided message
- Notable: Maintainer sign-off; upstream issue with ASAN reproduction
### Step 1.3: ANALYZE THE COMMIT BODY TEXT
**Record:**
- **Bug:** If `walk_state->return_desc` is a `RefOf` reference pointing
at a method local or argument namespace node (embedded in
`walk_state`), terminating the method deletes locals/args and later
frees `walk_state`, leaving a dangling pointer in `return_desc`.
- **Symptom:** Heap use-after-free when `acpi_ns_resolve_references()`
dereferences `node->object` during `acpi_evaluate_object()`.
- **Root cause:** `acpi_ds_method_data_delete_all()` and
`acpi_ds_delete_walk_state()` invalidate nodes still referenced by
`return_desc`.
- **Fix approach:** Before deleting locals/args, detect
`ACPI_REFCLASS_REFOF` references to `walk_state->local_variables[]` or
`walk_state->arguments[]`, drop the reference, and NULL `return_desc`.
### Step 1.4: DETECT HIDDEN BUG FIXES
**Record:** Not disguised — explicitly labeled as a use-after-free fix.
The mechanism is a classic dangling-pointer bug in interpreter teardown,
not cosmetic cleanup.
---
## PHASE 2: DIFF ANALYSIS
### Step 2.1: INVENTORY THE CHANGES
**Record:**
- **Files:** `drivers/acpi/acpica/dsmethod.c` (+43 lines, 0 removed)
- **Function modified:** `acpi_ds_terminate_control_method()`
- **Scope:** Single-file, surgical fix in ACPI interpreter dispatch path
### Step 2.2: UNDERSTAND THE CODE FLOW CHANGE
**Record:**
- **Hunk (before):** On method termination, immediately calls
`acpi_ds_method_data_delete_all(walk_state)` while
`walk_state->return_desc` may still hold a `RefOf` pointer into
`walk_state->local_variables[]` or `walk_state->arguments[]`.
- **Hunk (after):** Before `acpi_ds_method_data_delete_all()`, if
`return_desc` is `ACPI_TYPE_LOCAL_REFERENCE` / `ACPI_REFCLASS_REFOF`
and `reference.object` matches a local or argument node in this
`walk_state`, call `acpi_ut_remove_reference()` and set `return_desc =
NULL`.
- **Execution path:** Method termination during AML parse/execute
(normal and error paths), always under interpreter lock.
### Step 2.3: IDENTIFY THE BUG MECHANISM
**Record:**
- **Category:** Memory safety — use-after-free (dangling pointer)
- **Mechanism:** `local_variables[]` and `arguments[]` are embedded in
`struct acpi_walk_state` (`acstruct.h:66-67`). A `RefOf(LocalX)`
return value stores a pointer to those nodes. After method termination
frees `walk_state`, `acpi_ns_resolve_references()` at
`nsxfeval.c:496-501` reads `node->object` from freed memory.
### Step 2.4: ASSESS THE FIX QUALITY
**Record:**
- Fix is minimal, localized, and logically correct for the identified
failure mode.
- Regression risk is low: only affects the teardown path when
`return_desc` references ephemeral local/arg nodes.
- Trade-off: dropping the reference yields no return value instead of a
crash — acceptable vs. UAF, and explicit `Return(RefOf(Local))` paths
are supposed to resolve references earlier in `dscontrol.c`.
- No API changes, no new features.
---
## PHASE 3: GIT HISTORY INVESTIGATION
### Step 3.1: BLAME THE CHANGED LINES
**Record:** Buggy teardown sequence dates to **2005-2006**
(`b229cf92eee616` / `^1da177e4c3f41` on
`acpi_ds_method_data_delete_all()` call). Long-present bug, not a recent
regression.
### Step 3.2: FOLLOW THE FIXES: TAG
**Record:** No `Fixes:` tag in the kernel commit message. Upstream
ACPICA commit references `Fixes: #1119`.
### Step 3.3: CHECK FILE HISTORY FOR RELATED CHANGES
**Record:** Related prior UAF fix in this tree: `6fcab27915439`
("ACPICA: Refuse to evaluate a method if arguments are missing") —
different bug, same subsystem, also UAF from AML evaluation. Another:
`470188b09e92d` (package copy UAF). This specific
`terminate_control_method` fix is **not** present in 6.18.44.
### Step 3.4: CHECK THE AUTHOR'S OTHER COMMITS
**Record:** Author ikaros reported ACPICA issue #1119. Rafael J. Wysocki
is ACPI maintainer and regularly syncs ACPICA fixes (e.g.,
`6fcab27915439`, `e2c80b3c23782`).
### Step 3.5: CHECK FOR DEPENDENT/PREREQUISITE COMMITS
**Record:** Standalone fix. No series dependencies. Applies to existing
`acpi_ds_terminate_control_method()` with only path adjustment
(`source/components/dispatcher/dsmethod.c` →
`drivers/acpi/acpica/dsmethod.c`).
---
## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
### Step 4.1: FIND THE ORIGINAL PATCH DISCUSSION
**Record:** `b4 dig -c 36f22a94cb1b` failed — commit is upstream ACPICA
only, not in this kernel tree. `lore.kernel.org` returned 403.
`patch.msgid.link` blocked by bot protection. Upstream GitHub issue
#1119 provides full reproduction and ASAN stack trace.
### Step 4.2: CHECK WHO REVIEWED THE PATCH
**Record:** Could not verify via b4/lore. Upstream issue closed by Saket
Dumbre (ACPICA maintainer). Kernel commit signed by Rafael J. Wysocki.
### Step 4.3: SEARCH FOR THE BUG REPORT
**Record:** [ACPICA issue
#1119](https://github.com/acpica/acpica/issues/1119) — "Use-After-Free
in AcpiNsResolveReferences"
- **Reproducer:** `./acpiexec -m issue7.aml`
- **ASAN:** heap-use-after-free READ at `AcpiNsResolveReferences`
(nsxfeval.c:692 upstream)
- **Free site:** `AcpiDsDeleteWalkState` during `AcpiPsParseAml`
- **Alloc site:** `AcpiDsCreateWalkState`
- Severity: reproducible memory corruption in ACPI method evaluation
### Step 4.4: CHECK FOR RELATED PATCHES AND SERIES
**Record:** Single-commit fix in upstream ACPICA. No multi-patch series.
### Step 4.5: CHECK STABLE MAILING LIST HISTORY
**Record:** Could not access lore (403). No stable-list discussion found
via available tools.
---
## PHASE 5: CODE SEMANTIC ANALYSIS
### Step 5.1: IDENTIFY KEY FUNCTIONS IN THE DIFF
**Record:** `acpi_ds_terminate_control_method()` — only function
modified.
### Step 5.2: TRACE CALLERS
**Record:** Called from:
- `psxface.c:168` — internal method execution cleanup
- `psparse.c:434` — error path during thread creation
- `psparse.c:568` — normal method completion / error during parse
- `dsmethod.c:594` — nested method handling
All paths run during ACPI control method evaluation — core interpreter
hot path.
### Step 5.3: TRACE CALLEES
**Record:** Fix adds `acpi_ut_remove_reference()`; existing path calls
`acpi_ds_method_data_delete_all()`, namespace cleanup, mutex release,
thread count management.
### Step 5.4: FOLLOW THE CALL CHAIN
**Record:**
`acpi_evaluate_object()` → `acpi_ns_evaluate()` →
`acpi_ps_execute_method()` → `acpi_ps_parse_aml()` →
`acpi_ds_terminate_control_method()` → (later)
`acpi_ns_resolve_references()` on the return object.
Reachable whenever kernel code evaluates ACPI methods returning `RefOf`
references to locals/args without prior resolution — including firmware
AML during boot, suspend/resume, thermal, battery, and device
enumeration.
### Step 5.5: SEARCH FOR SIMILAR PATTERNS
**Record:** `dscontrol.c:236-254` and `dscontrol.c:264-286` already
resolve references on explicit `Return()`, but
`acpi_ds_restart_control_method()` (`dsmethod.c:658`) can propagate
unresolved `return_desc` from nested calls. The terminate-time guard
closes the gap.
---
## PHASE 6: CROSS-REFERENCING AGAINST THE LOCAL TREE
### Step 6.1: DOES THE BUGGY CODE EXIST IN THIS TREE?
**Record:** **YES.** `drivers/acpi/acpica/dsmethod.c:717-721` goes
directly to `acpi_ds_method_data_delete_all()` with no `return_desc`
guard. `local_variables[]` / `arguments[]` embedded in `walk_state` per
`acstruct.h:66-67`. `acpi_ns_resolve_references()` at
`nsxfeval.c:496-501` performs the dangling dereference. Fix is **not**
present (grep found no matching comment/pattern).
### Step 6.2: CHECK FOR BACKPORT COMPLICATIONS
**Record:** Expected **clean apply** with path adjustment only.
Insertion point at line 717 matches upstream hunk context exactly.
Upstream raw patch failed only due to path mismatch
(`source/components/dispatcher/` vs `drivers/acpi/acpica/`).
### Step 6.3: CHECK IF RELATED FIXES ARE ALREADY HERE
**Record:** No equivalent fix for this specific UAF. Prior ACPICA UAF
fixes (`6fcab27915439`, `470188b09e92d`) address different bugs.
---
## PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
### Step 7.1: IDENTIFY THE SUBSYSTEM AND ITS CRITICALITY
**Record:** **ACPI / ACPICA interpreter** — **CORE**. Affects all ACPI-
enabled systems (x86, ARM servers/laptops, etc.).
### Step 7.2: ASSESS SUBSYSTEM ACTIVITY
**Record:** Actively maintained; regular ACPICA syncs in 6.18.y (e.g.,
`e2c80b3c23782`, `6fcab27915439`).
---
## PHASE 8: IMPACT AND RISK ASSESSMENT
### Step 8.1: DETERMINE WHO IS AFFECTED
**Record:** All systems running ACPI firmware methods — universal on
ACPI platforms. `acpi_evaluate_object` is used across battery, thermal,
power, PCI, processor, and bus code (30+ files under `drivers/acpi/`).
### Step 8.2: DETERMINE THE TRIGGER CONDITIONS
**Record:** ACPI method returns a `RefOf` reference to its own local or
argument without the reference being fully resolved before method
termination. Triggered by specific AML (reproduced with `issue7.aml`;
potentially present in platform firmware). Not a direct unprivileged
syscall path, but firmware-controlled AML runs with kernel privileges.
### Step 8.3: DETERMINE THE FAILURE MODE SEVERITY
**Record:** **HIGH** — heap use-after-free during
`acpi_evaluate_object()`. Can cause kernel oops/crash or memory
corruption. Potential security relevance (UAF in privileged interpreter
context).
### Step 8.4: CALCULATE RISK-BENEFIT RATIO
**Record:**
- **Benefit:** HIGH — prevents real UAF on common ACPI evaluation path
- **Risk:** LOW — 43 lines, single function, teardown-only, maintainer-
reviewed pattern
- **Ratio:** Strongly favors backport
---
## PHASE 9: FINAL SYNTHESIS
### Step 9.1: COMPILE THE EVIDENCE
**FOR backport:**
- Confirmed heap UAF with ASAN reproduction (ACPICA #1119)
- Affects `acpi_evaluate_object()` — widely used kernel API
- Buggy code present in 6.18.44 since ~2005
- Small, surgical, obviously correct fix
- ACPI maintainer sign-off
- Precedent: similar ACPICA UAF fixes already in stable series
(`6fcab27915439`)
- Failure mode is crash/memory corruption, not cosmetic
**AGAINST backport:**
- Requires minor path adjustment for kernel tree (trivial)
- Trigger depends on specific AML patterns (may be rare in the wild, but
firmware is uncontrolled input)
- No in-kernel Tested-by / Reviewed-by tags in provided message
**UNRESOLVED:**
- Full lore.kernel.org review thread (403)
- Whether this exact commit has landed in mainline kernel yet (not in
6.18.44)
### Step 9.2: STABLE RULES CHECKLIST
1. Obviously correct and tested? **PASS** — logic is clear; ASAN-tested
upstream with reproducer; maintainer SOB
2. Fixes a real bug affecting users? **PASS** — confirmed UAF in ACPI
evaluation
3. Important issue? **PASS** — UAF / potential crash and memory
corruption (HIGH severity)
4. Small and contained? **PASS** — 43 lines, one function, one file
5. No new features or APIs? **PASS**
6. Can apply to the local tree? **PASS** — code exists; trivial path
adjustment
### Step 9.3: EXCEPTION CATEGORIES
**Record:** Not applicable (not device ID, quirk, DT, build, or docs).
Standard bug fix.
### Step 9.4: DECISION RATIONALE
This commit fixes a real, reproducible use-after-free in the ACPICA
interpreter teardown path. The vulnerable code is present in Linux
6.18.44, the failure occurs on the `acpi_evaluate_object()` return path
used throughout the kernel, and the fix is minimal with low regression
risk. This is appropriate stable material comparable to the already-
accepted `6fcab27915439` ACPICA UAF fix.
---
## Verification
- [Phase 1] Parsed subject, tags, body; identified UAF fix intent
- [Phase 1] GitHub API: upstream commit `36f22a94cb1b`, author ikaros,
`Fixes: #1119`
- [Phase 2] Diff: +43 lines in `acpi_ds_terminate_control_method()`,
REFOF local/arg guard before `acpi_ds_method_data_delete_all()`
- [Phase 3] `git blame -L 717,722`: buggy teardown from 2005-2006
- [Phase 3] `git log --grep`: fix not in tree; related UAF fix
`6fcab27915439` present
- [Phase 4] GitHub issue #1119: full ASAN report, reproducer `acpiexec
-m issue7.aml`
- [Phase 4] `b4 dig -c 36f22a94cb1b`: no match (ACPICA-only commit)
- [Phase 4] lore.kernel.org / patch.msgid.link: 403/bot-blocked —
UNVERIFIED for ML review
- [Phase 5] `grep acpi_ds_terminate_control_method`: callers in
`psxface.c`, `psparse.c`, `dsmethod.c`
- [Phase 5] Read `nsxfeval.c:472-517`: UAF dereference at `node->object`
for `ACPI_REFCLASS_REFOF`
- [Phase 5] Read `acstruct.h:66-67`: locals/args embedded in
`walk_state`
- [Phase 6] `git describe HEAD`: v6.18.44; buggy code confirmed at
`dsmethod.c:717-721`
- [Phase 6] `grep` for fix comment: not present in tree
- [Phase 6] Upstream patch dry-run: fails on path only; hunk context
matches kernel file
- [Phase 8] Failure mode: heap UAF → crash/corruption, severity HIGH
**YES**The background searches finished and line up with the earlier
analysis:
- **UAF fix commit search:** No match for “Fix use-after-free in
acpi_ds_terminate” in this tree — the fix is **not** in 6.18.44 yet.
- **Related fixes search:** Other ACPICA UAF fixes are already here
(`6fcab27915439` for missing method arguments, `470188b09e92d` for
package copy), but nothing equivalent for this
`acpi_ds_terminate_control_method()` issue.
**Verdict for 6.18.44 remains YES** — real, reproducible UAF on the
`acpi_evaluate_object()` path; small, surgical fix; should backport with
the usual ACPICA path adjustment.
drivers/acpi/acpica/dsmethod.c | 43 ++++++++++++++++++++++++++++++++++
1 file changed, 43 insertions(+)
diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c
index 45ec32e81903a..08bfe83030838 100644
--- a/drivers/acpi/acpica/dsmethod.c
+++ b/drivers/acpi/acpica/dsmethod.c
@@ -705,6 +705,8 @@ void
acpi_ds_terminate_control_method(union acpi_operand_object *method_desc,
struct acpi_walk_state *walk_state)
{
+ u32 i;
+ struct acpi_namespace_node *ref_node;
ACPI_FUNCTION_TRACE_PTR(ds_terminate_control_method, walk_state);
@@ -715,6 +717,47 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc,
}
if (walk_state) {
+ /*
+ * Check if the return value is a ref_of reference to a method local
+ * or argument. If so, clear the reference to avoid use-after-free
+ * when the walk state is deleted.
+ */
+ if (walk_state->return_desc &&
+ (walk_state->return_desc->common.type ==
+ ACPI_TYPE_LOCAL_REFERENCE)
+ && (walk_state->return_desc->reference.class ==
+ ACPI_REFCLASS_REFOF)) {
+ ref_node = walk_state->return_desc->reference.object;
+ if (ref_node) {
+
+ /* Check against method locals */
+ for (i = 0; i < ACPI_METHOD_NUM_LOCALS; i++) {
+ if (ref_node ==
+ &walk_state->local_variables[i]) {
+ acpi_ut_remove_reference
+ (walk_state->return_desc);
+ walk_state->return_desc = NULL;
+ break;
+ }
+ }
+
+ /* Check against method arguments if not already cleared */
+ if (walk_state->return_desc) {
+ for (i = 0; i < ACPI_METHOD_NUM_ARGS;
+ i++) {
+ if (ref_node ==
+ &walk_state->arguments[i]) {
+ acpi_ut_remove_reference
+ (walk_state->
+ return_desc);
+ walk_state->
+ return_desc = NULL;
+ break;
+ }
+ }
+ }
+ }
+ }
/* Delete all arguments and locals */
--
2.53.0
^ permalink raw reply related [flat|nested] 26+ messages in thread* [PATCH AUTOSEL 6.18-5.10] ACPICA: validate byte_count in acpi_ps_get_next_package_length()
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (13 preceding siblings ...)
2026-08-31 13:26 ` [PATCH AUTOSEL 6.18-5.10] ACPICA: Fix use-after-free in acpi_ds_terminate_control_method() Sasha Levin
@ 2026-08-31 13:27 ` Sasha Levin
2026-08-31 13:28 ` [PATCH AUTOSEL 6.18-6.12] platform/chrome: Resolve kb_wake_angle visibility race Sasha Levin
` (8 subsequent siblings)
23 siblings, 0 replies; 26+ messages in thread
From: Sasha Levin @ 2026-08-31 13:27 UTC (permalink / raw)
To: patches, stable
Cc: ikaros, Rafael J. Wysocki, Sasha Levin, rafael,
maciej.wieczor-retman, pawel.chmielewski, linux-acpi,
acpica-devel, linux-kernel
From: ikaros <void0red@gmail.com>
[ Upstream commit d49c6ee08365a8596f639da46eb7e71752b0cd42 ]
Validate package length reading in acpi_ps_get_next_package_length().
Link: https://github.com/acpica/acpica/commit/40e03f9941e2
Signed-off-by: ikaros <void0red@gmail.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Link: https://patch.msgid.link/3616255.QJadu78ljV@rafael.j.wysocki
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
# Stable Backport Analysis: ACPICA `acpi_ps_get_next_package_length()`
bounds check
**Local tree:** Linux **6.18.44** (`git describe HEAD` → `v6.18.44`)
---
## PHASE 1: COMMIT MESSAGE FORENSICS
### Step 1.1: Subject line
**Record:** `[ACPICA] [validate] validate byte_count in
acpi_ps_get_next_package_length()` — ACPI parser subsystem; verb is
“validate,” indicating a safety/bounds fix.
### Step 1.2: Tags
**Record:**
- **Link:** https://github.com/acpica/acpica/commit/40e03f9941e2
(upstream ACPICA commit)
- **Link:** https://patch.msgid.link/3616255.QJadu78ljV@rafael.j.wysocki
(kernel submission)
- **Signed-off-by:** ikaros \<void0red@gmail.com\> (author)
- **Signed-off-by:** Rafael J. Wysocki \<rafael.j.wysocki@intel.com\>
(ACPI maintainer)
- No Fixes:, Reported-by:, Tested-by:, Reviewed-by:, Acked-by:, or Cc:
stable tags
- Notable: submitted as **[PATCH v1 13/27]** in an ACPICA upstream sync
series (May 27, 2026)
### Step 1.3: Body analysis
**Record:**
- **Bug:** `acpi_ps_get_next_package_length()` reads package-length
encoding bytes without checking remaining AML buffer size.
- **Symptom:** Out-of-bounds read when `byte_count` (bits 6:7 of first
byte) claims more follow-on bytes than exist before `aml_end`.
- **Upstream evidence:** ACPICA issue #1123 documents ASAN heap-buffer-
overflow at `psargs.c:223` in `AcpiPsGetNextPackageLength`, triggered
by malformed `issue8.aml` via `acpiexec`.
- **Root cause:** Parser advances and reads `aml[byte_count]` in a loop
without validating `byte_count + 1 <= remaining`.
### Step 1.4: Hidden bug fix?
**Record:** Yes — despite minimal commit text, this is a confirmed
memory-safety bug fix (heap buffer overflow / OOB read), not cosmetic
cleanup.
---
## PHASE 2: DIFF ANALYSIS
### Step 2.1: Inventory
**Record:**
- **File:** `drivers/acpi/acpica/psargs.c` (+17 lines, 0 removed)
- **Function:** `acpi_ps_get_next_package_length()`
- **Scope:** Single-file, single-function surgical fix
### Step 2.2: Code flow change
**Record:**
- **Hunk 1 (remaining == 0):** Before → reads `aml[0]` unconditionally.
After → if no bytes remain, return 0 immediately.
- **Hunk 2 (byte_count >= remaining):** Before → reads `aml[0]`,
advances pointer, loops reading `aml[byte_count]` even past buffer
end. After → if encoding needs more bytes than available (`byte_count
>= remaining` means `byte_count + 1 > remaining`), set
`parser_state->aml = aml_end` and return 0.
- **Normal path:** Unchanged when sufficient bytes exist.
### Step 2.3: Bug mechanism
**Record:**
- **Category:** Buffer overflow / out-of-bounds read (memory safety)
- **Mechanism:** ACPI package-length encoding uses 1–4 bytes. With
truncated/corrupt AML near `aml_end`, `byte_count` can be 1–3 while
only 1–2 bytes remain. The `while (byte_count)` loop does
`aml[byte_count]` past the allocation — exactly matching the ASAN
report at line 223 (Linux tree line 71: `package_length |=
(aml[byte_count] << ...)`).
### Step 2.4: Fix quality
**Record:**
- Fix is obviously correct: compares available bytes against encoding
width before reading.
- Minimal, no unrelated changes.
- Low regression risk: only affects truncated/corrupt AML; valid tables
unchanged.
- On error, returns 0 and advances to `aml_end` — safe degradation vs.
OOB read.
---
## PHASE 3: GIT HISTORY INVESTIGATION
### Step 3.1: Blame
**Record:** Core parsing logic dates to **2005** (Bob Moore,
`drivers/acpi/parser/psargs.c`). Bug present since initial
implementation. `aml_end` field and `ACPI_PTR_DIFF` macro already exist
in this tree.
### Step 3.2: Fixes: tag
**Record:** N/A — no Fixes: tag. Upstream ACPICA commit references
GitHub issue #1123.
### Step 3.3: Related file history
**Record:** Recent `psargs.c` changes in 6.18.44 include memory-leak
fixes (`e6169a8ffee8a`, `5accb265f7a1b`) — same file, same maintainer
pattern for stable-worthy ACPICA parser fixes. This specific fix is
**not** yet in the tree.
### Step 3.4: Author context
**Record:** ikaros reported the ACPICA bug with ASAN PoC. Rafael Wysocki
(ACPI maintainer) carried it into kernel as patch 13/27 of an ACPICA
sync.
### Step 3.5: Dependencies
**Record:** Patch is part of a 27-patch series but **this hunk is self-
contained**:
- Uses existing `parser_state->aml_end` (in `struct acpi_parse_state`
since long ago)
- Uses existing `ACPI_PTR_DIFF` (`include/acpi/actypes.h:505`)
- `git apply --check` succeeds cleanly on 6.18.44
- No prerequisite structural changes from earlier series patches
required
---
## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
### Step 4.1: Original discussion
**Record:**
- **URL:** https://lkml.iu.edu/2605.3/06258.html (patch submission, May
27, 2026)
- **Series:** v1 13/27 of ACPICA upstream sync
- **Review thread:** No replies visible on lkml.iu.edu mirror; no NAKs
found
- **Stable nomination:** None found in available thread content
### Step 4.2: Reviewers
**Record:** `b4 dig -c 40e03f9941e2` failed (ACPICA hash, not in Linux
tree). Patch submitted by Rafael Wysocki to linux-acpi; maintainer sign-
off present.
### Step 4.3: Bug report
**Record:**
- **ACPICA issue #1123:** Heap-buffer-overflow, ASAN-confirmed,
reproducible with `acpiexec -m issue8.aml`
- Stack trace: `AcpiPsGetNextPackageLength` → `AcpiPsGetNextPackageEnd`
→ `AcpiPsGetNextArg` → `AcpiPsParseLoop` → `AcpiNsLoadTable` →
`AcpiLoadTables`
- Severity: memory safety violation during ACPI table parsing
### Step 4.4: Related patches
**Record:** Same series includes additional boundary checks in
`acpi_ps_peek_opcode()`, `acpi_ps_get_next_field()`,
`acpi_ps_get_next_namestring()` (patches 14–27). Those fix related but
separate OOB paths; this patch stands alone for this specific function.
### Step 4.5: Stable list history
**Record:** lore.kernel.org/stable blocked by bot protection; no stable-
specific discussion found via alternate sources.
---
## PHASE 5: CODE SEMANTIC ANALYSIS
### Step 5.1: Key functions
**Record:** `acpi_ps_get_next_package_length()` (modified); callers
include `acpi_ps_get_next_package_end()`.
### Step 5.2: Callers
**Record:**
- `acpi_ps_get_next_package_end()` → used from `acpi_ps_get_next_arg()`
(ARGP_PKGLENGTH, field parsing)
- `acpi_ps_get_next_package_length()` direct calls in
`acpi_ps_get_next_field()` (buffer/field length)
- Upstream call chain reaches `acpi_ps_parse_loop()` →
`acpi_ps_execute_table()` → `acpi_ns_load_table()` →
`acpi_load_tables()` → `acpi_bus_init()` at boot
### Step 5.3: Callees
**Record:** Uses `ACPI_PTR_DIFF`, pointer arithmetic on
`parser_state->aml` / `aml_end`; no allocations or locks.
### Step 5.4: Reachability
**Record:** **Yes — boot path.** `acpi_bus_init()` calls
`acpi_load_tables()` during ACPI subsystem init. Any corrupt/truncated
DSDT/SSDT AML with malformed package-length encoding can hit this. With
`CONFIG_ACPI_TABLE_OVERRIDE_VIA_BUILTIN_INITRD`, root can supply custom
ACPI tables.
### Step 5.5: Similar patterns
**Record:** Same series adds similar bounds checks elsewhere. Prior
stable-relevant fix in tree: `a3e525feaeec4` “Avoid subobject buffer
overflow when validating RSDP signature.”
---
## PHASE 6: CROSS-REFERENCE WITH LOCAL TREE (6.18.44)
### Step 6.1: Buggy code present?
**Record:** **Yes.** Lines 58–71 of `drivers/acpi/acpica/psargs.c` lack
bounds checking — exactly the vulnerable code. Bug present since ~2005.
### Step 6.2: Backport complications
**Record:** **Clean apply** — `git apply --check` passed with zero
conflicts. `aml_end` and `ACPI_PTR_DIFF` already present.
### Step 6.3: Fix already present?
**Record:** **No.** `git log --grep="validate byte_count"` found
nothing. Current function has no `remaining` variable or bounds checks.
---
## PHASE 7: SUBSYSTEM CONTEXT
### Step 7.1: Subsystem criticality
**Record:** **ACPI / ACPICA parser** — IMPORTANT/CORE for x86/ARM
systems with ACPI. Affects boot-time namespace loading for essentially
all ACPI-enabled machines.
### Step 7.2: Activity
**Record:** Actively maintained; regular ACPICA upstream merges. Recent
`psargs.c` leak fixes confirm ongoing parser hardening.
---
## PHASE 8: IMPACT AND RISK
### Step 8.1: Who is affected
**Record:** All systems using ACPI (most PCs, many ARM servers/laptops).
Config: `CONFIG_ACPI=y` (default on most platforms).
### Step 8.2: Trigger conditions
**Record:**
- Corrupt or truncated ACPI AML in DSDT/SSDT tables
- Malformed package-length encoding near end of AML buffer
- Triggered during boot `acpi_load_tables()` — every boot with bad
tables
- Root can inject tables via initrd override; firmware/QEMU can supply
bad tables
- Not directly triggerable by unprivileged userspace, but boot crash is
severe
### Step 8.3: Failure mode severity
**Record:** **HIGH** — heap-buffer-overflow / OOB read; can cause kernel
oops/panic during early boot, potential info leak with KASAN/ASAN. Boot
failure = system unusable.
### Step 8.4: Risk-benefit
**Record:**
- **Benefit:** HIGH — prevents OOB read on common boot path with corrupt
ACPI data
- **Risk:** VERY LOW — 17-line bounds check, no API changes, clean apply
- **Ratio:** Strongly favors backport
---
## PHASE 9: FINAL SYNTHESIS
### Step 9.1: Evidence summary
**FOR backport:**
- Confirmed heap-buffer-overflow (ASAN, ACPICA #1123)
- Boot-path ACPI table parsing (`acpi_load_tables`)
- Bug present since 2005 in this tree
- Small, surgical, maintainer-reviewed fix
- Applies cleanly to 6.18.44
- Precedent: similar ACPICA overflow/bounds fixes in stable trees
- Self-contained despite being patch 13/27
**AGAINST backport:**
- Part of larger 27-patch series (but this hunk has no code dependencies
on siblings)
- No syzbot report (but ASAN PoC exists)
- ACPI tables usually from firmware (limited direct attack surface, but
corrupt firmware and initrd override are real)
**Unresolved:**
- No visible reviewer stable nominations (lore blocked)
- Full series not yet merged to 6.18.44 (only this patch needed for this
specific bug)
### Step 9.2: Stable rules checklist
1. Obviously correct and tested? **PASS** — logic is straightforward;
ASAN-tested upstream
2. Fixes a real bug affecting users? **PASS** — OOB read on ACPI parse
3. Important issue? **PASS** — memory safety, boot-time crash risk
(HIGH)
4. Small and contained? **PASS** — 17 lines, one function
5. No new features/APIs? **PASS** — defensive bounds check only
6. Can apply to local tree? **PASS** — verified clean apply
### Step 9.3: Exception categories
**Record:** N/A (not device ID, quirk, DT, build fix, or docs — standard
bug fix)
### Step 9.4: Decision rationale
For **Linux 6.18.44**, the vulnerable code exists, the fix applies
cleanly, and the bug is a confirmed out-of-bounds read on the ACPI boot
parsing path. This meets all stable kernel criteria.
---
## Verification
- [Phase 1] Parsed subject, tags, body; identified ASAN-confirmed OOB
read
- [Phase 1] Fetched ACPICA commit 40e03f9941e2 and issue #1123 from
GitHub
- [Phase 2] Read current `psargs.c:45-80` — vulnerable code confirmed
- [Phase 2] Analyzed diff: adds `remaining` check before `byte_count`
read loop
- [Phase 3] `git blame`: buggy logic from 2005; fix not present
- [Phase 3] `git log --oneline -20 -- drivers/acpi/acpica/psargs.c`: no
matching fix
- [Phase 3] Verified `struct acpi_parse_state.aml_end` in
`aclocal.h:912`
- [Phase 3] Verified `ACPI_PTR_DIFF` in `include/acpi/actypes.h:505`
- [Phase 4] `b4 dig -c 40e03f9941e2`: no match (ACPICA-only hash)
- [Phase 4] lkml.iu.edu/2605.3/06258.html: patch 13/27, Rafael Wysocki
submission
- [Phase 4] GitHub issue #1123: ASAN stack trace and reproduction steps
- [Phase 5] Traced callers: `acpi_ps_get_next_package_end` →
`acpi_ps_get_next_arg` → parse loop → `acpi_ns_load_table` →
`acpi_load_tables` → `acpi_bus_init`
- [Phase 5] Confirmed `acpi_load_tables()` call in
`drivers/acpi/bus.c:1413`
- [Phase 6] `git describe HEAD`: v6.18.44
- [Phase 6] `git apply --check`: patch applies cleanly
- [Phase 6] Confirmed fix absent (`remaining` variable not in current
code)
- [Phase 8] Assessed severity: HIGH (boot-time OOB read)
- [UNVERIFIED] Full lore review thread replies (lore blocked by Anubis)
- [UNVERIFIED] Whether entire 27-patch series will merge before next
6.18.y release (does not affect standalone merit of this fix)
**YES****Verdict: YES** — backport to this tree (Linux 6.18.44).
The commit adds bounds checks in `acpi_ps_get_next_package_length()` so
truncated or corrupt ACPI AML cannot trigger an out-of-bounds read when
decoding package-length fields. That bug is confirmed upstream (ASAN
heap-buffer-overflow, ACPICA issue #1123), hits the boot path via
`acpi_load_tables()`, and the vulnerable code is still present in
6.18.44. The patch is small (17 lines), self-contained, and applies
cleanly.
drivers/acpi/acpica/psargs.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/drivers/acpi/acpica/psargs.c b/drivers/acpi/acpica/psargs.c
index 55273cbbfc67e..3526ea1094146 100644
--- a/drivers/acpi/acpica/psargs.c
+++ b/drivers/acpi/acpica/psargs.c
@@ -48,6 +48,7 @@ acpi_ps_get_next_package_length(struct acpi_parse_state *parser_state)
u32 package_length = 0;
u32 byte_count;
u8 byte_zero_mask = 0x3F; /* Default [0:5] */
+ u32 remaining;
ACPI_FUNCTION_TRACE(ps_get_next_package_length);
@@ -55,7 +56,23 @@ acpi_ps_get_next_package_length(struct acpi_parse_state *parser_state)
* Byte 0 bits [6:7] contain the number of additional bytes
* used to encode the package length, either 0,1,2, or 3
*/
+
+ /* Check if we have at least one byte to read */
+ remaining = (u32)ACPI_PTR_DIFF(parser_state->aml_end, aml);
+ if (remaining == 0) {
+ return_UINT32(0);
+ }
+
byte_count = (aml[0] >> 6);
+
+ /* Validate byte_count and ensure we have enough bytes to read */
+ if (byte_count >= remaining) {
+
+ /* Clamp to available bytes and advance to end */
+ parser_state->aml = parser_state->aml_end;
+ return_UINT32(0);
+ }
+
parser_state->aml += ((acpi_size)byte_count + 1);
/* Get bytes 3, 2, 1 as needed */
--
2.53.0
^ permalink raw reply related [flat|nested] 26+ messages in thread* [PATCH AUTOSEL 6.18-6.12] platform/chrome: Resolve kb_wake_angle visibility race
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (14 preceding siblings ...)
2026-08-31 13:27 ` [PATCH AUTOSEL 6.18-5.10] ACPICA: validate byte_count in acpi_ps_get_next_package_length() Sasha Levin
@ 2026-08-31 13:28 ` Sasha Levin
2026-08-31 13:28 ` [PATCH AUTOSEL 6.18] media: platform: cros-ec: Add Kulnex and Moxoe to the match table Sasha Levin
` (7 subsequent siblings)
23 siblings, 0 replies; 26+ messages in thread
From: Sasha Levin @ 2026-08-31 13:28 UTC (permalink / raw)
To: patches, stable
Cc: Tzung-Bi Shih, Gwendal Grignou, Sasha Levin, bleung,
chrome-platform, linux-kernel
From: Tzung-Bi Shih <tzungbi@kernel.org>
[ Upstream commit c40f5f9927b5bf6062daa1e293ae32d83afc963e ]
A race condition exists between the probe of cros-ec-sysfs and
cros-ec-sensorhub.
The `kb_wake_angle` attribute should only be visible if the sensor hub
detects two or more accelerometers. If cros_ec_sysfs_probe() runs
before cros_ec_sensorhub_register() completes sensor enumeration, the
sysfs attributes are created while `has_kb_wake_angle` is still false,
hiding `kb_wake_angle` incorrectly.
Store the created attribute group pointer in `ec_dev->group`. When
the sensor hub completes sensor enumeration, it checks for this group
and calls sysfs_update_group() to notify the sysfs core to re-evaluate
attribute visibility. This ensures the `kb_wake_angle` attribute
visibility is correctly updated regardless of the driver probe order.
Co-developed-by: Gwendal Grignou <gwendal@chromium.org>
Signed-off-by: Gwendal Grignou <gwendal@chromium.org>
Link: https://lore.kernel.org/r/20260407102615.1605317-1-tzungbi@kernel.org
Signed-off-by: Tzung-Bi Shih <tzungbi@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
# Stable Backport Analysis: `platform/chrome: Resolve kb_wake_angle
visibility race`
**Local tree:** Linux **6.18.43** (`git describe HEAD` →
`v6.18.43-1-gc7f0dac02d232`)
---
## PHASE 1: COMMIT MESSAGE FORENSICS
### Step 1.1: Subject line
**Record:** `[platform/chrome]` `[Resolve]` — fix a race affecting
`kb_wake_angle` sysfs attribute visibility between `cros-ec-sysfs` and
`cros-ec-sensorhub` probe paths.
### Step 1.2: Commit message tags
**Record:**
| Tag | Value |
|-----|-------|
| Co-developed-by | Gwendal Grignou \<gwendal@chromium.org\> |
| Signed-off-by | Gwendal Grignou, Tzung-Bi Shih \<tzungbi@kernel.org\>
|
| Link |
https://lore.kernel.org/r/20260407102615.1605317-1-tzungbi@kernel.org |
**Notable absences (expected, not negative):** No `Fixes:`, no `Cc:
stable@vger.kernel.org`, no `Reported-by:`, no `Reviewed-by:`, no
`Tested-by:`.
**Notable patterns:** Co-developed by a Chromium engineer; cover letter
says *"This is an old patch and we still need it. Revive the patch."*
with v3 dating to August 2021.
### Step 1.3: Body analysis
**Record:**
- **Bug:** Race between `cros_ec_sysfs_probe()` and
`cros_ec_sensorhub_register()` during sensor enumeration.
- **Symptom:** `/sys/class/chromeos/<ec>/kb_wake_angle` is permanently
hidden when sysfs is created while `has_kb_wake_angle` is still
`false`, even on hardware with ≥2 accelerometers.
- **Root cause:** `cros_ec_ctrl_visible()` is evaluated once at
`sysfs_create_group()` time; later setting `has_kb_wake_angle = true`
does not re-evaluate visibility without `sysfs_update_group()`.
- **Fix:** Store the attribute group pointer in `ec_dev->group`; call
`sysfs_update_group()` after sensor enumeration sets
`has_kb_wake_angle`.
### Step 1.4: Hidden bug fix detection
**Record:** Yes — despite "Resolve" rather than "fix", this is a
synchronization/race bug fix disguised as a visibility correction.
Permanent functional regression on affected Chromebooks.
---
## PHASE 2: DIFF ANALYSIS
### Step 2.1: Change inventory
**Record:**
| File | Changes | Functions |
|------|---------|-----------|
| `cros_ec_sensorhub.c` | +4 lines | `cros_ec_sensorhub_register()` |
| `cros_ec_sysfs.c` | +3/-2 lines | `cros_ec_sysfs_probe()`,
`cros_ec_sysfs_remove()` |
| `cros_ec_proto.h` | +2 lines | `struct cros_ec_dev` |
**Scope:** 3 files, ~10 insertions / 3 deletions — single-subsystem,
surgical fix.
### Step 2.2: Code flow per hunk
**Hunk 1 — `cros_ec_sensorhub.c`:**
- **Before:** Set `ec->has_kb_wake_angle = true` when ≥2 accelerometers
found; sysfs never notified.
- **After:** Same flag set, plus if `ec->group` exists, call
`sysfs_update_group()` to re-run `is_visible()`.
**Hunk 2 — `cros_ec_sysfs.c` probe:**
- **Before:** `sysfs_create_group(..., &cros_ec_attr_group)` directly.
- **After:** Store `ec_dev->group = &cros_ec_attr_group` first, then
create using stored pointer.
**Hunk 3 — `cros_ec_sysfs.c` remove:**
- **Before:** Remove using static `&cros_ec_attr_group`.
- **After:** Remove using `ec_dev->group` (consistent with stored
pointer).
**Hunk 4 — `cros_ec_proto.h`:**
- **Before:** No `group` field in `struct cros_ec_dev`.
- **After:** Add `const struct attribute_group *group`.
### Step 2.3: Bug mechanism
**Record:** **Category:** Race condition / sysfs visibility lifecycle
bug.
**Mechanism:** `cros_ec_ctrl_visible()` gates `kb_wake_angle` on
`ec->has_kb_wake_angle`:
```377:384:drivers/platform/chrome/cros_ec_sysfs.c
static umode_t cros_ec_ctrl_visible(struct kobject *kobj,
struct attribute *a, int n)
{
struct device *dev = kobj_to_dev(kobj);
struct cros_ec_dev *ec = to_cros_ec_dev(dev);
if (a == &dev_attr_kb_wake_angle.attr && !ec->has_kb_wake_angle)
return 0;
```
`has_kb_wake_angle` is set later in sensorhub enumeration:
```125:126:drivers/platform/chrome/cros_ec_sensorhub.c
if (sensor_type[MOTIONSENSE_TYPE_ACCEL] >= 2)
ec->has_kb_wake_angle = true;
```
Kernel documentation for `sysfs_update_group()` explicitly states it
exists *"after making a change that affects group visibility"* —
confirming the missing step in current code.
### Step 2.4: Fix quality
**Record:**
- **Obviously correct:** Yes — standard sysfs pattern; `ec` is
`kzalloc()`'d so `group` starts NULL; `if (ec->group && ...)` guards
the update path safely.
- **Minimal:** Yes — no unrelated changes.
- **Regression risk:** Very low — only affects attribute visibility
timing; failure path logs `dev_warn` and leaves sysfs in prior state.
---
## PHASE 3: GIT HISTORY INVESTIGATION
### Step 3.1: Blame
**Record:** Shallow repository (`rev-parse --is-shallow-repository` →
`true`). `git blame` attributes all relevant lines to `5d324e5159d9e`
(merge base). Cannot determine exact introduction commit from local
history. Buggy `has_kb_wake_angle` + `is_visible` logic **is present**
in current tree.
### Step 3.2: Fixes: tag
**Record:** N/A — no `Fixes:` tag in commit message.
### Step 3.3: Related file history
**Record:** `git log --oneline -30` on modified files returns only the
shallow merge base — insufficient local history. External evidence
(patch v3 from August 2021) indicates the race has existed since
conditional visibility was introduced years ago.
### Step 3.4: Author context
**Record:** Tzung-Bi Shih is an active `platform/chrome` maintainer. Co-
developer Gwendal Grignou is from Chromium. Patch cover letter
explicitly states production need.
### Step 3.5: Dependencies
**Record:** Standalone — no series dependencies, no prerequisite commits
referenced. Applies directly to existing `has_kb_wake_angle` /
`is_visible` infrastructure already in this tree.
---
## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
### Step 4.1: Original discussion
**Record:** Thread at https://yhbt.net/lore/chrome-
platform/20260407102615.1605317-1-tzungbi@kernel.org/T/ (v4, April
2026). Patch went through v1→v4 revisions. Queued in linux-next as
`c40f5f9927b5` (May 2026). Merged to mainline via `chrome-platform-v7.2`
pull. `b4 dig -c HEAD` could not match this commit (not in local tree).
No explicit stable nomination found in available thread content.
### Step 4.2: Reviewers
**Record:** Could not retrieve full recipient list (lore
blocked/redirected). Signed-off-by from subsystem maintainer Tzung-Bi
Shih and Chromium co-developer.
### Step 4.3: Bug report
**Record:** No external bug tracker or syzbot report. Production need
documented by Chromium in cover letter (*"old patch... we still need
it"*).
### Step 4.4: Series context
**Record:** Standalone 1-patch fix. v3 predecessor from 2021 at https://
lore.kernel.org/all/20210804213139.4139492-2-gwendal@chromium.org/
### Step 4.5: Stable list history
**Record:** No stable-list discussion found in accessible sources.
---
## PHASE 5: CODE SEMANTIC ANALYSIS
### Step 5.1: Key functions
**Record:** `cros_ec_sensorhub_register()`, `cros_ec_sysfs_probe()`,
`cros_ec_ctrl_visible()`, `ec_device_probe()` (MFD parent).
### Step 5.2: Callers / probe ordering
**Record:** In `drivers/mfd/cros_ec_dev.c`:
- Line 241–248: `cros-ec-sensorhub` MFD child registered **first** (when
sensors present).
- Line 333–338: `cros-ec-sysfs` registered **last** among platform
cells.
However, sensorhub probe calls `cros_ec_sensorhub_register()` which
loops over sensors with up to 50 EBUSY retries at 5–6 ms each
(`CROS_EC_CMD_INFO_RETRIES`). Meanwhile, numerous other MFD children are
registered and probed between sensorhub registration and sysfs
registration. **Sysfs probe can run while sensorhub_register() is still
enumerating sensors** — confirmed race window.
### Step 5.3: Callees
**Record:** `sysfs_create_group()`, `sysfs_update_group()`,
`cros_ec_cmd_xfer_status()` — all standard, well-understood APIs.
### Step 5.4: Reachability
**Record:** Triggered on every boot of Chromebook/ChromeOS hardware with
`CONFIG_CROS_EC_SENSORHUB` and ≥2 accelerometers. Userspace reads/writes
`/sys/class/chromeos/*/kb_wake_angle` (documented ABI since kernel
4.17). Not a syscall path, but standard sysfs interface for ChromeOS
power/tablet-mode configuration.
### Step 5.5: Similar patterns
**Record:** `sysfs_update_group()` used elsewhere for dynamic visibility
(e.g., `drivers/usb/typec/class.c`, `fs/btrfs/sysfs.c`). Same
established pattern.
---
## PHASE 6: CROSS-REFERENCE AGAINST LOCAL TREE (6.18.43)
### Step 6.1: Buggy code present?
**Record:** **YES.** Current tree lacks `ec_dev->group` field and
`sysfs_update_group()` call. Full buggy race infrastructure is present
(`has_kb_wake_angle`, `cros_ec_ctrl_visible`, sensorhub enumeration).
### Step 6.2: Backport complications
**Record:** **Clean apply expected** — no conflicting refactors in these
files; patch matches current code structure exactly.
### Step 6.3: Related fixes already present?
**Record:** **No** — `grep sysfs_update_group drivers/platform/chrome/`
returns no matches. Fix not yet applied.
---
## PHASE 7: SUBSYSTEM CONTEXT
### Step 7.1: Subsystem criticality
**Record:** `drivers/platform/chrome/` — **PERIPHERAL** (ChromeOS EC
platform driver). Important for Chromebook users; not core kernel.
### Step 7.2: Activity
**Record:** Actively maintained subsystem with ongoing chrome-platform
development.
---
## PHASE 8: IMPACT AND RISK
### Step 8.1: Who is affected
**Record:** Chromebook/convertible devices with ChromeOS EC,
`CONFIG_CROS_EC_SENSORHUB`, and ≥2 accelerometers. Config- and platform-
specific, but affects a widely deployed hardware class.
### Step 8.2: Trigger conditions
**Record:** Probe-order/timing race during boot — sysfs probes before
sensorhub finishes enumerating accelerometers. Plausible on every boot
when timing aligns; sensorhub EC communication can take hundreds of
milliseconds with EBUSY retries. Not userspace-triggerable; unprivileged
users cannot force it, but they suffer the consequence (missing sysfs
node).
### Step 8.3: Failure mode severity
**Record:** `kb_wake_angle` sysfs attribute **permanently hidden for
that boot** (sysfs does not re-evaluate `is_visible` without update).
Userspace cannot read/write keyboard wake lid angle. **Severity:
MEDIUM** — functional regression on documented ABI; no crash,
corruption, deadlock, or security impact.
### Step 8.4: Risk-benefit
**Record:**
- **Benefit:** MEDIUM — restores documented sysfs control on affected
convertibles; long-standing Chromium production issue.
- **Risk:** VERY LOW — 10-line change using documented sysfs API.
- **Ratio:** Favorable — low-risk fix for a real, persistent functional
bug.
---
## PHASE 9: FINAL SYNTHESIS
### Step 9.1: Evidence summary
**FOR backport:**
- Real, verifiable race with permanent per-boot impact
- Buggy code confirmed present in Linux 6.18.43
- Small, surgical, obviously correct fix using standard
`sysfs_update_group()` API
- Long-standing issue (known since ~2021); Chromium explicitly still
needs it
- Documented userspace ABI (`Documentation/ABI/testing/sysfs-class-
chromeos`)
- No dependencies; clean apply expected
**AGAINST backport:**
- Not crash/security/corruption/deadlock — functional sysfs visibility
only
- ChromeOS-specific driver; limited to one hardware ecosystem
- No syzbot report, no explicit stable nomination
- Failure is degraded functionality, not system instability
**Unresolved:** Exact commit that introduced `has_kb_wake_angle`
visibility (shallow clone limits local history). Full lore review thread
not accessible.
### Step 9.2: Stable rules checklist
| Criterion | Result |
|-----------|--------|
| 1. Obviously correct and tested? | **PASS** — standard sysfs pattern;
maintainer SOB; v4 after review |
| 2. Fixes real bug affecting users? | **PASS** — permanent missing
sysfs attr on affected Chromebooks |
| 3. Important issue? | **PASS (borderline)** — functional regression on
production hardware with documented ABI; not crash-level but persistent
and user-visible |
| 4. Small and contained? | **PASS** — 3 files, ~10 lines |
| 5. No new features/APIs? | **PASS** — fixes existing attribute
visibility only |
| 6. Can apply to local tree? | **PASS** — buggy code present; clean
apply |
### Step 9.3: Exception categories
**Record:** Not a device-ID/quirk/DT/build/docs exception. Qualifies as
a driver probe race fix for existing hardware functionality.
### Step 9.4: Decision rationale
For **Linux 6.18.43**, the race exists today: `has_kb_wake_angle`
conditional visibility without `sysfs_update_group()` means
`kb_wake_angle` can be permanently hidden on convertible Chromebooks
when sysfs probes before sensor enumeration completes. The fix is
minimal, uses the kernel's intended API for exactly this scenario, and
addresses a production issue Chromium has tracked since 2021. While
severity is functional rather than catastrophic, the bug is persistent
per boot, affects a documented userspace interface, and the backport
risk is negligible.
---
## Verification
- **[Phase 1]** Parsed subject, tags, body from provided commit message;
fetched v4 cover letter from ratatoskr.run
- **[Phase 2]** Read current `cros_ec_sysfs.c`, `cros_ec_sensorhub.c`,
`cros_ec_proto.h`; confirmed diff matches tree structure
- **[Phase 2]** Read `sysfs_update_group()` documentation in
`fs/sysfs/group.c` lines 271–287
- **[Phase 3]** `git describe HEAD` → v6.18.43; `rev-parse --is-shallow-
repository` → true
- **[Phase 3]** `git blame` on modified lines → all from shallow base
`5d324e5159d9e`
- **[Phase 3]** `git log --grep=kb_wake_angle` → empty (shallow history)
- **[Phase 4]** ratatoskr.run thread: v4, linux-next queue, v3 from
2021, Chromium co-developer
- **[Phase 4]** lore.kernel.org direct fetch blocked; yhbt.net returned
Tor redirect
- **[Phase 4]** `b4 dig -c HEAD` failed to match (commit not in tree)
- **[Phase 5]** Read `ec_device_probe()` in `drivers/mfd/cros_ec_dev.c`
— sensorhub at 241, sysfs at 333
- **[Phase 5]** Confirmed `CROS_EC_CMD_INFO_RETRIES 50` with 5–6ms
sleeps in sensorhub enumeration
- **[Phase 5]** `grep sysfs_update_group drivers/platform/chrome/` → no
matches (fix absent)
- **[Phase 6]** Confirmed `struct cros_ec_dev` lacks `group` field in
local tree
- **[Phase 6]** Confirmed `has_kb_wake_angle` + `is_visible` logic
present (bug exists)
- **[Phase 7]** Read `Documentation/ABI/testing/sysfs-class-chromeos` —
kb_wake_angle documented since 4.17
- **[Phase 8]** Confirmed `ec = kzalloc()` in `ec_device_probe()` —
`group` implicitly NULL-initialized
**YES**
drivers/platform/chrome/cros_ec_sensorhub.c | 6 +++++-
drivers/platform/chrome/cros_ec_sysfs.c | 5 +++--
include/linux/platform_data/cros_ec_proto.h | 2 ++
3 files changed, 10 insertions(+), 3 deletions(-)
diff --git a/drivers/platform/chrome/cros_ec_sensorhub.c b/drivers/platform/chrome/cros_ec_sensorhub.c
index 9bad8f72680ea..f938c3fc84e4f 100644
--- a/drivers/platform/chrome/cros_ec_sensorhub.c
+++ b/drivers/platform/chrome/cros_ec_sensorhub.c
@@ -122,8 +122,12 @@ static int cros_ec_sensorhub_register(struct device *dev,
sensor_type[sensorhub->resp->info.type]++;
}
- if (sensor_type[MOTIONSENSE_TYPE_ACCEL] >= 2)
+ if (sensor_type[MOTIONSENSE_TYPE_ACCEL] >= 2) {
ec->has_kb_wake_angle = true;
+ if (ec->group && sysfs_update_group(&ec->class_dev.kobj,
+ ec->group))
+ dev_warn(dev, "Unable to update sysfs");
+ }
if (cros_ec_check_features(ec,
EC_FEATURE_REFINED_TABLET_MODE_HYSTERESIS)) {
diff --git a/drivers/platform/chrome/cros_ec_sysfs.c b/drivers/platform/chrome/cros_ec_sysfs.c
index f22e9523da3e8..9d3767ab15480 100644
--- a/drivers/platform/chrome/cros_ec_sysfs.c
+++ b/drivers/platform/chrome/cros_ec_sysfs.c
@@ -405,7 +405,8 @@ static int cros_ec_sysfs_probe(struct platform_device *pd)
struct device *dev = &pd->dev;
int ret;
- ret = sysfs_create_group(&ec_dev->class_dev.kobj, &cros_ec_attr_group);
+ ec_dev->group = &cros_ec_attr_group;
+ ret = sysfs_create_group(&ec_dev->class_dev.kobj, ec_dev->group);
if (ret < 0)
dev_err(dev, "failed to create attributes. err=%d\n", ret);
@@ -416,7 +417,7 @@ static void cros_ec_sysfs_remove(struct platform_device *pd)
{
struct cros_ec_dev *ec_dev = dev_get_drvdata(pd->dev.parent);
- sysfs_remove_group(&ec_dev->class_dev.kobj, &cros_ec_attr_group);
+ sysfs_remove_group(&ec_dev->class_dev.kobj, ec_dev->group);
}
static const struct platform_device_id cros_ec_sysfs_id[] = {
diff --git a/include/linux/platform_data/cros_ec_proto.h b/include/linux/platform_data/cros_ec_proto.h
index de14923720a53..6ed1c4c5ce2ef 100644
--- a/include/linux/platform_data/cros_ec_proto.h
+++ b/include/linux/platform_data/cros_ec_proto.h
@@ -228,6 +228,7 @@ struct cros_ec_platform {
/**
* struct cros_ec_dev - ChromeOS EC device entry point.
* @class_dev: Device structure used in sysfs.
+ * @group: sysfs attributes groups for this EC.
* @ec_dev: cros_ec_device structure to talk to the physical device.
* @dev: Pointer to the platform device.
* @debug_info: cros_ec_debugfs structure for debugging information.
@@ -237,6 +238,7 @@ struct cros_ec_platform {
*/
struct cros_ec_dev {
struct device class_dev;
+ const struct attribute_group *group;
struct cros_ec_device *ec_dev;
struct device *dev;
struct cros_ec_debugfs *debug_info;
--
2.53.0
^ permalink raw reply related [flat|nested] 26+ messages in thread* [PATCH AUTOSEL 6.18] media: platform: cros-ec: Add Kulnex and Moxoe to the match table
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (15 preceding siblings ...)
2026-08-31 13:28 ` [PATCH AUTOSEL 6.18-6.12] platform/chrome: Resolve kb_wake_angle visibility race Sasha Levin
@ 2026-08-31 13:28 ` Sasha Levin
2026-08-31 13:28 ` [PATCH AUTOSEL 6.18-6.1] blk-cgroup: protect iterating blkgs with blkcg->lock in blkcg_print_stat() Sasha Levin
` (6 subsequent siblings)
23 siblings, 0 replies; 26+ messages in thread
From: Sasha Levin @ 2026-08-31 13:28 UTC (permalink / raw)
To: patches, stable
Cc: Ken Lin, Hans Verkuil, Sasha Levin, hverkuil, mchehab, bleung,
linux-media, chrome-platform, linux-kernel
From: Ken Lin <kenlin5@quanta.corp-partner.google.com>
[ Upstream commit e024767f90f9f50bfcce4b20bb74237ad72450f3 ]
The Google Kulnex and Moxoe device uses the same approach as Google Brask
which enables the HDMI CEC via the cros-ec-cec driver.
Signed-off-by: Ken Lin <kenlin5@quanta.corp-partner.google.com>
Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
## Phase 1: Commit Message Forensics
### Step 1.1: Parse the Subject Line
**Record:** `[media: platform: cros-ec]` `[Add]` — Add Kulnex and Moxoe
Google Chromebook board names to the CEC DMI match table so HDMI CEC can
be enabled on those platforms.
### Step 1.2: Parse All Commit Message Tags
**Record:**
- **Fixes:** none
- **Reported-by:** none
- **Tested-by:** none
- **Reviewed-by:** none
- **Acked-by:** none
- **Link:** none
- **Cc: stable:** none (expected; not a negative signal)
- **Signed-off-by:** Ken Lin `<kenlin5@quanta.corp-partner.google.com>`
(author)
- **Signed-off-by:** Hans Verkuil `<hverkuil+cisco@kernel.org>`
(media/CEC maintainer)
No syzbot, bugzilla, or user crash reports. Maintainer sign-off is a
positive quality signal.
### Step 1.3: Analyze Commit Body
**Record:**
- **Bug description:** Google Kulnex and Moxoe Chromebooks use the same
HDMI CEC-over-ChromeOS-EC approach as Brask, but are missing from
`cec_dmi_match_table[]`.
- **Symptom/failure mode:** `cros-ec-cec` probe fails on these boards;
HDMI CEC is unavailable. No crash is described.
- **Version information:** none in the commit message.
- **Root cause:** Driver uses an explicit DMI whitelist per Chromebook
model for HDMI DRM device and connector-port mapping. New boards were
never added.
### Step 1.4: Detect Hidden Bug Fixes
**Record:** Not a hidden crash/UAF/race fix. This is explicit hardware
enablement: adding board identification entries so an existing driver
can probe on two new platforms. Functionally equivalent to adding
PCI/USB IDs or a DMI quirk entry.
---
## Phase 2: Diff Analysis
### Step 2.1: Inventory the Changes
**Record:**
- **Files:** `drivers/media/cec/platform/cros-ec/cros-ec-cec.c` (+4
lines)
- **Functions modified:** none directly; only `cec_dmi_match_table[]`
data
- **Scope:** single-file, surgical, 4-line addition
### Step 2.2: Code Flow Change
**Record:**
- **Hunk (DMI table):** Before — Kulnex/Moxoe unmatched →
`cros_ec_cec_find_hdmi_dev()` warns and returns `-ENODEV`. After —
boards match like Brask/Moxie, DRM HDMI device (`0000:00:02.0`) and
`port_b_conns` mapping are selected, probe can succeed.
### Step 2.3: Bug Mechanism
**Record:**
- **Category:** hardware identification / platform quirk (DMI-based
board whitelist)
- **Mechanism:** Without a table entry, probe path in
`cros_ec_cec_probe()` exits early:
```501:503:drivers/media/cec/platform/cros-ec/cros-ec-cec.c
hdmi_dev = cros_ec_cec_find_hdmi_dev(&pdev->dev, &conns);
if (IS_ERR(hdmi_dev))
return PTR_ERR(hdmi_dev);
```
And the lookup function explicitly documents that hardware must be added
to the table:
```362:365:drivers/media/cec/platform/cros-ec/cros-ec-cec.c
/* Hardware support must be added in the cec_dmi_match_table */
dev_warn(dev, "CEC notifier not configured for this
hardware\n");
return ERR_PTR(-ENODEV);
```
### Step 2.4: Fix Quality Assessment
**Record:** Obviously correct — copies the proven Brask/Moxie pattern
(`port_b_conns`, same PCI DRM device name). Minimal diff. Regression
risk is very low: only affects DMI matches for "Google"/"Kulnex" and
"Google"/"Moxoe".
---
## Phase 3: Git History Investigation
### Step 3.1: Blame the Changed Lines
**Record:** The DMI table (lines 304–337) exists in this tree ending at
Moxie; Kulnex/Moxoe are absent. Git history in this checkout is heavily
rewritten/squashed (file history is unreliable), but the driver and full
match table are present since at least `ac3fd01e4c1ef` (Linux 6.18-rc7).
The "missing entry" condition is present in 6.18.43.
### Step 3.2: Follow Fixes: Tag
**Record:** N/A — no `Fixes:` tag.
### Step 3.3: File History for Related Changes
**Record:** The driver has accumulated many Google board entries (Fizz,
Brask, Moli, …, Moxie). This commit continues that pattern. Standalone
one-commit change; not part of a multi-patch series.
### Step 3.4: Author's Other Commits
**Record:** Ken Lin has no other commits visible in this checkout. Hans
Verkuil is the media/CEC maintainer and signed off. No related author
series found here.
### Step 3.5: Dependent/Prerequisite Commits
**Record:** No dependencies. Driver, `port_b_conns`, DMI/PCI
infrastructure, and `CONFIG_CEC_CROS_EC` all exist in this tree. Applies
standalone.
---
## Phase 4: Mailing List and External Research
### Step 4.1: Original Patch Discussion
**Record:** `b4 dig -c 4b3f9bff6067a` failed — commit hash not in local
repo. Lore search blocked (403/bot protection). **UNVERIFIED:** original
thread content, reviewer stable nominations, series revisions.
### Step 4.2: Reviewers
**Record:** **UNVERIFIED** via `b4 dig -w`. Hans Verkuil SOB confirms
maintainer involvement.
### Step 4.3: Bug Report
**Record:** N/A — no Reported-by or Link tags.
### Step 4.4: Related Patches/Series
**Record:** Same pattern as prior Brask/Moxie/Kinox additions to this
table. Standalone.
### Step 4.5: Stable Mailing List History
**Record:** **UNVERIFIED** — could not search lore stable archive.
---
## Phase 5: Code Semantic Analysis
### Step 5.1: Key Functions
**Record:** `cec_dmi_match_table[]` (data),
`cros_ec_cec_find_hdmi_dev()`, called from `cros_ec_cec_probe()`.
### Step 5.2: Trace Callers
**Record:** `cros_ec_cec_probe()` is the platform driver probe path
during boot/module load on Chromebooks with `CONFIG_CEC_CROS_EC` and
`CONFIG_CROS_EC`. Affects only matching Google hardware.
### Step 5.3: Trace Callees
**Record:** `dmi_match()`, `bus_find_device_by_name()` on PCI bus,
connector mapping via `port_b_conns`.
### Step 5.4: Call Chain / Reachability
**Record:** Boot-time platform probe on ChromeOS EC-equipped Google
devices. Not a syscall path. Userspace impact is missing `/dev/cec*` and
non-functional HDMI CEC on Kulnex/Moxoe.
### Step 5.5: Similar Patterns
**Record:** Fifteen other Google boards already use the same table
pattern; Brask and Moxie use identical `port_b_conns` mapping, matching
the commit message claim.
---
## Phase 6: Cross-Referencing Against Local Tree (6.18.43)
### Step 6.1: Does the Buggy Code Exist?
**Record:** **YES.** Local tree is `6.18.43`
(`v6.18.43-1-gc7f0dac02d232`). `drivers/media/cec/platform/cros-ec/cros-
ec-cec.c` exists (602 lines). Table ends at Moxie; Kulnex/Moxoe are
missing. Driver has been present since 6.18-rc7 in this tree.
### Step 6.2: Backport Complications
**Record:** **Clean apply expected.** Verified with `git apply --check`
against current tree — applies without conflicts.
### Step 6.3: Related Fixes Already Present?
**Record:** No — `grep` finds no Kulnex or Moxoe anywhere in the tree.
---
## Phase 7: Subsystem and Maintainer Context
### Step 7.1: Subsystem and Criticality
**Record:** `drivers/media/cec/` — media/CEC platform driver.
**IMPORTANT** for affected Chromebook users, **PERIPHERAL** globally
(CEC on two specific Google boards).
### Step 7.2: Subsystem Activity
**Record:** CEC subsystem is active in this tree (recent fixes for seco,
rc race, debugfs leak). The cros-ec driver itself is mature with a
growing DMI whitelist.
---
## Phase 8: Impact and Risk Assessment
### Step 8.1: Who Is Affected
**Record:** Users of Google Kulnex and Moxoe Chromebooks with
`CONFIG_CEC_CROS_EC=y/m`. Config- and platform-specific; not universal.
### Step 8.2: Trigger Conditions
**Record:** Booting one of these two board models with the cros-ec-cec
driver enabled. Deterministic on every boot. Not a security-relevant or
unprivileged-triggered path.
### Step 8.3: Failure Mode Severity
**Record:** HDMI CEC non-functional; driver probe returns `-ENODEV` with
a warning. **Severity: LOW** — feature absence, not crash, corruption,
deadlock, or security issue.
### Step 8.4: Risk-Benefit Ratio
**Record:**
- **Benefit:** Enables HDMI CEC on two new Chromebook models running
this kernel; matches established board-enablement pattern.
- **Risk:** Very low — 4 lines, no logic change, only new DMI strings.
- **Ratio:** Moderate benefit for a tiny audience vs. very low risk.
Does not meet strict "important bug" threshold, but fits the stable
exception for hardware identification additions.
---
## Phase 9: Final Synthesis
### Step 9.1: Evidence Compile
**FOR backport:**
- Driver and infrastructure fully present in 6.18.43
- Real hardware gap on Kulnex/Moxoe — CEC broken without entries
- Tiny, obviously correct, applies cleanly
- Follows proven Brask/Moxie `port_b_conns` mapping
- Media maintainer (Hans Verkuil) signed off
- Fits stable exception for hardware identification / quirk additions
(DMI board ID to existing driver)
**AGAINST backport:**
- Not a crash, security, corruption, or deadlock fix
- Failure mode is missing functionality (CEC), severity LOW
- Affects only two specific new Chromebook models
- No user reports, syzbot, or explicit stable nomination
- By-design whitelist: unsupported boards get `-ENODEV`, not a code
defect on already-supported hardware
- Mailing list review details unverified
**UNRESOLVED:**
- Whether Kulnex/Moxoe actually ship with 6.18.y kernels
- Lore discussion and any stable nominations from reviewers
### Step 9.2: Stable Rules Checklist
1. Obviously correct and tested? **PASS** — mechanical table entries;
maintainer SOB; pattern proven on Brask/Moxie.
2. Fixes a real bug affecting users? **PASS (narrow)** — real hardware
support gap for CEC on two boards, not a kernel logic bug.
3. Important issue (crash, security, corruption, deadlock)? **FAIL** —
CEC absence only; LOW severity.
4. Small and contained? **PASS** — 4 lines, one file.
5. No new features or APIs? **PASS** — no API change; board ID addition
to existing driver.
6. Can apply to local tree? **PASS** — verified clean apply.
### Step 9.3: Exception Categories
**Record:** **Hardware identification / quirk exception** — DMI match
table entry for an existing platform driver, analogous to adding
PCI/USB/ACPI IDs. Same category as prior Brask, Moxie, Kinox entries.
### Step 9.4: Decision Rationale
This commit does not fix a critical kernel defect. It enables HDMI CEC
on two new Google Chromebook platforms by extending the existing DMI
whitelist in `cros-ec-cec`. That is standard stable material under the
hardware-identification exception: the driver already exists in 6.18.43,
the change is trivial and low-risk, and it unblocks real hardware for
users on those boards. It does not meet the strict "important bug"
criterion on its own, but stable trees routinely take such board-ID
additions when the driver is already present.
For the locally checked-out **6.18.43** tree: the driver exists, the gap
exists, and the patch applies cleanly.
---
## Verification
- **[Phase 1]** Parsed subject, tags, body: hardware enablement for
Kulnex/Moxoe CEC; Hans Verkuil SOB; no Fixes/Reported-
by/Link/Cc:stable
- **[Phase 2]** Diff: +4 lines in `cec_dmi_match_table[]`; probe failure
path confirmed in source
- **[Phase 3]** `git describe HEAD`: v6.18.43-1-gc7f0dac02d232; `make
kernelversion`: 6.18.43
- **[Phase 3]** `git show ac3fd01e4c1ef:...cros-ec-cec.c`: driver
present since 6.18-rc7; Moxie present, Kulnex/Moxoe absent
- **[Phase 3]** `grep Kulnex|Moxoe`: no matches in tree
- **[Phase 3]** Git history in this repo is rewritten/unreliable for
blame; table content verified directly
- **[Phase 4]** `b4 dig -c 4b3f9bff6067a`: failed (commit not in repo)
- **[Phase 4]** Lore fetch: blocked (403/bot protection) —
**UNVERIFIED** mailing list discussion
- **[Phase 5]** Read `cros_ec_cec_probe()` and
`cros_ec_cec_find_hdmi_dev()`: confirmed `-ENODEV` path
- **[Phase 5]** `grep cros_ec_cec_find_hdmi_dev`: only called from probe
- **[Phase 6]** File exists at `drivers/media/cec/platform/cros-ec/cros-
ec-cec.c` (602 lines)
- **[Phase 6]** `git apply --check /tmp/kulnex.patch`: applies cleanly
- **[Phase 6]** `grep Kulnex|Moxoe`: absent from tree
- **[Phase 7]** `CONFIG_CEC_CROS_EC` in
`drivers/media/cec/platform/Kconfig`; depends on `CROS_EC`
- **[Phase 8]** Failure mode verified: `-ENODEV` + `dev_warn`, not
oops/panic
**YES**
drivers/media/cec/platform/cros-ec/cros-ec-cec.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c
index 419b9a7abcceb..4b3f9bff6067a 100644
--- a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c
+++ b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c
@@ -334,6 +334,10 @@ static const struct cec_dmi_match cec_dmi_match_table[] = {
{ "Google", "Dirks", "0000:00:02.0", port_ab_conns },
/* Google Moxie */
{ "Google", "Moxie", "0000:00:02.0", port_b_conns },
+ /* Google Kulnex */
+ { "Google", "Kulnex", "0000:00:02.0", port_b_conns },
+ /* Google Moxoe */
+ { "Google", "Moxoe", "0000:00:02.0", port_b_conns },
};
static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev,
--
2.53.0
^ permalink raw reply related [flat|nested] 26+ messages in thread* [PATCH AUTOSEL 6.18-6.1] blk-cgroup: protect iterating blkgs with blkcg->lock in blkcg_print_stat()
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (16 preceding siblings ...)
2026-08-31 13:28 ` [PATCH AUTOSEL 6.18] media: platform: cros-ec: Add Kulnex and Moxoe to the match table Sasha Levin
@ 2026-08-31 13:28 ` Sasha Levin
2026-08-31 13:28 ` [PATCH AUTOSEL 6.18-6.1] ACPICA: Enhance OEM ID and Table ID validation in acpi_ex_load_table_op() Sasha Levin
` (5 subsequent siblings)
23 siblings, 0 replies; 26+ messages in thread
From: Sasha Levin @ 2026-08-31 13:28 UTC (permalink / raw)
To: patches, stable
Cc: Yu Kuai, Jens Axboe, Sasha Levin, tj, josef, cgroups, linux-block,
linux-kernel
From: Yu Kuai <yukuai@fygo.io>
[ Upstream commit 25656304dabd26198ec69460c594a19d086ef099 ]
blkcg_print_one_stat() will be called for each blkg:
- access blkg->iostat, which is freed from rcu callback
blkg_free_workfn();
- access policy data from pd_stat_fn(), which is freed from
pd_free_fn(), while pd_free_fn() can be called by removing blkcg or
deactivating policy;
Take blkcg->lock while iterating so the blkgs stay online and both
blkg->iostat and policy data for activated policies stay valid. Use
irq-safe locking because blkcg->lock can be nested under q->queue_lock,
which is used from IRQ completion paths.
Prepare to convert protecting blkgs from request_queue with mutex.
Signed-off-by: Yu Kuai <yukuai@fygo.io>
Link: https://patch.msgid.link/05799877e720dcd300e2ddd4625e8e162959d7cc.1780621988.git.yukuai@fygo.io
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
## Phase 1: Commit Message Forensics
### Step 1.1: Subject Line
**Record:** `[blk-cgroup]` `[protect]` — Protect iteration over blkgs in
`blkcg_print_stat()` using `blkcg->lock`.
### Step 1.2: Tags
**Record:**
- **Signed-off-by:** Yu Kuai `<yukuai@fygo.io>` (author)
- **Link:** https://patch.msgid.link/05799877e720dcd300e2ddd4625e8e16295
9d7cc.1780621988.git.yukuai@fygo.io
- **Signed-off-by:** Jens Axboe `<axboe@kernel.dk>` (block maintainer)
- No `Fixes:`, `Reported-by:`, `Tested-by:`, `Reviewed-by:`, `Cc:
stable@vger.kernel.org`
Notable: maintainer sign-off from Jens Axboe; no syzbot/fuzzer report.
### Step 1.3: Body Analysis
**Record:**
- **Bug:** `blkcg_print_one_stat()` reads `blkg->iostat` (freed in
`blkg_free_workfn()`) and policy data via `pd_stat_fn()` (freed in
`pd_free_fn()` during cgroup removal or policy deactivation).
- **Symptom:** Use-after-free when reading cgroup I/O stats concurrently
with teardown/deactivation.
- **Root cause:** Iteration is RCU-protected and per-blkg `queue_lock`
is held, but neither prevents `pd_free_fn()` or async `blkg` teardown
from invalidating data being read.
- **Fix:** Hold `blkcg->lock` (IRQ-safe) for the full iteration so blkgs
stay online and policy/iostat data remain valid.
- **Note:** "Prepare to convert protecting blkgs from request_queue with
mutex" — future work, not a dependency.
### Step 1.4: Hidden Bug Fix?
**Record:** Yes — explicit UAF/race fix disguised as locking correction.
Not cosmetic cleanup.
---
## Phase 2: Diff Analysis
### Step 2.1: Inventory
**Record:**
- **File:** `block/blk-cgroup.c` (+3 / -6 net)
- **Function:** `blkcg_print_stat()` only
- **Scope:** Single-file, surgical (~10 lines touched)
### Step 2.2: Code Flow Change
**Record:**
- **Before:** `rcu_read_lock()` → `hlist_for_each_entry_rcu()` → per-
iteration `spin_lock_irq(&blkg->q->queue_lock)` →
`blkcg_print_one_stat()` → unlock → `rcu_read_unlock()`
- **After:** `guard(spinlock_irq)(&blkcg->lock)` →
`hlist_for_each_entry()` → `blkcg_print_one_stat()` → auto-unlock
- **Path:** `cgroup` `io.stat` seq_file read (normal monitoring path)
### Step 2.3: Bug Mechanism
**Record:** **Category:** Race condition / use-after-free (reference-
counting and lifetime)
**Mechanism (verified in tree):**
1. `blkcg_deactivate_policy()` holds `queue_lock`, then `blkcg->lock`,
then calls `pd_free_fn()`:
```1738:1744:block/blk-cgroup.c
spin_lock(&blkcg->lock);
if (blkg->pd[pol->plid]) {
if (blkg->pd[pol->plid]->online &&
pol->pd_offline_fn)
pol->pd_offline_fn(blkg->pd[pol->plid]);
pol->pd_free_fn(blkg->pd[pol->plid]);
blkg->pd[pol->plid] = NULL;
```
2. `blkg_destroy()` requires `blkcg->lock`, unhashes the blkg, and
eventually frees via `blkg_free_workfn()`:
```529:554:block/blk-cgroup.c
lockdep_assert_held(&blkg->q->queue_lock);
lockdep_assert_held(&blkcg->lock);
// ...
hlist_del_init_rcu(&blkg->blkcg_node);
```
3. `blkcg_print_stat()` currently does **not** hold `blkcg->lock`, so
`pd_stat_fn()` and `blkg->iostat` access can race with steps 1–2.
4. The kernel already documents that RCU alone is insufficient:
```177:184:block/blk-cgroup.c
- A group is RCU protected, but having an rcu lock does not mean that
one
- can access all the fields of blkg and assume these are valid.
```
### Step 2.4: Fix Quality
**Record:** Obviously correct. Aligns `blkcg_print_stat()` with
`blkcg_reset_stats()`, which already iterates `blkg_list` under
`spin_lock_irq(&blkcg->lock)`:
```662:669:block/blk-cgroup.c
spin_lock_irq(&blkcg->lock);
// ...
hlist_for_each_entry(blkg, &blkcg->blkg_list, blkcg_node) {
```
**Regression risk:** Low. `blkcg_print_stat()` takes only `blkcg->lock`
(no `queue_lock`), avoiding AB-BA with `blkcg_destroy_blkgs()` (blkcg
lock → queue lock) and `blkcg_deactivate_policy()` (queue lock → blkcg
lock).
---
## Phase 3: Git History Investigation
### Step 3.1: Blame
**Record:** Current RCU+`queue_lock` pattern in `blkcg_print_stat()`
from commit `49cb5168a7c6ab` (Aug 2021, "blk-cgroup: refactor
blkcg_print_stat"). Bug window is long; code is present in this tree.
### Step 3.2: Fixes: Tag
**Record:** N/A — no `Fixes:` tag.
### Step 3.3: Related File History
**Record:**
- `5e5b7f2ef8549` — separate UAF fix in `__blkcg_rstat_flush()` (already
in 6.18.y); same subsystem, different race.
- `5d726c4dbeedd` — Yu Kuai deadlock fix in policy configuration (same
author/subsystem).
- `810ecfa765f8b` (2013) — historical move from `blkcg->lock` to
`queue_lock` for `blkcg_print_blkgs()`; this patch partially reverses
that for `blkcg_print_stat()` where `queue_lock` is insufficient.
### Step 3.4: Author Context
**Record:** Yu Kuai is an active block/cgroup contributor
(`5d726c4dbeedd`, `dc96cefef0d30`, etc.).
### Step 3.5: Dependencies
**Record:** Standalone. `guard(spinlock_irq)` is defined in
`include/linux/spinlock.h` (available in 6.18). No series dependency.
---
## Phase 4: Mailing List and External Research
### Step 4.1–4.5
**Record:**
- `b4 dig -c <commit>`: **N/A** — commit not found in local `FETCH_HEAD`
master; patch appears not yet merged upstream.
- Lore/patch.msgid.link: **Blocked** (403/Anubis bot protection).
- **UNVERIFIED:** Full review-thread content, stable nominations from
reviewers, series revisions.
From available metadata: Jens Axboe merged sign-off indicates maintainer
acceptance.
---
## Phase 5: Code Semantic Analysis
### Step 5.1: Key Functions
**Record:** `blkcg_print_stat()`, `blkcg_print_one_stat()` (caller
context unchanged).
### Step 5.2: Callers
**Record:** `blkcg_print_stat` is `.seq_show` for cgroup `stat` file:
```1254:1258:block/blk-cgroup.c
static struct cftype blkcg_files[] = {
{
.name = "stat",
.seq_show = blkcg_print_stat,
```
Triggered via cgroupfs reads (`/sys/fs/cgroup/.../io.stat`).
### Step 5.3: Callees
**Record:** `blkcg_print_one_stat()` reads `blkg->iostat`, calls
`pol->pd_stat_fn()`, uses `blkg_dev_name()`.
### Step 5.4: Reachability
**Record:** Reachable from userspace via cgroup stat reads. Concurrent
with cgroup deletion (`blkcg_destroy_blkgs`) and policy deactivation
(`blkcg_deactivate_policy`) in container/VM environments.
### Step 5.5: Similar Patterns
**Record:** `blkcg_print_blkgs()` still uses RCU+`queue_lock` (lines
718–724) — same class of issue may exist there, but is out of scope for
this commit. `blkcg_reset_stats()` already uses the correct
`blkcg->lock` pattern.
---
## Phase 6: Cross-Reference Against Local Tree
### Step 6.1: Buggy Code Present?
**Record:** **Yes.** Tree is **v6.18.44** (`linux-6.18.y` stable). Buggy
code at lines 1244–1250:
```1244:1250:block/blk-cgroup.c
rcu_read_lock();
hlist_for_each_entry_rcu(blkg, &blkcg->blkg_list, blkcg_node) {
spin_lock_irq(&blkg->q->queue_lock);
blkcg_print_one_stat(blkg, sf);
spin_unlock_irq(&blkg->q->queue_lock);
}
rcu_read_unlock();
```
### Step 6.2: Backport Complications
**Record:** Clean apply expected — hunk matches current file.
`blkcg->lock` exists in `struct blkcg` (`blk-cgroup.h:96`).
`guard(spinlock_irq)` available via `spinlock.h` include chain.
### Step 6.3: Related Fixes Already Present?
**Record:** `5e5b7f2ef8549` (rstat flush UAF) is present; it does
**not** fix this `blkcg_print_stat()` race.
---
## Phase 7: Subsystem Context
### Step 7.1: Subsystem / Criticality
**Record:** **block / blk-cgroup** — **IMPORTANT** (cgroup I/O
accounting; widely used with containers/systemd/cgroup v2).
### Step 7.2: Activity
**Record:** Actively maintained; recent stable fixes in same file
(`5e5b7f2ef8549`, `6a01413a4e8fc`).
---
## Phase 8: Impact and Risk Assessment
### Step 8.1: Who Is Affected
**Record:** Users with `CONFIG_BLK_CGROUP` reading I/O cgroup stats
while cgroups are deleted or policies deactivated — common in
Kubernetes/container teardown with concurrent monitoring.
### Step 8.2: Trigger Conditions
**Record:** Concurrent `io.stat` read + cgroup rmdir or block policy
deactivation/disk removal. Realistic in production; not purely
theoretical given `pd_free_fn()` runs under `blkcg->lock` that
`blkcg_print_stat()` does not take.
### Step 8.3: Failure Mode
**Record:** UAF on policy data and/or iostat → kernel oops, memory
corruption. **Severity: HIGH (potential CRITICAL security impact).**
### Step 8.4: Risk-Benefit
**Record:**
- **Benefit:** High — prevents UAF on a userspace-reachable path.
- **Risk:** Very low — ~7-line locking change matching existing
`blkcg_reset_stats()` pattern.
- **Ratio:** Strongly favors backport.
---
## Phase 9: Final Synthesis
### Step 9.1: Evidence Summary
**FOR:**
- Real UAF race with verified mechanism in local tree
- Userspace-reachable via cgroup `stat` file
- Small, surgical, matches established locking in `blkcg_reset_stats()`
/ `blkcg_destroy_blkgs()`
- Block maintainer (Jens Axboe) sign-off
- Long-standing buggy pattern (since 2021 refactor)
- Related UAF fix already backported to this tree — demonstrates
subsystem stability priority
**AGAINST:**
- Commit not yet verified as merged to mainline (stable rules require
upstream merge before submission)
- `blkcg_print_blkgs()` may have a similar latent issue (not fixed here;
not a reason to reject this fix)
- Mailing list review details unverified due to lore access blocks
### Step 9.2: Stable Rules Checklist
1. Obviously correct and tested? **PASS** — locking matches sibling
functions; maintainer SOB; mechanism clear from code.
2. Fixes a real bug affecting users? **PASS** — UAF on cgroup stat read
path.
3. Important issue? **PASS** — UAF / potential crash or corruption (HIGH
severity).
4. Small and contained? **PASS** — single function, <20 lines.
5. No new features or APIs? **PASS** — synchronization only.
6. Can apply to local tree? **PASS** — buggy code present; dependencies
(`blkcg->lock`, `guard(spinlock_irq)`) exist in 6.18.44.
### Step 9.3: Exception Category
**Record:** N/A — standard bug fix, not device-ID/quirk/build/doc
exception.
### Step 9.4: Decision Rationale
This commit fixes a genuine use-after-free race in `blkcg_print_stat()`
when users read block cgroup statistics concurrently with cgroup
teardown or policy deactivation. The buggy code is present in the local
6.18.44 tree, the fix is minimal and mirrors the already-correct
`blkcg_reset_stats()` locking, and the failure mode is a kernel crash or
memory corruption. This is appropriate stable material once merged
upstream.
---
## Verification
- [Phase 1] Parsed subject, tags, body from user-provided commit message
- [Phase 1] Identified as explicit UAF/race fix, not cosmetic cleanup
- [Phase 2] Diff: 1 file, `blkcg_print_stat()` only, ~10 lines
- [Phase 2] Verified `pd_free_fn()` called under `blkcg->lock` in
`blkcg_deactivate_policy()` (lines 1738–1744)
- [Phase 2] Verified `blkg_destroy()` requires `blkcg->lock` (lines
529–530, 554)
- [Phase 2] Verified `blkg_free_workfn()` frees policy data and iostat
(lines 114–142)
- [Phase 2] Verified RCU insufficiency comment (lines 177–184)
- [Phase 2] Verified `blkcg_reset_stats()` uses
`spin_lock_irq(&blkcg->lock)` for same list iteration (lines 662–669)
- [Phase 3] `git blame`: RCU+queue_lock pattern from `49cb5168a7c6ab`
(2021)
- [Phase 3] `git log -20 -- block/blk-cgroup.c`: related fixes
`5e5b7f2ef8549`, `5d726c4dbeedd`
- [Phase 3] `git show 5e5b7f2ef8549`: separate rstat UAF fix, already in
tree
- [Phase 3] No `Fixes:` tag to follow
- [Phase 3] `guard(spinlock_irq)` defined in `include/linux/spinlock.h`
lines 571–573
- [Phase 4] `b4 dig`: N/A — commit not in `FETCH_HEAD` master
- [Phase 4] Lore/patch.msgid.link fetch: blocked (403/Anubis)
- [Phase 4] **UNVERIFIED:** Review-thread stable nominations, Tested-by
reports
- [Phase 5] `blkcg_print_stat` registered as `.seq_show` for `"stat"`
(lines 1254–1258)
- [Phase 5] `blkcg_print_one_stat` accesses `blkg->iostat` and
`pd_stat_fn()` (lines 1182–1228)
- [Phase 6] `git describe HEAD`: v6.18.44 on `stable/linux-6.18.y`
- [Phase 6] Buggy code confirmed at lines 1244–1250
- [Phase 6] `struct blkcg` has `spinlock_t lock` in `blk-cgroup.h:96`
- [Phase 6] No equivalent fix already present for `blkcg_print_stat()`
- [Phase 7] Subsystem: block/blk-cgroup, CONFIG_BLK_CGROUP
- [Phase 8] Failure mode: UAF → oops/corruption, HIGH severity
- [Phase 8] Trigger: cgroup stat read during teardown/deactivation
**YES**
block/blk-cgroup.c | 9 +++------
1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c
index a2347b5795874..812f60905a708 100644
--- a/block/blk-cgroup.c
+++ b/block/blk-cgroup.c
@@ -1241,13 +1241,10 @@ static int blkcg_print_stat(struct seq_file *sf, void *v)
else
css_rstat_flush(&blkcg->css);
- rcu_read_lock();
- hlist_for_each_entry_rcu(blkg, &blkcg->blkg_list, blkcg_node) {
- spin_lock_irq(&blkg->q->queue_lock);
+ guard(spinlock_irq)(&blkcg->lock);
+ hlist_for_each_entry(blkg, &blkcg->blkg_list, blkcg_node)
blkcg_print_one_stat(blkg, sf);
- spin_unlock_irq(&blkg->q->queue_lock);
- }
- rcu_read_unlock();
+
return 0;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 26+ messages in thread* [PATCH AUTOSEL 6.18-6.1] ACPICA: Enhance OEM ID and Table ID validation in acpi_ex_load_table_op()
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (17 preceding siblings ...)
2026-08-31 13:28 ` [PATCH AUTOSEL 6.18-6.1] blk-cgroup: protect iterating blkgs with blkcg->lock in blkcg_print_stat() Sasha Levin
@ 2026-08-31 13:28 ` Sasha Levin
2026-08-31 13:28 ` [PATCH AUTOSEL 6.18-5.10] ACPICA: Add validation for node in acpi_ns_build_normalized_path() Sasha Levin
` (4 subsequent siblings)
23 siblings, 0 replies; 26+ messages in thread
From: Sasha Levin @ 2026-08-31 13:28 UTC (permalink / raw)
To: patches, stable
Cc: ikaros, Rafael J. Wysocki, Sasha Levin, rafael,
maciej.wieczor-retman, pawel.chmielewski, linux-acpi,
acpica-devel, linux-kernel
From: ikaros <void0red@gmail.com>
[ Upstream commit 485829e6999b7909f50761a1c708660304edc945 ]
Enhance OEM ID and Table ID validation in acpi_ex_load_table_op() to
prevent buffer overflows.
Link: https://github.com/acpica/acpica/commit/f85a43098d65
Signed-off-by: ikaros <void0red@gmail.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Link: https://patch.msgid.link/2230782.OBFZWjSADL@rafael.j.wysocki
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
# Stable Backport Analysis: ACPICA OEM ID/Table ID Validation in
`acpi_ex_load_table_op()`
**Local tree:** `v6.18.44` (Linux 6.18.y stable)
**Mainline commit:** `485829e6999b7` (not yet in this tree)
---
## PHASE 1: COMMIT MESSAGE FORENSICS
### Step 1.1: Subject Line
**Record:** `[ACPICA] [enhance/validate] Enhance OEM ID and Table ID
validation in acpi_ex_load_table_op() to prevent buffer overflows`
### Step 1.2: Tags
**Record:**
- **Link:** https://github.com/acpica/acpica/commit/f85a43098d65
(upstream ACPICA fix)
- **Link:** https://patch.msgid.link/2230782.OBFZWjSADL@rafael.j.wysocki
(kernel submission)
- **Signed-off-by:** ikaros \<void0red@gmail.com\> (author)
- **Signed-off-by:** Rafael J. Wysocki \<rafael.j.wysocki@intel.com\>
(ACPI maintainer)
- No `Fixes:`, `Reported-by:`, `Cc: stable@vger.kernel.org`, `Tested-
by:`, or `Reviewed-by:` tags
- Notable: maintainer merge; part of ACPICA 20260408 import series
(patch 22/27)
### Step 1.3: Body Analysis
**Record:**
- **Bug:** `acpi_ex_load_table_op()` passes AML string operand pointers
directly to `acpi_tb_find_table()`, which reads fixed
`ACPI_OEM_ID_SIZE` (6) and `ACPI_OEM_TABLE_ID_SIZE` (8) bytes via
`memcpy()` regardless of actual string length.
- **Symptom:** Heap-buffer-overflow on read when OEM ID/Table ID strings
are shorter than those fixed sizes.
- **Root cause:** AML strings have explicit `.length` fields;
allocations are `length + 1` bytes. `acpi_tb_find_table()` always
copies 6/8 bytes from the pointer.
- **Version info:** None in commit message; bug mechanism dates to
original `acpi_ex_load_table_op()` code (2005).
### Step 1.4: Hidden Bug Fix Detection
**Record:** Yes — despite "Enhance validation" wording, this is a real
memory-safety bug fix. Upstream ACPICA issue
[#1144](https://github.com/acpica/acpica/issues/1144) documents an ASAN
heap-buffer-overflow with reproducer (`issue49.aml`).
---
## PHASE 2: DIFF ANALYSIS
### Step 2.1: Change Inventory
**Record:**
- **File:** `drivers/acpi/acpica/exconfig.c` (+24 / -2)
- **Function:** `acpi_ex_load_table_op()`
- **Scope:** Single-file, surgical fix
### Step 2.2: Code Flow Change
**Record:**
- **Hunk 1 (stack buffers):** Adds `oem_id[7]` and `oem_table_id[9]`
local buffers.
- **Hunk 2 (validation):** Before calling `acpi_tb_find_table()`, checks
`operand[1]->string.length <= ACPI_OEM_ID_SIZE` and
`operand[2]->string.length <= ACPI_OEM_TABLE_ID_SIZE`; returns
`AE_AML_STRING_LIMIT` on violation.
- **Hunk 3 (safe copy):** Copies only `operand[n]->string.length` bytes
into local buffers, null-terminates, passes local buffers to
`acpi_tb_find_table()` instead of raw AML pointers.
- **Before:** Raw AML pointers passed → `acpi_tb_find_table()` does
`memcpy(..., ACPI_OEM_ID_SIZE)` (6 bytes) from potentially 1–2 byte
allocation.
- **After:** Length-validated, null-terminated stack buffers of exactly
the right size are passed.
### Step 2.3: Bug Mechanism
**Record:**
- **Category:** Buffer over-read / heap-buffer-overflow (memory safety)
- **Mechanism:** In `acpi_tb_find_table()` at lines 60–61 of `tbfind.c`:
```60:61:drivers/acpi/acpica/tbfind.c
memcpy(header.oem_id, oem_id, ACPI_OEM_ID_SIZE);
memcpy(header.oem_table_id, oem_table_id,
ACPI_OEM_TABLE_ID_SIZE);
```
`strlen()` validation (lines 51–53) only checks upper bound; it does
not prevent reading past a short string's allocation. A 1-byte OEM ID
gets a 2-byte allocation (`string_size + 1` in
`acpi_ut_create_string_object()`), but `memcpy` reads 6 bytes.
### Step 2.4: Fix Quality
**Record:**
- Fix is obviously correct and minimal.
- Uses known AML `.length` rather than `strlen()` on potentially
non–null-terminated data.
- Stack buffers are correctly sized (`ACPI_OEM_ID_SIZE + 1`,
`ACPI_OEM_TABLE_ID_SIZE + 1`).
- **Regression risk:** Very low. Only affects the `LoadTable` AML opcode
path; oversized strings now correctly return `AE_AML_STRING_LIMIT`
instead of proceeding to over-read.
- Error-path cleanup is handled by `exoparg6.c` cleanup on
`ACPI_FAILURE(status)`.
---
## PHASE 3: GIT HISTORY INVESTIGATION
### Step 3.1: Blame
**Record:**
- Vulnerable `acpi_tb_find_table(operand[0]..., operand[1]...,
operand[2]...)` call introduced in commit `4be44fcd3bf648` (Len Brown,
2005-08-05).
- Bug present in this tree since kernel import of ACPICA.
### Step 3.2: Fixes Tag
**Record:** N/A — no `Fixes:` tag in commit message.
### Step 3.3: Related File History
**Record:**
- Commit `9f41fd8a175ff` (2015, "Update parameter validation for
data_table_region and load_table") **removed** length validation from
`acpi_ex_load_table_op()` and relied on `acpi_tb_find_table()`'s
`strlen()` checks — which do not prevent the short-string `memcpy`
over-read.
- Fix is **not** in 6.18.y (`git log --grep="Enhance OEM"` returns
nothing on this branch).
- Fix **is** on mainline: `485829e6999b7` (merged May 27, 2026).
### Step 3.4: Author Context
**Record:** ikaros (void0red) reported ACPICA issue #1144 and
contributed 14 patches in the ACPICA 20260408 series. Rafael J. Wysocki
merged to mainline.
### Step 3.5: Dependencies
**Record:** Patch is labeled 22/27 in the ACPICA import series but is
**standalone** — it only touches `acpi_ex_load_table_op()` and has no
structural dependencies on other series patches. `git cherry-pick --no-
commit 485829e6999b7` applies cleanly to v6.18.44.
---
## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
### Step 4.1: Original Discussion
**Record:**
- **b4 dig URL:**
https://patch.msgid.link/2230782.OBFZWjSADL@rafael.j.wysocki
- **Series:** v1 only (ACPICA 20260408, 27 patches); no v2/v3 revisions
for this patch.
- **Review feedback:** No NAKs or stable nominations found in saved
thread mbox.
- Maintainer cover letter confirms routine ACPICA upstream sync.
### Step 4.2: Reviewers
**Record:** CC'd: Rafael J. Wysocki, linux-acpi@vger.kernel.org, LKML,
Saket Dumbre (Intel), Pawel Chmielewski (Intel).
### Step 4.3: Bug Report
**Record:**
- **ACPICA issue #1144:** Heap-buffer-overflow in `AcpiTbFindTable` via
`LOAD_TABLE_OP`.
- **ASAN:** READ of size 6, 0 bytes past end of 49-byte region;
reproducer `issue49.aml` via `acpiexec`.
- **Call chain:** `AcpiExLoadTableOp` → `AcpiTbFindTable` →
`AcpiPsParseAml` → `AcpiNsLoadTable` → `AcpiLoadTables`.
### Step 4.4: Related Patches
**Record:** Same author has 13 other fixes in the series (integer
overflows, NULL checks, etc.). This patch is independent. Note:
`acpi_ds_eval_table_region_operands()` in `dsopcode.c` still passes raw
pointers to `acpi_tb_find_table()` — a separate, unfixed path not
addressed by this commit.
### Step 4.5: Stable List History
**Record:** No stable-list discussion found for this specific fix. (Lore
stable search blocked by bot protection; b4 mbox had no stable
mentions.)
---
## PHASE 5: CODE SEMANTIC ANALYSIS
### Step 5.1: Key Functions
**Record:** `acpi_ex_load_table_op()` (modified), `acpi_tb_find_table()`
(caller of fixed behavior).
### Step 5.2: Callers
**Record:**
- `exoparg6.c:272` — `case AML_LOAD_TABLE_OP: status =
acpi_ex_load_table_op(...)`
- Invoked during AML interpretation when `LoadTable()` opcode executes.
### Step 5.3: Callees
**Record:** `acpi_ut_create_integer_object()`, `acpi_tb_find_table()`,
`acpi_ex_add_table()`, namespace/scope operations.
### Step 5.4: Reachability
**Record:**
- **Boot:** ACPI table loading/parsing (`acpi_load_tables()` → namespace
load → AML parse).
- **Runtime:** `acpi_load_table()` API (e.g., `acpi_configfs.c` for
root-loaded SSDTs).
- **Trigger:** Malformed/crafted ACPI AML containing `LoadTable()` with
undersized OEM ID/Table ID string operands.
- **Userspace reachability:** Root can inject ACPI tables via configfs;
firmware-supplied tables are the common case. Not directly triggerable
by unprivileged users, but boot-time parsing of malicious firmware
tables is a realistic attack surface.
### Step 5.5: Similar Patterns
**Record:** `dsopcode.c:507-509` (`acpi_ds_eval_table_region_operands`)
has the same raw-pointer pattern — unfixed by this commit. The 2015 BZ
1184 fix targeted `data_table_region` error handling but did not fix the
`LoadTable` opcode path addressed here.
---
## PHASE 6: CROSS-REFERENCE AGAINST LOCAL TREE
### Step 6.1: Buggy Code Present?
**Record:** **Yes.** Current `exconfig.c` lines 108–110 pass raw operand
pointers:
```108:110:drivers/acpi/acpica/exconfig.c
status = acpi_tb_find_table(operand[0]->string.pointer,
operand[1]->string.pointer,
operand[2]->string.pointer,
&table_index);
```
### Step 6.2: Backport Complications
**Record:** **Clean apply.** Cherry-pick tested successfully on
v6.18.44. No conflicts expected.
### Step 6.3: Related Fixes Already Present?
**Record:** **No.** `git log --grep="Enhance OEM"` on this branch
returns nothing. Mainline has `485829e6999b7`; 6.18.y does not.
---
## PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
### Step 7.1: Subsystem Criticality
**Record:** **ACPI / ACPICA interpreter** — IMPORTANT. ACPI is on every
ACPI-enabled system; interpreter bugs affect boot and runtime ACPI
method execution.
### Step 7.2: Subsystem Activity
**Record:** Actively maintained; periodic ACPICA upstream syncs. Recent
6.18.y history is mostly copyright updates, not functional changes to
this path.
---
## PHASE 8: IMPACT AND RISK ASSESSMENT
### Step 8.1: Who Is Affected
**Record:** All systems with `CONFIG_ACPI` on ACPI firmware or
dynamically loaded ACPI tables that execute `LoadTable()` AML with short
OEM strings.
### Step 8.2: Trigger Conditions
**Record:**
- **When:** ACPI AML interpretation executing `LoadTable(Sig, OEMID,
OEMTableID, ...)`.
- **Condition:** OEM ID string operand length < 6 bytes, or OEM Table ID
< 8 bytes.
- **Likelihood:** Uncommon in legitimate firmware (OEM fields are
typically padded to full size), but trivially reproducible with
crafted AML (confirmed by upstream reproducer).
- **Privilege:** Root for dynamic table load; boot-time for firmware
tables.
### Step 8.3: Failure Mode Severity
**Record:** Heap-buffer-overflow (read past allocation) → **HIGH**
severity. Can cause kernel oops/crash; potential info leak or further
memory corruption depending on heap layout. ASAN-confirmed.
### Step 8.4: Risk-Benefit
**Record:**
- **Benefit:** HIGH — closes a confirmed memory-safety hole in ACPI
interpreter.
- **Risk:** VERY LOW — 22 lines, single function, no API changes.
- **Ratio:** Strongly favors backport.
---
## PHASE 9: FINAL SYNTHESIS
### Step 9.1: Evidence Summary
**FOR backport:**
- Confirmed heap-buffer-overflow with ASAN reproducer (ACPICA #1144)
- Bug exists in v6.18.44 tree (verified in source)
- Small, surgical, obviously correct fix
- Applies cleanly to 6.18.y
- Maintainer-merged on mainline
- Memory-safety issue in core ACPI interpreter path
- Self-contained (no series dependencies)
**AGAINST backport:**
- Trigger requires crafted/short OEM strings in `LoadTable` AML — rare
in legitimate firmware
- Not directly exploitable by unprivileged users (requires root or
malicious firmware)
- `dsopcode.c` data-table-region path has similar unfixed pattern (out
of scope)
**Unresolved:**
- No explicit `Cc: stable` or reviewer stable nomination found
- Full lore thread review limited to b4-saved mbox (no replies captured)
### Step 9.2: Stable Rules Checklist
1. Obviously correct and tested? **PASS** — ASAN reproducer upstream;
logic is straightforward.
2. Fixes a real bug affecting users? **PASS** — confirmed heap-buffer-
overflow.
3. Important issue? **PASS** — memory-safety / potential crash (HIGH).
4. Small and contained? **PASS** — 1 file, ~22 lines.
5. No new features or APIs? **PASS** — validation/copy only.
6. Can apply to local tree? **PASS** — cherry-pick applies cleanly to
v6.18.44.
### Step 9.3: Exception Categories
**Record:** N/A (not a device ID, quirk, DT, build, or docs fix —
standard bug fix).
### Step 9.4: Decision Rationale
This commit fixes a real, ASAN-confirmed heap-buffer-overflow in the
ACPI `LoadTable` opcode handler. The vulnerable code is present in Linux
6.18.y and has been since the function was introduced.
`acpi_tb_find_table()` unconditionally reads 6/8 bytes from OEM string
pointers, but AML string objects may be allocated with fewer bytes. The
fix validates lengths using the AML `.length` field and copies into
properly sized, null-terminated stack buffers before calling
`acpi_tb_find_table()`.
For 6.18.y stable users, this is exactly the kind of memory-safety fix
that belongs in -stable: small, contained, obviously correct, and
preventing a confirmed kernel memory corruption path during ACPI table
operations.
---
## Verification
- [Phase 1] Parsed subject, tags, body; identified buffer overflow fix
intent
- [Phase 1] GitHub ACPICA issue #1144: ASAN heap-buffer-overflow,
reproducer confirmed
- [Phase 2] Read diff: +24/-2 in `exconfig.c`, adds validation + safe
copy
- [Phase 2] Read `tbfind.c:51-61`: `strlen` upper-bound check + fixed-
size `memcpy` confirms over-read mechanism
- [Phase 2] Read `utobject.c:256-274`: string allocation is `string_size
+ 1` bytes
- [Phase 3] `git describe HEAD`: v6.18.44 (6.18.y stable)
- [Phase 3] `git blame exconfig.c:108-110`: vulnerable call since 2005
(4be44fcd3bf648)
- [Phase 3] `git show 9f41fd8a175ff`: 2015 commit removed length
validation from `acpi_ex_load_table_op`, did not fix short-string
over-read
- [Phase 3] `git log --grep="Enhance OEM"` on 6.18.y: no results (fix
absent)
- [Phase 3] `git show 485829e6999b7`: mainline commit confirmed
- [Phase 3] `git cherry-pick --no-commit 485829e6999b7`: applies cleanly
(exit 0)
- [Phase 4] `b4 dig -c 485829e6999b7`: lore URL found
- [Phase 4] `b4 dig -a`: v1 series only, patch 22/27
- [Phase 4] `b4 dig -w`: Rafael Wysocki, linux-acpi, Intel developers
CC'd
- [Phase 4] `b4 dig -m /tmp/acpica_thread.mbox`: thread saved; no
stable/NAK mentions
- [Phase 5] `grep acpi_ex_load_table_op`: caller in `exoparg6.c:272`
(`AML_LOAD_TABLE_OP`)
- [Phase 5] `grep acpi_load_table`: reachable via `acpi_configfs.c`,
`bus.c`
- [Phase 6] Read current `exconfig.c:108-110`: buggy code confirmed
present
- [Phase 6] Cherry-pick test: clean apply to v6.18.44
- [Phase 8] Failure mode: heap-buffer-overflow, severity HIGH
**YES**The background searches finished and match the earlier analysis:
- **Fix search:** No “Enhance OEM ID” commit on **6.18.y** — the fix is
only on mainline (`485829e6999b7`).
- **Author search:** **ikaros** has other kernel commits here, but not
this ACPI validation patch.
**Verdict for 6.18.y:** **YES** — backport the heap-buffer-overflow fix
in `acpi_ex_load_table_op()`; it applies cleanly.
drivers/acpi/acpica/exconfig.c | 26 ++++++++++++++++++++++++--
1 file changed, 24 insertions(+), 2 deletions(-)
diff --git a/drivers/acpi/acpica/exconfig.c b/drivers/acpi/acpica/exconfig.c
index 4d7dd0fc6b07b..894695db0cf94 100644
--- a/drivers/acpi/acpica/exconfig.c
+++ b/drivers/acpi/acpica/exconfig.c
@@ -90,6 +90,8 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state,
union acpi_operand_object *return_obj;
union acpi_operand_object *ddb_handle;
u32 table_index;
+ char oem_id[ACPI_OEM_ID_SIZE + 1];
+ char oem_table_id[ACPI_OEM_TABLE_ID_SIZE + 1];
ACPI_FUNCTION_TRACE(ex_load_table_op);
@@ -102,12 +104,32 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state,
*return_desc = return_obj;
+ /*
+ * Validate OEM ID and OEM Table ID string lengths.
+ * acpi_tb_find_table expects strings that can safely read
+ * ACPI_OEM_ID_SIZE and ACPI_OEM_TABLE_ID_SIZE bytes.
+ */
+ if ((operand[1]->string.length > ACPI_OEM_ID_SIZE) ||
+ (operand[2]->string.length > ACPI_OEM_TABLE_ID_SIZE)) {
+ return_ACPI_STATUS(AE_AML_STRING_LIMIT);
+ }
+
+ /*
+ * Copy OEM strings to local buffers with guaranteed null-termination.
+ * This prevents heap-buffer-overflow when acpi_tb_find_table reads
+ * ACPI_OEM_ID_SIZE/ACPI_OEM_TABLE_ID_SIZE bytes.
+ */
+ memcpy(oem_id, operand[1]->string.pointer, operand[1]->string.length);
+ oem_id[operand[1]->string.length] = 0;
+ memcpy(oem_table_id, operand[2]->string.pointer,
+ operand[2]->string.length);
+ oem_table_id[operand[2]->string.length] = 0;
+
/* Find the ACPI table in the RSDT/XSDT */
acpi_ex_exit_interpreter();
status = acpi_tb_find_table(operand[0]->string.pointer,
- operand[1]->string.pointer,
- operand[2]->string.pointer, &table_index);
+ oem_id, oem_table_id, &table_index);
acpi_ex_enter_interpreter();
if (ACPI_FAILURE(status)) {
if (status != AE_NOT_FOUND) {
--
2.53.0
^ permalink raw reply related [flat|nested] 26+ messages in thread* [PATCH AUTOSEL 6.18-5.10] ACPICA: Add validation for node in acpi_ns_build_normalized_path()
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (18 preceding siblings ...)
2026-08-31 13:28 ` [PATCH AUTOSEL 6.18-6.1] ACPICA: Enhance OEM ID and Table ID validation in acpi_ex_load_table_op() Sasha Levin
@ 2026-08-31 13:28 ` Sasha Levin
2026-08-31 13:29 ` [PATCH AUTOSEL 6.18-5.10] ACPICA: add boundary checks in acpi_ps_get_next_field() Sasha Levin
` (3 subsequent siblings)
23 siblings, 0 replies; 26+ messages in thread
From: Sasha Levin @ 2026-08-31 13:28 UTC (permalink / raw)
To: patches, stable
Cc: ikaros, Rafael J. Wysocki, Sasha Levin, rafael,
maciej.wieczor-retman, pawel.chmielewski, linux-acpi,
acpica-devel, linux-kernel
From: ikaros <void0red@gmail.com>
[ Upstream commit 96b2b616870e46e2bc04efec03879683a0036e66 ]
Add validation for node in acpi_ns_build_normalized_path()
to prevent use-after-free vulnerabilities.
Link: https://github.com/acpica/acpica/commit/b35adf49e89a
Signed-off-by: ikaros <void0red@gmail.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Link: https://patch.msgid.link/118666237.nniJfEyVGO@rafael.j.wysocki
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
## Phase 1: Commit Message Forensics
**Step 1.1 — Subject line**
Record: `[ACPICA] [Add] validation for node in
acpi_ns_build_normalized_path() to prevent use-after-free`
**Step 1.2 — Tags**
Record:
- Link: https://github.com/acpica/acpica/commit/b35adf49e89a
- Link: https://patch.msgid.link/118666237.nniJfEyVGO@rafael.j.wysocki
- Signed-off-by: ikaros \<void0red@gmail.com\>
- Signed-off-by: Rafael J. Wysocki \<rafael.j.wysocki@intel.com\>
- No Fixes:, Reported-by:, Tested-by:, Reviewed-by:, or Cc: stable tags
- Notable: ACPICA maintainer (Rafael J. Wysocki) signed off; upstream
ACPICA commit link present
**Step 1.3 — Body analysis**
Record:
- Bug: `acpi_ns_build_normalized_path()` can dereference an
invalid/freed namespace node pointer
- Symptom: heap use-after-free when reading `next_node->name`
- Root cause (from upstream issue #1138): during ACPI AML
parsing/cleanup, walk state is freed while a stale `method_node` is
still passed into pathname building via `acpi_ex_stop_trace_method()`
→ `acpi_ns_get_normalized_pathname()` →
`acpi_ns_build_normalized_path()`
- No kernel version range stated in commit message
**Step 1.4 — Hidden bug fix?**
Record: No — explicitly described as UAF prevention, not disguised
cleanup.
---
## Phase 2: Diff Analysis
**Step 2.1 — Inventory**
Record:
- `drivers/acpi/acpica/nsnames.c`: +6 lines, 0 removed
- Function modified: `acpi_ns_build_normalized_path()`
- Scope: single-file, surgical fix
**Step 2.2 — Code flow change**
Record:
- Before: after NULL check on `node`, function immediately walks
`next_node->parent` chain and reads `next_node->name` via
`ACPI_MOVE_32_TO_32`
- After: if `ACPI_GET_DESCRIPTOR_TYPE(node) != ACPI_DESC_TYPE_NAMED`,
jump to `build_trailing_null` (return empty path with trailing NUL)
instead of dereferencing
- Affected path: any caller passing a stale/invalid node into
`acpi_ns_build_normalized_path()`
**Step 2.3 — Bug mechanism**
Record:
- Category: **memory safety / use-after-free**
- Mechanism: freed walk-state memory is still referenced as a namespace
node; reading `next_node->name` at the line equivalent to current line
232 triggers ASAN heap-use-after-free (confirmed upstream in ACPICA
issue #1138)
**Step 2.4 — Fix quality**
Record:
- Obviously correct: matches existing ACPICA validation pattern used in
`acpi_ns_get_pathname_length()` (lines 56–63 of the same file),
`acpi_ns_validate_handle()`, and `acpi_ut_get_node_name()`
- Minimal, no unrelated changes
- Regression risk: very low — invalid nodes get empty path instead of
crash; valid nodes unchanged
---
## Phase 3: Git History Investigation
**Step 3.1 — Blame**
Record: vulnerable loop introduced in `d1e7ffe50ba58` (2015, "ACPICA:
Namespace: Add function to directly return normalized full path"). Bug
has been present since that function was added.
**Step 3.2 — Fixes: tag**
Record: N/A — no Fixes: tag in commit message.
**Step 3.3 — File history**
Record: `nsnames.c` is long-stable ACPI code; recent changes are
formatting/copyright, not structural refactors. Fix is standalone (not
dependent on other patches in the 27-patch ACPICA series).
**Step 3.4 — Author**
Record: ikaros (void0red) reported the UAF to upstream ACPICA; Rafael J.
Wysocki (ACPI maintainer) committed to Linux.
**Step 3.5 — Dependencies**
Record: no prerequisites. Patch 12/27 in the same series fixes a related
UAF in `acpi_ds_terminate_control_method()`, but this validation patch
is independent and self-contained. `git apply --check` confirms clean
apply to this tree.
---
## Phase 4: Mailing List and External Research
**Step 4.1 — Original discussion**
Record:
- b4 dig found: [PATCH v1 19/27] at
https://patch.msgid.link/118666237.nniJfEyVGO@rafael.j.wysocki
- Part of "ACPI: ACPICA 20260408" series (27 patches)
- v1 only revision found
- No NAKs or stable nominations found in thread mbox
**Step 4.2 — Reviewers**
Record: CC'd to Rafael J. Wysocki, linux-acpi, LKML, Saket Dumbre, Pawel
Chmielewski (Intel ACPICA developers).
**Step 4.3 — Bug report**
Record: ACPICA GitHub issue #1138 documents:
- ASAN heap-use-after-free at `AcpiNsBuildNormalizedPath` reading 4
bytes (`next_node->name`)
- Reproducer: `./generate/unix/bin/acpiexec -m issue33.aml`
- Call chain: `acpi_ns_build_normalized_path` ←
`acpi_ns_get_normalized_pathname` ← `acpi_ex_stop_trace_method` ←
`acpi_ds_terminate_control_method` ← AML parse/table load path
- Severity: confirmed memory safety bug with concrete reproducer
**Step 4.4 — Related patches**
Record: patch 12/27 addresses a different UAF root cause in
`acpi_ds_terminate_control_method()`. Patch 19/27 (this commit) is a
defensive guard at the common pathname builder. Both are security-
relevant; this one stands alone.
**Step 4.5 — Stable list**
Record: no Cc: stable discussion found in downloaded thread.
---
## Phase 5: Code Semantic Analysis
**Step 5.1 — Key functions**
Record: `acpi_ns_build_normalized_path()` (modified); callers include
`acpi_ns_get_pathname_length()`, `acpi_ns_handle_to_pathname()`,
`acpi_ns_get_normalized_pathname()`
**Step 5.2 — Callers**
Record: `acpi_ns_get_normalized_pathname()` is called from many ACPI
paths including:
- `acpi_ex_stop_trace_method()` in `extrace.c` (UAF trigger path)
- `acpi_ns_get_external_pathname()`, `nsparse.c`, `nsinit.c`,
`dsmethod.c`, `nseval.c`, `nssearch.c`
- Debugger-only paths (`db*.c`) — less relevant for production
**Step 5.3 — Callees**
Record: reads node descriptor type, walks parent chain, copies 4-byte
ACPI names; no allocation in the vulnerable section.
**Step 5.4 — Reachability**
Record:
- Call chain reaches ACPI table loading and method termination during
normal kernel ACPI operation (boot + runtime method execution)
- Trigger requires crafted/malformed ACPI AML that causes walk-state
teardown with stale node reference — demonstrated with `issue33.aml`
in acpiexec; same ACPICA code runs in the kernel
**Step 5.5 — Similar patterns**
Record: `acpi_ns_get_pathname_length()` already validates descriptor
type before calling `acpi_ns_build_normalized_path()`, but
`acpi_ns_get_normalized_pathname()` does not — creating the gap this
patch closes at the lowest common level.
---
## Phase 6: Cross-Reference Against Local Tree
**Step 6.1 — Buggy code in tree?**
Record: **YES**. Local tree is **Linux 6.18.44** (`git describe HEAD` →
`v6.18.44`). Vulnerable code is present at lines 221–244 of
`drivers/acpi/acpica/nsnames.c` without the descriptor-type check. Fix
commit `96b2b616870e4` is **not** an ancestor of HEAD.
**Step 6.2 — Backport complications**
Record: clean apply confirmed (`git apply --check` → CLEAN APPLY). No
rework needed.
**Step 6.3 — Related fixes already present?**
Record: no — `git log -S "Validate the Node to avoid use-after-free"`
finds nothing in this tree; related patch 12/27
(`acpi_ds_terminate_control_method` UAF fix) also absent.
---
## Phase 7: Subsystem and Maintainer Context
**Step 7.1 — Subsystem criticality**
Record: **ACPI/ACPICA** — IMPORTANT to CORE. ACPI is on every x86/ARM
server, laptop, and most embedded systems with firmware tables.
**Step 7.2 — Activity**
Record: ACPI subsystem actively maintained in this tree (recent NULL-
deref and execution-abort fixes in `drivers/acpi/acpica/`).
---
## Phase 8: Impact and Risk Assessment
**Step 8.1 — Who is affected**
Record: all systems using in-kernel ACPICA for ACPI table parsing and
AML method execution.
**Step 8.2 — Trigger conditions**
Record: malformed/crafted ACPI AML during table load or method
termination with tracing enabled path; demonstrated with acpiexec +
crafted AML. Requires specific ACPI content, but ACPI tables are
firmware-supplied and occasionally attacker-influenced (e.g., custom
DSDT injection in some environments).
**Step 8.3 — Failure mode severity**
Record: **heap use-after-free** → kernel oops/panic or potential
information disclosure/exploitation primitive. Severity: **HIGH**.
**Step 8.4 — Risk-benefit**
Record:
- Benefit: **HIGH** — prevents real UAF on ACPI parsing path
- Risk: **VERY LOW** — 6-line defensive check, established ACPICA
pattern
- Ratio: strongly favors backport
---
## Phase 9: Final Synthesis
**Step 9.1 — Evidence summary**
FOR backport:
- Confirmed heap UAF with ASAN report and reproducer (ACPICA #1138)
- Affects ACPI table/method execution — common kernel path
- Small, surgical, obviously correct fix
- Matches existing validation patterns in same subsystem
- Applies cleanly to Linux 6.18.44
- Signed off by ACPI maintainer
- Bug present since 2015 — long exposure window
AGAINST backport:
- Part of larger ACPICA import series (but this patch is standalone)
- No explicit stable nomination in mailing list
- Related root-cause fix exists separately in patch 12/27 (but this
defensive fix has independent value)
UNRESOLVED: none material to the decision.
**Step 9.2 — Stable rules checklist**
1. Obviously correct and tested? **PASS** — ASAN-verified bug, standard
ACPICA validation pattern
2. Fixes a real bug? **PASS** — confirmed heap UAF
3. Important issue? **PASS** — memory safety during ACPI parsing
(crash/security)
4. Small and contained? **PASS** — 6 lines, one function
5. No new features/APIs? **PASS** — defensive validation only
6. Can apply to local tree? **PASS** — clean apply verified
**Step 9.3 — Exception category**
Record: N/A (security/memory-safety bug fix, not a quirk/ID/DT
exception).
**Step 9.4 — Decision rationale**
For **Linux 6.18.44**, this commit should be backported. The vulnerable
`acpi_ns_build_normalized_path()` code exists in this tree, the fix is
absent, and upstream has demonstrated a reproducible heap use-after-free
on the ACPI AML parsing/teardown path that the kernel shares. The fix is
minimal, follows established ACPICA conventions already used in sibling
functions in the same file, and prevents dereferencing freed namespace
nodes by validating the descriptor type before walking the parent chain.
---
## Verification
- [Phase 1] Parsed commit message and tags from `git show 96b2b616870e4`
- [Phase 1] Fetched ACPICA upstream issue #1138 — ASAN UAF confirmed
with stack trace and reproducer
- [Phase 2] Diff analysis: +6 lines adding `ACPI_GET_DESCRIPTOR_TYPE`
check before node walk
- [Phase 2] Read current `nsnames.c` lines 193–270 in tree — vulnerable
code confirmed present
- [Phase 3] `git blame -L 221,245`: buggy loop from `d1e7ffe50ba58`
(2015)
- [Phase 3] `git merge-base --is-ancestor 96b2b616870e4 HEAD` → FIX NOT
IN TREE
- [Phase 3] `git apply --check` on patch → CLEAN APPLY
- [Phase 4] `b4 dig -c 96b2b616870e4` → lore URL found; patch 19/27 of
ACPICA series
- [Phase 4] `b4 dig -w` → Rafael Wysocki, linux-acpi, LKML CC'd
- [Phase 4] Downloaded mbox; grep found no Cc: stable; found related
patch 12/27
- [Phase 5] `grep acpi_ns_get_normalized_pathname` — multiple kernel
callers including `extrace.c:284`
- [Phase 5] Read `extrace.c` `acpi_ex_stop_trace_method()` and
`dsmethod.c:850` call site
- [Phase 5] Confirmed `acpi_ns_get_pathname_length()` already validates
at line 58; `acpi_ns_get_normalized_pathname()` does not
- [Phase 6] `git describe HEAD` → v6.18.44
- [Phase 6] Confirmed validation check absent in current `nsnames.c`
- [Phase 7] `git log --oneline -20 -- drivers/acpi/acpica/` — active
subsystem
- [Phase 8] UAF severity assessed from ASAN report in issue #1138
**YES**The analysis is complete for **ACPICA: Add validation for node in
acpi_ns_build_normalized_path()** on **Linux 6.18.44**.
**Summary:** This is a small (6-line) fix for a confirmed heap use-
after-free in ACPI pathname building. The vulnerable code is present in
this tree; the fix is not. It applies cleanly and follows existing
ACPICA validation patterns. Upstream demonstrated the bug with ASAN on
the ACPI AML parse/teardown path (`acpi_ex_stop_trace_method` →
`acpi_ns_get_normalized_pathname` → `acpi_ns_build_normalized_path`).
**Verdict for this tree: YES** — worth backporting as a memory-safety
fix on a common ACPI path.
drivers/acpi/acpica/nsnames.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/acpi/acpica/nsnames.c b/drivers/acpi/acpica/nsnames.c
index 22aeeeb56cffd..19802da865c54 100644
--- a/drivers/acpi/acpica/nsnames.c
+++ b/drivers/acpi/acpica/nsnames.c
@@ -222,6 +222,12 @@ acpi_ns_build_normalized_path(struct acpi_namespace_node *node,
goto build_trailing_null;
}
+ /* Validate the Node to avoid use-after-free vulnerabilities */
+
+ if (ACPI_GET_DESCRIPTOR_TYPE(node) != ACPI_DESC_TYPE_NAMED) {
+ goto build_trailing_null;
+ }
+
next_node = node;
while (next_node && next_node != acpi_gbl_root_node) {
if (next_node != node) {
--
2.53.0
^ permalink raw reply related [flat|nested] 26+ messages in thread* [PATCH AUTOSEL 6.18-5.10] ACPICA: add boundary checks in acpi_ps_get_next_field()
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (19 preceding siblings ...)
2026-08-31 13:28 ` [PATCH AUTOSEL 6.18-5.10] ACPICA: Add validation for node in acpi_ns_build_normalized_path() Sasha Levin
@ 2026-08-31 13:29 ` Sasha Levin
2026-08-31 13:30 ` [PATCH AUTOSEL 6.18] ceph: convert inode flags to named bit positions and atomic bitops Sasha Levin
` (2 subsequent siblings)
23 siblings, 0 replies; 26+ messages in thread
From: Sasha Levin @ 2026-08-31 13:29 UTC (permalink / raw)
To: patches, stable
Cc: ikaros, Rafael J. Wysocki, Sasha Levin, rafael,
maciej.wieczor-retman, pawel.chmielewski, linux-acpi,
acpica-devel, linux-kernel
From: ikaros <void0red@gmail.com>
[ Upstream commit e15aa60de0256d63df2331bf5a4bc4dd287504cd ]
Add boundary checks in acpi_ps_get_next_field() to prevent out-of-bounds
access.
Link: https://github.com/acpica/acpica/commit/c39183ea84bc
Signed-off-by: ikaros <void0red@gmail.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Link: https://patch.msgid.link/24388159.6Emhk5qWAg@rafael.j.wysocki
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
# Stable Backport Analysis: ACPICA boundary checks in
`acpi_ps_get_next_field()`
## Phase 1: Commit Message Forensics
### Step 1.1: Subject Line
**Record:** `[ACPICA] [add] boundary checks in acpi_ps_get_next_field()
to prevent out-of-bounds access`
### Step 1.2: Commit Message Tags
**Record:**
- **Link:** https://github.com/acpica/acpica/commit/c39183ea84bc
(upstream ACPICA commit)
- **Signed-off-by:** ikaros <void0red@gmail.com> (author)
- **Signed-off-by:** Rafael J. Wysocki <rafael.j.wysocki@intel.com>
(ACPI maintainer)
- **Link:**
https://patch.msgid.link/24388159.6Emhk5qWAg@rafael.j.wysocki (Linux
integration patch reference)
- No `Fixes:`, `Reported-by:`, `Cc: stable@vger.kernel.org`, `Tested-
by:`, or `Reviewed-by:` tags
- Notable: upstream ACPICA issue **#1125** with ASAN heap-buffer-
overflow report and reproducible `acpiexec` test case
### Step 1.3: Commit Body Analysis
**Record:**
- **Bug:** `acpi_ps_get_next_field()` reads AML bytes without verifying
they remain within the AML buffer (`aml_end`)
- **Symptom:** Heap-buffer-overflow (ASAN) when parsing
malformed/truncated ACPI AML field lists
- **Root cause:** Reads of 1, 2, and 4 bytes proceed without checking
`parser_state->aml_end`; caller loop uses `pkg_end`, which can extend
past `aml_end` on corrupt package-length encoding
- **Version info:** None in commit message; bug exists in long-standing
code (function dates to 2005)
### Step 1.4: Hidden Bug Fix Detection
**Record:** Not disguised — explicitly a defensive boundary-check fix
for out-of-bounds memory access. This is a real memory-safety bug fix,
not cleanup.
---
## Phase 2: Diff Analysis
### Step 2.1: Change Inventory
**Record:**
- **File:** `drivers/acpi/acpica/psargs.c` (+20 / -0)
- **Function:** `acpi_ps_get_next_field()` only
- **Scope:** Single-file, surgical fix
### Step 2.2: Code Flow Changes
**Record:**
1. **Entry check:** Before any AML read, if `aml >=
parser_state->aml_end`, return NULL
2. **Named field path:** Before 4-byte name read (`ACPI_MOVE_32_TO_32`),
verify `aml + ACPI_NAMESEG_SIZE <= aml_end`; free allocated op on
failure
3. **Access field path:** Before reading 2 bytes (type/attribute),
verify `aml + 2 <= aml_end`; free op on failure
4. **Extended access field:** Before reading third byte
(`access_length`), verify `aml < aml_end`; free op on failure
**Before → After:** Unbounded AML pointer advancement → bounded reads
with graceful NULL return and proper `acpi_ps_free_op()` cleanup on
post-allocation failures.
### Step 2.3: Bug Mechanism
**Record:**
- **Category:** Buffer overflow / out-of-bounds read (memory safety)
- **Mechanism:** On truncated or malformed AML,
`acpi_ps_get_next_field()` advances `parser_state->aml` and reads past
the end of the AML buffer. ASAN report confirms a 4-byte read past a
175-byte heap allocation at the named-field path.
### Step 2.4: Fix Quality
**Record:**
- Fix is minimal, follows existing `aml_end` semantics used elsewhere in
ACPICA
- Properly frees `field` on error paths after `acpi_ps_alloc_op()`
succeeds
- Does not cover every read in the function (e.g.,
`AML_INT_CONNECTION_OP` sub-paths,
`acpi_ps_get_next_package_length()`), but addresses the ASAN-confirmed
overflow sites
- Low regression risk; only adds early-exit guards on malformed input
---
## Phase 3: Git History Investigation
### Step 3.1: Blame
**Record:** Core `acpi_ps_get_next_field()` logic introduced in 2005
(`^1da177e4c3f4`). Buggy unbounded-read pattern has been present since
initial implementation. `parser_state->aml_end` field added long ago and
is set in `dswstate.c`.
### Step 3.2: Fixes: Tag
**Record:** N/A — no `Fixes:` tag in commit message.
### Step 3.3: Related File History
**Record:** Related recent fix in this tree:
- `e6169a8ffee8a` — "ACPICA: Fix memory leak if acpi_ps_get_next_field()
fails" (April 2024)
- Ensures caller frees partial field list when
`acpi_ps_get_next_field()` returns NULL
- Complements this fix: boundary failure returns NULL, and caller
already handles that path
### Step 3.4: Author Context
**Record:** Author ikaros reported the bug via ACPICA GitHub issue
#1125. Patch integrated by Rafael J. Wysocki (ACPI subsystem
maintainer). No other commits from this author in the Linux ACPICA tree.
### Step 3.5: Dependencies
**Record:**
- Requires `parser_state->aml_end` in `struct acpi_parse_state` —
**present** in this tree (`aclocal.h:912`)
- Requires `ACPI_NAMESEG_SIZE` — **present** (used at line 527)
- Requires `acpi_ps_free_op()` — **present**
- Standalone; no patch-series dependency
- **This commit is NOT yet in the local tree** (6.18.44); boundary
checks absent from current `psargs.c`
---
## Phase 4: Mailing List and External Research
### Step 4.1: Original Discussion
**Record:**
- `b4 dig -c c39183ea84bc` — no match (hash is from upstream ACPICA
repo, not Linux kernel)
- ACPICA GitHub issue #1125: detailed ASAN report, reproduction with
`acpiexec -m issue10.aml`, fixed by commit c39183ea84bc
- lore.kernel.org — blocked by bot protection; could not fetch thread
### Step 4.2: Reviewers
**Record:** Rafael J. Wysocki signed off on Linux integration (per
commit message). Full lore review thread unverified due to access block.
### Step 4.3: Bug Report
**Record:**
- **Severity:** Heap-buffer-overflow (ASAN), READ of 4 bytes past
allocation boundary
- **Reproducible:** Yes, with crafted AML via `acpiexec`
- **Stack trace:** `AcpiPsGetNextField` → `AcpiPsGetNextArg` →
`AcpiPsGetArguments` → `AcpiPsParseLoop` → `AcpiPsParseAml` → table
load path
### Step 4.4: Related Patches
**Record:** Standalone fix. Related but separate: memory-leak fix
`e6169a8ffee8a` already in this tree.
### Step 4.5: Stable List Discussion
**Record:** Could not verify stable-list discussion (lore blocked).
Absence of prior stable nomination is not a negative signal per review
guidelines.
---
## Phase 5: Code Semantic Analysis
### Step 5.1: Key Functions
**Record:** `acpi_ps_get_next_field()` (modified), called from
`acpi_ps_get_next_arg()` for `ARGP_FIELDLIST`.
### Step 5.2: Callers
**Record:**
- `acpi_ps_get_next_arg()` — `psargs.c:787`, in `ARGP_FIELDLIST` case
- Called from `acpi_ps_get_arguments()` in `psloop.c`
- Reached during ACPI AML parsing: `acpi_ps_execute_table()` →
`acpi_ns_parse_table()` → `acpi_ns_load_table()`
- **Context:** ACPI table load at boot (DSDT/SSDT) and dynamic table
load paths
### Step 5.3: Callees
**Record:** `ACPI_GET8()`, `ACPI_MOVE_32_TO_32()`, `acpi_ps_alloc_op()`,
`acpi_ps_free_op()`, `acpi_ps_get_next_package_length()`,
`acpi_ps_get_next_namestring()`
### Step 5.4: Reachability
**Record:**
- Triggered when kernel parses ACPI AML containing malformed field lists
- ACPI tables come from firmware at boot on virtually all x86/ARM
systems with ACPI
- Additional paths: `CONFIG_ACPI_TABLE_UPGRADE`, initrd ACPI override
(`tables.c`), configfs (`acpi_configfs.c`) — root/privileged, but
firmware-supplied tables are the primary real-world vector
- **Userspace trigger:** Indirect — via firmware/BIOS ACPI tables, not
direct syscall; still kernel memory safety issue
### Step 5.5: Similar Patterns
**Record:** `aml_end` used as bound in `psloop.c:300`, `dswexec.c:745`,
but **not** in `acpi_ps_get_next_field()` in this tree — this is a gap
the fix addresses.
---
## Phase 6: Cross-Reference Against Local Tree (6.18.44)
### Step 6.1: Buggy Code Present?
**Record:** **YES.** Current `psargs.c` at lines 474–586 performs
unbounded reads in `acpi_ps_get_next_field()` with no `aml_end` checks.
`aml_end` field exists and is initialized in `dswstate.c:580–585`.
### Step 6.2: Backport Complications
**Record:** `git apply --check` on the provided diff — **applies
cleanly** to this tree. No conflicts expected.
### Step 6.3: Related Fixes Already Present?
**Record:** Memory-leak companion fix `e6169a8ffee8a` is present.
Boundary-check fix is **not** present.
---
## Phase 7: Subsystem Context
### Step 7.1: Subsystem Criticality
**Record:** **drivers/acpi/acpica** — ACPI core parser. **Criticality:
CORE/IMPORTANT** — affects all ACPI-enabled systems during table
parsing.
### Step 7.2: Subsystem Activity
**Record:** ACPICA receives periodic syncs from upstream; active
maintenance by Rafael Wysocki's team. Recent related fix (memory leak)
landed in 2024.
---
## Phase 8: Impact and Risk Assessment
### Step 8.1: Who Is Affected
**Record:** All systems using ACPI (majority of PCs, servers, many ARM
boards) when loading ACPI tables with malformed field-list AML.
### Step 8.2: Trigger Conditions
**Record:**
- Malformed/truncated ACPI DSDT/SSDT field definitions
- Most likely: buggy firmware ACPI tables; also crafted tables via
override mechanisms
- Not every boot — requires specific AML corruption in field lists
- Unprivileged direct trigger unlikely; firmware is primary vector
### Step 8.3: Failure Mode Severity
**Record:**
- **Failure mode:** Out-of-bounds heap read during ACPI AML parsing
- **Severity: HIGH** — memory safety violation; potential info leak or
crash during boot/table load; ASAN-confirmed
### Step 8.4: Risk-Benefit
**Record:**
- **Benefit: HIGH** — prevents OOB read in widely-used ACPI parser
- **Risk: LOW** — 20-line additive guards, only affects malformed-input
paths
- **Ratio:** Strongly favors backport
---
## Phase 9: Final Synthesis
### Step 9.1: Evidence Summary
**FOR backport:**
- Real, ASAN-confirmed heap-buffer-overflow
- Fixes memory safety bug in ACPI core parser used at boot
- Small (+20 lines), single file, applies cleanly
- Signed off by ACPI maintainer (Rafael Wysocki)
- Complements existing memory-leak fix already in tree
- `aml_end` infrastructure already present — no structural dependency
**AGAINST backport:**
- Partial coverage (does not add bounds checks to all read paths in the
function, e.g., connection-op sub-path)
- Trigger primarily via firmware ACPI tables (not direct userspace
attack)
- NULL return on boundary failure reported as `AE_NO_MEMORY` by caller
(pre-existing semantic imprecision, not introduced by this patch)
**Unresolved:**
- Full lore.kernel.org review thread not accessible
- Whether Linux mainline has merged this yet (not in 6.18.44)
### Step 9.2: Stable Rules Checklist
1. Obviously correct and tested? **PASS** — straightforward bounds
checks; ASAN-tested upstream via acpiexec/issue #1125
2. Fixes a real bug? **PASS** — confirmed heap-buffer-overflow
3. Important issue? **PASS** — OOB read in kernel ACPI parser (HIGH
severity)
4. Small and contained? **PASS** — +20 lines, one function, one file
5. No new features/APIs? **PASS** — defensive checks only
6. Can apply to local tree? **PASS** — verified clean apply;
prerequisites present
### Step 9.3: Exception Category
**Record:** N/A — standard memory-safety bug fix, not a device-
ID/quirk/DT/build/doc exception.
### Step 9.4: Decision Rationale
This commit fixes a confirmed out-of-bounds heap read in the ACPI AML
field parser — a core subsystem path exercised during every ACPI table
load. The fix is minimal, uses existing `aml_end` bounds infrastructure,
applies cleanly to Linux 6.18.44, and is signed off by the ACPI
maintainer. While the primary trigger is malformed firmware ACPI tables
rather than direct userspace input, heap buffer overflows in kernel
parsers are exactly the class of fixes stable trees exist to deliver.
The companion memory-leak fix is already in this tree, making the NULL-
return error path safe.
---
## Verification
- **[Phase 1]** Parsed commit message and tags; confirmed ASAN report
via ACPICA GitHub issue #1125
- **[Phase 1]** Identified subsystem (ACPICA), action (add boundary
checks), bug type (OOB access)
- **[Phase 2]** Diff analysis: +20 lines in `acpi_ps_get_next_field()`,
4 boundary-check insertion points
- **[Phase 2]** Read current `psargs.c:457-686` — confirmed buggy code
without bounds checks
- **[Phase 3]** `git describe HEAD` → `v6.18.44`; `make kernelversion` →
`6.18.44`
- **[Phase 3]** `git blame` on lines 474–590: function code from 2005,
long-standing vulnerability
- **[Phase 3]** `git log --oneline -20 -- drivers/acpi/acpica/psargs.c`:
found related fix `e6169a8ffee8a`
- **[Phase 3]** `git show e6169a8ffee8a`: memory-leak fix on NULL return
from same function
- **[Phase 3]** `git log --grep="boundary checks in
acpi_ps_get_next_field"`: no match — fix not in tree
- **[Phase 4]** WebFetch ACPICA commit c39183ea84bc and issue #1125:
ASAN heap-buffer-overflow confirmed
- **[Phase 4]** `b4 dig -c c39183ea84bc`: no Linux kernel match (ACPICA-
only hash)
- **[Phase 4]** lore.kernel.org fetch: blocked (bot protection) — review
thread unverified
- **[Phase 5]** Grep callers: `acpi_ps_get_next_field` called from
`acpi_ps_get_next_arg()` at line 787
- **[Phase 5]** Traced load path: `acpi_ns_load_table` →
`acpi_ns_parse_table` → `acpi_ps_execute_table`
- **[Phase 5]** Read caller at `psargs.c:780-807`: NULL return handled
with field-list cleanup
- **[Phase 6]** Confirmed `struct acpi_parse_state` has `aml_end` at
`aclocal.h:912`
- **[Phase 6]** Confirmed `dswstate.c:580-585` initializes `aml_end`
from AML buffer length
- **[Phase 6]** `git apply --check` on provided diff: **clean apply**
- **[Phase 6]** Grep `aml >= parser_state->aml_end` in `psargs.c`: no
matches — fix absent
- **[Phase 8]** Assessed severity: heap OOB read during ACPI parse =
HIGH
**YES**The analysis is done: **backport recommended** for Linux
**6.18.44**.
The commit adds `aml_end` boundary checks in `acpi_ps_get_next_field()`
to stop out-of-bounds reads when parsing malformed ACPI AML. That’s a
real, ASAN-confirmed heap buffer overflow on the ACPI table load path,
the patch is small (+20 lines), applies cleanly here, and the needed
`aml_end` infrastructure is already in this tree.
**YES**
drivers/acpi/acpica/psargs.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/drivers/acpi/acpica/psargs.c b/drivers/acpi/acpica/psargs.c
index 6f6ae38ec044c..55273cbbfc67e 100644
--- a/drivers/acpi/acpica/psargs.c
+++ b/drivers/acpi/acpica/psargs.c
@@ -474,6 +474,10 @@ static union acpi_parse_object *acpi_ps_get_next_field(struct acpi_parse_state
ASL_CV_CAPTURE_COMMENTS_ONLY(parser_state);
aml = parser_state->aml;
+ if (aml >= parser_state->aml_end) {
+ return_PTR(NULL);
+ }
+
/* Determine field type */
switch (ACPI_GET8(parser_state->aml)) {
@@ -522,6 +526,11 @@ static union acpi_parse_object *acpi_ps_get_next_field(struct acpi_parse_state
/* Get the 4-character name */
+ if ((parser_state->aml + ACPI_NAMESEG_SIZE) >
+ parser_state->aml_end) {
+ acpi_ps_free_op(field);
+ return_PTR(NULL);
+ }
ACPI_MOVE_32_TO_32(&name, parser_state->aml);
acpi_ps_set_name(field, name);
parser_state->aml += ACPI_NAMESEG_SIZE;
@@ -567,6 +576,10 @@ static union acpi_parse_object *acpi_ps_get_next_field(struct acpi_parse_state
/* Get the two bytes (Type/Attribute) */
+ if ((parser_state->aml + 2) > parser_state->aml_end) {
+ acpi_ps_free_op(field);
+ return_PTR(NULL);
+ }
access_type = ACPI_GET8(parser_state->aml);
parser_state->aml++;
access_attribute = ACPI_GET8(parser_state->aml);
@@ -578,6 +591,10 @@ static union acpi_parse_object *acpi_ps_get_next_field(struct acpi_parse_state
/* This opcode has a third byte, access_length */
if (opcode == AML_INT_EXTACCESSFIELD_OP) {
+ if (parser_state->aml >= parser_state->aml_end) {
+ acpi_ps_free_op(field);
+ return_PTR(NULL);
+ }
access_length = ACPI_GET8(parser_state->aml);
parser_state->aml++;
--
2.53.0
^ permalink raw reply related [flat|nested] 26+ messages in thread* [PATCH AUTOSEL 6.18] ceph: convert inode flags to named bit positions and atomic bitops
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (20 preceding siblings ...)
2026-08-31 13:29 ` [PATCH AUTOSEL 6.18-5.10] ACPICA: add boundary checks in acpi_ps_get_next_field() Sasha Levin
@ 2026-08-31 13:30 ` Sasha Levin
2026-08-31 13:31 ` [PATCH AUTOSEL 6.18-5.15] firmware: google: Add bounds checks in coreboot_table_populate() Sasha Levin
2026-08-31 13:31 ` [PATCH AUTOSEL 6.18-5.10] ACPICA: Enhance buffer validation in acpi_ut_walk_aml_resources() Sasha Levin
23 siblings, 0 replies; 26+ messages in thread
From: Sasha Levin @ 2026-08-31 13:30 UTC (permalink / raw)
To: patches, stable
Cc: Alex Markuze, Viacheslav Dubeyko, Ilya Dryomov, Sasha Levin,
slava, ceph-devel, linux-kernel
From: Alex Markuze <amarkuze@redhat.com>
[ Upstream commit e120e2b666851c4c0c7bffd315ff69a09f9fe4ac ]
Define named bit-position constants for all CEPH_I_* inode flags and
derive the bitmask values from them. This gives every flag a named
_BIT constant usable with the test_bit/set_bit/clear_bit family.
The intentionally unused bit position 1 is documented inline.
Convert all flag modifications to use atomic bitops (set_bit,
clear_bit, test_and_clear_bit). The previous code mixed lockless
atomic ops on some flags (ERROR_WRITE, ODIRECT) with non-atomic
read-modify-write (|= / &= ~) on other flags sharing the same
unsigned long. A concurrent non-atomic RMW can clobber an
adjacent lockless atomic update -- for example, a lockless
clear_bit(ERROR_WRITE) could be silently resurrected by a
concurrent ci->i_ceph_flags |= CEPH_I_FLUSH under the spinlock.
Using atomic bitops for all modifications eliminates this class
of race entirely.
Flags whose only users are now the _BIT form (ERROR_WRITE,
ASYNC_CHECK_CAPS) have their old mask defines removed to document
that callers must use the _BIT constant with the set_bit/test_bit
family. ERROR_FILELOCK and SHUTDOWN retain their mask defines
because they are still used via bitmask tests in lockless readers
(ceph_inode_is_shutdown, reconnect_caps_cb).
The direct assignment in ceph_finish_async_create() is converted
from i_ceph_flags = CEPH_I_ASYNC_CREATE to set_bit(). This
inode is I_NEW at this point -- still invisible to other threads
and guaranteed to have zero flags from alloc_inode -- so either
form is safe, but set_bit() keeps the conversion uniform.
Signed-off-by: Alex Markuze <amarkuze@redhat.com>
Reviewed-by: Viacheslav Dubeyko <Slava.Dubeyko@ibm.com>
Signed-off-by: Viacheslav Dubeyko <Slava.Dubeyko@ibm.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
# Stable Backport Analysis: `ceph: convert inode flags to named bit
positions and atomic bitops`
**Local tree:** Linux **6.18.44** (`git describe HEAD` →
`v6.18.44-1-g2736c32da98b9`)
**Commit analyzed:** `e120e2b666851` (on `master`, **not** in this tree)
**Patch applies cleanly:** `git show e120e2b666851 | git apply --check`
→ success
---
## PHASE 1: COMMIT MESSAGE FORENSICS
### Step 1.1: Subject line
**Record:** `[ceph]` `[convert]` — Convert Ceph inode `i_ceph_flags` to
named `_BIT` constants and use atomic bitops for all flag modifications.
### Step 1.2: Tags
**Record:**
| Tag | Value |
|-----|-------|
| Signed-off-by | Alex Markuze, Viacheslav Dubeyko, Ilya Dryomov |
| Reviewed-by | Viacheslav Dubeyko |
| Fixes: | **Absent** (expected for manual review) |
| Reported-by: | **Absent** |
| Tested-by: | **Absent** in commit; series cover letter has `Tested-by:
Viacheslav Dubeyko` |
| Cc: stable | **Absent** |
| Link: | **Absent** |
No syzbot, no CVE, no explicit stable nomination in the commit.
### Step 1.3: Body analysis
**Record:**
- **Bug:** `i_ceph_flags` mixes atomic per-bit ops
(`set_bit`/`clear_bit`) with non-atomic word RMW (`|=` / `&= ~`) on
the same `unsigned long`.
- **Symptom:** Concurrent non-atomic RMW can clobber adjacent atomic bit
updates (example: `clear_bit(ERROR_WRITE)` resurrected by
`ci->i_ceph_flags |= CEPH_I_FLUSH`).
- **Root cause:** Inconsistent flag-update mechanism on a shared
bitfield.
- **Versions:** Not stated; prerequisite context is `fbeafe782bd98`
(ODIRECT atomic bitops), which **is** in 6.18.44.
### Step 1.4: Hidden bug fix?
**Record:** **Yes.** Described as a conversion, but it fixes a real
concurrency defect class (CWE-366 / lost-update on shared bitfield).
Also removes spinlocks from some hot paths (`ERROR_WRITE`,
`ERROR_FILELOCK`) only after making all flag updates atomic.
---
## PHASE 2: DIFF ANALYSIS
### Step 2.1: Inventory
**Record:**
| File | Change |
|------|--------|
| `fs/ceph/super.h` | Define `_BIT` constants; convert
`ceph_set/clear_error_write()` to lockless `set_bit`/`clear_bit` |
| `fs/ceph/caps.c` | 12 flag mutations → atomic bitops |
| `fs/ceph/addr.c` | Pool-perm flags → `set_bit`; re-read flags after
update |
| `fs/ceph/file.c` | `ASYNC_CREATE`/`ERROR_WRITE` → atomic; rename
`CEPH_ASYNC_CREATE_BIT` → `CEPH_I_ASYNC_CREATE_BIT` |
| `fs/ceph/locks.c` | Lockless `test_bit`/`clear_bit` for
`ERROR_FILELOCK` |
| `fs/ceph/inode.c`, `snap.c`, `xattr.c`, `mds_client.c/h` | Mechanical
conversions |
**Scope:** 10 files, +74/−82 lines. Multi-file but mechanical; not a
refactor for its own sake.
### Step 2.2: Code flow (key hunks)
**Record:**
- **Before:** `ci->i_ceph_flags |= CEPH_I_FLUSH` (load/OR/store) under
`cap_delay_lock`; `clear_bit(CEPH_I_ODIRECT_BIT, ...)` under
`i_ceph_lock` (since `fbeafe782bd98`).
- **After:** All modifications use
`set_bit`/`clear_bit`/`test_and_clear_bit`.
- **`ceph_set_error_write()`:** spinlock + `|=` → lockless `set_bit`.
- **`ceph_fl_release_lock()`:** spinlock + `&= ~` → lockless
`clear_bit`.
- **`ceph_pool_perm_check()`:** builds flag mask then `|=` → individual
`set_bit` calls; re-reads flags under lock before `goto check`.
### Step 2.3: Bug mechanism
**Record:** **Category:** Race condition / lost update on shared
bitfield.
**Mechanism:** Non-atomic word RMW is not composable with concurrent
atomic bitops on the same `unsigned long` unless all writers use atomic
bitops. A non-atomic `|=` can write back a stale word value and undo a
concurrent `clear_bit()` on a different bit.
### Step 2.4: Fix quality
**Record:** Fix is standard kernel practice for multi-bit `unsigned
long` fields. Minimal logic change; no API changes. Low regression risk;
slightly changes locking for `ERROR_WRITE`/`ERROR_FILELOCK`
(intentionally lockless, made safe by uniform atomic bitops).
---
## PHASE 3: GIT HISTORY
### Step 3.1: Blame
**Record:**
- `ceph_set/clear_error_write()`: Jeff Layton, 2017 (`26544c623e741a`) —
non-atomic RMW under `i_ceph_lock`.
- ODIRECT `clear_bit()`: `fbeafe782bd98` (Viacheslav Dubeyko, Jul 2025)
— **in 6.18.44**.
- ODIRECT flag itself: `321fe13c93987` (Jeff Layton, 2019) — xfstest
generic/451 data-coherency fix.
### Step 3.2: Fixes: tag
**Record:** N/A — no `Fixes:` tag. Bug partially introduced/worsened by
`fbeafe782bd98`, which converted ODIRECT to atomic bitops while other
flags remained non-atomic RMW.
### Step 3.3: Related history
**Record:**
- `fbeafe782bd98` — Coverity CWE-366 fix for ODIRECT; ancestor of HEAD.
- Commit is **v4 01/11** of “ceph: manual client session reset” series;
later patches add debugfs/tracepoints (not in 6.18.44).
- On `master`, 3 commits ahead of HEAD in `fs/ceph/super.h`; this is the
oldest of them.
### Step 3.4: Author context
**Record:** Alex Markuze (Red Hat ceph contributor). Reviewed/acked by
Viacheslav Dubeyko (IBM, authored ODIRECT race fix). Committed by Ilya
Dryomov (ceph maintainer).
### Step 3.5: Dependencies
**Record:** **Standalone for backport purposes.** Patch 1/11 of a larger
series, but only renames/converts existing flag handling. No new
structures or APIs. `git apply --check` passes on 6.18.44 HEAD.
---
## PHASE 4: MAILING LIST / EXTERNAL
### Step 4.1: Discussion
**Record:** `b4 dig -c e120e2b666851` →
https://patch.msgid.link/20260507122737.2804094-2-amarkuze@redhat.com
Series: v1 (RFC 1/4) → v2 (1/7) → v3 (01/11) → v4 (01/11, committed
version).
WebFetch of lore blocked by bot protection; thread retrieved via `b4 dig
-m`.
### Step 4.2: Reviewers
**Record:** CC'd: `ceph-devel@vger.kernel.org`, `idryomov@gmail.com`,
`vdubeyko@redhat.com`. Multiple `Reviewed-by: Viacheslav Dubeyko` across
series. `Tested-by: Viacheslav Dubeyko` on cover letter.
### Step 4.3: Bug reports
**Record:** No external bug report. Related: Coverity CID findings for
ODIRECT in `fbeafe782bd98`. No syzbot.
### Step 4.4: Series context
**Record:** Patch 1 enables atomic flag handling for the manual session-
reset series (patches 2–11). Patches 2–11 are new functionality and
would not accompany this backport; patch 1 is independently correct.
### Step 4.5: Stable list
**Record:** No `Cc: stable` found in mbox thread grep. No stable-list
discussion found.
---
## PHASE 5: CODE SEMANTIC ANALYSIS
### Step 5.1: Key functions
**Record:** `ceph_set/clear_error_write()`,
`__cap_delay_requeue_front()`, `__prep_cap()`, `ceph_check_caps()`,
`ceph_block_o_direct()`, `ceph_block_buffered()`,
`ceph_pool_perm_check()`, `wake_async_create_waiters()`,
`ceph_fl_release_lock()`, `ceph_inode_shutdown()`.
### Step 5.2: Callers
**Record:**
- `ceph_start_io_direct()` / `ceph_start_io_read()` — from `file.c`
read/write paths (common I/O).
- `__cap_delay_requeue_front()` — from `ceph_write_inode()` (sync/fsync
path).
- `ceph_set/clear_error_write()` — from `file.c`, `addr.c` on I/O
errors.
- `ceph_check_caps()` — cap management hot path.
- `ceph_fl_release_lock()` — file lock release.
### Step 5.3: Callees
**Record:** `set_bit`, `clear_bit`, `test_bit`, `test_and_clear_bit`,
`clear_and_wake_up_bit`, spinlocks (`i_ceph_lock`, `cap_delay_lock`).
### Step 5.4: Reachability
**Record:** All paths reachable from normal CephFS mount activity — file
I/O, cap flush, pool permission checks, file locking. Triggerable by
unprivileged users with access to mounted Ceph filesystem.
### Step 5.5: Similar patterns
**Record:** `fbeafe782bd98` already uses atomic bitops for ODIRECT only.
`clear_and_wake_up_bit(CEPH_ASYNC_CREATE_BIT, ...)` already uses atomic
ops for async-create. This commit unifies the pattern across all flags.
---
## PHASE 6: CROSS-REFERENCE WITH LOCAL TREE (6.18.44)
### Step 6.1: Buggy code present?
**Record:** **Yes.** Current tree has:
- `clear_bit(CEPH_I_ODIRECT_BIT, ...)` in `io.c` (`fbeafe782bd98`)
- Non-atomic `ci->i_ceph_flags |= CEPH_I_FLUSH` in
`__cap_delay_requeue_front()` (line 551)
- Non-atomic `|=` / `&= ~` throughout `caps.c`, `super.h`, etc.
Fix commit `e120e2b666851` is **not** in this tree (only on `master`).
### Step 6.2: Backport complications
**Record:** **Clean apply** verified. No conflicting changes in 6.18.44
for these hunks.
### Step 6.3: Related fixes already present?
**Record:** `fbeafe782bd98` (partial ODIRECT fix with barriers) is
present. The unified atomic-bitops fix is **not** present. No duplicate
fix found.
---
## PHASE 7: SUBSYSTEM CONTEXT
### Step 7.1: Subsystem / criticality
**Record:** `fs/ceph` — CephFS client. **IMPORTANT** (network
filesystem; data/metadata integrity matters to production users).
### Step 7.2: Activity
**Record:** Actively maintained; recent fixes in caps, MDS client, and
I/O paths in 6.18.y.
---
## PHASE 8: IMPACT AND RISK
### Step 8.1: Who is affected
**Record:** CephFS users (`CONFIG_CEPH_FS`). All workloads using mixed
buffered/direct I/O, cap flushing, write-error handling, or file
locking.
### Step 8.2: Trigger conditions
**Record:** Concurrent flag updates on the same inode from different
code paths — e.g., O_DIRECT mode transition (`io.c`) concurrent with cap
flush flagging (`caps.c`), or (after this patch) lockless
`ERROR_WRITE`/`ERROR_FILELOCK` updates concurrent with cap operations.
Realistic under multi-threaded I/O on the same file.
### Step 8.3: Failure mode severity
**Record:**
- **Corrupted `CEPH_I_ODIRECT` state** → buffered and direct I/O not
properly excluded → **stale data reads** (the original problem ODIRECT
flag was added to solve in xfstest generic/451).
- **Corrupted `CEPH_I_ERROR_WRITE`** → incorrect write-error
propagation.
- **Corrupted cap flush flags** → delayed/incorrect metadata flush to
MDS.
- **Severity: HIGH** (data integrity / coherency); not a typical kernel
oops, but silent wrong-data risk.
### Step 8.4: Risk-benefit
**Record:**
- **Benefit: HIGH** for CephFS correctness under concurrency.
- **Risk: LOW** — mechanical, reviewer-approved, applies cleanly, no new
APIs.
- **Ratio:** Favorable.
---
## PHASE 9: FINAL SYNTHESIS
### Step 9.1: Evidence summary
**FOR backport:**
- Fixes a real, well-understood concurrency defect (atomic vs non-atomic
bitfield updates).
- Prerequisite asymmetric pattern exists in 6.18.44 since
`fbeafe782bd98`.
- CephFS data coherency impact (ODIRECT/buffered exclusion).
- Small, mechanical, maintainer-reviewed, applies cleanly.
- Filesystem correctness fix, not a feature add.
**AGAINST backport:**
- No user crash report or syzbot reproduction.
- Part of an 11-patch feature series (though patch 1 is self-contained).
- Most current-tree flag writers hold `i_ceph_lock`, which serializes
many paths today; the worst races become fully exposed when this patch
makes `ERROR_WRITE`/`ERROR_FILELOCK` lockless (which it also fixes
atomically).
- No explicit stable nomination.
**Unresolved:** No runtime reproduction or KCSAN report for the specific
clobber scenario in 6.18.44. Impact inferred from code analysis and
maintainer description.
### Step 9.2: Stable rules checklist
| Criterion | Result |
|-----------|--------|
| 1. Obviously correct and tested? | **PASS** — standard atomic-bitops
pattern; `Reviewed-by` + `Tested-by` on series |
| 2. Fixes real bug affecting users? | **PASS** — inode flag lost-update
can corrupt ODIRECT/cap/error state |
| 3. Important issue? | **PASS** — data coherency / metadata flush
correctness (**HIGH**) |
| 4. Small and contained? | **PASS** — ~156 lines, 10 files, mechanical
|
| 5. No new features/APIs? | **PASS** — behavior fix only |
| 6. Can apply to local tree? | **PASS** — verified clean apply on
6.18.44 |
### Step 9.3: Exception categories
**Record:** None (not a quirk, device ID, DT, build, or docs fix).
### Step 9.4: Decision rationale
For **Linux 6.18.44**, the asymmetric flag-update pattern introduced by
`fbeafe782bd98` is present and the fix is absent. The commit eliminates
a class of lost-update races on `i_ceph_flags` that can affect
O_DIRECT/buffered I/O exclusion and cap/error-flag correctness — issues
with direct data-integrity impact for CephFS production users. The patch
is small, obviously correct, self-contained, and applies cleanly.
Conservative stable policy still favors this kind of filesystem
coherency fix over leaving a known race in place.
---
## Verification
- **[Phase 1]** Parsed commit message and tags from user query and `git
show e120e2b666851`
- **[Phase 2]** Diff analysis from provided patch; grep confirmed `|=` /
`&= ~` and `set_bit`/`clear_bit` coexistence in tree
- **[Phase 3]** `git describe HEAD` → 6.18.44; `git show fbeafe782bd98`;
`git blame` on `super.h:692-708`, `io.c:30-36`; `git merge-base --is-
ancestor fbeafe782bd98 HEAD` → ancestor; commit on `master` not in
HEAD
- **[Phase 4]** `b4 dig -c e120e2b666851` → lore URL; `b4 dig -a` →
v1–v4 revisions; `b4 dig -w` → recipients; `b4 dig -m` → mbox saved;
grep found `Tested-by`/`Reviewed-by`, no stable nomination
- **[Phase 5]** Grep callers of `__cap_delay_requeue_front`,
`ceph_start_io_direct`, `ceph_set_error_write`; read `caps.c`, `io.c`,
`locks.c`
- **[Phase 6]** `git show e120e2b666851 | git apply --check` → clean;
grep confirms buggy pattern in HEAD; fix not in HEAD
- **[Phase 7]** Subsystem identified as `fs/ceph`
- **[Phase 8]** Failure mode derived from ODIRECT flag purpose
(`321fe13c93987` xfstest generic/451) and flag semantics in `super.h`
- **UNVERIFIED:** No runtime reproduction of flag clobber on 6.18.44;
lore thread body not fully readable via WebFetch (bot blocked), relied
on mbox grep
**YES**The background searches finished and match the earlier analysis:
- **Commit location:** `e120e2b666851` ("ceph: convert inode flags to
named bit positions and atomic bitops") is on `master`, not in the
checked-out **6.18.44** tree.
- **Current tree state:** The asymmetric flag pattern is still present
(atomic `clear_bit`/`set_bit` for ODIRECT mixed with non-atomic `|=` /
`&= ~` elsewhere). No equivalent fix is already applied.
- **Backport readiness:** The patch applies cleanly to 6.18.44.
**Verdict for this tree: YES** — backport as a CephFS
concurrency/correctness fix with data-coherency impact.
fs/ceph/addr.c | 20 +++++++-------
fs/ceph/caps.c | 24 ++++++++---------
fs/ceph/file.c | 13 ++++-----
fs/ceph/inode.c | 4 +--
fs/ceph/locks.c | 22 ++++-----------
fs/ceph/mds_client.c | 3 ++-
fs/ceph/mds_client.h | 2 +-
fs/ceph/snap.c | 2 +-
fs/ceph/super.h | 64 +++++++++++++++++++++++---------------------
fs/ceph/xattr.c | 2 +-
10 files changed, 74 insertions(+), 82 deletions(-)
diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c
index ea31c892a1fb1..9d496da6683e7 100644
--- a/fs/ceph/addr.c
+++ b/fs/ceph/addr.c
@@ -2565,7 +2565,8 @@ int ceph_pool_perm_check(struct inode *inode, int need)
struct ceph_inode_info *ci = ceph_inode(inode);
struct ceph_string *pool_ns;
s64 pool;
- int ret, flags;
+ int ret;
+ unsigned long flags;
/* Only need to do this for regular files */
if (!S_ISREG(inode->i_mode))
@@ -2607,20 +2608,19 @@ int ceph_pool_perm_check(struct inode *inode, int need)
if (ret < 0)
return ret;
- flags = CEPH_I_POOL_PERM;
- if (ret & POOL_READ)
- flags |= CEPH_I_POOL_RD;
- if (ret & POOL_WRITE)
- flags |= CEPH_I_POOL_WR;
-
spin_lock(&ci->i_ceph_lock);
if (pool == ci->i_layout.pool_id &&
pool_ns == rcu_dereference_raw(ci->i_layout.pool_ns)) {
- ci->i_ceph_flags |= flags;
- } else {
+ set_bit(CEPH_I_POOL_PERM_BIT, &ci->i_ceph_flags);
+ if (ret & POOL_READ)
+ set_bit(CEPH_I_POOL_RD_BIT, &ci->i_ceph_flags);
+ if (ret & POOL_WRITE)
+ set_bit(CEPH_I_POOL_WR_BIT, &ci->i_ceph_flags);
+ } else {
pool = ci->i_layout.pool_id;
- flags = ci->i_ceph_flags;
}
+ /* Re-read flags under the lock so check: sees the updated bits. */
+ flags = ci->i_ceph_flags;
spin_unlock(&ci->i_ceph_lock);
goto check;
}
diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c
index d9924ef55f4a2..2974bb1184264 100644
--- a/fs/ceph/caps.c
+++ b/fs/ceph/caps.c
@@ -548,7 +548,7 @@ static void __cap_delay_requeue_front(struct ceph_mds_client *mdsc,
doutc(mdsc->fsc->client, "%p %llx.%llx\n", inode, ceph_vinop(inode));
spin_lock(&mdsc->cap_delay_lock);
- ci->i_ceph_flags |= CEPH_I_FLUSH;
+ set_bit(CEPH_I_FLUSH_BIT, &ci->i_ceph_flags);
if (!list_empty(&ci->i_cap_delay_list))
list_del_init(&ci->i_cap_delay_list);
list_add(&ci->i_cap_delay_list, &mdsc->cap_delay_list);
@@ -1408,7 +1408,7 @@ static void __prep_cap(struct cap_msg_args *arg, struct ceph_cap *cap,
ceph_cap_string(revoking));
BUG_ON((retain & CEPH_CAP_PIN) == 0);
- ci->i_ceph_flags &= ~CEPH_I_FLUSH;
+ clear_bit(CEPH_I_FLUSH_BIT, &ci->i_ceph_flags);
cap->issued &= retain; /* drop bits we don't want */
/*
@@ -1665,7 +1665,7 @@ static void __ceph_flush_snaps(struct ceph_inode_info *ci,
last_tid = capsnap->cap_flush.tid;
}
- ci->i_ceph_flags &= ~CEPH_I_FLUSH_SNAPS;
+ clear_bit(CEPH_I_FLUSH_SNAPS_BIT, &ci->i_ceph_flags);
while (first_tid <= last_tid) {
struct ceph_cap *cap = ci->i_auth_cap;
@@ -2025,7 +2025,7 @@ void ceph_check_caps(struct ceph_inode_info *ci, int flags)
spin_lock(&ci->i_ceph_lock);
if (ci->i_ceph_flags & CEPH_I_ASYNC_CREATE) {
- ci->i_ceph_flags |= CEPH_I_ASYNC_CHECK_CAPS;
+ set_bit(CEPH_I_ASYNC_CHECK_CAPS_BIT, &ci->i_ceph_flags);
/* Don't send messages until we get async create reply */
spin_unlock(&ci->i_ceph_lock);
@@ -2576,7 +2576,7 @@ static void __kick_flushing_caps(struct ceph_mds_client *mdsc,
if (ci->i_ceph_flags & CEPH_I_ASYNC_CREATE)
return;
- ci->i_ceph_flags &= ~CEPH_I_KICK_FLUSH;
+ clear_bit(CEPH_I_KICK_FLUSH_BIT, &ci->i_ceph_flags);
list_for_each_entry_reverse(cf, &ci->i_cap_flush_list, i_list) {
if (cf->is_capsnap) {
@@ -2685,7 +2685,7 @@ void ceph_early_kick_flushing_caps(struct ceph_mds_client *mdsc,
__kick_flushing_caps(mdsc, session, ci,
oldest_flush_tid);
} else {
- ci->i_ceph_flags |= CEPH_I_KICK_FLUSH;
+ set_bit(CEPH_I_KICK_FLUSH_BIT, &ci->i_ceph_flags);
}
spin_unlock(&ci->i_ceph_lock);
@@ -2828,7 +2828,7 @@ static int try_get_cap_refs(struct inode *inode, int need, int want,
spin_lock(&ci->i_ceph_lock);
if ((flags & CHECK_FILELOCK) &&
- (ci->i_ceph_flags & CEPH_I_ERROR_FILELOCK)) {
+ test_bit(CEPH_I_ERROR_FILELOCK_BIT, &ci->i_ceph_flags)) {
doutc(cl, "%p %llx.%llx error filelock\n", inode,
ceph_vinop(inode));
ret = -EIO;
@@ -3206,7 +3206,7 @@ static int ceph_try_drop_cap_snap(struct ceph_inode_info *ci,
BUG_ON(capsnap->cap_flush.tid > 0);
ceph_put_snap_context(capsnap->context);
if (!list_is_last(&capsnap->ci_item, &ci->i_cap_snaps))
- ci->i_ceph_flags |= CEPH_I_FLUSH_SNAPS;
+ set_bit(CEPH_I_FLUSH_SNAPS_BIT, &ci->i_ceph_flags);
list_del(&capsnap->ci_item);
ceph_put_cap_snap(capsnap);
@@ -3395,7 +3395,7 @@ void ceph_put_wrbuffer_cap_refs(struct ceph_inode_info *ci, int nr,
if (ceph_try_drop_cap_snap(ci, capsnap)) {
put++;
} else {
- ci->i_ceph_flags |= CEPH_I_FLUSH_SNAPS;
+ set_bit(CEPH_I_FLUSH_SNAPS_BIT, &ci->i_ceph_flags);
flush_snaps = true;
}
}
@@ -3647,7 +3647,7 @@ static void handle_cap_grant(struct inode *inode,
if (ci->i_layout.pool_id != old_pool ||
extra_info->pool_ns != old_ns)
- ci->i_ceph_flags &= ~CEPH_I_POOL_PERM;
+ clear_bit(CEPH_I_POOL_PERM_BIT, &ci->i_ceph_flags);
extra_info->pool_ns = old_ns;
@@ -4812,7 +4812,7 @@ int ceph_drop_caps_for_unlink(struct inode *inode)
doutc(mdsc->fsc->client, "%p %llx.%llx\n", inode,
ceph_vinop(inode));
spin_lock(&mdsc->cap_delay_lock);
- ci->i_ceph_flags |= CEPH_I_FLUSH;
+ set_bit(CEPH_I_FLUSH_BIT, &ci->i_ceph_flags);
if (!list_empty(&ci->i_cap_delay_list))
list_del_init(&ci->i_cap_delay_list);
list_add_tail(&ci->i_cap_delay_list,
@@ -5077,7 +5077,7 @@ int ceph_purge_inode_cap(struct inode *inode, struct ceph_cap *cap, bool *invali
if (atomic_read(&ci->i_filelock_ref) > 0) {
/* make further file lock syscall return -EIO */
- ci->i_ceph_flags |= CEPH_I_ERROR_FILELOCK;
+ set_bit(CEPH_I_ERROR_FILELOCK_BIT, &ci->i_ceph_flags);
pr_warn_ratelimited_client(cl,
" dropping file locks for %p %llx.%llx\n",
inode, ceph_vinop(inode));
diff --git a/fs/ceph/file.c b/fs/ceph/file.c
index ceb5706fe3665..7893150db858b 100644
--- a/fs/ceph/file.c
+++ b/fs/ceph/file.c
@@ -579,12 +579,12 @@ static void wake_async_create_waiters(struct inode *inode,
spin_lock(&ci->i_ceph_lock);
if (ci->i_ceph_flags & CEPH_I_ASYNC_CREATE) {
- clear_and_wake_up_bit(CEPH_ASYNC_CREATE_BIT, &ci->i_ceph_flags);
+ /* Serialized by i_ceph_lock; the two ops touch different bits. */
+ clear_and_wake_up_bit(CEPH_I_ASYNC_CREATE_BIT, &ci->i_ceph_flags);
- if (ci->i_ceph_flags & CEPH_I_ASYNC_CHECK_CAPS) {
- ci->i_ceph_flags &= ~CEPH_I_ASYNC_CHECK_CAPS;
+ if (test_and_clear_bit(CEPH_I_ASYNC_CHECK_CAPS_BIT,
+ &ci->i_ceph_flags))
check_cap = true;
- }
}
ceph_kick_flushing_inode_caps(session, ci);
spin_unlock(&ci->i_ceph_lock);
@@ -747,7 +747,8 @@ static int ceph_finish_async_create(struct inode *dir, struct inode *inode,
* that point and don't worry about setting
* CEPH_I_ASYNC_CREATE.
*/
- ceph_inode(inode)->i_ceph_flags = CEPH_I_ASYNC_CREATE;
+ set_bit(CEPH_I_ASYNC_CREATE_BIT,
+ &ceph_inode(inode)->i_ceph_flags);
unlock_new_inode(inode);
}
if (d_in_lookup(dentry) || d_really_is_negative(dentry)) {
@@ -2422,7 +2423,7 @@ static ssize_t ceph_write_iter(struct kiocb *iocb, struct iov_iter *from)
if ((got & (CEPH_CAP_FILE_BUFFER|CEPH_CAP_FILE_LAZYIO)) == 0 ||
(iocb->ki_flags & IOCB_DIRECT) || (fi->flags & CEPH_F_SYNC) ||
- (ci->i_ceph_flags & CEPH_I_ERROR_WRITE)) {
+ test_bit(CEPH_I_ERROR_WRITE_BIT, &ci->i_ceph_flags)) {
struct ceph_snap_context *snapc;
struct iov_iter data;
diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c
index b6c60d787692e..2804c64252980 100644
--- a/fs/ceph/inode.c
+++ b/fs/ceph/inode.c
@@ -1153,7 +1153,7 @@ int ceph_fill_inode(struct inode *inode, struct page *locked_page,
rcu_assign_pointer(ci->i_layout.pool_ns, pool_ns);
if (ci->i_layout.pool_id != old_pool || pool_ns != old_ns)
- ci->i_ceph_flags &= ~CEPH_I_POOL_PERM;
+ clear_bit(CEPH_I_POOL_PERM_BIT, &ci->i_ceph_flags);
pool_ns = old_ns;
@@ -3216,7 +3216,7 @@ void ceph_inode_shutdown(struct inode *inode)
bool invalidate = false;
spin_lock(&ci->i_ceph_lock);
- ci->i_ceph_flags |= CEPH_I_SHUTDOWN;
+ set_bit(CEPH_I_SHUTDOWN_BIT, &ci->i_ceph_flags);
p = rb_first(&ci->i_caps);
while (p) {
struct ceph_cap *cap = rb_entry(p, struct ceph_cap, ci_node);
diff --git a/fs/ceph/locks.c b/fs/ceph/locks.c
index dd764f9c64b9f..c4ff2266bb944 100644
--- a/fs/ceph/locks.c
+++ b/fs/ceph/locks.c
@@ -57,9 +57,7 @@ static void ceph_fl_release_lock(struct file_lock *fl)
ci = ceph_inode(inode);
if (atomic_dec_and_test(&ci->i_filelock_ref)) {
/* clear error when all locks are released */
- spin_lock(&ci->i_ceph_lock);
- ci->i_ceph_flags &= ~CEPH_I_ERROR_FILELOCK;
- spin_unlock(&ci->i_ceph_lock);
+ clear_bit(CEPH_I_ERROR_FILELOCK_BIT, &ci->i_ceph_flags);
}
fl->fl_u.ceph.inode = NULL;
iput(inode);
@@ -271,15 +269,10 @@ int ceph_lock(struct file *file, int cmd, struct file_lock *fl)
else if (IS_SETLKW(cmd))
wait = 1;
- spin_lock(&ci->i_ceph_lock);
- if (ci->i_ceph_flags & CEPH_I_ERROR_FILELOCK) {
- err = -EIO;
- }
- spin_unlock(&ci->i_ceph_lock);
- if (err < 0) {
+ if (test_bit(CEPH_I_ERROR_FILELOCK_BIT, &ci->i_ceph_flags)) {
if (op == CEPH_MDS_OP_SETFILELOCK && lock_is_unlock(fl))
posix_lock_file(file, fl, NULL);
- return err;
+ return -EIO;
}
if (lock_is_read(fl))
@@ -331,15 +324,10 @@ int ceph_flock(struct file *file, int cmd, struct file_lock *fl)
doutc(cl, "fl_file: %p\n", fl->c.flc_file);
- spin_lock(&ci->i_ceph_lock);
- if (ci->i_ceph_flags & CEPH_I_ERROR_FILELOCK) {
- err = -EIO;
- }
- spin_unlock(&ci->i_ceph_lock);
- if (err < 0) {
+ if (test_bit(CEPH_I_ERROR_FILELOCK_BIT, &ci->i_ceph_flags)) {
if (lock_is_unlock(fl))
locks_lock_file_wait(file, fl);
- return err;
+ return -EIO;
}
if (IS_SETLKW(cmd))
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c
index ba9f96efc8ee7..af7137661c8fc 100644
--- a/fs/ceph/mds_client.c
+++ b/fs/ceph/mds_client.c
@@ -3600,7 +3600,8 @@ static void __do_request(struct ceph_mds_client *mdsc,
spin_lock(&ci->i_ceph_lock);
cap = ci->i_auth_cap;
- if (ci->i_ceph_flags & CEPH_I_ASYNC_CREATE && mds != cap->mds) {
+ if (test_bit(CEPH_I_ASYNC_CREATE_BIT, &ci->i_ceph_flags) &&
+ mds != cap->mds) {
doutc(cl, "session changed for auth cap %d -> %d\n",
cap->session->s_mds, session->s_mds);
diff --git a/fs/ceph/mds_client.h b/fs/ceph/mds_client.h
index 0428a5eaf28c6..e91a199d56fd8 100644
--- a/fs/ceph/mds_client.h
+++ b/fs/ceph/mds_client.h
@@ -658,7 +658,7 @@ static inline int ceph_wait_on_async_create(struct inode *inode)
{
struct ceph_inode_info *ci = ceph_inode(inode);
- return wait_on_bit(&ci->i_ceph_flags, CEPH_ASYNC_CREATE_BIT,
+ return wait_on_bit(&ci->i_ceph_flags, CEPH_I_ASYNC_CREATE_BIT,
TASK_KILLABLE);
}
diff --git a/fs/ceph/snap.c b/fs/ceph/snap.c
index c65f2b202b2b3..0ba33749a37dd 100644
--- a/fs/ceph/snap.c
+++ b/fs/ceph/snap.c
@@ -700,7 +700,7 @@ int __ceph_finish_cap_snap(struct ceph_inode_info *ci,
return 0;
}
- ci->i_ceph_flags |= CEPH_I_FLUSH_SNAPS;
+ set_bit(CEPH_I_FLUSH_SNAPS_BIT, &ci->i_ceph_flags);
doutc(cl, "%p %llx.%llx cap_snap %p snapc %p %llu %s s=%llu\n",
inode, ceph_vinop(inode), capsnap, capsnap->context,
capsnap->context->seq, ceph_cap_string(capsnap->dirty),
diff --git a/fs/ceph/super.h b/fs/ceph/super.h
index 29a980e22dc26..1168103659b51 100644
--- a/fs/ceph/super.h
+++ b/fs/ceph/super.h
@@ -655,23 +655,34 @@ static inline struct inode *ceph_find_inode(struct super_block *sb,
/*
* Ceph inode.
*/
-#define CEPH_I_DIR_ORDERED (1 << 0) /* dentries in dir are ordered */
-#define CEPH_I_FLUSH (1 << 2) /* do not delay flush of dirty metadata */
-#define CEPH_I_POOL_PERM (1 << 3) /* pool rd/wr bits are valid */
-#define CEPH_I_POOL_RD (1 << 4) /* can read from pool */
-#define CEPH_I_POOL_WR (1 << 5) /* can write to pool */
-#define CEPH_I_SEC_INITED (1 << 6) /* security initialized */
-#define CEPH_I_KICK_FLUSH (1 << 7) /* kick flushing caps */
-#define CEPH_I_FLUSH_SNAPS (1 << 8) /* need flush snapss */
-#define CEPH_I_ERROR_WRITE (1 << 9) /* have seen write errors */
-#define CEPH_I_ERROR_FILELOCK (1 << 10) /* have seen file lock errors */
-#define CEPH_I_ODIRECT_BIT (11) /* inode in direct I/O mode */
-#define CEPH_I_ODIRECT (1 << CEPH_I_ODIRECT_BIT)
-#define CEPH_ASYNC_CREATE_BIT (12) /* async create in flight for this */
-#define CEPH_I_ASYNC_CREATE (1 << CEPH_ASYNC_CREATE_BIT)
-#define CEPH_I_SHUTDOWN (1 << 13) /* inode is no longer usable */
-#define CEPH_I_ASYNC_CHECK_CAPS (1 << 14) /* check caps immediately after async
- creating finishes */
+#define CEPH_I_DIR_ORDERED_BIT (0) /* dentries in dir are ordered */
+ /* bit 1 historically unused */
+#define CEPH_I_FLUSH_BIT (2) /* do not delay flush of dirty metadata */
+#define CEPH_I_POOL_PERM_BIT (3) /* pool rd/wr bits are valid */
+#define CEPH_I_POOL_RD_BIT (4) /* can read from pool */
+#define CEPH_I_POOL_WR_BIT (5) /* can write to pool */
+#define CEPH_I_SEC_INITED_BIT (6) /* security initialized */
+#define CEPH_I_KICK_FLUSH_BIT (7) /* kick flushing caps */
+#define CEPH_I_FLUSH_SNAPS_BIT (8) /* need flush snaps */
+#define CEPH_I_ERROR_WRITE_BIT (9) /* have seen write errors */
+#define CEPH_I_ERROR_FILELOCK_BIT (10) /* have seen file lock errors */
+#define CEPH_I_ODIRECT_BIT (11) /* inode in direct I/O mode */
+#define CEPH_I_ASYNC_CREATE_BIT (12) /* async create in flight for this */
+#define CEPH_I_SHUTDOWN_BIT (13) /* inode is no longer usable */
+#define CEPH_I_ASYNC_CHECK_CAPS_BIT (14) /* check caps after async creating finishes */
+
+#define CEPH_I_DIR_ORDERED (1 << CEPH_I_DIR_ORDERED_BIT)
+#define CEPH_I_FLUSH (1 << CEPH_I_FLUSH_BIT)
+#define CEPH_I_POOL_PERM (1 << CEPH_I_POOL_PERM_BIT)
+#define CEPH_I_POOL_RD (1 << CEPH_I_POOL_RD_BIT)
+#define CEPH_I_POOL_WR (1 << CEPH_I_POOL_WR_BIT)
+#define CEPH_I_SEC_INITED (1 << CEPH_I_SEC_INITED_BIT)
+#define CEPH_I_KICK_FLUSH (1 << CEPH_I_KICK_FLUSH_BIT)
+#define CEPH_I_FLUSH_SNAPS (1 << CEPH_I_FLUSH_SNAPS_BIT)
+#define CEPH_I_ERROR_FILELOCK (1 << CEPH_I_ERROR_FILELOCK_BIT)
+#define CEPH_I_ODIRECT (1 << CEPH_I_ODIRECT_BIT)
+#define CEPH_I_ASYNC_CREATE (1 << CEPH_I_ASYNC_CREATE_BIT)
+#define CEPH_I_SHUTDOWN (1 << CEPH_I_SHUTDOWN_BIT)
/*
* Masks of ceph inode work.
@@ -684,27 +695,18 @@ static inline struct inode *ceph_find_inode(struct super_block *sb,
/*
* We set the ERROR_WRITE bit when we start seeing write errors on an inode
- * and then clear it when they start succeeding. Note that we do a lockless
- * check first, and only take the lock if it looks like it needs to be changed.
- * The write submission code just takes this as a hint, so we're not too
- * worried if a few slip through in either direction.
+ * and then clear it when they start succeeding. The write submission code
+ * just takes this as a hint, so we're not too worried if a few slip through
+ * in either direction.
*/
static inline void ceph_set_error_write(struct ceph_inode_info *ci)
{
- if (!(READ_ONCE(ci->i_ceph_flags) & CEPH_I_ERROR_WRITE)) {
- spin_lock(&ci->i_ceph_lock);
- ci->i_ceph_flags |= CEPH_I_ERROR_WRITE;
- spin_unlock(&ci->i_ceph_lock);
- }
+ set_bit(CEPH_I_ERROR_WRITE_BIT, &ci->i_ceph_flags);
}
static inline void ceph_clear_error_write(struct ceph_inode_info *ci)
{
- if (READ_ONCE(ci->i_ceph_flags) & CEPH_I_ERROR_WRITE) {
- spin_lock(&ci->i_ceph_lock);
- ci->i_ceph_flags &= ~CEPH_I_ERROR_WRITE;
- spin_unlock(&ci->i_ceph_lock);
- }
+ clear_bit(CEPH_I_ERROR_WRITE_BIT, &ci->i_ceph_flags);
}
static inline void __ceph_dir_set_complete(struct ceph_inode_info *ci,
diff --git a/fs/ceph/xattr.c b/fs/ceph/xattr.c
index caf0fe4d2b1b7..7e8b1b2bda743 100644
--- a/fs/ceph/xattr.c
+++ b/fs/ceph/xattr.c
@@ -1056,7 +1056,7 @@ ssize_t __ceph_getxattr(struct inode *inode, const char *name, void *value,
if (current->journal_info &&
!strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) &&
security_ismaclabel(name + XATTR_SECURITY_PREFIX_LEN))
- ci->i_ceph_flags |= CEPH_I_SEC_INITED;
+ set_bit(CEPH_I_SEC_INITED_BIT, &ci->i_ceph_flags);
out:
spin_unlock(&ci->i_ceph_lock);
return err;
--
2.53.0
^ permalink raw reply related [flat|nested] 26+ messages in thread* [PATCH AUTOSEL 6.18-5.15] firmware: google: Add bounds checks in coreboot_table_populate()
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (21 preceding siblings ...)
2026-08-31 13:30 ` [PATCH AUTOSEL 6.18] ceph: convert inode flags to named bit positions and atomic bitops Sasha Levin
@ 2026-08-31 13:31 ` Sasha Levin
2026-08-31 13:31 ` [PATCH AUTOSEL 6.18-5.10] ACPICA: Enhance buffer validation in acpi_ut_walk_aml_resources() Sasha Levin
23 siblings, 0 replies; 26+ messages in thread
From: Sasha Levin @ 2026-08-31 13:31 UTC (permalink / raw)
To: patches, stable
Cc: Titouan Ameline de Cadeville, Julius Werner, Tzung-Bi Shih,
Sasha Levin, chrome-platform, linux-kernel
From: Titouan Ameline de Cadeville <titouan.ameline@gmail.com>
[ Upstream commit 7b1a1af4556a4f95ef273e91435fe804cbfcd223 ]
coreboot_table_populate() iterates over firmware-provided table entries
with no validation that the entries stay within the mapped memory
region. A corrupt table with a large `entry->size` advances `ptr_entry`
past the mapped region, causing an out-of-bounds read on the next
iteration.
Add a check before dereferencing `ptr_entry` to ensure the entry header
is readable, and a second check after reading `entry->size` to ensure
the full entry stays within the mapped region.
Pass `len` from coreboot_table_probe() into coreboot_table_populate() to
make the mapped region size available for validation.
Signed-off-by: Titouan Ameline de Cadeville <titouan.ameline@gmail.com>
Reviewed-by: Julius Werner <jwerner@chromium.org>
Link: https://lore.kernel.org/r/20260426214739.117131-1-titouan.ameline@gmail.com
Signed-off-by: Tzung-Bi Shih <tzungbi@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
# Stable Backport Analysis: `firmware: google: Add bounds checks in
coreboot_table_populate()`
**Local tree:** Linux **6.18.43** (`git describe HEAD` → `v6.18.43`,
Makefile `6.18.43`)
---
## PHASE 1: COMMIT MESSAGE FORENSICS
### Step 1.1: Parse Subject Line
**Record:** `[firmware: google]` `[add]` — Add bounds checks in
`coreboot_table_populate()` to validate firmware table entries stay
within the mapped region.
### Step 1.2: Parse All Commit Message Tags
**Record:**
| Tag | Value |
|-----|-------|
| Signed-off-by | Titouan Ameline de Cadeville
\<titouan.ameline@gmail.com\> (author) |
| Reviewed-by | Julius Werner \<jwerner@chromium.org\> (Chromium/Google
firmware maintainer) |
| Link | https://lore.kernel.org/r/20260426214739.117131-1-
titouan.ameline@gmail.com |
| Signed-off-by | Tzung-Bi Shih \<tzungbi@kernel.org\> (firmware
maintainer) |
**Notable patterns:** Reviewed by a Chromium firmware maintainer. No
`Fixes:`, `Reported-by:`, `Cc: stable`, or syzbot tags. Absence of
stable tags is expected per pipeline rules.
### Step 1.3: Analyze Commit Body
**Record:**
- **Bug:** `coreboot_table_populate()` walks firmware-provided table
entries without verifying each entry fits inside the memremapped
region.
- **Symptom:** A corrupt entry with a large `entry->size` advances
`ptr_entry` past the mapped end; the next iteration dereferences past
the mapping → out-of-bounds read. `memcpy(device->raw, ptr_entry,
entry->size)` can also read past the mapping on the current entry.
- **Root cause:** No upper-bound validation against mapped length; only
a minimum-size check (`entry->size < sizeof(*entry)`) existed.
- **Fix approach:** Pass `len` from `coreboot_table_probe()` into
`coreboot_table_populate()`; check header readability and full entry
containment before use.
### Step 1.4: Detect Hidden Bug Fixes
**Record:** Not disguised — explicitly an OOB-read / memory-safety fix,
though described as "add bounds checks" rather than "fix OOB read."
---
## PHASE 2: DIFF ANALYSIS
### Step 2.1: Inventory Changes
**Record:**
- **File:** `drivers/firmware/google/coreboot_table.c` only
- **Scope:** ~10 lines added, 2 signature lines changed — single-file
surgical fix
- **Functions modified:** `coreboot_table_populate()`,
`coreboot_table_probe()` (call site only)
### Step 2.2: Code Flow Change (per hunk)
**Hunk 1 — `coreboot_table_populate()`:**
- **Before:** Loop over `header->table_entries`; dereference `entry =
ptr_entry` with no end-of-region check; advance `ptr_entry +=
entry->size` unconditionally.
- **After:** Compute `ptr_end = ptr + len`; before dereferencing, verify
`ptr_entry + sizeof(*entry) <= ptr_end`; after reading `entry->size`,
verify `ptr_entry + entry->size <= ptr_end`; return `-EINVAL` on
violation.
**Hunk 2 — `coreboot_table_probe()`:**
- **Before:** `coreboot_table_populate(dev, ptr)`
- **After:** `coreboot_table_populate(dev, ptr, len)` where `len =
header->header_bytes + header->table_bytes`
**Record:** Normal boot probe path and error path both affected; no
change to remove/teardown paths.
### Step 2.3: Bug Mechanism
**Record:**
- **Category:** Buffer overflow / out-of-bounds access (memory safety)
- **Mechanism:** Firmware-controlled `entry->size` and
`header->table_entries` can describe a layout larger than the
memremapped `[ptr, ptr+len)` region. The loop trusts per-entry sizes
without summing or bounding against `len`. Corrupt or malicious table
data causes reads past the mapping on `entry` dereference and in
`memcpy()`. A very large `entry->size` also drives
`kzalloc(sizeof(device->dev) + entry->size)` before the bounds check
in the unpatched code.
### Step 2.4: Fix Quality
**Record:**
- Fix is minimal and obviously correct: standard `ptr_end` bounds
pattern.
- Returns `-EINVAL` on bad data — consistent with existing `entry->size
< sizeof(*entry)` handling.
- **Regression risk:** Very low. Only adds validation on a firmware-
parsing path; no locking, no API changes.
- **Minor note:** `header->header_bytes + header->table_bytes` is still
trusted from firmware (pre-existing); this fix bounds entry iteration
within that self-reported length, which is the right scope.
---
## PHASE 3: GIT HISTORY INVESTIGATION
### Step 3.1: Blame Changed Lines
**Record:** `git blame` on `coreboot_table_populate()` attributes all
lines to `19eef1d98eeda` (an unrelated AFS commit) due to history
squashing in this stable tree — not reliable for origin dating. `git log
--follow` shows the vulnerable function present at `ac3fd01e4c1ef`
("Linux 6.18-rc7") with identical logic. **Buggy code exists throughout
the 6.18.y series in this checkout.**
### Step 3.2: Follow Fixes: Tag
**Record:** No `Fixes:` tag present — step N/A.
### Step 3.3: File History for Related Changes
**Record:** Recent `drivers/firmware/google/` history in this tree:
- `75d40ccf38ca7` — framebuffer probe cleanup
- `ecb3e4fa31ffa` — framebuffer busy flag fix
- No prior bounds-check fix for `coreboot_table.c`. **Standalone fix,
not part of a series.**
### Step 3.4: Author's Other Commits
**Record:** No commits by Titouan Ameline in `drivers/firmware/google/`
in this tree. Author appears to be a new contributor to this subsystem;
patch was reviewed by Julius Werner (Chromium).
### Step 3.5: Prerequisites / Dependencies
**Record:** No dependencies. The patch only needs `coreboot_table.c` as
it exists in this tree. `resource_size_t len` is already used in
`coreboot_table_probe()`. **Applies standalone.**
---
## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
### Step 4.1: Original Patch Discussion
**Record:** `b4 dig -c <commit>` not possible — commit is not in this
checkout. `WebFetch` and `curl` to lore.kernel.org returned 403/bot-
wall. **Lore thread content UNVERIFIED.** Commit message provides Link
and `Reviewed-by: Julius Werner`.
### Step 4.2: Reviewers
**Record:** Julius Werner (Chromium firmware) reviewed. Tzung-Bi Shih
committed. Appropriate subsystem coverage assumed from tags; full
recipient list UNVERIFIED.
### Step 4.3: Bug Report
**Record:** No `Reported-by:`, no syzbot link, no stack trace in commit
message. Bug identified by code review / defensive analysis, not a filed
crash report.
### Step 4.4: Related Patches / Series
**Record:** Single-patch fix. No series dependencies.
### Step 4.5: Stable Mailing List History
**Record:** UNVERIFIED — could not search lore stable list due to access
restrictions.
---
## PHASE 5: CODE SEMANTIC ANALYSIS
### Step 5.1: Key Functions
**Record:** `coreboot_table_populate()`, `coreboot_table_probe()`
### Step 5.2: Callers
**Record:**
- `coreboot_table_populate()` — called only from
`coreboot_table_probe()` (verified via grep)
- `coreboot_table_probe()` — platform driver `.probe` for
`coreboot_table_driver`, registered at module init
**Context:** Runs once at boot when `CONFIG_GOOGLE_COREBOOT_TABLE` is
enabled, on ACPI `GOOGCB00` / `BOOT0000` or OF `compatible = "coreboot"`
platforms (Chromebooks, Chromium embedded boards).
### Step 5.3: Callees
**Record:** `memremap()`, `memunmap()`, `kzalloc()`, `memcpy()`,
`device_register()`, `dev_warn()` — memory mapping and device
enumeration from firmware table.
### Step 5.4: Call Chain / Reachability
**Record:**
```
module_init → platform_driver_register → coreboot_table_probe (ACPI/OF
match)
→ memremap firmware table → coreboot_table_populate → iterate entries
```
- **Userspace trigger:** Not directly syscall-reachable.
- **Indirect trigger:** Corrupt or attacker-modified coreboot table in
firmware flash or ACPI-described memory region.
- **Affected platforms:** Google Chromebooks and other coreboot/Chromium
devices with `CONFIG_GOOGLE_FIRMWARE` / `CONFIG_GOOGLE_COREBOOT_TABLE`
(e.g. `arch/arm64/configs/defconfig` has both enabled).
### Step 5.5: Similar Patterns
**Record:** This stable tree has already accepted similar firmware OOB
fixes:
- `cf5708c9d78c9` — `firmware: arm_ffa: Fix out-of-bound writes`
- `11daac2817dca` — `firmware: arm_scmi: Fix OOB in
scmi_power_name_get()`
Precedent supports firmware-parser bounds-check backports to 6.18.y.
---
## PHASE 6: CROSS-REFERENCE AGAINST LOCAL TREE
### Step 6.1: Does Buggy Code Exist?
**Record:** **YES.** Current `drivers/firmware/google/coreboot_table.c`
lines 104–147 contain the vulnerable loop with no `ptr_end` checks.
Identical logic confirmed at `ac3fd01e4c1ef` (6.18-rc7). Fix is **not**
already present (grep found no `ptr_end` or bounds-check commit).
### Step 6.2: Backport Complications
**Record:** **Clean apply expected.** Local file matches the patch's
pre-change structure exactly (function signature, loop body, probe call
site). No conflicting refactors in recent history.
### Step 6.3: Related Fixes Already Present?
**Record:** **None** for this bug. Grep for `coreboot_table_populate`
bounds fixes returned nothing.
---
## PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
### Step 7.1: Subsystem Criticality
**Record:** `drivers/firmware/google/` — **PERIPHERAL** (platform-
specific Google/coreboot firmware driver). Not core kernel, but used on
production Chromebook fleet when enabled.
### Step 7.2: Subsystem Activity
**Record:** Moderate activity in this tree (recent framebuffer probe
fixes). `coreboot_table.c` itself has been stable since 6.18-rc7 with no
prior hardening.
---
## PHASE 8: IMPACT AND RISK ASSESSMENT
### Step 8.1: Who Is Affected
**Record:** **Platform-specific, config-dependent** — systems with
`CONFIG_GOOGLE_COREBOOT_TABLE` (Chromebooks, Chromium ARM boards, some
x86 Google platforms). Not universal; significant within that fleet.
### Step 8.2: Trigger Conditions
**Record:**
- Corrupt coreboot table: flash wear/corruption, buggy coreboot build,
or compromised firmware
- Mismatch between `table_entries`/per-entry `size` fields and actual
mapped `len`
- **Likelihood:** Low in normal operation; non-zero with flash
corruption or firmware bugs
- **Unprivileged userspace:** Cannot trigger directly; requires
firmware-level corruption
### Step 8.3: Failure Mode Severity
**Record:**
- OOB read on `entry` dereference → possible page fault / kernel oops at
boot
- OOB read in `memcpy()` → information leak from adjacent mapped memory
- Unchecked large `entry->size` → excessive `kzalloc()` attempt (boot-
time DoS / OOM)
- **Severity: HIGH** for affected platforms (boot failure or memory-
safety violation), **LOW** population-wide
### Step 8.4: Risk-Benefit Ratio
**Record:**
- **Benefit:** Prevents OOB reads and unbounded allocation on a firmware
trust boundary; hardens boot on Chromebook/coreboot systems. Aligns
with existing stable practice (arm_ffa, arm_scmi OOB backports in this
tree).
- **Risk:** Very low — ~10 lines of validation, no behavior change on
valid tables.
- **Ratio:** Favorable for backport to this tree.
---
## PHASE 9: FINAL SYNTHESIS
### Step 9.1: Evidence Summary
**FOR backport:**
- Real, verifiable OOB-read bug in firmware table parser
- Small, surgical, obviously correct fix
- Buggy code present in Linux 6.18.43 checkout
- Clean apply, no dependencies
- Reviewed by Chromium firmware maintainer
- Precedent: similar `firmware:` OOB fixes already in this 6.18.y tree
- Prevents boot-time crash and unbounded allocation on corrupt firmware
data
**AGAINST backport:**
- No syzbot report or user crash report
- Trigger requires corrupt/malicious firmware table (not common)
- Platform-specific driver behind `CONFIG_GOOGLE_COREBOOT_TABLE`
(default N in Kconfig)
- Boot-only path, not directly userspace-exploitable
- Lore review thread content could not be fetched
**Unresolved:** Full lore discussion content; whether reviewers
explicitly nominated for stable.
### Step 9.2: Stable Rules Checklist
| Criterion | Result |
|-----------|--------|
| 1. Obviously correct and tested? | **PASS** — standard bounds checks;
reviewed by subsystem expert |
| 2. Fixes a real bug affecting users? | **PASS** — OOB read on corrupt
firmware table on Chromebook/coreboot systems |
| 3. Important issue? | **PASS** — OOB access / potential boot crash
(HIGH on affected platforms) |
| 4. Small and contained? | **PASS** — one file, ~10 lines |
| 5. No new features/APIs? | **PASS** — validation only, static function
signature change |
| 6. Can apply to local tree? | **PASS** — code present, clean apply
expected |
### Step 9.3: Exception Categories
**Record:** None (not device ID, quirk, DT, build, or docs). Qualifies
as a memory-safety / OOB fix on its own merits.
### Step 9.4: Decision Rationale
For **Linux 6.18.y** specifically: the vulnerable
`coreboot_table_populate()` loop exists in this checkout, the fix is
self-contained and low-risk, and it addresses a genuine out-of-bounds
read when parsing firmware-provided table entries. While the trigger
(corrupt coreboot table) is uncommon and the driver is platform-
specific, the fix matches stable-tree practice already established in
this same tree for firmware OOB issues, and failure modes include boot-
time kernel faults and unbounded allocation from attacker-influenced
firmware fields. The conservative stable choice here is to include the
hardening.
---
## Verification
- **[Phase 1]** Parsed commit message from user query: subsystem, tags,
bug description recorded
- **[Phase 2]** Read `drivers/firmware/google/coreboot_table.c`:
confirmed vulnerable loop at lines 104–147, no `ptr_end` checks
- **[Phase 2]** Diff analysis: two bounds checks + `len` parameter pass-
through verified against local file
- **[Phase 3]** `git describe HEAD` → `v6.18.43`; Makefile → 6.18.43
- **[Phase 3]** `git blame` on `coreboot_table_populate()`: squashed
history (unreliable origin)
- **[Phase 3]** `git log --follow` on file: vulnerable code at
`ac3fd01e4c1ef` (Linux 6.18-rc7)
- **[Phase 3]** `git log --oneline -20 --
drivers/firmware/google/coreboot_table.c`: limited history due to
stable tree squash
- **[Phase 3]** No `Fixes:` tag; no prerequisite commits found
- **[Phase 4]** `b4 dig -c` failed — commit not in local repo
- **[Phase 4]** `WebFetch` lore URL → bot wall; `curl` raw lore → 403.
**Lore content UNVERIFIED**
- **[Phase 5]** `grep coreboot_table_populate`: only caller is
`coreboot_table_probe()`
- **[Phase 5]** Read Kconfig: `GOOGLE_COREBOOT_TABLE` depends on
`HAS_IOMEM && (ACPI || OF)`
- **[Phase 5]** `arch/arm64/configs/defconfig`:
`CONFIG_GOOGLE_FIRMWARE=y`, `CONFIG_GOOGLE_COREBOOT_TABLE=m`
- **[Phase 5]** Precedent: `cf5708c9d78c9`, `11daac2817dca` firmware OOB
fixes in this tree
- **[Phase 6]** Buggy code confirmed present; fix not present (`grep
ptr_end` → no match in coreboot_table.c)
- **[Phase 6]** Local file structure matches patch base — clean apply
expected
- **[Phase 8]** Failure mode: OOB read / boot oops / kzalloc abuse —
severity HIGH on affected platforms
**YES**
drivers/firmware/google/coreboot_table.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/drivers/firmware/google/coreboot_table.c b/drivers/firmware/google/coreboot_table.c
index 882db32e51be9..f212b84ee2f93 100644
--- a/drivers/firmware/google/coreboot_table.c
+++ b/drivers/firmware/google/coreboot_table.c
@@ -101,16 +101,20 @@ void coreboot_driver_unregister(struct coreboot_driver *driver)
}
EXPORT_SYMBOL(coreboot_driver_unregister);
-static int coreboot_table_populate(struct device *dev, void *ptr)
+static int coreboot_table_populate(struct device *dev, void *ptr, resource_size_t len)
{
int i, ret;
void *ptr_entry;
struct coreboot_device *device;
struct coreboot_table_entry *entry;
struct coreboot_table_header *header = ptr;
+ void *ptr_end;
+ ptr_end = ptr + len;
ptr_entry = ptr + header->header_bytes;
for (i = 0; i < header->table_entries; i++) {
+ if (ptr_entry + sizeof(*entry) > ptr_end)
+ return -EINVAL;
entry = ptr_entry;
if (entry->size < sizeof(*entry)) {
@@ -118,6 +122,9 @@ static int coreboot_table_populate(struct device *dev, void *ptr)
return -EINVAL;
}
+ if (ptr_entry + entry->size > ptr_end)
+ return -EINVAL;
+
device = kzalloc(sizeof(device->dev) + entry->size, GFP_KERNEL);
if (!device)
return -ENOMEM;
@@ -183,7 +190,7 @@ static int coreboot_table_probe(struct platform_device *pdev)
if (!ptr)
return -ENOMEM;
- ret = coreboot_table_populate(dev, ptr);
+ ret = coreboot_table_populate(dev, ptr, len);
memunmap(ptr);
--
2.53.0
^ permalink raw reply related [flat|nested] 26+ messages in thread* [PATCH AUTOSEL 6.18-5.10] ACPICA: Enhance buffer validation in acpi_ut_walk_aml_resources()
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (22 preceding siblings ...)
2026-08-31 13:31 ` [PATCH AUTOSEL 6.18-5.15] firmware: google: Add bounds checks in coreboot_table_populate() Sasha Levin
@ 2026-08-31 13:31 ` Sasha Levin
23 siblings, 0 replies; 26+ messages in thread
From: Sasha Levin @ 2026-08-31 13:31 UTC (permalink / raw)
To: patches, stable
Cc: ikaros, Rafael J. Wysocki, Sasha Levin, rafael,
maciej.wieczor-retman, pawel.chmielewski, linux-acpi,
acpica-devel, linux-kernel
From: ikaros <void0red@gmail.com>
[ Upstream commit b2e21fe8c3361c3d0d57ee56d359bea9b51fda3d ]
Enhance buffer validation in acpi_ut_walk_aml_resources() to prevent
buffer overflows.
Link: https://github.com/acpica/acpica/commit/975cb20c7992
Signed-off-by: ikaros <void0red@gmail.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Link: https://patch.msgid.link/2481429.NG923GbCHz@rafael.j.wysocki
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
The background git searches finished and line up with the earlier
analysis:
- **No matching fix in 6.18.44** — searches for “Enhance buffer
validation” and `AE_AML_BUFFER_LENGTH` usage in `utresrc.c` found
nothing; the patch is not in this tree yet.
- **Prerequisites are present** — `AE_AML_BUFFER_LENGTH` is already
defined in `include/acpi/acexcep.h` (since 2018); recent `utresrc.c`
churn is only pack(1)/alignment work, not this bounds-check fix.
- **Vulnerable code is still there** — the walk loop in
`acpi_ut_walk_aml_resources()` lacks the new validation.
That supports the **YES** backport verdict for linux-6.18.y: a confirmed
heap-buffer-overflow fix, small and self-contained, with no dependency
blockers in this tree.
drivers/acpi/acpica/utresrc.c | 30 ++++++++++++++++++++++++++++++
1 file changed, 30 insertions(+)
diff --git a/drivers/acpi/acpica/utresrc.c b/drivers/acpi/acpica/utresrc.c
index e1cc3d3487508..86ebd9fb869af 100644
--- a/drivers/acpi/acpica/utresrc.c
+++ b/drivers/acpi/acpica/utresrc.c
@@ -165,6 +165,28 @@ acpi_ut_walk_aml_resources(struct acpi_walk_state *walk_state,
/* Walk the byte list, abort on any invalid descriptor type or length */
while (aml < end_aml) {
+ /*
+ * Validate that the remaining buffer space can hold enough
+ * bytes to safely access fields during validation.
+ * For large resource descriptors (bit 7 set), we need enough
+ * bytes to access the Type field in serial_bus resources.
+ * Small resource descriptors only need sizeof(struct aml_resource_end_tag).
+ */
+ if ((acpi_size)(end_aml - aml) <
+ sizeof(struct aml_resource_end_tag)) {
+ return_ACPI_STATUS(AE_AML_BUFFER_LENGTH);
+ }
+
+ /*
+ * For large resource descriptors, ensure enough space for
+ * the header plus serial_bus Type field access.
+ */
+ if ((ACPI_GET8(aml) & ACPI_RESOURCE_NAME_LARGE) &&
+ ((acpi_size)(end_aml - aml) <
+ ACPI_OFFSET(struct aml_resource_common_serialbus,
+ type) + 1)) {
+ return_ACPI_STATUS(AE_AML_BUFFER_LENGTH);
+ }
/* Validate the Resource Type and Resource Length */
@@ -182,6 +204,14 @@ acpi_ut_walk_aml_resources(struct acpi_walk_state *walk_state,
length = acpi_ut_get_descriptor_length(aml);
+ /*
+ * Validate that the descriptor length doesn't exceed the
+ * remaining buffer size to prevent reading beyond the end.
+ */
+ if (length > (acpi_size)(end_aml - aml)) {
+ return_ACPI_STATUS(AE_AML_BUFFER_LENGTH);
+ }
+
/* Invoke the user function */
if (user_function) {
--
2.53.0
^ permalink raw reply related [flat|nested] 26+ messages in thread