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

Reply via email to