Skip to content

Commit 7444f83

Browse files
Wer-Wolfij-intel
authored andcommitted
platform/x86: wmi: Fix refcounting of WMI devices in legacy functions
Until now, legacy GUID-based functions where using find_guid() when searching for WMI devices, which did no refcounting on the returned WMI device. This meant that the WMI device could disappear at any moment, potentially leading to various errors. Fix this by using bus_find_device() which returns an actual reference to the found WMI device. Signed-off-by: Armin Wolf <[email protected]> Link: https://lore.kernel.org/r/[email protected] Reviewed-by: Ilpo Järvinen <[email protected]> Signed-off-by: Ilpo Järvinen <[email protected]>
1 parent 4186a47 commit 7444f83

File tree

1 file changed

+107
-60
lines changed
  • drivers/platform/x86

1 file changed

+107
-60
lines changed

drivers/platform/x86/wmi.c

Lines changed: 107 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -109,33 +109,13 @@ static const char * const allow_duplicates[] = {
109109
NULL
110110
};
111111

112+
#define dev_to_wblock(__dev) container_of_const(__dev, struct wmi_block, dev.dev)
113+
#define dev_to_wdev(__dev) container_of_const(__dev, struct wmi_device, dev)
114+
112115
/*
113116
* GUID parsing functions
114117
*/
115118

116-
static acpi_status find_guid(const char *guid_string, struct wmi_block **out)
117-
{
118-
guid_t guid_input;
119-
struct wmi_block *wblock;
120-
121-
if (!guid_string)
122-
return AE_BAD_PARAMETER;
123-
124-
if (guid_parse(guid_string, &guid_input))
125-
return AE_BAD_PARAMETER;
126-
127-
list_for_each_entry(wblock, &wmi_block_list, list) {
128-
if (guid_equal(&wblock->gblock.guid, &guid_input)) {
129-
if (out)
130-
*out = wblock;
131-
132-
return AE_OK;
133-
}
134-
}
135-
136-
return AE_NOT_FOUND;
137-
}
138-
139119
static bool guid_parse_and_compare(const char *string, const guid_t *guid)
140120
{
141121
guid_t guid_input;
@@ -245,6 +225,41 @@ static acpi_status get_event_data(const struct wmi_block *wblock, struct acpi_bu
245225
return acpi_evaluate_object(wblock->acpi_device->handle, "_WED", &input, out);
246226
}
247227

228+
static int wmidev_match_guid(struct device *dev, const void *data)
229+
{
230+
struct wmi_block *wblock = dev_to_wblock(dev);
231+
const guid_t *guid = data;
232+
233+
if (guid_equal(guid, &wblock->gblock.guid))
234+
return 1;
235+
236+
return 0;
237+
}
238+
239+
static struct bus_type wmi_bus_type;
240+
241+
static struct wmi_device *wmi_find_device_by_guid(const char *guid_string)
242+
{
243+
struct device *dev;
244+
guid_t guid;
245+
int ret;
246+
247+
ret = guid_parse(guid_string, &guid);
248+
if (ret < 0)
249+
return ERR_PTR(ret);
250+
251+
dev = bus_find_device(&wmi_bus_type, NULL, &guid, wmidev_match_guid);
252+
if (!dev)
253+
return ERR_PTR(-ENODEV);
254+
255+
return dev_to_wdev(dev);
256+
}
257+
258+
static void wmi_device_put(struct wmi_device *wdev)
259+
{
260+
put_device(&wdev->dev);
261+
}
262+
248263
/*
249264
* Exported WMI functions
250265
*/
@@ -279,18 +294,17 @@ EXPORT_SYMBOL_GPL(set_required_buffer_size);
279294
*/
280295
int wmi_instance_count(const char *guid_string)
281296
{
282-
struct wmi_block *wblock;
283-
acpi_status status;
297+
struct wmi_device *wdev;
298+
int ret;
284299

285-
status = find_guid(guid_string, &wblock);
286-
if (ACPI_FAILURE(status)) {
287-
if (status == AE_BAD_PARAMETER)
288-
return -EINVAL;
300+
wdev = wmi_find_device_by_guid(guid_string);
301+
if (IS_ERR(wdev))
302+
return PTR_ERR(wdev);
289303

290-
return -ENODEV;
291-
}
304+
ret = wmidev_instance_count(wdev);
305+
wmi_device_put(wdev);
292306

293-
return wmidev_instance_count(&wblock->dev);
307+
return ret;
294308
}
295309
EXPORT_SYMBOL_GPL(wmi_instance_count);
296310

@@ -325,15 +339,18 @@ EXPORT_SYMBOL_GPL(wmidev_instance_count);
325339
acpi_status wmi_evaluate_method(const char *guid_string, u8 instance, u32 method_id,
326340
const struct acpi_buffer *in, struct acpi_buffer *out)
327341
{
328-
struct wmi_block *wblock = NULL;
342+
struct wmi_device *wdev;
329343
acpi_status status;
330344

331-
status = find_guid(guid_string, &wblock);
332-
if (ACPI_FAILURE(status))
333-
return status;
345+
wdev = wmi_find_device_by_guid(guid_string);
346+
if (IS_ERR(wdev))
347+
return AE_ERROR;
348+
349+
status = wmidev_evaluate_method(wdev, instance, method_id, in, out);
334350

335-
return wmidev_evaluate_method(&wblock->dev, instance, method_id,
336-
in, out);
351+
wmi_device_put(wdev);
352+
353+
return status;
337354
}
338355
EXPORT_SYMBOL_GPL(wmi_evaluate_method);
339356

@@ -472,13 +489,19 @@ acpi_status wmi_query_block(const char *guid_string, u8 instance,
472489
struct acpi_buffer *out)
473490
{
474491
struct wmi_block *wblock;
492+
struct wmi_device *wdev;
475493
acpi_status status;
476494

477-
status = find_guid(guid_string, &wblock);
478-
if (ACPI_FAILURE(status))
479-
return status;
495+
wdev = wmi_find_device_by_guid(guid_string);
496+
if (IS_ERR(wdev))
497+
return AE_ERROR;
480498

481-
return __query_block(wblock, instance, out);
499+
wblock = container_of(wdev, struct wmi_block, dev);
500+
status = __query_block(wblock, instance, out);
501+
502+
wmi_device_put(wdev);
503+
504+
return status;
482505
}
483506
EXPORT_SYMBOL_GPL(wmi_query_block);
484507

@@ -516,8 +539,9 @@ EXPORT_SYMBOL_GPL(wmidev_block_query);
516539
acpi_status wmi_set_block(const char *guid_string, u8 instance,
517540
const struct acpi_buffer *in)
518541
{
519-
struct wmi_block *wblock = NULL;
542+
struct wmi_block *wblock;
520543
struct guid_block *block;
544+
struct wmi_device *wdev;
521545
acpi_handle handle;
522546
struct acpi_object_list input;
523547
union acpi_object params[2];
@@ -527,19 +551,26 @@ acpi_status wmi_set_block(const char *guid_string, u8 instance,
527551
if (!in)
528552
return AE_BAD_DATA;
529553

530-
status = find_guid(guid_string, &wblock);
531-
if (ACPI_FAILURE(status))
532-
return status;
554+
wdev = wmi_find_device_by_guid(guid_string);
555+
if (IS_ERR(wdev))
556+
return AE_ERROR;
533557

558+
wblock = container_of(wdev, struct wmi_block, dev);
534559
block = &wblock->gblock;
535560
handle = wblock->acpi_device->handle;
536561

537-
if (block->instance_count <= instance)
538-
return AE_BAD_PARAMETER;
562+
if (block->instance_count <= instance) {
563+
status = AE_BAD_PARAMETER;
564+
565+
goto err_wdev_put;
566+
}
539567

540568
/* Check GUID is a data block */
541-
if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD))
542-
return AE_ERROR;
569+
if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD)) {
570+
status = AE_ERROR;
571+
572+
goto err_wdev_put;
573+
}
543574

544575
input.count = 2;
545576
input.pointer = params;
@@ -551,7 +582,12 @@ acpi_status wmi_set_block(const char *guid_string, u8 instance,
551582

552583
get_acpi_method_name(wblock, 'S', method);
553584

554-
return acpi_evaluate_object(handle, method, &input, NULL);
585+
status = acpi_evaluate_object(handle, method, &input, NULL);
586+
587+
err_wdev_put:
588+
wmi_device_put(wdev);
589+
590+
return status;
555591
}
556592
EXPORT_SYMBOL_GPL(wmi_set_block);
557593

@@ -742,7 +778,15 @@ EXPORT_SYMBOL_GPL(wmi_get_event_data);
742778
*/
743779
bool wmi_has_guid(const char *guid_string)
744780
{
745-
return ACPI_SUCCESS(find_guid(guid_string, NULL));
781+
struct wmi_device *wdev;
782+
783+
wdev = wmi_find_device_by_guid(guid_string);
784+
if (IS_ERR(wdev))
785+
return false;
786+
787+
wmi_device_put(wdev);
788+
789+
return true;
746790
}
747791
EXPORT_SYMBOL_GPL(wmi_has_guid);
748792

@@ -756,20 +800,23 @@ EXPORT_SYMBOL_GPL(wmi_has_guid);
756800
*/
757801
char *wmi_get_acpi_device_uid(const char *guid_string)
758802
{
759-
struct wmi_block *wblock = NULL;
760-
acpi_status status;
803+
struct wmi_block *wblock;
804+
struct wmi_device *wdev;
805+
char *uid;
761806

762-
status = find_guid(guid_string, &wblock);
763-
if (ACPI_FAILURE(status))
807+
wdev = wmi_find_device_by_guid(guid_string);
808+
if (IS_ERR(wdev))
764809
return NULL;
765810

766-
return acpi_device_uid(wblock->acpi_device);
811+
wblock = container_of(wdev, struct wmi_block, dev);
812+
uid = acpi_device_uid(wblock->acpi_device);
813+
814+
wmi_device_put(wdev);
815+
816+
return uid;
767817
}
768818
EXPORT_SYMBOL_GPL(wmi_get_acpi_device_uid);
769819

770-
#define dev_to_wblock(__dev) container_of_const(__dev, struct wmi_block, dev.dev)
771-
#define dev_to_wdev(__dev) container_of_const(__dev, struct wmi_device, dev)
772-
773820
static inline struct wmi_driver *drv_to_wdrv(struct device_driver *drv)
774821
{
775822
return container_of(drv, struct wmi_driver, driver);

0 commit comments

Comments
 (0)