diff mbox series

efi: Fix memory leak in efivar_ssdt_load

Message ID ZyizcvscUWIyZYdE@grain
State Superseded
Headers show
Series efi: Fix memory leak in efivar_ssdt_load | expand

Commit Message

Cyrill Gorcunov Nov. 4, 2024, 11:43 a.m. UTC
When we load ssdt from efi variable (specified with efivar_ssdt=something
boot command line argument) a name for the variable is allocated
dynamically because we traverse all efi variables. Unlike an acpi table
data, which is later used by acpi engine, the name is no longer needed
once traverse is complete -- don't forget to free this memory.

Same time we silently ignore any errors happened here lets print
a message if something went wrong (but do not exit since this is
not a critical error and the system should continue to boot).

Also while here -- add a note why we keep ssdt table on success.

Signed-off-by: Cyrill Gorcunov <gorcunov@gmail.com>
Cc: Ard Biesheuvel <ardb@kernel.org>
---
 drivers/firmware/efi/efi.c |   38 ++++++++++++++++++++++++++------------
 1 file changed, 26 insertions(+), 12 deletions(-)

Comments

Cyrill Gorcunov Nov. 4, 2024, 11:53 a.m. UTC | #1
On Mon, Nov 04, 2024 at 02:43:46PM +0300, Cyrill Gorcunov wrote:
> When we load ssdt from efi variable (specified with efivar_ssdt=something
> boot command line argument) a name for the variable is allocated
> dynamically because we traverse all efi variables. Unlike an acpi table
> data, which is later used by acpi engine, the name is no longer needed
> once traverse is complete -- don't forget to free this memory.

Drop it for a while: found that ret variable is shadowed while compiler
didn't spit a warn about, not a bug but better fix it. Will send v2.
diff mbox series

Patch

Index: linux-tip.git/drivers/firmware/efi/efi.c
===================================================================
--- linux-tip.git.orig/drivers/firmware/efi/efi.c
+++ linux-tip.git/drivers/firmware/efi/efi.c
@@ -273,6 +273,7 @@  static __init int efivar_ssdt_load(void)
 	efi_char16_t *name = NULL;
 	efi_status_t status;
 	efi_guid_t guid;
+	int ret = 0;
 
 	if (!efivar_ssdt[0])
 		return 0;
@@ -294,8 +295,8 @@  static __init int efivar_ssdt_load(void)
 			efi_char16_t *name_tmp =
 				krealloc(name, name_size, GFP_KERNEL);
 			if (!name_tmp) {
-				kfree(name);
-				return -ENOMEM;
+				ret = -ENOMEM;
+				goto out;
 			}
 			name = name_tmp;
 			continue;
@@ -309,26 +310,37 @@  static __init int efivar_ssdt_load(void)
 		pr_info("loading SSDT from variable %s-%pUl\n", efivar_ssdt, &guid);
 
 		status = efi.get_variable(name, &guid, NULL, &data_size, NULL);
-		if (status != EFI_BUFFER_TOO_SMALL || !data_size)
-			return -EIO;
+		if (status != EFI_BUFFER_TOO_SMALL || !data_size) {
+			ret = -EIO;
+			goto out;
+		}
 
 		data = kmalloc(data_size, GFP_KERNEL);
-		if (!data)
-			return -ENOMEM;
+		if (!data) {
+			ret = -ENOMEM;
+			goto out;
+		}
 
 		status = efi.get_variable(name, &guid, NULL, &data_size, data);
 		if (status == EFI_SUCCESS) {
 			acpi_status ret = acpi_load_table(data, NULL);
-			if (ret)
-				pr_err("failed to load table: %u\n", ret);
-			else
+			if (ret) {
+				pr_err("efivar_ssdt: failed to load table: %u\n", ret);
+			} else {
+				/*
+				 * The @data will be in use by ACPI engine,
+				 * do not free it!
+				 */
 				continue;
+			}
 		} else {
-			pr_err("failed to get var data: 0x%lx\n", status);
+			pr_err("efivar_ssdt: failed to get var data: 0x%lx\n", status);
 		}
 		kfree(data);
 	}
-	return 0;
+out:
+	kfree(name);
+	return ret;
 }
 #else
 static inline int efivar_ssdt_load(void) { return 0; }
@@ -433,7 +445,9 @@  static int __init efisubsys_init(void)
 		error = generic_ops_register();
 		if (error)
 			goto err_put;
-		efivar_ssdt_load();
+		error = efivar_ssdt_load();
+		if (error)
+			pr_err("efi: failed to load SSDT, error %d.\n", error);
 		platform_device_register_simple("efivars", 0, NULL, 0);
 	}