Thank you for your contribution! Sashiko AI review found 1 potential issue(s) 
to consider:
- [Medium] fbcon: race in fbcon_del_cursor_work() lets fb_flashcursor() re-arm 
work
--

commit e9056993ba6eca270987e2b77d6a3977beffec71
Author: Yao Yiqi <[email protected]>

fbcon: Avoid cancel_delayed_work_sync() in atomic context

This commit replaces cancel_delayed_work_sync() with cancel_delayed_work() in
fbcon_del_cursor_work() to avoid sleeping in atomic console printing contexts,
while adding fbcon_del_cursor_work_sync() for teardown in fbcon_release() and
moving the delayed work requeue in fb_flashcursor() inside console_lock.

> diff --git a/drivers/video/fbdev/core/fbcon.c 
> b/drivers/video/fbdev/core/fbcon.c
> index 7720dfc80c165..066cd974ea3bb 100644
> --- a/drivers/video/fbdev/core/fbcon.c
> +++ b/drivers/video/fbdev/core/fbcon.c
> @@ -422,10 +422,14 @@ static void fb_flashcursor(struct work_struct *work)
>       par->bitops->cursor(vc, info, enable,
>                           get_fg_color(vc, info, c),
>                           get_bg_color(vc, info, c));
> -     console_unlock();
>  
> +     /*
> +      * Re-arm under console_lock so that a concurrent
> +      * fbcon_del_cursor_work() cannot race with this requeue.
> +      */
>       queue_delayed_work(system_power_efficient_wq, &par->cursor_work,
>                          par->cur_blink_jiffies);
> +     console_unlock();
>  }
>  
>  static void fbcon_add_cursor_work(struct fb_info *info)
> @@ -437,10 +441,30 @@ static void fbcon_add_cursor_work(struct fb_info *info)
>                                  par->cur_blink_jiffies);
>  }
>  
> +/*
> + * Stop the cursor blink.
> + *
> + * Does not wait for a callback that is already running, so it is safe to
> + * call from any context.
> + *
> + * console_lock serializes this with the requeue in fb_flashcursor();
> + * otherwise a running callback could re-arm the work.
> + */
>  static void fbcon_del_cursor_work(struct fb_info *info)
>  {
>       struct fbcon_par *par = info->fbcon_par;
>  
> +     cancel_delayed_work(&par->cursor_work);
> +}

[Severity: Medium]
Can fb_flashcursor() still race with fbcon_del_cursor_work() and re-arm
par->cursor_work after blinking has been stopped?

When par->cursor_work expires, process_one_work() clears
WORK_STRUCT_PENDING_BIT before invoking fb_flashcursor(). If a caller holding
console_lock (such as cursor_blink_store(), fbcon_blank(), fbcon_switch(),
fbcon_deinit(), or fbcon_cursor() with CUR_SW) runs fbcon_del_cursor_work()
after WORK_STRUCT_PENDING_BIT is cleared, but before the worker executes
console_trylock() in fb_flashcursor():

CPU0 (holding console_lock)          CPU1 (worker thread)
                                     process_one_work()
                                       /* clears WORK_STRUCT_PENDING_BIT */
                                       fb_flashcursor()
fbcon_del_cursor_work()
  cancel_delayed_work(&par->cursor_work)
  /* returns false without waiting */
console_unlock()
                                         ret = console_trylock();
                                         /* succeeds */

Because fb_flashcursor() only checks:

        if (!vc || !con_is_visible(vc) ||
            fbcon_info_from_console(vc->vc_num) != info ||
            vc->vc_deccm != 1) {
                console_unlock();
                return;
        }

and does not verify whether blinking is still supposed to be active (for
example fbcon_cursor_blink, vc->vc_cursor_type & CUR_SW,par->graphics /
KD_GRAPHICS, par->blank_state, or par->initialized), won't it draw the cursor
and call queue_delayed_work() to perpetually re-arm par->cursor_work?

-- 
Sashiko AI review ยท 
https://sashiko.dev/#/patchset/[email protected]?part=1

Reply via email to