4.10-rc3, firmware loading via user space helper crashes if firmware not present
Hi!
If one requests a FW which does not exist in the FS and the user space helper is used then fw_load_abort() will be called twice which leads to NULL-deref.
It will be called once in firmware_loading_store() (handling the -1 case) and then again in _request_firmware_load() because return value from fw_state_wait_timeout() was negative.
I think this is introduced in by f52cc379423d ("firmware: refactor loading status").
The simple fix would be to not "unlink" the buf by fw_load_abort() in firmware_loading_store() and always rely on firmware_loading_store().
------->8------------------------------------
(quoted diff) +0 -0
b/drivers/base/firmware_class.c index 4497d263209f..89eb9de81145 100644
drivers/base/firmware_class.c +0 -0
@@ -766,7 +770,7 @@ static ssize_t firmware_loading_store(struct device
*dev, dev_err(dev, "%s: unexpected value (%d)\n", __func__, loading);
/* fallthrough */
case -1:
- fw_load_abort(fw_priv);
+ fw_state_aborted(&fw_buf->fw_st);
break;
}
out:
-------8<------------------------------------
Or should we fix up the ret code handling in __fw_state_wait_common()?
Kuba
Quoted 32 lines · Jakub Kicinski
If one requests a FW which does not exist in the FS and the user space helper is used then
fw_load_abort()will be called twice which leads to NULL-deref.It will be called once in
firmware_loading_store()(handling the -1 case) and then again in_request_firmware_load()because return value fromfw_state_wait_timeout()was negative.I think this is introduced in by
f52cc379423d("firmware: refactor loading status").The simple fix would be to not "unlink" the buf by
fw_load_abort()infirmware_loading_store()and always rely onfirmware_loading_store().------->8------------------------------------
(quoted diff) +0
-0
b/drivers/base/firmware_class.cindex4497d263209f..89eb9de81145100644drivers/base/firmware_class.c +1
-2@@ -766,7 +770,7 @@ static ssize_t firmware_loading_store(struct device *dev,dev_err (dev,"%s: unexpected value (%d)\n" , __func__, loading);/* fallthrough */ case -1 : -fw_load_abort (fw_priv); +fw_state_aborted (&fw_buf->fw_st);break ; } out: -------8<------------------------------------
Quoted 1 line
Or should we fix up the ret code handling in
__fw_state_wait_common()?
I got this backwards, I blamed the wrong commit, it's the 5d47ec02c37e ("firmware: Correct handling of fw_state_wait() return value") in fact. It made the assumption that all errors returned from fw_state_wait_timeout() require calling the abort, while in fact abort should only be called if user mode helper didn't do anything (either it timed out or someone hit ^C).
I'm leaning towards this:
------->8------------------------------------
drivers/base/firmware_class.c +1 -1
@@ -1020,7 +1020,7 @@ static int _request_firmware_load(struct firmware_priv *fw_priv, } retval =fw_state_wait_timeout (&buf->fw_st, timeout); -if (retval <0 ) { +if (retval == -ETIMEDOUT || retval == -ERESTARTSYS ) {mutex_lock (&fw_lock);fw_load_abort (fw_priv);mutex_unlock (&fw_lock);
-------8<------------------------------------
Unless advised otherwise I will submit this officially on Monday :)