Re: [PATCH] workqueue: Try to catch flush_work() without INIT_WORK().

From: Tetsuo Handa
Date: Fri Jan 18 2019 - 21:41:43 EST


On 2019/01/19 4:48, Daniel Jordan wrote:
> On Sat, Jan 19, 2019 at 02:04:58AM +0900, Tetsuo Handa wrote:
>> syzbot found a flush_work() caller who forgot to call INIT_WORK()
>> because that work_struct was allocated by kzalloc(). But the message
>>
>> INFO: trying to register non-static key.
>> the code is fine but needs lockdep annotation.
>> turning off the locking correctness validator.
>>
>> by lock_map_acquire() is failing to tell that INIT_WORK() is missing.
>>
>> Since flush_work() without INIT_WORK() is a bug, and INIT_WORK() should
>> set ->func field to non-zero, let's warn if ->func field is zero.
>
> Agree that it's a good idea to catch this. So the caller did flush_work
> without queueing it beforehand? Out of curiosity, what situation leads to
> this? Link to the report might be helpful.

I quoted the patch below.

>
>> diff --git a/kernel/workqueue.c b/kernel/workqueue.c
>> index 392be4b..a503ad9 100644
>> --- a/kernel/workqueue.c
>> +++ b/kernel/workqueue.c
>> @@ -2908,6 +2908,9 @@ static bool __flush_work(struct work_struct *work, bool from_cancel)
>> if (WARN_ON(!wq_online))
>> return false;
>>
>> + if (WARN_ON(!work->func))
>> + return false;
>> +
>
> __queue_work has a sanity check already for work, but using list_empty. Seems
> slightly better to be consistent?
>

list_empty() won't work, for "struct work_struct" is embedded into a struct
which is allocated by kzalloc().