* [PATCH v2 0/1] platform/x86: asus-armoury: fix Use-After-Free and memory leak in driver init
@ 2026-07-01 16:42 Marco Scardovi
2026-07-01 16:42 ` [PATCH v2 1/1] " Marco Scardovi
0 siblings, 1 reply; 3+ messages in thread
From: Marco Scardovi @ 2026-07-01 16:42 UTC (permalink / raw)
To: ilpo.jarvinen
Cc: corentin.chary, denis.benato, hansg, linux-kernel, luke,
platform-driver-x86, Marco Scardovi
This patch series addresses a Use-After-Free (UAF) vulnerability
and a memory leak during driver initialization in the asus-armoury
driver.
Changes in v2:
- Restructured init_rog_tunables() to use local pointers
(ac_rog_tunables, dc_rog_tunables) and only update the global
static asus_armoury.rog_tunables structure once all allocations
have successfully succeeded. This removes the risk of exposing
freed or partially allocated pointers to the global struct.
- Removed redundant assignments to NULL in the error paths. Since
initialization fails and the driver is not loaded, cleaning the
global static pointers to NULL is not necessary.
- In init_rog_tunables(), replaced 'goto err_nomem' with direct
'return -ENOMEM'. The 'err_nomem' label in the original code
printed a generic OOM error message, which is discouraged in the
kernel as the allocator already issues OOM details. Because that
label did not perform rollback cleanup, a direct return is cleaner
and simpler.
- Replaced inline cleanup in asus_fw_init() with a standard goto
rollback block at the end of the function for cleaner error path
styling.
Marco Scardovi (1):
platform/x86: asus-armoury: fix Use-After-Free and memory leak in
driver init
drivers/platform/x86/asus-armoury.c | 38 ++++++++++++++++++-----------
1 file changed, 24 insertions(+), 14 deletions(-)
--
2.55.0
^ permalink raw reply [flat|nested] 3+ messages in thread* [PATCH v2 1/1] platform/x86: asus-armoury: fix Use-After-Free and memory leak in driver init 2026-07-01 16:42 [PATCH v2 0/1] platform/x86: asus-armoury: fix Use-After-Free and memory leak in driver init Marco Scardovi @ 2026-07-01 16:42 ` Marco Scardovi 2026-07-03 9:59 ` Ilpo Järvinen 0 siblings, 1 reply; 3+ messages in thread From: Marco Scardovi @ 2026-07-01 16:42 UTC (permalink / raw) To: ilpo.jarvinen Cc: corentin.chary, denis.benato, hansg, linux-kernel, luke, platform-driver-x86, Marco Scardovi In init_rog_tunables(), if dc_limits are defined and allocating dc_rog_tunables fails, the already allocated ac_rog_tunables gets freed but the pointer stored in asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_AC] is not cleared. Since init_rog_tunables() returns void, the driver initialization continues, which can lead to a Use-After-Free (UAF) when asus_fw_attr_add() accesses the freed AC tunables pointer. Additionally, if init_rog_tunables() succeeds but asus_fw_attr_add() fails, the allocated tunables are not freed, resulting in a memory leak. Fix these issues by making init_rog_tunables() return an error code and propagating it in asus_fw_init(). Defer setting the global pointers in asus_armoury.rog_tunables until both tunables have been successfully allocated. If asus_fw_attr_add() fails, release the allocated resources using a standard goto rollback block in asus_fw_init(). Signed-off-by: Marco Scardovi <scardracs@disroot.org> --- v2: - Restructure init_rog_tunables() to use local pointers and defer assignment to the global struct until all allocations succeed, eliminating the need to set global pointers to NULL on error. - Use a goto-rollback pattern in asus_fw_init() for cleaner error handling as requested by Ilpo. drivers/platform/x86/asus-armoury.c | 38 ++++++++++++++++++----------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/drivers/platform/x86/asus-armoury.c b/drivers/platform/x86/asus-armoury.c index 495dc1e31d40..ea53a005bb25 100644 --- a/drivers/platform/x86/asus-armoury.c +++ b/drivers/platform/x86/asus-armoury.c @@ -989,7 +989,7 @@ static int asus_fw_attr_add(void) /* Init / exit ****************************************************************/ /* Set up the min/max and defaults for ROG tunables */ -static void init_rog_tunables(void) +static int init_rog_tunables(void) { const struct power_limits *ac_limits, *dc_limits; struct rog_tunables *ac_rog_tunables = NULL, *dc_rog_tunables = NULL; @@ -1000,24 +1000,23 @@ static void init_rog_tunables(void) dmi_id = dmi_first_match(power_limits); if (!dmi_id) { pr_warn("No matching power limits found for this system\n"); - return; + return 0; } /* Get the power data for this system */ power_data = dmi_id->driver_data; if (!power_data) { pr_info("No power data available for this system\n"); - return; + return 0; } /* Initialize AC power tunables */ ac_limits = power_data->ac_data; if (ac_limits) { - ac_rog_tunables = kzalloc_obj(*asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_AC]); + ac_rog_tunables = kzalloc_obj(*ac_rog_tunables); if (!ac_rog_tunables) - goto err_nomem; + return -ENOMEM; - asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_AC] = ac_rog_tunables; ac_rog_tunables->power_limits = ac_limits; /* Set initial AC values */ @@ -1060,13 +1059,12 @@ static void init_rog_tunables(void) /* Initialize DC power tunables */ dc_limits = power_data->dc_data; if (dc_limits) { - dc_rog_tunables = kzalloc_obj(*asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_DC]); + dc_rog_tunables = kzalloc_obj(*dc_rog_tunables); if (!dc_rog_tunables) { kfree(ac_rog_tunables); - goto err_nomem; + return -ENOMEM; } - asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_DC] = dc_rog_tunables; dc_rog_tunables->power_limits = dc_limits; /* Set initial DC values */ @@ -1106,15 +1104,16 @@ static void init_rog_tunables(void) pr_debug("No DC PPT limits defined\n"); } - return; + asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_AC] = ac_rog_tunables; + asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_DC] = dc_rog_tunables; -err_nomem: - pr_err("Failed to allocate memory for tunables\n"); + return 0; } static int __init asus_fw_init(void) { char *wmi_uid; + int err; wmi_uid = wmi_get_acpi_device_uid(ASUS_WMI_MGMT_GUID); if (!wmi_uid) @@ -1127,10 +1126,21 @@ static int __init asus_fw_init(void) if (!strcmp(wmi_uid, ASUS_ACPI_UID_ASUSWMI)) return -ENODEV; - init_rog_tunables(); + err = init_rog_tunables(); + if (err) + return err; /* Must always be last step to ensure data is available */ - return asus_fw_attr_add(); + err = asus_fw_attr_add(); + if (err) + goto err_free_tunables; + + return 0; + +err_free_tunables: + kfree(asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_AC]); + kfree(asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_DC]); + return err; } static void __exit asus_fw_exit(void) -- 2.55.0 ^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH v2 1/1] platform/x86: asus-armoury: fix Use-After-Free and memory leak in driver init 2026-07-01 16:42 ` [PATCH v2 1/1] " Marco Scardovi @ 2026-07-03 9:59 ` Ilpo Järvinen 0 siblings, 0 replies; 3+ messages in thread From: Ilpo Järvinen @ 2026-07-03 9:59 UTC (permalink / raw) To: Marco Scardovi Cc: corentin.chary, denis.benato, Hans de Goede, LKML, luke, platform-driver-x86 On Wed, 1 Jul 2026, Marco Scardovi wrote: > In init_rog_tunables(), if dc_limits are defined and allocating > dc_rog_tunables fails, the already allocated ac_rog_tunables gets > freed but the pointer stored in > asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_AC] is not cleared. Since > init_rog_tunables() returns void, the driver initialization continues, > which can lead to a Use-After-Free (UAF) when asus_fw_attr_add() > accesses the freed AC tunables pointer. > > Additionally, if init_rog_tunables() succeeds but asus_fw_attr_add() > fails, the allocated tunables are not freed, resulting in a memory leak. > > Fix these issues by making init_rog_tunables() return an error code and > propagating it in asus_fw_init(). Defer setting the global pointers in > asus_armoury.rog_tunables until both tunables have been successfully > allocated. If asus_fw_attr_add() fails, release the allocated resources > using a standard goto rollback block in asus_fw_init(). > > Signed-off-by: Marco Scardovi <scardracs@disroot.org> > --- > v2: > - Restructure init_rog_tunables() to use local pointers and defer assignment > to the global struct until all allocations succeed, eliminating the need > to set global pointers to NULL on error. > - Use a goto-rollback pattern in asus_fw_init() for cleaner error handling > as requested by Ilpo. > > drivers/platform/x86/asus-armoury.c | 38 ++++++++++++++++++----------- > 1 file changed, 24 insertions(+), 14 deletions(-) > > diff --git a/drivers/platform/x86/asus-armoury.c b/drivers/platform/x86/asus-armoury.c > index 495dc1e31d40..ea53a005bb25 100644 > --- a/drivers/platform/x86/asus-armoury.c > +++ b/drivers/platform/x86/asus-armoury.c > @@ -989,7 +989,7 @@ static int asus_fw_attr_add(void) > /* Init / exit ****************************************************************/ > > /* Set up the min/max and defaults for ROG tunables */ > -static void init_rog_tunables(void) > +static int init_rog_tunables(void) > { > const struct power_limits *ac_limits, *dc_limits; > struct rog_tunables *ac_rog_tunables = NULL, *dc_rog_tunables = NULL; > @@ -1000,24 +1000,23 @@ static void init_rog_tunables(void) > dmi_id = dmi_first_match(power_limits); > if (!dmi_id) { > pr_warn("No matching power limits found for this system\n"); > - return; > + return 0; > } > > /* Get the power data for this system */ > power_data = dmi_id->driver_data; > if (!power_data) { > pr_info("No power data available for this system\n"); > - return; > + return 0; > } > > /* Initialize AC power tunables */ > ac_limits = power_data->ac_data; > if (ac_limits) { > - ac_rog_tunables = kzalloc_obj(*asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_AC]); > + ac_rog_tunables = kzalloc_obj(*ac_rog_tunables); > if (!ac_rog_tunables) > - goto err_nomem; > + return -ENOMEM; > > - asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_AC] = ac_rog_tunables; > ac_rog_tunables->power_limits = ac_limits; > > /* Set initial AC values */ > @@ -1060,13 +1059,12 @@ static void init_rog_tunables(void) > /* Initialize DC power tunables */ > dc_limits = power_data->dc_data; > if (dc_limits) { > - dc_rog_tunables = kzalloc_obj(*asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_DC]); > + dc_rog_tunables = kzalloc_obj(*dc_rog_tunables); > if (!dc_rog_tunables) { > kfree(ac_rog_tunables); > - goto err_nomem; > + return -ENOMEM; > } > > - asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_DC] = dc_rog_tunables; > dc_rog_tunables->power_limits = dc_limits; > > /* Set initial DC values */ > @@ -1106,15 +1104,16 @@ static void init_rog_tunables(void) > pr_debug("No DC PPT limits defined\n"); > } > > - return; > + asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_AC] = ac_rog_tunables; > + asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_DC] = dc_rog_tunables; > > -err_nomem: > - pr_err("Failed to allocate memory for tunables\n"); > + return 0; This works as well but now we also want to convert it to use __free() + no_free_ptr() so we can get rid of that manual kfree() to remove potential for future mem management errors. ...If you could add a second patch to this series to that effect, it would great. -- i. > } > > static int __init asus_fw_init(void) > { > char *wmi_uid; > + int err; > > wmi_uid = wmi_get_acpi_device_uid(ASUS_WMI_MGMT_GUID); > if (!wmi_uid) > @@ -1127,10 +1126,21 @@ static int __init asus_fw_init(void) > if (!strcmp(wmi_uid, ASUS_ACPI_UID_ASUSWMI)) > return -ENODEV; > > - init_rog_tunables(); > + err = init_rog_tunables(); > + if (err) > + return err; > > /* Must always be last step to ensure data is available */ > - return asus_fw_attr_add(); > + err = asus_fw_attr_add(); > + if (err) > + goto err_free_tunables; > + > + return 0; > + > +err_free_tunables: > + kfree(asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_AC]); > + kfree(asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_DC]); > + return err; > } > > static void __exit asus_fw_exit(void) > ^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-07-03 9:59 UTC | newest] Thread overview: 3+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-07-01 16:42 [PATCH v2 0/1] platform/x86: asus-armoury: fix Use-After-Free and memory leak in driver init Marco Scardovi 2026-07-01 16:42 ` [PATCH v2 1/1] " Marco Scardovi 2026-07-03 9:59 ` Ilpo Järvinen
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox