From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AEF4244236B; Mon, 31 Aug 2026 13:33:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788183233; cv=none; b=VT6v+AqPwRQbV2dEd16y0f9ESPNScXtODtIT8Eb6IABlQjptXh9pzQTNJ0m/YDRbmEguRxVdRD+liXnFQNo2WmFVDaprCi0fmAxVy2esVoITvOOYqPY5AAQ4svDTI1VvYdmC9SJshVKch1omWuOnBgQyEws/X1ap8Bp8csnE8is= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788183233; c=relaxed/simple; bh=V7sbAJfojpViBi9NF9WshJ5gEPS+pZYWlgpCHUkkIho=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=dLF6e+f9G5ZlqNQaOG5hz7sAmy6Pwzb+ggv96Mg6aKaVL/l10WqV8qfWrHMPyJKiv1866ovW1tA7V2PhcFVNL7ZtAm/411FDjLshaBE7H6TPqsvj2Y0rGxtDJY4zgHt8w4ZIblq6BYdbFOomTGR+rYaal8jzd4oZ9LyivQ3YGrk= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=jmixC4rq; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="jmixC4rq" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 39AF11F00A3F; Mon, 31 Aug 2026 13:33:50 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1788183231; bh=Cqd//VPcToMiX8rAslIYH5tBq/ViuVFDxNgrqV68/Os=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=jmixC4rqpIwE9etwyxxfzVccRgds96FfGnEeBgXs1Btfdf84wzBf/EbUbO48WrHG+ EAtPQjXvSq0G61vY1Dm3zgo4Yax5B4YWkxu6aKAoG2dCfuQGyT+RuVa/zCBVjpDr54 ynl7cgQWazG+mfP4TwXMmlDlRybGM9JklVfdRCe1r1VSveQCd9NiFWmwbbam7ofbvV lI8o9wzan0srUVwb8F3XaghGEeEPIHNBUh19FpxCJvAAziZiwpaZGomntYuZny5oUH gNkxIKHvsJz0p6p+hYIjWAscU9IrIlhMau048VTjFS2/G/5BI4ahwu1RuZCPEQq8zm 6UPRbr43LfqEg== From: Sasha Levin To: patches@lists.linux.dev, stable@vger.kernel.org Cc: Albert Esteve , Neil Armstrong , Maxime Ripard , Dmitry Baryshkov , Thomas Zimmermann , Sasha Levin , maarten.lankhorst@linux.intel.com, airlied@gmail.com, simona@ffwll.ch, dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org Subject: [PATCH AUTOSEL 6.18] drm/panel/tdo-tl070wsh30: Use refcounted allocation in place of devm_kzalloc() Date: Mon, 31 Aug 2026 09:20:52 -0400 Message-ID: <20260831133314.4125787-24-sashal@kernel.org> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260831133314.4125787-1-sashal@kernel.org> References: <20260831133314.4125787-1-sashal@kernel.org> Precedence: bulk X-Mailing-List: patches@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-stable: review X-Patchwork-Hint: Ignore X-stable-base: Linux 6.18.48 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From: Albert Esteve [ Upstream commit 928decbed75bf215a8d0eecc88aa2edc77023db2 ] Move to using the new API devm_drm_panel_alloc() to allocate the panel. In the call to the new API, avoid using explicit type and use __typeof() for more type safety. Reviewed-by: Neil Armstrong Reviewed-by: Maxime Ripard Signed-off-by: Albert Esteve Reviewed-by: Dmitry Baryshkov Reviewed-by: Thomas Zimmermann Link: https://patch.msgid.link/20260508-drm_panel_init_rm-v2-6-0bd4ac429971@redhat.com Signed-off-by: Maxime Ripard Signed-off-by: Sasha Levin --- LLM Generated explanations, may be completely bogus: # Stable Backport Analysis: `drm/panel/tdo-tl070wsh30: Use refcounted allocation in place of devm_kzalloc()` **Local tree:** `v6.18.43` (`6.18.43`) — Linux 6.18.y stable series --- ## PHASE 1: COMMIT MESSAGE FORENSICS ### Step 1.1: Parse the subject line **Record:** `[drm/panel/tdo-tl070wsh30]` — migrate allocation — convert from `devm_kzalloc()` + `drm_panel_init()` to `devm_drm_panel_alloc()`. ### Step 1.2: Parse all commit message tags **Record:** - **Reviewed-by:** Neil Armstrong, Maxime Ripard, Dmitry Baryshkov, Thomas Zimmermann (DRM/panel maintainers/reviewers) - **Signed-off-by:** Albert Esteve (author), Maxime Ripard (maintainer) - **Link:** `https://patch.msgid.link/20260508-drm_panel_init_rm-v2-6- 0bd4ac429971@redhat.com` (patch 6/10 of `drm_panel_init_rm` v2 series) - **No** Fixes:, Reported-by:, Cc: stable, Tested-by:, Acked-by: Notable: multiple maintainer Reviewed-by tags; part of a reviewed 10-patch series. ### Step 1.3: Analyze commit body **Record:** - **Bug described:** Not in the per-driver commit body itself; the series cover letter (patch 00/10) states the old `devm_kzalloc()` + `drm_panel_init()` pattern is unsafe. - **Symptom:** Use-after-free when the panel device is unbound — `devm` frees the panel context struct immediately, but the DRM device may still reference the embedded `drm_panel` via a panel bridge. - **Root cause (series):** Panel memory lifetime tied to `devm_kzalloc` does not match the lifetime of DRM-side panel bridge references. `devm_drm_panel_alloc()` wraps allocation in a `kref` scheme so memory is freed only when the last reference is dropped. - **Version info:** None in commit message. ### Step 1.4: Detect hidden bug fixes **Record:** Yes — despite no "fix" in the subject, this is a **use- after-free prevention** fix, not a cosmetic refactor. The series cover letter explicitly documents UAF on panel device unbind. The per-driver commit is the mechanical driver-side half of that fix. --- ## PHASE 2: DIFF ANALYSIS ### Step 2.1: Inventory the changes **Record:** - **Files:** `drivers/gpu/drm/panel/panel-tdo-tl070wsh30.c` only (+7/−7 lines) - **Functions modified:** `tdo_tl070wsh30_panel_add()`, `tdo_tl070wsh30_panel_probe()` - **Scope:** Single-file, surgical driver fix ### Step 2.2: Code flow change per hunk **Hunk 1 — `tdo_tl070wsh30_panel_add()`:** - **Before:** Explicit `drm_panel_init()` call to initialize the embedded `drm_panel`. - **After:** `drm_panel_init()` removed; initialization now happens inside `devm_drm_panel_alloc()` during probe. - **Path affected:** Normal probe path. **Hunk 2 — `tdo_tl070wsh30_panel_probe()`:** - **Before:** `devm_kzalloc()` allocation; `-ENOMEM` on failure. - **After:** `devm_drm_panel_alloc()` with `__typeof(*tdo_tl070wsh30), base, ...`; `IS_ERR()` / `PTR_ERR()` error handling. - **Path affected:** Probe initialization path. ### Step 2.3: Bug mechanism **Record:** - **Category:** Use-after-free / memory lifetime bug - **Mechanism:** `devm_kzalloc()` ties panel struct lifetime to panel device devres release. When the panel DSI device unbinds, memory is freed while `drmm_panel_bridge_add()` / `devm_drm_of_get_bridge()` on the display side may still hold a `struct drm_panel *` through a panel bridge. `devm_drm_panel_alloc()` allocates via `kzalloc()` (not devres-backed memory), initializes `kref`, and registers a devm cleanup action calling `drm_panel_put()`, decoupling panel memory lifetime from naive devres free ordering. ### Step 2.4: Fix quality assessment **Record:** - **Obviously correct:** Yes — identical pattern already applied to 100+ panel drivers in this tree (e.g., `panel-jdi-lt070me05000.c`, `panel- novatek-nt36672a.c`). - **Minimal/surgical:** Yes — only allocation/init changes, no logic changes. - **Regression risk:** Very low — mechanical API swap using existing, exported API. - **Red flags:** None. No API changes, no cross-subsystem impact. --- ## PHASE 3: GIT HISTORY INVESTIGATION ### Step 3.1: Blame changed lines **Record:** Shallow history — all lines blame to `5d324e5159d9e` (6.18 merge base). Driver has used `devm_kzalloc()` + `drm_panel_init()` since import into this tree. The vulnerable pattern is long-standing in this driver. ### Step 3.2: Follow Fixes: tag **Record:** N/A — no Fixes: tag present. ### Step 3.3: File history for related changes **Record:** - `devm_drm_panel_alloc()` infrastructure present in `drivers/gpu/drm/drm_panel.c` and `include/drm/drm_panel.h`. - Bulk migration already done: **100+** panel drivers use `devm_drm_panel_alloc`. - **6 drivers** still use `drm_panel_init()` — exactly the set targeted by this series: - `panel-tdo-tl070wsh30.c` (this commit) - `panel-visionox-g2647fb105.c`, `panel-samsung-s6e63m0.c`, `panel- sharp-ls043t1le01.c`, `panel-truly-nt35597.c`, `panel-startek- kd070fhfid015.c` - This commit is **patch 6/10** of `drm_panel_init_rm` v2; patch 10/10 makes `drm_panel_init()` static but is **not required** for this driver patch to function. ### Step 3.4: Author's other commits **Record:** Albert Esteve authored the full 10-patch series converting the last remaining panel drivers. Maxime Ripard (DRM maintainer) signed off. Multiple subsystem maintainers reviewed. ### Step 3.5: Prerequisites **Record:** - **Required:** `devm_drm_panel_alloc()` — **present** in 6.18.43. - **Not required:** Patch 10/10 (`drm_panel_init()` static) — this driver patch compiles and works without it; `drm_panel_init()` remains exported in this tree. - **Standalone:** Yes — single-driver change, self-contained. --- ## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH ### Step 4.1: Original patch discussion **Record:** - **Series URL:** https://lkml.iu.edu/hypermail/linux/kernel/2605.1/00251.html (`[PATCH v2 00/10]`) - **This patch URL:** https://www.spinics.net/lists/kernel/msg6193227.html (`[PATCH v2 06/10]`) - **Series revisions:** v1 → v2 (v2 removed kdoc precedence mentions) - **Key feedback:** Series cover letter documents UAF; v2 is latest revision. - **Stable nominations:** None found in thread excerpts. - **NAKs/concerns:** None found. ### Step 4.2: Reviewers **Record:** CC'd to dri-devel, linux-kernel. To: Neil Armstrong, Maxime Ripard, Thomas Zimmermann, David Airlie, Maarten Lankhorst, and other DRM maintainers. Reviewed-by from Neil Armstrong and Maxime Ripard on this specific patch. ### Step 4.3: Bug report **Record:** No syzbot/KASAN report. Bug identified through API lifetime analysis in the series cover letter, not a specific crash report. Severity is still real (UAF on unbind). ### Step 4.4: Related patches **Record:** Part of 10-patch series; each driver patch is independent. Other patches in series target the other 5 remaining `drm_panel_init()` callers. `panel-ilitek-ili9806e` was already converted in this tree via earlier work. ### Step 4.5: Stable mailing list **Record:** No stable-specific discussion found (not searched exhaustively on lore stable list; no evidence against backport). --- ## PHASE 5: CODE SEMANTIC ANALYSIS ### Step 5.1: Key functions **Record:** `tdo_tl070wsh30_panel_probe()`, `tdo_tl070wsh30_panel_add()`, `tdo_tl070wsh30_panel_remove()` ### Step 5.2: Callers **Record:** - `tdo_tl070wsh30_panel_probe()` — MIPI DSI core during device probe (`module_mipi_dsi_driver`) - `tdo_tl070wsh30_panel_add()` — called from probe - Panel registered globally via `drm_panel_add()`; discovered by display drivers via `of_drm_find_panel()` / `drm_of_find_panel_or_bridge()` → `drmm_panel_bridge_add()` / `devm_drm_of_get_bridge()` ### Step 5.3: Callees **Record:** `devm_drm_panel_alloc()` → `kzalloc()`, `kref_init()`, `devm_add_action_or_reset(drm_panel_put_void)`, `drm_panel_init()`. Probe also calls `devm_regulator_get()`, `devm_gpiod_get()`, `drm_panel_of_backlight()`, `drm_panel_add()`, `mipi_dsi_attach()`. ### Step 5.4: Call chain / reachability **Record:** ``` Device probe → mipi_dsi_driver.probe → devm_drm_panel_alloc → drm_panel_add Display probe → drm_of_find_panel_or_bridge → drmm_panel_bridge_add (stores panel pointer) Panel unbind → devm cleanup → [UAF if old pattern, fixed with refcounted alloc] ``` **Userspace reachable:** Yes — via device hot-unplug, module unload, or driver rebinding on embedded systems using this panel. ### Step 5.5: Similar patterns **Record:** Same fix pattern applied to 100+ sibling panel drivers in this tree. Six drivers (including this one) are the remaining unmigrated instances targeted by the series. --- ## PHASE 6: CROSS-REFERENCING AGAINST LOCAL TREE ### Step 6.1: Does buggy code exist? **Record:** **Yes.** `panel-tdo-tl070wsh30.c` at lines 165–166 and 186–189 still uses `drm_panel_init()` + `devm_kzalloc()`. `CONFIG_DRM_PANEL_TDO_TL070WSH30` is present in Kconfig. ### Step 6.2: Backport complications **Record:** **Clean apply expected.** Current file content matches the patch base (`index 227f97f9b136f`). Diff is identical to published v2-6/10 on spinics. No conflicting changes in this file. ### Step 6.3: Related fixes already present? **Record:** Infrastructure fix (`devm_drm_panel_alloc`) and bulk driver migration already in 6.18.43. This specific driver conversion is **not** yet applied. No alternate fix for this driver found. --- ## PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT ### Step 7.1: Subsystem criticality **Record:** `drivers/gpu/drm/panel/` — **IMPORTANT** (display subsystem). Affects embedded platforms using the TDO TL070WSH30 1024×600 DSI panel (`compatible = "tdo,tl070wsh30"`). ### Step 7.2: Subsystem activity **Record:** Actively maintained. Recent 6.18.y commits include multiple `drm/panel` fixes. Panel refcount infrastructure recently landed and bulk-converted. --- ## PHASE 8: IMPACT AND RISK ASSESSMENT ### Step 8.1: Who is affected **Record:** **Driver-specific / platform-specific** — systems with `CONFIG_DRM_PANEL_TDO_TL070WSH30` enabled and the TDO TL070WSH30 panel connected via MIPI DSI. Not universal, but real hardware (listed in `panel-simple-dsi.yaml` compatible list). ### Step 8.2: Trigger conditions **Record:** - Panel DSI device unbinds (module unload, device removal, driver unbind) while DRM display driver still holds a panel bridge reference - Requires display + panel driver interaction via `drm_of_find_panel_or_bridge()` path - **Unprivileged direct trigger:** No (requires device/module management capability) - **Likelihood:** Low-to-moderate on embedded systems with hotplug or driver reload; not every boot ### Step 8.3: Failure mode severity **Record:** **Use-after-free** → kernel oops/panic when DRM accesses freed panel memory through panel bridge. **Severity: HIGH** (crash, potential security implications from UAF). ### Step 8.4: Risk-benefit **Record:** - **Benefit:** HIGH for affected hardware — prevents UAF crash on panel unbind - **Risk:** VERY LOW — 7-line mechanical change, pattern proven across 100+ drivers, multiple maintainer reviews - **Ratio:** Strong benefit, minimal risk --- ## PHASE 9: FINAL SYNTHESIS ### Step 9.1: Evidence summary **FOR backport:** - Fixes documented UAF on panel device unbind (series cover letter) - Same pattern already applied to 100+ panel drivers in 6.18.43 - Prerequisite API (`devm_drm_panel_alloc`) exists in this tree - Buggy code still present in this tree (6 of 6 remaining `drm_panel_init()` users) - Small, surgical, reviewed by Neil Armstrong, Maxime Ripard, Dmitry Baryshkov, Thomas Zimmermann - UAF → crash is stable-worthy **AGAINST backport:** - Per-driver commit message doesn't explicitly say "fix UAF" (rationale is in series cover) - No syzbot/reporter crash report - Affects niche hardware only - Part of a series (though this patch is standalone-applicable) **Unresolved:** - `drm_panel_get()` has no external callers in this tree; exact UAF prevention mechanism relies on devm action ordering and kref-managed lifetime rather than explicit `drm_panel_get()` from bridge code. Maintainers accepted this across the subsystem. ### Step 9.2: Stable rules checklist 1. Obviously correct and tested? **PASS** — mechanical API migration, multiple Reviewed-by from maintainers, proven pattern in 100+ sibling drivers. 2. Fixes a real bug? **PASS** — UAF on panel unbind documented in series. 3. Important issue? **PASS** — UAF/crash, severity HIGH. 4. Small and contained? **PASS** — 1 file, ~14 lines changed. 5. No new features/APIs? **PASS** — uses existing `devm_drm_panel_alloc()`. 6. Can apply to local tree? **PASS** — API present, buggy code present, clean apply expected. ### Step 9.3: Exception categories **Record:** N/A — not a device ID, quirk, DT, build, or docs fix. This is a genuine memory-safety bug fix. ### Step 9.4: Decision rationale This commit completes the refcounted-allocation migration for one of the last six panel drivers still using the unsafe `devm_kzalloc()` + `drm_panel_init()` pattern in Linux 6.18.43. The prerequisite infrastructure is already in this stable tree, the vulnerable code is present, and the fix matches a pattern already applied across the vast majority of panel drivers. The series documents a real use-after-free when the panel device unbinds while the DRM subsystem retains a panel bridge reference. The change is minimal, maintainer-reviewed, and low- risk. --- ## What Problem This Solves The TDO TL070WSH30 panel driver allocates its context structure with `devm_kzalloc()`, which frees memory immediately when the panel DSI device unbinds. Display drivers that wrap the panel in a `panel_bridge` (via `drmm_panel_bridge_add()` / `devm_drm_of_get_bridge()`) can retain a pointer to the embedded `drm_panel` after that free, causing a use- after-free and potential kernel crash on subsequent DRM access. Switching to `devm_drm_panel_alloc()` ties panel memory lifetime to a `kref` with a devm-managed `drm_panel_put()` cleanup action, matching the allocation model used by the rest of the panel subsystem in 6.18.y. --- ## Verification - [Phase 1] Parsed subject, tags, body; identified series context from Link tag - [Phase 1] Fetched series cover letter at lkml.iu.edu — confirmed UAF rationale - [Phase 1] Fetched patch 6/10 at spinics.net — confirmed diff matches provided commit - [Phase 2] Read full `panel-tdo-tl070wsh30.c` — confirmed old pattern at lines 165–166, 186–189 - [Phase 2] Read `__devm_drm_panel_alloc()` in `drm_panel.c` — confirmed kref + devm put action - [Phase 3] `git describe HEAD` → `v6.18.43`; `make kernelversion` → `6.18.43` - [Phase 3] Counted drivers: 6 still use `drm_panel_init()`, 100+ use `devm_drm_panel_alloc` - [Phase 3] Verified `panel-jdi-lt070me05000.c` as example of already- converted sibling driver - [Phase 4] Series discussion at https://lkml.iu.edu/hypermail/linux/kernel/2605.1/00251.html - [Phase 4] Patch discussion at https://www.spinics.net/lists/kernel/msg6193227.html - [Phase 4] b4 dig: could not run — commit not present in local tree (no commit hash available) - [Phase 5] Traced `drmm_panel_bridge_add()` / `devm_drm_of_get_bridge()` in `bridge/panel.c` — panel pointer stored in bridge - [Phase 5] Confirmed `drm_panel_get()` has no external callers in this tree (only definition in `drm_panel.c`) - [Phase 6] Confirmed `devm_drm_panel_alloc` in `include/drm/drm_panel.h` and `drm_panel.c` - [Phase 6] Confirmed `CONFIG_DRM_PANEL_TDO_TL070WSH30` in Kconfig - [Phase 6] Confirmed `compatible = "tdo,tl070wsh30"` in DT bindings - [Phase 8] Assessed UAF → crash as HIGH severity for affected platforms **YES**The background git history lookups finished. Both searches (`-S "allocated by devm_drm_panel_alloc"` and `-S "kref_init"` / `-S "__devm_drm_panel_alloc"`) only hit the shallow tree base (`5d324e5159d9e`, the 6.18-rc8 merge), so they didn’t add finer-grained history beyond what we already verified in code. That’s consistent with this checkout: `devm_drm_panel_alloc()` and the panel refcount machinery are already in 6.18.43, while `panel-tdo- tl070wsh30.c` is still one of six drivers on the old `devm_kzalloc()` + `drm_panel_init()` path. The backport recommendation remains **YES**. drivers/gpu/drm/panel/panel-tdo-tl070wsh30.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-tdo-tl070wsh30.c b/drivers/gpu/drm/panel/panel-tdo-tl070wsh30.c index 227f97f9b136f..13cfe252a838d 100644 --- a/drivers/gpu/drm/panel/panel-tdo-tl070wsh30.c +++ b/drivers/gpu/drm/panel/panel-tdo-tl070wsh30.c @@ -162,9 +162,6 @@ static int tdo_tl070wsh30_panel_add(struct tdo_tl070wsh30_panel *tdo_tl070wsh30) return err; } - drm_panel_init(&tdo_tl070wsh30->base, &tdo_tl070wsh30->link->dev, - &tdo_tl070wsh30_panel_funcs, DRM_MODE_CONNECTOR_DSI); - err = drm_panel_of_backlight(&tdo_tl070wsh30->base); if (err) return err; @@ -183,10 +180,13 @@ static int tdo_tl070wsh30_panel_probe(struct mipi_dsi_device *dsi) dsi->format = MIPI_DSI_FMT_RGB888; dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_LPM; - tdo_tl070wsh30 = devm_kzalloc(&dsi->dev, sizeof(*tdo_tl070wsh30), - GFP_KERNEL); - if (!tdo_tl070wsh30) - return -ENOMEM; + tdo_tl070wsh30 = devm_drm_panel_alloc(&dsi->dev, + __typeof(*tdo_tl070wsh30), base, + &tdo_tl070wsh30_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + + if (IS_ERR(tdo_tl070wsh30)) + return PTR_ERR(tdo_tl070wsh30); mipi_dsi_set_drvdata(dsi, tdo_tl070wsh30); tdo_tl070wsh30->link = dsi; -- 2.53.0