From 4965b8cd1bc1ffb017e5c58e622da82b55e49414 Mon Sep 17 00:00:00 2001 From: Prateek Sood Date: Fri, 21 Aug 2020 02:27:50 +0530 Subject: firmware_loader: fix memory leak for paged buffer vfree() is being called on paged buffer allocated using alloc_page() and mapped using vmap(). Freeing of pages in vfree() relies on nr_pages of struct vm_struct. vmap() does not update nr_pages. It can lead to memory leaks. Fixes: ddaf29fd9bb6 ("firmware: Free temporary page table after vmapping") Signed-off-by: Prateek Sood Reviewed-by: Takashi Iwai Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/1597957070-27185-1-git-send-email-prsood@codeaurora.org Signed-off-by: Greg Kroah-Hartman --- drivers/base/firmware_loader/firmware.h | 2 ++ drivers/base/firmware_loader/main.c | 17 +++++++++++------ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/drivers/base/firmware_loader/firmware.h b/drivers/base/firmware_loader/firmware.h index 933e2192fbe8..d08efc77cf16 100644 --- a/drivers/base/firmware_loader/firmware.h +++ b/drivers/base/firmware_loader/firmware.h @@ -142,10 +142,12 @@ int assign_fw(struct firmware *fw, struct device *device, u32 opt_flags); void fw_free_paged_buf(struct fw_priv *fw_priv); int fw_grow_paged_buf(struct fw_priv *fw_priv, int pages_needed); int fw_map_paged_buf(struct fw_priv *fw_priv); +bool fw_is_paged_buf(struct fw_priv *fw_priv); #else static inline void fw_free_paged_buf(struct fw_priv *fw_priv) {} static inline int fw_grow_paged_buf(struct fw_priv *fw_priv, int pages_needed) { return -ENXIO; } static inline int fw_map_paged_buf(struct fw_priv *fw_priv) { return -ENXIO; } +static inline bool fw_is_paged_buf(struct fw_priv *fw_priv) { return false; } #endif #endif /* __FIRMWARE_LOADER_H */ diff --git a/drivers/base/firmware_loader/main.c b/drivers/base/firmware_loader/main.c index 9da0c9d5f538..63b9714a0154 100644 --- a/drivers/base/firmware_loader/main.c +++ b/drivers/base/firmware_loader/main.c @@ -252,9 +252,11 @@ static void __free_fw_priv(struct kref *ref) list_del(&fw_priv->list); spin_unlock(&fwc->lock); - fw_free_paged_buf(fw_priv); /* free leftover pages */ - if (!fw_priv->allocated_size) + if (fw_is_paged_buf(fw_priv)) + fw_free_paged_buf(fw_priv); + else if (!fw_priv->allocated_size) vfree(fw_priv->data); + kfree_const(fw_priv->fw_name); kfree(fw_priv); } @@ -268,6 +270,11 @@ static void free_fw_priv(struct fw_priv *fw_priv) } #ifdef CONFIG_FW_LOADER_PAGED_BUF +bool fw_is_paged_buf(struct fw_priv *fw_priv) +{ + return fw_priv->is_paged_buf; +} + void fw_free_paged_buf(struct fw_priv *fw_priv) { int i; @@ -275,6 +282,8 @@ void fw_free_paged_buf(struct fw_priv *fw_priv) if (!fw_priv->pages) return; + vunmap(fw_priv->data); + for (i = 0; i < fw_priv->nr_pages; i++) __free_page(fw_priv->pages[i]); kvfree(fw_priv->pages); @@ -328,10 +337,6 @@ int fw_map_paged_buf(struct fw_priv *fw_priv) if (!fw_priv->data) return -ENOMEM; - /* page table is no longer needed after mapping, let's free */ - kvfree(fw_priv->pages); - fw_priv->pages = NULL; - return 0; } #endif -- cgit From 40b8b826a6998639dd1c26f0e127f18371e1058d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 3 Aug 2020 11:27:06 +0300 Subject: kobject: Restore old behaviour of kobject_del(NULL) The commit 079ad2fb4bf9 ("kobject: Avoid premature parent object freeing in kobject_cleanup()") inadvertently dropped a possibility to call kobject_del() with NULL pointer. Restore the old behaviour. Fixes: 079ad2fb4bf9 ("kobject: Avoid premature parent object freeing in kobject_cleanup()") Cc: stable Reported-by: Qu Wenruo Cc: Heikki Krogerus Signed-off-by: Andy Shevchenko Reviewed-by: Qu Wenruo Link: https://lore.kernel.org/r/20200803082706.65347-1-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- lib/kobject.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/kobject.c b/lib/kobject.c index 3afb939f2a1c..9dce68c378e6 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -637,8 +637,12 @@ static void __kobject_del(struct kobject *kobj) */ void kobject_del(struct kobject *kobj) { - struct kobject *parent = kobj->parent; + struct kobject *parent; + + if (!kobj) + return; + parent = kobj->parent; __kobject_del(kobj); kobject_put(parent); } -- cgit From e3b9fc7eec55e6fdc8beeed18f2ed207086341e2 Mon Sep 17 00:00:00 2001 From: Vladis Dronov Date: Tue, 11 Aug 2020 17:01:29 +0200 Subject: debugfs: Fix module state check condition The '#ifdef MODULE' check in the original commit does not work as intended. The code under the check is not built at all if CONFIG_DEBUG_FS=y. Fix this by using a correct check. Fixes: 275678e7a9be ("debugfs: Check module state before warning in {full/open}_proxy_open()") Signed-off-by: Vladis Dronov Cc: stable Link: https://lore.kernel.org/r/20200811150129.53343-1-vdronov@redhat.com Signed-off-by: Greg Kroah-Hartman --- fs/debugfs/file.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index b167d2d02148..a768a09430c3 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c @@ -177,7 +177,7 @@ static int open_proxy_open(struct inode *inode, struct file *filp) goto out; if (!fops_get(real_fops)) { -#ifdef MODULE +#ifdef CONFIG_MODULES if (real_fops->owner && real_fops->owner->state == MODULE_STATE_GOING) goto out; @@ -312,7 +312,7 @@ static int full_proxy_open(struct inode *inode, struct file *filp) goto out; if (!fops_get(real_fops)) { -#ifdef MODULE +#ifdef CONFIG_MODULES if (real_fops->owner && real_fops->owner->state == MODULE_STATE_GOING) goto out; -- cgit From 693a8e936590f93451e6f5a3d748616f5a59c80b Mon Sep 17 00:00:00 2001 From: Michał Mirosław Date: Fri, 28 Aug 2020 18:14:35 +0200 Subject: driver code: print symbolic error code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit dev_err_probe() prepends the message with an error code. Let's make it more readable by translating the code to a more recognisable symbol. Fixes: a787e5400a1c ("driver core: add device probe log helper") Signed-off-by: Michał Mirosław Link: https://lore.kernel.org/r/ea3f973e4708919573026fdce52c264db147626d.1598630856.git.mirq-linux@rere.qmqm.pl Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/base/core.c b/drivers/base/core.c index ac1046a382bc..1a4706310b28 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -4237,10 +4237,10 @@ int dev_err_probe(const struct device *dev, int err, const char *fmt, ...) vaf.va = &args; if (err != -EPROBE_DEFER) { - dev_err(dev, "error %d: %pV", err, &vaf); + dev_err(dev, "error %pe: %pV", ERR_PTR(err), &vaf); } else { device_set_deferred_probe_reason(dev, &vaf); - dev_dbg(dev, "error %d: %pV", err, &vaf); + dev_dbg(dev, "error %pe: %pV", ERR_PTR(err), &vaf); } va_end(args); -- cgit From 51de18bff23362bfaa3c7af33bb455de274b49c9 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 27 Aug 2020 20:20:29 +0200 Subject: MAINTAINERS: Add the security document to SECURITY CONTACT When changing the document related to kernel security workflow, notify the security mailing list as its concerned by this. Cc: Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20200827182029.3458-1-krzk@kernel.org Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index f0068bceeb61..c5317a7ddee0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15546,6 +15546,7 @@ F: include/uapi/linux/sed* SECURITY CONTACT M: Security Officers S: Supported +F: Documentation/admin-guide/security-bugs.rst SECURITY SUBSYSTEM M: James Morris -- cgit From 6b57b15abe11aa334ebf726e02c0deaf123ba040 Mon Sep 17 00:00:00 2001 From: Saravana Kannan Date: Tue, 1 Sep 2020 11:44:44 -0700 Subject: driver core: Fix device_pm_lock() locking for device links This commit fixes two issues: 1. The lockdep warning reported by Dong Aisheng [1]. It is a warning about a cycle (dpm_list_mtx --> kn->active#3 --> fw_lock) that was introduced when device-link devices were added to expose device link information in sysfs. The patch that "introduced" this cycle can't be reverted because it's fixes a real SRCU issue and also ensures that the device-link device is deleted as soon as the device-link is deleted. This is important to avoid sysfs name collisions if the device-link is create again immediately (this can happen a lot with deferred probing). 2. Inconsistency in grabbing device_pm_lock() during device link deletion Some device link deletion code paths grab device_pm_lock(), while others don't. The device_pm_lock() is grabbed during device_link_add() because it checks if the supplier is in the dpm_list and also reorders the dpm_list. However, when a device link is deleted, it does not do either of those and therefore device_pm_lock() is not necessary. Dropping the device_pm_lock() in all the device link deletion paths removes the inconsistency in locking. Thanks to Stephen Boyd for helping me understand the lockdep splat. Fixes: 843e600b8a2b ("driver core: Fix sleeping in invalid context during device link deletion") [1] - https://lore.kernel.org/lkml/CAA+hA=S4eAreb7vo69LAXSk2t5=DEKNxHaiY1wSpk4xTp9urLg@mail.gmail.com/ Reported-by: Dong Aisheng Signed-off-by: Saravana Kannan Tested-by: Peng Fan Link: https://lore.kernel.org/r/20200901184445.1736658-1-saravanak@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/base/core.c b/drivers/base/core.c index 1a4706310b28..97812a5f42b8 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -807,9 +807,7 @@ static void device_link_put_kref(struct device_link *link) void device_link_del(struct device_link *link) { device_links_write_lock(); - device_pm_lock(); device_link_put_kref(link); - device_pm_unlock(); device_links_write_unlock(); } EXPORT_SYMBOL_GPL(device_link_del); @@ -830,7 +828,6 @@ void device_link_remove(void *consumer, struct device *supplier) return; device_links_write_lock(); - device_pm_lock(); list_for_each_entry(link, &supplier->links.consumers, s_node) { if (link->consumer == consumer) { @@ -839,7 +836,6 @@ void device_link_remove(void *consumer, struct device *supplier) } } - device_pm_unlock(); device_links_write_unlock(); } EXPORT_SYMBOL_GPL(device_link_remove); -- cgit From 07ecc6693f9157cf293da5d165c73fb28fd69bf4 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 3 Aug 2020 11:35:20 +0300 Subject: kobject: Drop unneeded conditional in __kobject_del() __kobject_del() is called from two places, in one where kobj is dereferenced before and thus can't be NULL, and in the other the NULL check is done before call. Drop unneeded conditional in __kobject_del(). Signed-off-by: Andy Shevchenko Reviewed-by: Rafael J. Wysocki Link: https://lore.kernel.org/r/20200803083520.5460-1-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- lib/kobject.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/kobject.c b/lib/kobject.c index 9dce68c378e6..ea53b30cf483 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -604,9 +604,6 @@ static void __kobject_del(struct kobject *kobj) struct kernfs_node *sd; const struct kobj_type *ktype; - if (!kobj) - return; - sd = kobj->sd; ktype = get_ktype(kobj); -- cgit From 1c30474826682bc970c3200700d8bcfa2b771278 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 6 Sep 2020 20:42:52 -0700 Subject: PM: : fix @em_pd kernel-doc warning Fix kernel-doc warning in : ../include/linux/device.h:613: warning: Function parameter or member 'em_pd' not described in 'device' Fixes: 1bc138c62295 ("PM / EM: add support for other devices than CPUs in Energy Model") Signed-off-by: Randy Dunlap Cc: Rafael J. Wysocki Reviewed-by: Lukasz Luba Link: https://lore.kernel.org/r/d97f40ad-3033-703a-c3cb-2843ce0f6371@infradead.org Signed-off-by: Greg Kroah-Hartman --- include/linux/device.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/device.h b/include/linux/device.h index ca18da4768e3..9e6ea8931a52 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -454,6 +454,7 @@ struct dev_links_info { * @pm_domain: Provide callbacks that are executed during system suspend, * hibernation, system resume and during runtime PM transitions * along with subsystem-level and driver-level callbacks. + * @em_pd: device's energy model performance domain * @pins: For device pin management. * See Documentation/driver-api/pinctl.rst for details. * @msi_list: Hosts MSI descriptors -- cgit From baaabecfc80fad255f866563b53b8c7a3eec176e Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 9 Sep 2020 15:53:54 -0700 Subject: test_firmware: Test platform fw loading on non-EFI systems On non-EFI systems, it wasn't possible to test the platform firmware loader because it will have never set "checked_fw" during __init. Instead, allow the test code to override this check. Additionally split the declarations into a private symbol namespace so there is greater enforcement of the symbol visibility. Fixes: 548193cba2a7 ("test_firmware: add support for firmware_request_platform") Cc: stable@vger.kernel.org Signed-off-by: Kees Cook Acked-by: Ard Biesheuvel Link: https://lore.kernel.org/r/20200909225354.3118328-1-keescook@chromium.org Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/efi/embedded-firmware.c | 10 +++++----- include/linux/efi_embedded_fw.h | 6 ++---- lib/test_firmware.c | 9 +++++++++ 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/drivers/firmware/efi/embedded-firmware.c b/drivers/firmware/efi/embedded-firmware.c index e97a9c9d010c..21ae0c48232a 100644 --- a/drivers/firmware/efi/embedded-firmware.c +++ b/drivers/firmware/efi/embedded-firmware.c @@ -16,9 +16,9 @@ /* Exported for use by lib/test_firmware.c only */ LIST_HEAD(efi_embedded_fw_list); -EXPORT_SYMBOL_GPL(efi_embedded_fw_list); - -static bool checked_for_fw; +EXPORT_SYMBOL_NS_GPL(efi_embedded_fw_list, TEST_FIRMWARE); +bool efi_embedded_fw_checked; +EXPORT_SYMBOL_NS_GPL(efi_embedded_fw_checked, TEST_FIRMWARE); static const struct dmi_system_id * const embedded_fw_table[] = { #ifdef CONFIG_TOUCHSCREEN_DMI @@ -116,14 +116,14 @@ void __init efi_check_for_embedded_firmwares(void) } } - checked_for_fw = true; + efi_embedded_fw_checked = true; } int efi_get_embedded_fw(const char *name, const u8 **data, size_t *size) { struct efi_embedded_fw *iter, *fw = NULL; - if (!checked_for_fw) { + if (!efi_embedded_fw_checked) { pr_warn("Warning %s called while we did not check for embedded fw\n", __func__); return -ENOENT; diff --git a/include/linux/efi_embedded_fw.h b/include/linux/efi_embedded_fw.h index 57eac5241303..a97a12bb2c9e 100644 --- a/include/linux/efi_embedded_fw.h +++ b/include/linux/efi_embedded_fw.h @@ -8,8 +8,8 @@ #define EFI_EMBEDDED_FW_PREFIX_LEN 8 /* - * This struct and efi_embedded_fw_list are private to the efi-embedded fw - * implementation they are in this header for use by lib/test_firmware.c only! + * This struct is private to the efi-embedded fw implementation. + * They are in this header for use by lib/test_firmware.c only! */ struct efi_embedded_fw { struct list_head list; @@ -18,8 +18,6 @@ struct efi_embedded_fw { size_t length; }; -extern struct list_head efi_embedded_fw_list; - /** * struct efi_embedded_fw_desc - This struct is used by the EFI embedded-fw * code to search for embedded firmwares. diff --git a/lib/test_firmware.c b/lib/test_firmware.c index 9fee2b93a8d1..06c955057756 100644 --- a/lib/test_firmware.c +++ b/lib/test_firmware.c @@ -26,6 +26,8 @@ #include #include +MODULE_IMPORT_NS(TEST_FIRMWARE); + #define TEST_FIRMWARE_NAME "test-firmware.bin" #define TEST_FIRMWARE_NUM_REQS 4 #define TEST_FIRMWARE_BUF_SIZE SZ_1K @@ -489,6 +491,9 @@ out: static DEVICE_ATTR_WO(trigger_request); #ifdef CONFIG_EFI_EMBEDDED_FIRMWARE +extern struct list_head efi_embedded_fw_list; +extern bool efi_embedded_fw_checked; + static ssize_t trigger_request_platform_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -501,6 +506,7 @@ static ssize_t trigger_request_platform_store(struct device *dev, }; struct efi_embedded_fw efi_embedded_fw; const struct firmware *firmware = NULL; + bool saved_efi_embedded_fw_checked; char *name; int rc; @@ -513,6 +519,8 @@ static ssize_t trigger_request_platform_store(struct device *dev, efi_embedded_fw.data = (void *)test_data; efi_embedded_fw.length = sizeof(test_data); list_add(&efi_embedded_fw.list, &efi_embedded_fw_list); + saved_efi_embedded_fw_checked = efi_embedded_fw_checked; + efi_embedded_fw_checked = true; pr_info("loading '%s'\n", name); rc = firmware_request_platform(&firmware, name, dev); @@ -530,6 +538,7 @@ static ssize_t trigger_request_platform_store(struct device *dev, rc = count; out: + efi_embedded_fw_checked = saved_efi_embedded_fw_checked; release_firmware(firmware); list_del(&efi_embedded_fw.list); kfree(name); -- cgit