lists.openwall.net | lists / announce owl-users owl-dev john-users john-dev passwdqc-users yescrypt popa3d-users / oss-security kernel-hardening musl sabotage tlsify passwords / crypt-dev xvendor / Bugtraq Full-Disclosure linux-kernel linux-netdev linux-ext4 linux-hardening linux-cve-announce PHC | |
Open Source and information security mailing list archives
| ||
|
Date: Wed, 26 Apr 2017 07:51:32 -0700 From: Adrian Salido <salidoa@...gle.com> To: Greg KH <gregkh@...uxfoundation.org> Cc: linux-kernel@...r.kernel.org Subject: Re: [PATCH] driver core: platform: fix race condition with driver_override > > The driver_override implementation is susceptible to race condition when > > different threads are reading vs storing a different driver override. > > Add locking to avoid race condition. > > > > Fixes: 3d713e0e382e ("driver core: platform: add device binding path 'driver_override'") > > Cc: stable@...r.kernel.org > > Signed-off-by: Adrian Salido <salidoa@...gle.com> > > --- > > drivers/base/platform.c | 11 +++++++++-- > > 1 file changed, 9 insertions(+), 2 deletions(-) > > > > diff --git a/drivers/base/platform.c b/drivers/base/platform.c > > index c2456839214a..493e03fa0e07 100644 > > --- a/drivers/base/platform.c > > +++ b/drivers/base/platform.c > > @@ -866,7 +866,7 @@ static ssize_t driver_override_store(struct device *dev, > > const char *buf, size_t count) > > { > > struct platform_device *pdev = to_platform_device(dev); > > - char *driver_override, *old = pdev->driver_override, *cp; > > + char *driver_override, *old, *cp; > > > > if (count > PATH_MAX) > > return -EINVAL; > > @@ -879,12 +879,15 @@ static ssize_t driver_override_store(struct device *dev, > > if (cp) > > *cp = '\0'; > > > > + device_lock(dev); > > + old = pdev->driver_override; > > if (strlen(driver_override)) { > > pdev->driver_override = driver_override; > > } else { > > kfree(driver_override); > > pdev->driver_override = NULL; > > } > > + device_unlock(dev); > > > > kfree(old); > > Shouldn't you move the lock until after the kfree()? Or am I missing > what the lock is trying to protect here? not really, the lock only protecting the variable pdev->driver_override. Once the value has changed we no longer care about "old" variable > > if (cp) > > *cp = '\0'; > > > > + device_lock(dev); > > + old = pdev->driver_override; > > if (strlen(driver_override)) { > > pdev->driver_override = driver_override; > > } else { > > kfree(driver_override); > > pdev->driver_override = NULL; > > } > > + device_unlock(dev); > > > > kfree(old); > > > > > @@ -895,8 +898,12 @@ static ssize_t driver_override_show(struct device *dev, > > struct device_attribute *attr, char *buf) > > { > > struct platform_device *pdev = to_platform_device(dev); > > + ssize_t len; > > > > - return sprintf(buf, "%s\n", pdev->driver_override); > > + device_lock(dev); > > + len = sprintf(buf, "%s\n", pdev->driver_override); > > + device_unlock(dev); > > + return len; > > Why does the show function need to be changed at all? How can anything > "race" here? The lock is trying to protect again race between store and show. Suppose there are 2 threads: Thread1: while (1) { driver_override_store("foo"); driver_override_store(""); } Thread2: while (1) driver_override_show(); Thread 1 | Thread 2 ----------------------------------------|----------------------- old = pdev->driver_override; | | len = sprintf(buf, "%s\n", pdev->driver_override); | /* snprintf starts reading */ pdev->driver_override = | driver_override; | kfree(old); | /* use after free before snprintf finishes execution */ Similarly there could be a race between multiple threads doing store where memory leaks could happen Thanks, Adrian
Powered by blists - more mailing lists