[PATCH AUTOSEL 6.18-5.10] ACPICA: Fix use-after-free in acpi_ds_terminate_control_method()
Sasha Levin <[email protected]>
| Newsgroups | org.kernel.vger.linux-acpi,dev.linux.lists.acpica-devel,dev.linux.lists.patches,org.kernel.vger.linux-kernel,org.kernel.vger.stable |
|---|---|
| Message-ID | <[email protected]> |
From: ikaros <[email protected]> [ 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 <[email protected]> Signed-off-by: Rafael J. Wysocki <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Sasha Levin <[email protected]> --- 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/[email protected] (kernel submission; could not fetch) - **Signed-off-by:** ikaros \<[email protected]\> (author) - **Signed-off-by:** Rafael J. Wysocki \<[email protected]\> (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