linux-hwmon.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [BUG] drivers: adm9240: possible data race bug in adm9240_fan_read()
@ 2022-09-21 23:31 Li Zhong
  2022-09-22  3:16 ` Guenter Roeck
  0 siblings, 1 reply; 5+ messages in thread
From: Li Zhong @ 2022-09-21 23:31 UTC (permalink / raw)
  To: linux-hwmon; +Cc: linux, jdelvare, Li Zhong

Hello,

My static analysis tool reports a possible bug in the adm9240 driver in Linux
v6.0:

drivers/hwmon/adm9240.c:

adm9240_read()
    adm9240_fan_read() --> Line 509
        adm9240_write_fan_div()

adm9240_write_fan_div() says 'callers must hold
data->update_lock'. However, it seems like the context does
not hold the lock it requires. So it may cause data race when
setting new fan div.

I am not quite sure whether this is a real bug. Any feedback would be
appreciated!

Thanks,
Li Zhong

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [BUG] drivers: adm9240: possible data race bug in adm9240_fan_read()
  2022-09-21 23:31 [BUG] drivers: adm9240: possible data race bug in adm9240_fan_read() Li Zhong
@ 2022-09-22  3:16 ` Guenter Roeck
  2022-09-22 20:37   ` Li Zhong
  0 siblings, 1 reply; 5+ messages in thread
From: Guenter Roeck @ 2022-09-22  3:16 UTC (permalink / raw)
  To: Li Zhong, linux-hwmon; +Cc: jdelvare

On 9/21/22 16:31, Li Zhong wrote:
> Hello,
> 
> My static analysis tool reports a possible bug in the adm9240 driver in Linux
> v6.0:
> 
> drivers/hwmon/adm9240.c:
> 
> adm9240_read()
>      adm9240_fan_read() --> Line 509
>          adm9240_write_fan_div()
> 
> adm9240_write_fan_div() says 'callers must hold
> data->update_lock'. However, it seems like the context does
> not hold the lock it requires. So it may cause data race when
> setting new fan div.
> 
> I am not quite sure whether this is a real bug. Any feedback would be
> appreciated!
> 

You are correct, the code in adm9240_fan_read() should acquire
the mutex before calling adm9240_write_fan_div() and while
manipulating data->fan_div[channel].

Guenter

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [BUG] drivers: adm9240: possible data race bug in adm9240_fan_read()
  2022-09-22  3:16 ` Guenter Roeck
@ 2022-09-22 20:37   ` Li Zhong
  2022-09-22 21:53     ` Guenter Roeck
  0 siblings, 1 reply; 5+ messages in thread
From: Li Zhong @ 2022-09-22 20:37 UTC (permalink / raw)
  To: Guenter Roeck; +Cc: linux-hwmon, jdelvare

On Wed, Sep 21, 2022 at 8:16 PM Guenter Roeck <linux@roeck-us.net> wrote:
>
> On 9/21/22 16:31, Li Zhong wrote:
> > Hello,
> >
> > My static analysis tool reports a possible bug in the adm9240 driver in Linux
> > v6.0:
> >
> > drivers/hwmon/adm9240.c:
> >
> > adm9240_read()
> >      adm9240_fan_read() --> Line 509
> >          adm9240_write_fan_div()
> >
> > adm9240_write_fan_div() says 'callers must hold
> > data->update_lock'. However, it seems like the context does
> > not hold the lock it requires. So it may cause data race when
> > setting new fan div.
> >
> > I am not quite sure whether this is a real bug. Any feedback would be
> > appreciated!
> >
>
> You are correct, the code in adm9240_fan_read() should acquire
> the mutex before calling adm9240_write_fan_div() and while
> manipulating data->fan_div[channel].
>
> Guenter

Thanks for your patient reply! Can I submit a patch on this? The draft will
be something like:

+  mutex_lock(&data->update_lock)
    err = adm9240_write_fan_div(data, channel, ++data->fan_div[channel]);
    if (err)
        return err;
+  mutex_unlock(&data->update_lock);

Let me know if you have any suggestions!

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [BUG] drivers: adm9240: possible data race bug in adm9240_fan_read()
  2022-09-22 20:37   ` Li Zhong
@ 2022-09-22 21:53     ` Guenter Roeck
  2022-09-22 23:46       ` Li Zhong
  0 siblings, 1 reply; 5+ messages in thread
From: Guenter Roeck @ 2022-09-22 21:53 UTC (permalink / raw)
  To: Li Zhong; +Cc: linux-hwmon, jdelvare

On 9/22/22 13:37, Li Zhong wrote:
> On Wed, Sep 21, 2022 at 8:16 PM Guenter Roeck <linux@roeck-us.net> wrote:
>>
>> On 9/21/22 16:31, Li Zhong wrote:
>>> Hello,
>>>
>>> My static analysis tool reports a possible bug in the adm9240 driver in Linux
>>> v6.0:
>>>
>>> drivers/hwmon/adm9240.c:
>>>
>>> adm9240_read()
>>>       adm9240_fan_read() --> Line 509
>>>           adm9240_write_fan_div()
>>>
>>> adm9240_write_fan_div() says 'callers must hold
>>> data->update_lock'. However, it seems like the context does
>>> not hold the lock it requires. So it may cause data race when
>>> setting new fan div.
>>>
>>> I am not quite sure whether this is a real bug. Any feedback would be
>>> appreciated!
>>>
>>
>> You are correct, the code in adm9240_fan_read() should acquire
>> the mutex before calling adm9240_write_fan_div() and while
>> manipulating data->fan_div[channel].
>>
>> Guenter
> 
> Thanks for your patient reply! Can I submit a patch on this? The draft will
> be something like:
> 
> +  mutex_lock(&data->update_lock)
>      err = adm9240_write_fan_div(data, channel, ++data->fan_div[channel]);
>      if (err)
>          return err;
> +  mutex_unlock(&data->update_lock);
> 
> Let me know if you have any suggestions!

That would leave the mutex in locked state after an error, and it does not
take into account that data->fan_div[channel] might still change after being
checked but before being used. The lock has to be around the if() statement,
and the lock must be released after an error was observed.

At the very least, the code has to be something like

	...
	mutex_lock(&data->update_lock);
         if (regval == 255 && data->fan_div[channel] < 3) {
                 /* adjust fan clock divider on overflow */
                 err = adm9240_write_fan_div(data, channel,
                                             ++data->fan_div[channel]);
                 if (err) {
			mutex_unlock(&data->update_lock);
                         return err;
		}
         }
	mutex_unlock(&data->update_lock);
	...

However, that isn't perfect since the fan divisor and the fan speed
register value are not in sync. Technically it needs to be something like

	u8 fan_div;
	...

	mutex_lock(&data->update_lock);
	err = regmap_read(data->regmap, ADM9240_REG_FAN(channel), &regval);
	if (err) {
		mutex_unlock(&data->update_lock);
		return err;
	}
	fan_div = data->fan_div[channel];
	if (regval == 255 && fan_div < 3) {
		err = adm9240_write_fan_div(data, channel, fan_div + 1);
		if (err) {
			mutex_unlock(&data->update_lock);
			return err;
		}
		data->fan_div[channel] = fan_div + 1;
	}
	mutex_unlock(&data->update_lock);
	*val = FAN_FROM_REG(regval, BIT(fan_div));
	break;

Thanks,
Guenter

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [BUG] drivers: adm9240: possible data race bug in adm9240_fan_read()
  2022-09-22 21:53     ` Guenter Roeck
@ 2022-09-22 23:46       ` Li Zhong
  0 siblings, 0 replies; 5+ messages in thread
From: Li Zhong @ 2022-09-22 23:46 UTC (permalink / raw)
  To: Guenter Roeck; +Cc: linux-hwmon, jdelvare

On Thu, Sep 22, 2022 at 2:53 PM Guenter Roeck <linux@roeck-us.net> wrote:
>
> On 9/22/22 13:37, Li Zhong wrote:
> > On Wed, Sep 21, 2022 at 8:16 PM Guenter Roeck <linux@roeck-us.net> wrote:
> >>
> >> On 9/21/22 16:31, Li Zhong wrote:
> >>> Hello,
> >>>
> >>> My static analysis tool reports a possible bug in the adm9240 driver in Linux
> >>> v6.0:
> >>>
> >>> drivers/hwmon/adm9240.c:
> >>>
> >>> adm9240_read()
> >>>       adm9240_fan_read() --> Line 509
> >>>           adm9240_write_fan_div()
> >>>
> >>> adm9240_write_fan_div() says 'callers must hold
> >>> data->update_lock'. However, it seems like the context does
> >>> not hold the lock it requires. So it may cause data race when
> >>> setting new fan div.
> >>>
> >>> I am not quite sure whether this is a real bug. Any feedback would be
> >>> appreciated!
> >>>
> >>
> >> You are correct, the code in adm9240_fan_read() should acquire
> >> the mutex before calling adm9240_write_fan_div() and while
> >> manipulating data->fan_div[channel].
> >>
> >> Guenter
> >
> > Thanks for your patient reply! Can I submit a patch on this? The draft will
> > be something like:
> >
> > +  mutex_lock(&data->update_lock)
> >      err = adm9240_write_fan_div(data, channel, ++data->fan_div[channel]);
> >      if (err)
> >          return err;
> > +  mutex_unlock(&data->update_lock);
> >
> > Let me know if you have any suggestions!
>
> That would leave the mutex in locked state after an error, and it does not
> take into account that data->fan_div[channel] might still change after being
> checked but before being used. The lock has to be around the if() statement,
> and the lock must be released after an error was observed.
>
> At the very least, the code has to be something like
>
>         ...
>         mutex_lock(&data->update_lock);
>          if (regval == 255 && data->fan_div[channel] < 3) {
>                  /* adjust fan clock divider on overflow */
>                  err = adm9240_write_fan_div(data, channel,
>                                              ++data->fan_div[channel]);
>                  if (err) {
>                         mutex_unlock(&data->update_lock);
>                          return err;
>                 }
>          }
>         mutex_unlock(&data->update_lock);
>         ...
>
> However, that isn't perfect since the fan divisor and the fan speed
> register value are not in sync. Technically it needs to be something like
>
>         u8 fan_div;
>         ...
>
>         mutex_lock(&data->update_lock);
>         err = regmap_read(data->regmap, ADM9240_REG_FAN(channel), &regval);
>         if (err) {
>                 mutex_unlock(&data->update_lock);
>                 return err;
>         }
>         fan_div = data->fan_div[channel];
>         if (regval == 255 && fan_div < 3) {
>                 err = adm9240_write_fan_div(data, channel, fan_div + 1);
>                 if (err) {
>                         mutex_unlock(&data->update_lock);
>                         return err;
>                 }
>                 data->fan_div[channel] = fan_div + 1;
>         }
>         mutex_unlock(&data->update_lock);
>         *val = FAN_FROM_REG(regval, BIT(fan_div));
>         break;
>
> Thanks,
> Guenter

Thanks for your suggestions and drafts! I submit the patch.

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2022-09-22 23:47 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-09-21 23:31 [BUG] drivers: adm9240: possible data race bug in adm9240_fan_read() Li Zhong
2022-09-22  3:16 ` Guenter Roeck
2022-09-22 20:37   ` Li Zhong
2022-09-22 21:53     ` Guenter Roeck
2022-09-22 23:46       ` Li Zhong

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).