Re: [BUG] drivers: adm9240: possible data race bug in adm9240_fan_read()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, Sep 22, 2022 at 2:53 PM Guenter Roeck <linux@xxxxxxxxxxxx> wrote:
>
> On 9/22/22 13:37, Li Zhong wrote:
> > On Wed, Sep 21, 2022 at 8:16 PM Guenter Roeck <linux@xxxxxxxxxxxx> 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.



[Index of Archives]     [LM Sensors]     [Linux Sound]     [ALSA Users]     [ALSA Devel]     [Linux Audio Users]     [Linux Media]     [Kernel]     [Gimp]     [Yosemite News]     [Linux Media]

  Powered by Linux