| From 581dd69830341d299b0c097fc366097ab497d679 Mon Sep 17 00:00:00 2001 |
| From: =?UTF-8?q?Thi=C3=A9baud=20Weksteen?= <tweek@google.com> |
| Date: Mon, 2 May 2022 10:49:52 +1000 |
| Subject: firmware_loader: use kernel credentials when reading firmware |
| MIME-Version: 1.0 |
| Content-Type: text/plain; charset=UTF-8 |
| Content-Transfer-Encoding: 8bit |
| |
| From: Thiébaud Weksteen <tweek@google.com> |
| |
| commit 581dd69830341d299b0c097fc366097ab497d679 upstream. |
| |
| Device drivers may decide to not load firmware when probed to avoid |
| slowing down the boot process should the firmware filesystem not be |
| available yet. In this case, the firmware loading request may be done |
| when a device file associated with the driver is first accessed. The |
| credentials of the userspace process accessing the device file may be |
| used to validate access to the firmware files requested by the driver. |
| Ensure that the kernel assumes the responsibility of reading the |
| firmware. |
| |
| This was observed on Android for a graphic driver loading their firmware |
| when the device file (e.g. /dev/mali0) was first opened by userspace |
| (i.e. surfaceflinger). The security context of surfaceflinger was used |
| to validate the access to the firmware file (e.g. |
| /vendor/firmware/mali.bin). |
| |
| Previously, Android configurations were not setting up the |
| firmware_class.path command line argument and were relying on the |
| userspace fallback mechanism. In this case, the security context of the |
| userspace daemon (i.e. ueventd) was consistently used to read firmware |
| files. More Android devices are now found to set firmware_class.path |
| which gives the kernel the opportunity to read the firmware directly |
| (via kernel_read_file_from_path_initns). In this scenario, the current |
| process credentials were used, even if unrelated to the loading of the |
| firmware file. |
| |
| Signed-off-by: Thiébaud Weksteen <tweek@google.com> |
| Cc: <stable@vger.kernel.org> # 5.10 |
| Reviewed-by: Paul Moore <paul@paul-moore.com> |
| Acked-by: Luis Chamberlain <mcgrof@kernel.org> |
| Link: https://lore.kernel.org/r/20220502004952.3970800-1-tweek@google.com |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/base/firmware_loader/main.c | 17 +++++++++++++++++ |
| 1 file changed, 17 insertions(+) |
| |
| --- a/drivers/base/firmware_loader/main.c |
| +++ b/drivers/base/firmware_loader/main.c |
| @@ -793,6 +793,8 @@ _request_firmware(const struct firmware |
| size_t offset, u32 opt_flags) |
| { |
| struct firmware *fw = NULL; |
| + struct cred *kern_cred = NULL; |
| + const struct cred *old_cred; |
| bool nondirect = false; |
| int ret; |
| |
| @@ -809,6 +811,18 @@ _request_firmware(const struct firmware |
| if (ret <= 0) /* error or already assigned */ |
| goto out; |
| |
| + /* |
| + * We are about to try to access the firmware file. Because we may have been |
| + * called by a driver when serving an unrelated request from userland, we use |
| + * the kernel credentials to read the file. |
| + */ |
| + kern_cred = prepare_kernel_cred(NULL); |
| + if (!kern_cred) { |
| + ret = -ENOMEM; |
| + goto out; |
| + } |
| + old_cred = override_creds(kern_cred); |
| + |
| ret = fw_get_filesystem_firmware(device, fw->priv, "", NULL); |
| |
| /* Only full reads can support decompression, platform, and sysfs. */ |
| @@ -834,6 +848,9 @@ _request_firmware(const struct firmware |
| } else |
| ret = assign_fw(fw, device); |
| |
| + revert_creds(old_cred); |
| + put_cred(kern_cred); |
| + |
| out: |
| if (ret < 0) { |
| fw_abort_batch_reqs(fw); |