This is a note to let you know that I've just added the patch titled
firmware loader: Fix the concurrent request_firmware() race for
to my driver-core git tree which can be found at
git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core.git
in the driver-core-next branch.
The patch will show up in the next release of the linux-next tree
(usually sometime within the next 24 hours during the week.)
The patch will also be merged in the next major kernel release
during the merge window.
If you have any questions about this process, please let me know.
>From bd9eb7fbe69111ea0ff1f999ef4a5f26d223d1d5 Mon Sep 17 00:00:00 2001
From: Chuansheng Liu <[email protected]>
Date: Sat, 10 Nov 2012 01:27:22 +0800
Subject: firmware loader: Fix the concurrent request_firmware() race for
kref_get/put
There is one race that both request_firmware() with the same
firmware name.
The race scenerio is as below:
CPU1 CPU2
request_firmware() -->
_request_firmware_load() return err another
request_firmware() is coming -->
_request_firmware_cleanup is called --> _request_firmware_prepare
-->
release_firmware --->
fw_lookup_and_allocate_buf -->
spin_lock(&fwc->lock)
... __fw_lookup_buf() return
true
fw_free_buf() will be called --> ...
kref_put -->
decrease the refcount to 0
kref_get(&tmp->ref) ==>
it will trigger warning
due to refcount == 0
__fw_free_buf() -->
... spin_unlock(&fwc->lock)
spin_lock(&fwc->lock)
list_del(&buf->list)
spin_unlock(&fwc->lock)
kfree(buf)
After that, the freed buf
will be used.
The key race is decreasing refcount to 0 and list_del is not protected together
by
fwc->lock, and it is possible another thread try to get it between refcount==0
and list_del.
Fix it here to protect it together.
Acked-by: Ming Lei <[email protected]>
Signed-off-by: liu chuansheng <[email protected]>
Cc: stable <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
---
drivers/base/firmware_class.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index b44ed35..be5f7aa 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -246,7 +246,6 @@ static void __fw_free_buf(struct kref *ref)
__func__, buf->fw_id, buf, buf->data,
(unsigned int)buf->size);
- spin_lock(&fwc->lock);
list_del(&buf->list);
spin_unlock(&fwc->lock);
@@ -263,7 +262,10 @@ static void __fw_free_buf(struct kref *ref)
static void fw_free_buf(struct firmware_buf *buf)
{
- kref_put(&buf->ref, __fw_free_buf);
+ struct firmware_cache *fwc = buf->fwc;
+ spin_lock(&fwc->lock);
+ if (!kref_put(&buf->ref, __fw_free_buf))
+ spin_unlock(&fwc->lock);
}
/* direct firmware loading support */
--
1.7.12.2.421.g261b511
--
To unsubscribe from this list: send the line "unsubscribe stable" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html