diff mbox series

platform/x86: dell-wmi-sysman: correct an initialization failure

Message ID 20210218191723.20030-1-mario.limonciello@dell.com (mailing list archive)
State Changes Requested, archived
Headers show
Series platform/x86: dell-wmi-sysman: correct an initialization failure | expand

Commit Message

Limonciello, Mario Feb. 18, 2021, 7:17 p.m. UTC
On Dell systems that don't support this interface the module is
mistakingly returning error code "0", when it should be returning
-ENODEV.  Correct a logic error to guarantee the correct return code.

Cc: Divya Bharathi <Divya_Bharathi@Dell.com>
Reported-by: Alexander Naumann <alexandernaumann@gmx.de>
Signed-off-by: Mario Limonciello <mario.limonciello@dell.com>
---
 drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c     | 4 +++-
 drivers/platform/x86/dell-wmi-sysman/passwordattr-interface.c | 4 +++-
 drivers/platform/x86/dell-wmi-sysman/sysman.c                 | 4 ++--
 3 files changed, 8 insertions(+), 4 deletions(-)

Comments

mark gross Feb. 18, 2021, 10:48 p.m. UTC | #1
On Thu, Feb 18, 2021 at 01:17:23PM -0600, Mario Limonciello wrote:
> On Dell systems that don't support this interface the module is
> mistakingly returning error code "0", when it should be returning
> -ENODEV.  Correct a logic error to guarantee the correct return code.
> 
> Cc: Divya Bharathi <Divya_Bharathi@Dell.com>
> Reported-by: Alexander Naumann <alexandernaumann@gmx.de>
> Signed-off-by: Mario Limonciello <mario.limonciello@dell.com>
> ---
>  drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c     | 4 +++-
>  drivers/platform/x86/dell-wmi-sysman/passwordattr-interface.c | 4 +++-
>  drivers/platform/x86/dell-wmi-sysman/sysman.c                 | 4 ++--
>  3 files changed, 8 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c b/drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c
> index f95d8ddace5a..8d59f81f9db4 100644
> --- a/drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c
> +++ b/drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c
> @@ -175,7 +175,9 @@ static struct wmi_driver bios_attr_set_interface_driver = {
>  
>  int init_bios_attr_set_interface(void)
>  {
> -	return wmi_driver_register(&bios_attr_set_interface_driver);
> +	int ret = wmi_driver_register(&bios_attr_set_interface_driver);
I have to ask if the propper fix should be in wmi_driver_register
> +
> +	return wmi_priv.bios_attr_wdev ? ret : -ENODEV;
Also, is there any point to call wmi_driver_register if returning -ENODEV?
i.e. should the call to driver register be wrapped in a test for
bios_atter_wdev?


>  }
>  
>  void exit_bios_attr_set_interface(void)
> diff --git a/drivers/platform/x86/dell-wmi-sysman/passwordattr-interface.c b/drivers/platform/x86/dell-wmi-sysman/passwordattr-interface.c
> index 5780b4d94759..bf449dc5ff47 100644
> --- a/drivers/platform/x86/dell-wmi-sysman/passwordattr-interface.c
> +++ b/drivers/platform/x86/dell-wmi-sysman/passwordattr-interface.c
> @@ -142,7 +142,9 @@ static struct wmi_driver bios_attr_pass_interface_driver = {
>  
>  int init_bios_attr_pass_interface(void)
>  {
> -	return wmi_driver_register(&bios_attr_pass_interface_driver);
> +	int ret = wmi_driver_register(&bios_attr_pass_interface_driver);
> +
> +	return wmi_priv.password_attr_wdev ? ret : -ENODEV;
same comments as above only for password_atter_wdev.

--mark

>  }
>  
>  void exit_bios_attr_pass_interface(void)
> diff --git a/drivers/platform/x86/dell-wmi-sysman/sysman.c b/drivers/platform/x86/dell-wmi-sysman/sysman.c
> index cb81010ba1a2..d9ad0e83b66f 100644
> --- a/drivers/platform/x86/dell-wmi-sysman/sysman.c
> +++ b/drivers/platform/x86/dell-wmi-sysman/sysman.c
> @@ -513,13 +513,13 @@ static int __init sysman_init(void)
>  	}
>  
>  	ret = init_bios_attr_set_interface();
> -	if (ret || !wmi_priv.bios_attr_wdev) {
> +	if (ret) {
>  		pr_debug("failed to initialize set interface\n");
>  		goto fail_set_interface;
>  	}
>  
>  	ret = init_bios_attr_pass_interface();
> -	if (ret || !wmi_priv.password_attr_wdev) {
> +	if (ret) {
>  		pr_debug("failed to initialize pass interface\n");
>  		goto fail_pass_interface;
>  	}
> -- 
> 2.25.1
>
Limonciello, Mario Feb. 18, 2021, 11:26 p.m. UTC | #2
> -----Original Message-----
> From: mark gross <mgross@linux.intel.com>
> Sent: Thursday, February 18, 2021 16:49
> To: Limonciello, Mario
> Cc: Hans De Goede; Mark Gross; LKML; platform-driver-x86@vger.kernel.org;
> Bharathi, Divya; Alexander Naumann
> Subject: Re: [PATCH] platform/x86: dell-wmi-sysman: correct an initialization
> failure
> 
> 
> [EXTERNAL EMAIL]
> 
> On Thu, Feb 18, 2021 at 01:17:23PM -0600, Mario Limonciello wrote:
> > On Dell systems that don't support this interface the module is
> > mistakingly returning error code "0", when it should be returning
> > -ENODEV.  Correct a logic error to guarantee the correct return code.
> >
> > Cc: Divya Bharathi <Divya_Bharathi@Dell.com>
> > Reported-by: Alexander Naumann <alexandernaumann@gmx.de>
> > Signed-off-by: Mario Limonciello <mario.limonciello@dell.com>
> > ---
> >  drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c     | 4 +++-
> >  drivers/platform/x86/dell-wmi-sysman/passwordattr-interface.c | 4 +++-
> >  drivers/platform/x86/dell-wmi-sysman/sysman.c                 | 4 ++--
> >  3 files changed, 8 insertions(+), 4 deletions(-)
> >
> > diff --git a/drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c
> b/drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c
> > index f95d8ddace5a..8d59f81f9db4 100644
> > --- a/drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c
> > +++ b/drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c
> > @@ -175,7 +175,9 @@ static struct wmi_driver bios_attr_set_interface_driver
> = {
> >
> >  int init_bios_attr_set_interface(void)
> >  {
> > -	return wmi_driver_register(&bios_attr_set_interface_driver);
> > +	int ret = wmi_driver_register(&bios_attr_set_interface_driver);
> I have to ask if the propper fix should be in wmi_driver_register

Do you mean something like this?

diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c
index c669676ea8e8..89d04c5e3ab9 100644
--- a/drivers/platform/x86/wmi.c
+++ b/drivers/platform/x86/wmi.c
@@ -1415,6 +1415,11 @@ static int acpi_wmi_probe(struct platform_device *device)
 int __must_check __wmi_driver_register(struct wmi_driver *driver,
                                       struct module *owner)
 {
+       const struct wmi_device_id *id = driver->id_table;
+
+       if (!wmi_has_guid(id->guid_string))
+               return -ENODEV;
+
        driver->driver.owner = owner;
        driver->driver.bus = &wmi_bus_type;

> > +
> > +	return wmi_priv.bios_attr_wdev ? ret : -ENODEV;
> Also, is there any point to call wmi_driver_register if returning -ENODEV?
> i.e. should the call to driver register be wrapped in a test for
> bios_atter_wdev?

With some bus types it probably makes sense to register the driver whether or
not the device is present.  With the wmi bus it's fixed at bootup.

> 
> 
> >  }
> >
> >  void exit_bios_attr_set_interface(void)
> > diff --git a/drivers/platform/x86/dell-wmi-sysman/passwordattr-interface.c
> b/drivers/platform/x86/dell-wmi-sysman/passwordattr-interface.c
> > index 5780b4d94759..bf449dc5ff47 100644
> > --- a/drivers/platform/x86/dell-wmi-sysman/passwordattr-interface.c
> > +++ b/drivers/platform/x86/dell-wmi-sysman/passwordattr-interface.c
> > @@ -142,7 +142,9 @@ static struct wmi_driver bios_attr_pass_interface_driver
> = {
> >
> >  int init_bios_attr_pass_interface(void)
> >  {
> > -	return wmi_driver_register(&bios_attr_pass_interface_driver);
> > +	int ret = wmi_driver_register(&bios_attr_pass_interface_driver);
> > +
> > +	return wmi_priv.password_attr_wdev ? ret : -ENODEV;
> same comments as above only for password_atter_wdev.
> 
> --mark
> 
> >  }
> >
> >  void exit_bios_attr_pass_interface(void)
> > diff --git a/drivers/platform/x86/dell-wmi-sysman/sysman.c
> b/drivers/platform/x86/dell-wmi-sysman/sysman.c
> > index cb81010ba1a2..d9ad0e83b66f 100644
> > --- a/drivers/platform/x86/dell-wmi-sysman/sysman.c
> > +++ b/drivers/platform/x86/dell-wmi-sysman/sysman.c
> > @@ -513,13 +513,13 @@ static int __init sysman_init(void)
> >  	}
> >
> >  	ret = init_bios_attr_set_interface();
> > -	if (ret || !wmi_priv.bios_attr_wdev) {
> > +	if (ret) {
> >  		pr_debug("failed to initialize set interface\n");
> >  		goto fail_set_interface;
> >  	}
> >
> >  	ret = init_bios_attr_pass_interface();
> > -	if (ret || !wmi_priv.password_attr_wdev) {
> > +	if (ret) {
> >  		pr_debug("failed to initialize pass interface\n");
> >  		goto fail_pass_interface;
> >  	}
> > --
> > 2.25.1
> >
Hans de Goede Feb. 19, 2021, 10:42 a.m. UTC | #3
Hi,

On 2/19/21 12:26 AM, Limonciello, Mario wrote:
> 
> 
>> -----Original Message-----
>> From: mark gross <mgross@linux.intel.com>
>> Sent: Thursday, February 18, 2021 16:49
>> To: Limonciello, Mario
>> Cc: Hans De Goede; Mark Gross; LKML; platform-driver-x86@vger.kernel.org;
>> Bharathi, Divya; Alexander Naumann
>> Subject: Re: [PATCH] platform/x86: dell-wmi-sysman: correct an initialization
>> failure
>>
>>
>> [EXTERNAL EMAIL]
>>
>> On Thu, Feb 18, 2021 at 01:17:23PM -0600, Mario Limonciello wrote:
>>> On Dell systems that don't support this interface the module is
>>> mistakingly returning error code "0", when it should be returning
>>> -ENODEV.  Correct a logic error to guarantee the correct return code.
>>>
>>> Cc: Divya Bharathi <Divya_Bharathi@Dell.com>
>>> Reported-by: Alexander Naumann <alexandernaumann@gmx.de>
>>> Signed-off-by: Mario Limonciello <mario.limonciello@dell.com>
>>> ---
>>>  drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c     | 4 +++-
>>>  drivers/platform/x86/dell-wmi-sysman/passwordattr-interface.c | 4 +++-
>>>  drivers/platform/x86/dell-wmi-sysman/sysman.c                 | 4 ++--
>>>  3 files changed, 8 insertions(+), 4 deletions(-)
>>>
>>> diff --git a/drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c
>> b/drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c
>>> index f95d8ddace5a..8d59f81f9db4 100644
>>> --- a/drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c
>>> +++ b/drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c
>>> @@ -175,7 +175,9 @@ static struct wmi_driver bios_attr_set_interface_driver
>> = {
>>>
>>>  int init_bios_attr_set_interface(void)
>>>  {
>>> -	return wmi_driver_register(&bios_attr_set_interface_driver);
>>> +	int ret = wmi_driver_register(&bios_attr_set_interface_driver);
>> I have to ask if the propper fix should be in wmi_driver_register
> 
> Do you mean something like this?
> 
> diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c
> index c669676ea8e8..89d04c5e3ab9 100644
> --- a/drivers/platform/x86/wmi.c
> +++ b/drivers/platform/x86/wmi.c
> @@ -1415,6 +1415,11 @@ static int acpi_wmi_probe(struct platform_device *device)
>  int __must_check __wmi_driver_register(struct wmi_driver *driver,
>                                        struct module *owner)
>  {
> +       const struct wmi_device_id *id = driver->id_table;
> +
> +       if (!wmi_has_guid(id->guid_string))
> +               return -ENODEV;
> +
>         driver->driver.owner = owner;
>         driver->driver.bus = &wmi_bus_type;
> 

No, drivers should be able to register before the GUID shows up. I know that
the GUID showing up later will likely never happen with WMI, but having a match
check like this in the driver_register function is highly unusual and would
be different from what all other busses do.

But your initial fix here is wrong too, because it does call wmi_driver_register,
which succeeds and then makes sysman_init() exit with -ENODEV.

Returning -ENODEV from sysman_init() is what we want, this causes the entire
insmod to be aborted, without logging an error (because of -ENODEV) so the
code will not be taking up memory.

This means that the memory into which the module was loaded before the kernel
calls sysman_init() will be free-ed and now the *still* registered WMI driver
entry will point to that free-ed memory, which is not good (TM).

So instead init_bios_attr_set_interface() should become something like this:

int init_bios_attr_set_interface(void)
{
	int ret;

	ret = wmi_driver_register(&bios_attr_set_interface_driver);
	if (ret)
		return ret;

	if (!wmi_priv.bios_attr_wdev) {
		wmi_driver_unregister(&bios_attr_set_interface_driver);
		return -ENODEV;
	}

	return 0;
}

And the same for the init_bios_attr_pass_interface() function.

This follows the standard kernel pattern that a function should always
undo any things / resource-allocations it has done on error before
exiting with an error.

Regards,

Hans
diff mbox series

Patch

diff --git a/drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c b/drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c
index f95d8ddace5a..8d59f81f9db4 100644
--- a/drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c
+++ b/drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c
@@ -175,7 +175,9 @@  static struct wmi_driver bios_attr_set_interface_driver = {
 
 int init_bios_attr_set_interface(void)
 {
-	return wmi_driver_register(&bios_attr_set_interface_driver);
+	int ret = wmi_driver_register(&bios_attr_set_interface_driver);
+
+	return wmi_priv.bios_attr_wdev ? ret : -ENODEV;
 }
 
 void exit_bios_attr_set_interface(void)
diff --git a/drivers/platform/x86/dell-wmi-sysman/passwordattr-interface.c b/drivers/platform/x86/dell-wmi-sysman/passwordattr-interface.c
index 5780b4d94759..bf449dc5ff47 100644
--- a/drivers/platform/x86/dell-wmi-sysman/passwordattr-interface.c
+++ b/drivers/platform/x86/dell-wmi-sysman/passwordattr-interface.c
@@ -142,7 +142,9 @@  static struct wmi_driver bios_attr_pass_interface_driver = {
 
 int init_bios_attr_pass_interface(void)
 {
-	return wmi_driver_register(&bios_attr_pass_interface_driver);
+	int ret = wmi_driver_register(&bios_attr_pass_interface_driver);
+
+	return wmi_priv.password_attr_wdev ? ret : -ENODEV;
 }
 
 void exit_bios_attr_pass_interface(void)
diff --git a/drivers/platform/x86/dell-wmi-sysman/sysman.c b/drivers/platform/x86/dell-wmi-sysman/sysman.c
index cb81010ba1a2..d9ad0e83b66f 100644
--- a/drivers/platform/x86/dell-wmi-sysman/sysman.c
+++ b/drivers/platform/x86/dell-wmi-sysman/sysman.c
@@ -513,13 +513,13 @@  static int __init sysman_init(void)
 	}
 
 	ret = init_bios_attr_set_interface();
-	if (ret || !wmi_priv.bios_attr_wdev) {
+	if (ret) {
 		pr_debug("failed to initialize set interface\n");
 		goto fail_set_interface;
 	}
 
 	ret = init_bios_attr_pass_interface();
-	if (ret || !wmi_priv.password_attr_wdev) {
+	if (ret) {
 		pr_debug("failed to initialize pass interface\n");
 		goto fail_pass_interface;
 	}