Skip to content

Commit

Permalink
efi: Fix memory leak in efivar_ssdt_load
Browse files Browse the repository at this point in the history
When we load SSDT from efi variable (specified with efivar_ssdt=<var>
boot command line argument) a name for the variable is allocated
dynamically because we traverse all EFI variables. Unlike 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 let's 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 <[email protected]>
Signed-off-by: Ard Biesheuvel <[email protected]>
  • Loading branch information
cyrillos authored and ardbiesheuvel committed Nov 17, 2024
1 parent 8510622 commit c5d91b1
Showing 1 changed file with 28 additions and 13 deletions.
41 changes: 28 additions & 13 deletions drivers/firmware/efi/efi.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -309,26 +310,38 @@ 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
acpi_status acpi_ret = acpi_load_table(data, NULL);
if (ACPI_FAILURE(acpi_ret)) {
pr_err("efivar_ssdt: failed to load table: %u\n",
acpi_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; }
Expand Down Expand Up @@ -433,7 +446,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);
}

Expand Down

0 comments on commit c5d91b1

Please sign in to comment.