The use-after-free happens when a fw_priv object has been freed but
hasn't been removed from the pending list (pending_fw_head). The next
time fw_load_sysfs_fallback tries to insert into the list, it ends up
accessing the pending_list member of the previoiusly freed fw_priv.

In bcfbd3523f3c ("firmware: fix a double abort case with
fw_load_sysfs_fallback"), fw_load_abort() is skipped if
fw_sysfs_wait_timeout() returns -ENOENT. This causes the fw_priv to
not be removed from the pending list.

To fix this, delete the fw_priv from the pending list when retval
is -ENOENT instead of skipping the entire block.

Fixes: bcfbd3523f3c ("firmware: fix a double abort case with 
fw_load_sysfs_fallback")
Reported-and-tested-by: syzbot+de271708674e20930...@syzkaller.appspotmail.com
Signed-off-by: Anirudh Rayabharam <m...@anirudhrb.com>
---
 drivers/base/firmware_loader/fallback.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/drivers/base/firmware_loader/fallback.c 
b/drivers/base/firmware_loader/fallback.c
index 91899d185e31..56ae4ab3199d 100644
--- a/drivers/base/firmware_loader/fallback.c
+++ b/drivers/base/firmware_loader/fallback.c
@@ -526,9 +526,14 @@ static int fw_load_sysfs_fallback(struct fw_sysfs 
*fw_sysfs, long timeout)
        }
 
        retval = fw_sysfs_wait_timeout(fw_priv, timeout);
-       if (retval < 0 && retval != -ENOENT) {
+       if (retval < 0) {
                mutex_lock(&fw_lock);
-               fw_load_abort(fw_sysfs);
+
+               if (retval != -ENOENT)
+                       fw_load_abort(fw_sysfs);
+               else
+                       list_del_init(&fw_priv->pending_list);
+
                mutex_unlock(&fw_lock);
        }
 
-- 
2.26.2

Reply via email to