On Thu Jul 16, 2026 at 5:28 PM CST, sashiko-bot wrote:
> Thank you for your contribution! Sashiko AI review found 3 potential issue(s) 
> to consider:
>
> New issues:
> - [Critical] Global state data race in `atomic_enable` leading to a NULL 
> pointer dereference.
> - [High] Pending vblank events are leaked when the CRTC is disabled, causing 
> userspace to hang.
>
> Pre-existing issues:
> - [High] Global state data race in `atomic_update` causing stolen events and 
> userspace hangs.
> --
>
> --- Patch [8]: [PATCH v2 8/8] drm/xen: replace struct drm_simple_display_pipe 
> with regular atomic helpers ---
> commit 545da3a98a8e32db9ed9bc44680620afafb3b601
> Author: Ze Huang <[email protected]>
>
> drm/xen: replace struct drm_simple_display_pipe with regular atomic helpers
>
> Replace Xen frontend simple display pipe with explicit plane, CRTC and
> encoder objects for each pipeline.
>
>> diff --git a/drivers/gpu/drm/xen/xen_drm_front_kms.c 
>> b/drivers/gpu/drm/xen/xen_drm_front_kms.c
>> --- a/drivers/gpu/drm/xen/xen_drm_front_kms.c
>> +++ b/drivers/gpu/drm/xen/xen_drm_front_kms.c
>> @@ -105,24 +111,21 @@ static void send_pending_event(struct 
>> xen_drm_front_drm_pipeline *pipeline)
>>      spin_unlock_irqrestore(&dev->event_lock, flags);
>>  }
>>  
>> -static void display_enable(struct drm_simple_display_pipe *pipe,
>> -                       struct drm_crtc_state *crtc_state,
>> -                       struct drm_plane_state *plane_state)
>> +static void xen_drm_crtc_helper_atomic_enable(struct drm_crtc *crtc,
>> +                                          struct drm_atomic_commit *commit)
>>  {
>> -    struct xen_drm_front_drm_pipeline *pipeline =
>> -                    to_xen_drm_pipeline(pipe);
>> -    struct drm_crtc *crtc = &pipe->crtc;
>> +    struct xen_drm_front_drm_pipeline *pipeline = 
>> xen_drm_pipeline_from_crtc(crtc);
>> +    struct drm_plane_state *plane_state = pipeline->plane.state;
>> +    struct drm_framebuffer *fb = plane_state->fb;
>>      int ret, idx;
>>  
>> -    if (!drm_dev_enter(pipe->crtc.dev, &idx))
>> +    if (!drm_dev_enter(crtc->dev, &idx))
>>              return;
>>  
>>      ret = xen_drm_front_mode_set(pipeline, crtc->x, crtc->y,
>>                                   fb->width, fb->height,
>
> [Severity: Critical]
> Can this sequence cause a NULL pointer dereference?
>
> In xen_drm_crtc_helper_atomic_enable(), the global plane state is
> read asynchronously and fb is dereferenced directly.
>
> If userspace submits two non-blocking atomic commits rapidly (the
> first enabling the CRTC and plane, and the second disabling the plane),
> the global state pointer (pipeline->plane.state) is swapped
> synchronously during the ioctl.
>
> When the first commit's worker executes, it reads the newer state where
> fb is NULL, and unconditionally dereferences fb->width.
>
> Would it be safer to extract the state from the commit object using
> drm_atomic_get_new_plane_state(commit, &pipeline->plane)?

As replied in patch 5, will do

>
>>                                   fb->format->cpp[0] * 8,
>>                                   xen_drm_front_fb_to_cookie(fb));
>> -
>>      if (ret) {
>>              DRM_ERROR("Failed to enable display: %d\n", ret);
>
> [ ... ]
>
>> @@ -131,13 +134,13 @@ static void display_enable(struct 
>> drm_simple_display_pipe *pipe,
>>      drm_dev_exit(idx);
>>  }
>>  
>> -static void display_disable(struct drm_simple_display_pipe *pipe)
>> +static void xen_drm_crtc_helper_atomic_disable(struct drm_crtc *crtc,
>> +                                           struct drm_atomic_commit *commit)
>>  {
>> -    struct xen_drm_front_drm_pipeline *pipeline =
>> -                    to_xen_drm_pipeline(pipe);
>> +    struct xen_drm_front_drm_pipeline *pipeline = 
>> xen_drm_pipeline_from_crtc(crtc);
>>      int ret = 0, idx;
>>  
>> -    if (drm_dev_enter(pipe->crtc.dev, &idx)) {
>> +    if (drm_dev_enter(crtc->dev, &idx)) {
>>              ret = xen_drm_front_mode_set(pipeline, 0, 0, 0, 0, 0,
>>                                           xen_drm_front_fb_to_cookie(NULL));
>>              drm_dev_exit(idx);
>> @@ -147,6 +150,11 @@ static void display_disable(struct 
>> drm_simple_display_pipe *pipe)
>>  
>>      /* Make sure we can restart with enabled connector next time */
>>      pipeline->conn_connected = true;
>> +
>> +    /* release stalled event if any */
>> +    send_pending_event(pipeline);
>> +}
>
> [Severity: High]
> Does this function leak the vblank event when the CRTC is disabled?
>
> When moving away from drm_simple_kms_helper, the driver loses the core
> helper's automatic consumption of crtc_state->event during CRTC
> disable.
>
> If userspace submits an atomic commit that disables the CRTC and
> requests a vblank event (e.g., modeset to 0 or DPMS off),
> xen_drm_crtc_helper_atomic_disable() completely omits the consumption and
> signaling of the event.
>
> This leaves the event dangling, which causes a kernel warning in the
> commit tail and hangs the userspace compositor indefinitely as it waits
> for the pageflip event.
>
> Should this function pull and signal the event from
> drm_atomic_get_new_crtc_state(commit, crtc)->event?
>

I would like to preserve the original xen frontend behavior here.

> [ ... ]
>
>> @@ -242,12 +261,12 @@ static int display_check(struct 
>> drm_simple_display_pipe *pipe,
>>      return 0;
>>  }
>>  
>> -static void display_update(struct drm_simple_display_pipe *pipe,
>> -                       struct drm_plane_state *old_plane_state)
>> +static void xen_drm_plane_helper_atomic_update(struct drm_plane *plane,
>> +                                           struct drm_atomic_commit *commit)
>>  {
>> -    struct xen_drm_front_drm_pipeline *pipeline =
>> -                    to_xen_drm_pipeline(pipe);
>> -    struct drm_crtc *crtc = &pipe->crtc;
>> +    struct drm_plane_state *old_plane_state = 
>> drm_atomic_get_old_plane_state(commit, plane);
>> +    struct xen_drm_front_drm_pipeline *pipeline = 
>> xen_drm_pipeline_from_plane(plane);
>> +    struct drm_crtc *crtc = &pipeline->crtc;
>>      struct drm_pending_vblank_event *event;
>>      int idx;
>
> [Severity: High]
> This is a pre-existing issue, but can this code steal events from
> future commits?
>
> In xen_drm_plane_helper_atomic_update(), the global CRTC state's event
> is accessed directly:
>
> event = crtc->state->event;
>
> Since crtc->state is swapped synchronously, it may reflect a future
> commit's state by the time this worker runs. The worker would then steal
> the future commit's event and clear it.
>
> When the future commit's worker runs, it finds no event, while the
> current commit's original event is stranded on its old state object and
> never signaled, resulting in userspace hangs.
>
> Should the event be fetched reliably from the specific commit object
> using drm_atomic_get_new_crtc_state(commit, crtc)->event?

Will access crtc state with drm_atomic_get_new_crtc_state(commit, crtc)

Reply via email to