| From 6f957724b94cb19f5c1c97efd01dd4df8ced323c Mon Sep 17 00:00:00 2001 |
| From: Linus Torvalds <torvalds@linux-foundation.org> |
| Date: Thu, 9 Jul 2015 11:20:01 -0700 |
| Subject: Fix firmware loader uevent buffer NULL pointer dereference |
| |
| From: Linus Torvalds <torvalds@linux-foundation.org> |
| |
| commit 6f957724b94cb19f5c1c97efd01dd4df8ced323c upstream. |
| |
| The firmware class uevent function accessed the "fw_priv->buf" buffer |
| without the proper locking and testing for NULL. This is an old bug |
| (looks like it goes back to 2012 and commit 1244691c73b2: "firmware |
| loader: introduce firmware_buf"), but for some reason it's triggering |
| only now in 4.2-rc1. |
| |
| Shuah Khan is trying to bisect what it is that causes this to trigger |
| more easily, but in the meantime let's just fix the bug since others are |
| hitting it too (at least Ingo reports having seen it as well). |
| |
| Reported-and-tested-by: Shuah Khan <shuahkh@osg.samsung.com> |
| Acked-by: Ming Lei <ming.lei@canonical.com> |
| Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/base/firmware_class.c | 16 +++++++++++++--- |
| 1 file changed, 13 insertions(+), 3 deletions(-) |
| |
| --- a/drivers/base/firmware_class.c |
| +++ b/drivers/base/firmware_class.c |
| @@ -513,10 +513,8 @@ static void fw_dev_release(struct device |
| module_put(THIS_MODULE); |
| } |
| |
| -static int firmware_uevent(struct device *dev, struct kobj_uevent_env *env) |
| +static int do_firmware_uevent(struct firmware_priv *fw_priv, struct kobj_uevent_env *env) |
| { |
| - struct firmware_priv *fw_priv = to_firmware_priv(dev); |
| - |
| if (add_uevent_var(env, "FIRMWARE=%s", fw_priv->buf->fw_id)) |
| return -ENOMEM; |
| if (add_uevent_var(env, "TIMEOUT=%i", loading_timeout)) |
| @@ -527,6 +525,18 @@ static int firmware_uevent(struct device |
| return 0; |
| } |
| |
| +static int firmware_uevent(struct device *dev, struct kobj_uevent_env *env) |
| +{ |
| + struct firmware_priv *fw_priv = to_firmware_priv(dev); |
| + int err = 0; |
| + |
| + mutex_lock(&fw_lock); |
| + if (fw_priv->buf) |
| + err = do_firmware_uevent(fw_priv, env); |
| + mutex_unlock(&fw_lock); |
| + return err; |
| +} |
| + |
| static struct class firmware_class = { |
| .name = "firmware", |
| .class_attrs = firmware_class_attrs, |