[PATCH AUTOSEL 6.18-5.10] ACPICA: validate byte_count in acpi_ps_get_next_package_length()

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 d49c6ee08365a8596f639da46eb7e71752b0cd42 ]

Validate package length reading in acpi_ps_get_next_package_length().

Link: https://github.com/acpica/acpica/commit/40e03f9941e2
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 `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/[email protected]
  (kernel submission)
- **Signed-off-by:** ikaros \<[email protected]\> (author)
- **Signed-off-by:** Rafael J. Wysocki \<[email protected]\>
  (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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.