From: lyude@redhat.com
To: Marek Czernohous <mczernohous@gmail.com>,
nouveau@lists.freedesktop.org, dri-devel@lists.freedesktop.org
Cc: linux-kernel@vger.kernel.org, Danilo Krummrich <dakr@kernel.org>,
David Airlie <airlied@gmail.com>, Simona Vetter <simona@ffwll.ch>
Subject: Re: [PATCH v4 2/2] drm/nouveau/kms: guard NULL crtc in nv50_sor_atomic_disable()
Date: Tue, 18 Aug 2026 16:44:08 -0400 [thread overview]
Message-ID: <e428a3e8d4c0500c112d8deb756fdec884790623.camel@redhat.com> (raw)
In-Reply-To: <178688574402.522643.5471719764843371376@gmail.com>
This isn't correct
On Sun, 2026-08-16 at 15:09 +0200, Marek Czernohous wrote:
> From: Marek Czernohous <marek@czernohous.de>
>
> nv50_sor_atomic_disable() unconditionally computes
> nv50_head(nv_encoder->crtc) and dereferences the result a few lines
> later. nv_encoder->crtc is nouveau's own shadow pointer, set in
> .atomic_enable and cleared at the end of .atomic_disable.
> Commit f575f2bdb6c3 ("drm/nouveau/kms/nv50-: Remove (nv_encoder-
> >crtc)
> checks in ->disable callbacks") removed the NULL check here,
> reasoning that the atomic helpers never call ->disable without a
> crtc. On NVAC (MCP79) under Wayland sessions (observed with Weston's
> DRM backend and with labwc/wlroots) we have hit the NULL case in
> practice during session teardown and VT switches: disable runs
> without
> (or after) its matching enable, and because nv50_head() is
> container_of(), the NULL does not stay NULL but becomes a bogus
> non-NULL pointer, so the subsequent head dereferences fault and the
> kernel oopses.
In the future you should probably put a backtrace if you've seen this
in the wild
>
> Restore the guard, as drm_WARN_ON_ONCE() instead of a silent return:
> a NULL crtc here still indicates a state-tracking inconsistency that
> should stay visible. Return without touching the output; in this
> path
> either enable never ran (nothing to tear down) or an earlier disable
> already did the teardown, and the encoder release is handled by the
> commit_tail release loop in both cases. (That loop then rejects the
> release of a never-acquired output with -EINVAL in the nvif layer,
> which is harmless; the vanilla code oopsed before ever reaching it.)
>
> The same inconsistent-state path can also leave the encoder without
> an
> old connector state, in which case nv50_outp_get_old_connector()
> returns NULL while the backlight teardown dereferenced it
> unconditionally, so the oops would only have moved there. Hoist the
> guard above all of that and look at the old connector only after
> checking it.
>
> Fixes: f575f2bdb6c3 ("drm/nouveau/kms/nv50-: Remove (nv_encoder-
> >crtc) checks in ->disable callbacks")
> Cc: <stable@vger.kernel.org>
> Tested-by: Fab Stz <fabstz-it@yahoo.fr>
> Assisted-by: Claude:claude-opus-4-7
> Assisted-by: Claude:claude-opus-4-8
> Assisted-by: Claude:claude-opus-5
> Signed-off-by: Marek Czernohous <marek@czernohous.de>
> ---
> drivers/gpu/drm/nouveau/dispnv50/disp.c | 30 ++++++++++++++++++++---
> --
> 1 file changed, 25 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c
> b/drivers/gpu/drm/nouveau/dispnv50/disp.c
> index 364227f5456f..f532b0ed8880 100644
> --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c
> +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c
> @@ -1565,16 +1565,36 @@ static void
> nv50_sor_atomic_disable(struct drm_encoder *encoder, struct
> drm_atomic_commit *state)
> {
> struct nouveau_encoder *nv_encoder =
> nouveau_encoder(encoder);
> - struct nv50_head *head = nv50_head(nv_encoder->crtc);
> + struct nv50_head *head;
> #ifdef CONFIG_DRM_NOUVEAU_BACKLIGHT
> - struct nouveau_connector *nv_connector =
> nv50_outp_get_old_connector(state, nv_encoder);
> + struct nouveau_connector *nv_connector;
> struct nouveau_drm *drm = nouveau_drm(nv_encoder-
> >base.base.dev);
> - struct nouveau_backlight *backlight = nv_connector-
> >backlight;
> - struct drm_dp_aux *aux = &nv_connector->aux;
> + struct nouveau_backlight *backlight;
> int ret;
> +#endif
>
> + /* nv_encoder->crtc is the driver's shadow pointer, set in
It's actually an outdated variable from the pre-atomic days
> + * .atomic_enable (and by the boot-time hardware readback)
> and
We don't set nv_encoder->crtc at the boot-time hardware state readback.
> + * cleared at the end of this function. NULL here
> + * means disable-without-enable or a double disable; bail
> before
> + * container_of() turns it into a bogus head pointer
> (checking the
> + * result would not work, container_of(NULL) is never
> NULL). The
> + * encoder release is handled by the commit_tail release
> loop, so
> + * there is nothing to clean up here.
> + */
this is way too verbose
> + if (drm_WARN_ON_ONCE(encoder->dev, !nv_encoder->crtc))
> + return;
> + head = nv50_head(nv_encoder->crtc);
this isn't the bug, the bug is that we're reading nv_encoder->crtc at
all here.
> +
> +#ifdef CONFIG_DRM_NOUVEAU_BACKLIGHT
> + /* The same inconsistent-state path can leave us without an
> old
> + * connector state, so check before touching it.
> + */
> + nv_connector = nv50_outp_get_old_connector(state,
> nv_encoder);
> + backlight = nv_connector ? nv_connector->backlight : NULL;
> if (backlight && backlight->uses_dpcd) {
> - ret = drm_edp_backlight_disable(aux, &backlight-
> >edp_info);
> + ret = drm_edp_backlight_disable(&nv_connector->aux,
> + &backlight-
> >edp_info);
This doesn't need changing either if we just fix where the encoder came
from.
I'll send out proper fixes for this in a moment
> if (ret < 0)
> NV_ERROR(drm, "Failed to disable backlight
> on [CONNECTOR:%d:%s]: %d\n",
> nv_connector->base.base.id,
> nv_connector->base.name, ret);
next prev parent reply other threads:[~2026-08-18 20:44 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-16 13:09 [PATCH v4 0/2] drm/nouveau: NVAC (MCP79) stability: MSI rearm and a NULL crtc guard Marek Czernohous
2026-08-16 13:09 ` [PATCH v4 2/2] drm/nouveau/kms: guard NULL crtc in nv50_sor_atomic_disable() Marek Czernohous
[not found] ` <20260816131755.1B99B1F000E9@smtp.kernel.org>
2026-08-16 16:49 ` Marek Czernohous
2026-08-18 20:44 ` lyude [this message]
2026-08-18 22:32 ` lyude
2026-08-16 13:09 ` [PATCH v4 1/2] drm/nouveau/pci: use config-space MSI rearm on MCP79/MCP7A (NVAC) Marek Czernohous
2026-08-18 20:28 ` lyude
2026-08-19 0:02 ` [PATCH v4 0/2] drm/nouveau: NVAC (MCP79) stability: MSI rearm and a NULL crtc guard lyude
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=e428a3e8d4c0500c112d8deb756fdec884790623.camel@redhat.com \
--to=lyude@redhat.com \
--cc=airlied@gmail.com \
--cc=dakr@kernel.org \
--cc=dri-devel@lists.freedesktop.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mczernohous@gmail.com \
--cc=nouveau@lists.freedesktop.org \
--cc=simona@ffwll.ch \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®