From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
To: Dirk Behme <dirk.behme@de.bosch.com>
Cc: linux-kernel@vger.kernel.org,
Rafael J Wysocki <rafael@kernel.org>,
syzbot+ffa8143439596313a85a@syzkaller.appspotmail.com,
Eugeniu Rosca <eugeniu.rosca@bosch.com>
Subject: Re: [PATCH] drivers: core: Make dev->driver usage safe in dev_uevent()
Date: Tue, 30 Apr 2024 10:57:17 +0200 [thread overview]
Message-ID: <2024043005-crusher-repaint-e02b@gregkh> (raw)
In-Reply-To: <4f197ed9-e0d2-478b-b236-bea682303e91@de.bosch.com>
On Tue, Apr 30, 2024 at 10:50:52AM +0200, Dirk Behme wrote:
> On 30.04.2024 10:41, Greg Kroah-Hartman wrote:
> > On Tue, Apr 30, 2024 at 10:23:36AM +0200, Dirk Behme wrote:
> > > Hi Greg,
> > >
> > > On 30.04.2024 09:20, Greg Kroah-Hartman wrote:
> > > > On Tue, Apr 30, 2024 at 06:55:31AM +0200, Dirk Behme wrote:
> > > > > Inspired by the function dev_driver_string() in the same file make sure
> > > > > in case of uninitialization dev->driver is used safely in dev_uevent(),
> > > > > as well.
> > > >
> > > > I think you are racing and just getting "lucky" with your change here,
> > > > just like dev_driver_string() is doing there (that READ_ONCE() really
> > > > isn't doing much to protect you...)
> > > >
> > > > > This change is based on the observation of the following race condition:
> > > > >
> > > > > Thread #1:
> > > > > ==========
> > > > >
> > > > > really_probe() {
> > > > > ...
> > > > > probe_failed:
> > > > > ...
> > > > > device_unbind_cleanup(dev) {
> > > > > ...
> > > > > dev->driver = NULL; // <= Failed probe sets dev->driver to NULL
> > > > > ...
> > > > > }
> > > > > ...
> > > > > }
> > > > >
> > > > > Thread #2:
> > > > > ==========
> > > > >
> > > > > dev_uevent() {
> > > >
> > > > Wait, how can dev_uevent() be called if probe fails? Who is calling
> > > > that?
> > > >
> > > > > ...
> > > > > if (dev->driver)
> > > > > // If dev->driver is NULLed from really_probe() from here on,
> > > > > // after above check, the system crashes
> > > > > add_uevent_var(env, "DRIVER=%s", dev->driver->name);
> > > > >
> > > > > dev_driver_string() can't be used here because we want NULL and not
> > > > > anything else in the non-init case.
> > > > >
> > > > > Similar cases are reported by syzkaller in
> > > > >
> > > > > https://syzkaller.appspot.com/bug?extid=ffa8143439596313a85a
> > > > >
> > > > > But these are regarding the *initialization* of dev->driver
> > > > >
> > > > > dev->driver = drv;
> > > > >
> > > > > As this switches dev->driver to non-NULL these reports can be considered
> > > > > to be false-positives (which should be "fixed" by this commit, as well,
> > > > > though).
> > > > >
> > > > > Fixes: 239378f16aa1 ("Driver core: add uevent vars for devices of a class")
> > > > > Cc: syzbot+ffa8143439596313a85a@syzkaller.appspotmail.com
> > > > > Reviewed-by: Eugeniu Rosca <eugeniu.rosca@bosch.com>
> > > > > Tested-by: Eugeniu Rosca <eugeniu.rosca@bosch.com>
> > > > > Signed-off-by: Dirk Behme <dirk.behme@de.bosch.com>
> > > > > ---
> > > > > drivers/base/core.c | 9 +++++++--
> > > > > 1 file changed, 7 insertions(+), 2 deletions(-)
> > > > >
> > > > > diff --git a/drivers/base/core.c b/drivers/base/core.c
> > > > > index 5f4e03336e68..99ead727c08f 100644
> > > > > --- a/drivers/base/core.c
> > > > > +++ b/drivers/base/core.c
> > > > > @@ -2639,6 +2639,7 @@ static const char *dev_uevent_name(const struct kobject *kobj)
> > > > > static int dev_uevent(const struct kobject *kobj, struct kobj_uevent_env *env)
> > > > > {
> > > > > const struct device *dev = kobj_to_dev(kobj);
> > > > > + struct device_driver *drv;
> > > > > int retval = 0;
> > > > > /* add device node properties if present */
> > > > > @@ -2667,8 +2668,12 @@ static int dev_uevent(const struct kobject *kobj, struct kobj_uevent_env *env)
> > > > > if (dev->type && dev->type->name)
> > > > > add_uevent_var(env, "DEVTYPE=%s", dev->type->name);
> > > > > - if (dev->driver)
> > > > > - add_uevent_var(env, "DRIVER=%s", dev->driver->name);
> > > > > + /* dev->driver can change to NULL underneath us because of unbinding
> > > > > + * or failing probe(), so be careful about accessing it.
> > > > > + */
> > > > > + drv = READ_ONCE(dev->driver);
> > > > > + if (drv)
> > > > > + add_uevent_var(env, "DRIVER=%s", drv->name);
> > > >
> > > > Again, you are just reducing the window here. Maybe a bit, but not all
> > > > that much overall as there is no real lock present.
> > > >
> > > > So how is this actually solving anything?
> > >
> > >
> > > Looking at dev_driver_string() I hoped that it just reads *once*. I.e. we
> > > don't care if we read NULL or any valid pointer, as long as this pointer
> > > read is done only once ("atomically"?). If READ_ONCE() doesn't do that, I
> > > agree, it's not the (race) fix we are looking for.
> >
> > Yes, what if you read it, and then it is unloaded from the system before
> > you attempt to access drv->name? not good.
> >
> > > Initially, I was thinking about anything like [1] below. I.e. adding a mutex
> > > lock. But not sure if that is better (acceptable?).
> >
> > a proper lock is the only way to correctly solve this.
>
>
> Would using device_lock()/unlock() for locking like done below [1]
> acceptable?
Why not test it out and see! :)
next prev parent reply other threads:[~2024-04-30 8:57 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-04-30 4:55 [PATCH] drivers: core: Make dev->driver usage safe in dev_uevent() Dirk Behme
2024-04-30 7:20 ` Greg Kroah-Hartman
2024-04-30 8:17 ` Eugeniu Rosca
2024-04-30 8:27 ` Greg Kroah-Hartman
2024-04-30 13:18 ` Eugeniu Rosca
2024-04-30 8:23 ` Dirk Behme
2024-04-30 8:41 ` Greg Kroah-Hartman
2024-04-30 8:50 ` Dirk Behme
2024-04-30 8:57 ` Greg Kroah-Hartman [this message]
2024-05-06 6:04 ` Dirk Behme
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=2024043005-crusher-repaint-e02b@gregkh \
--to=gregkh@linuxfoundation.org \
--cc=dirk.behme@de.bosch.com \
--cc=eugeniu.rosca@bosch.com \
--cc=linux-kernel@vger.kernel.org \
--cc=rafael@kernel.org \
--cc=syzbot+ffa8143439596313a85a@syzkaller.appspotmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.