X86 platform drivers
 help / color / mirror / Atom feed
* [PATCH v3 0/3] dell-wmi: DMI misuse fixes
@ 2016-01-19 19:07 Andy Lutomirski
  2016-01-19 19:07 ` [PATCH v3 1/3] dell-wmi: Stop storing pointers to DMI tables Andy Lutomirski
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Andy Lutomirski @ 2016-01-19 19:07 UTC (permalink / raw)
  To: Pali Rohár, platform-driver-x86, Jean Delvare
  Cc: linux-kernel, Andy Lutomirski

This may all be 4.5 material.

Changes from v2:
 - Dropped the dmi_walk return value change.  I'll resend it separately.
 - Rewrite the hotkey_num change
 - Add the select DMI patch.
 - Fix patch 1 error handling.

Changes from v1:
 - Patch 1 has minor tweaks from Jean.
 - Patches 2 and 3 are new.
 
Andy Lutomirski (3):
  dell-wmi: Stop storing pointers to DMI tables
  dell-wmi, dell-laptop: select DMI
  dell-wmi: Clean up hotkey table size check

 drivers/platform/x86/Kconfig    |  2 +
 drivers/platform/x86/dell-wmi.c | 85 +++++++++++++++++++++++++++--------------
 2 files changed, 59 insertions(+), 28 deletions(-)

-- 
2.5.0

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH v3 1/3] dell-wmi: Stop storing pointers to DMI tables
  2016-01-19 19:07 [PATCH v3 0/3] dell-wmi: DMI misuse fixes Andy Lutomirski
@ 2016-01-19 19:07 ` Andy Lutomirski
  2016-01-19 19:07 ` [PATCH v3 2/3] dell-wmi, dell-laptop: select DMI Andy Lutomirski
  2016-01-19 19:07 ` [PATCH v3 3/3] dell-wmi: Clean up hotkey table size check Andy Lutomirski
  2 siblings, 0 replies; 4+ messages in thread
From: Andy Lutomirski @ 2016-01-19 19:07 UTC (permalink / raw)
  To: Pali Rohár, platform-driver-x86, Jean Delvare
  Cc: linux-kernel, Andy Lutomirski

The dmi_walk function maps the DMI table, walks it, and unmaps it.
This means that the dell_bios_hotkey_table that find_hk_type stores
points to unmapped memory by the time it gets read.

I've been able to trigger crashes caused by the stale pointer a
couple of times, but never on a stock kernel.

Fix it by generating the keymap in the dmi_walk callback instead of
storing a pointer.

Signed-off-by: Andy Lutomirski <luto@kernel.org>
---

Changes from v2:
 - dmi_walk failure is no longer fatal (Jean)

Changes from v1:
 - Rename handle_dmi_table to handle_dmi_entry (Jean)
 - Remove useless assignment to results->err (Jean)

drivers/platform/x86/dell-wmi.c | 74 +++++++++++++++++++++++++----------------
 1 file changed, 46 insertions(+), 28 deletions(-)

diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c
index b6f193b07566..5f5b321062a4 100644
--- a/drivers/platform/x86/dell-wmi.c
+++ b/drivers/platform/x86/dell-wmi.c
@@ -114,7 +114,10 @@ struct dell_bios_hotkey_table {
 
 };
 
-static const struct dell_bios_hotkey_table *dell_bios_hotkey_table;
+struct dell_dmi_results {
+	int err;
+	struct key_entry *keymap;
+};
 
 /* Uninitialized entries here are KEY_RESERVED == 0. */
 static const u16 bios_to_linux_keycode[256] __initconst = {
@@ -315,20 +318,34 @@ static void dell_wmi_notify(u32 value, void *context)
 	kfree(obj);
 }
 
-static const struct key_entry * __init dell_wmi_prepare_new_keymap(void)
+static void __init handle_dmi_entry(const struct dmi_header *dm,
+				    void *opaque)
 {
-	int hotkey_num = (dell_bios_hotkey_table->header.length - 4) /
-				sizeof(struct dell_bios_keymap_entry);
+	struct dell_dmi_results *results = opaque;
+	struct dell_bios_hotkey_table *table;
 	struct key_entry *keymap;
-	int i;
+	int hotkey_num, i;
+
+	if (results->err || results->keymap)
+		return;		/* We already found the hotkey table. */
+
+	if (dm->type != 0xb2 || dm->length <= 6)
+		return;
+
+	table = container_of(dm, struct dell_bios_hotkey_table, header);
+
+	hotkey_num = (table->header.length - 4) /
+				sizeof(struct dell_bios_keymap_entry);
 
 	keymap = kcalloc(hotkey_num + 1, sizeof(struct key_entry), GFP_KERNEL);
-	if (!keymap)
-		return NULL;
+	if (!keymap) {
+		results->err = -ENOMEM;
+		return;
+	}
 
 	for (i = 0; i < hotkey_num; i++) {
 		const struct dell_bios_keymap_entry *bios_entry =
-					&dell_bios_hotkey_table->keymap[i];
+					&table->keymap[i];
 
 		/* Uninitialized entries are 0 aka KEY_RESERVED. */
 		u16 keycode = (bios_entry->keycode <
@@ -357,11 +374,12 @@ static const struct key_entry * __init dell_wmi_prepare_new_keymap(void)
 
 	keymap[hotkey_num].type = KE_END;
 
-	return keymap;
+	results->keymap = keymap;
 }
 
 static int __init dell_wmi_input_setup(void)
 {
+	struct dell_dmi_results dmi_results = {};
 	int err;
 
 	dell_wmi_input_dev = input_allocate_device();
@@ -372,20 +390,31 @@ static int __init dell_wmi_input_setup(void)
 	dell_wmi_input_dev->phys = "wmi/input0";
 	dell_wmi_input_dev->id.bustype = BUS_HOST;
 
-	if (dell_new_hk_type) {
-		const struct key_entry *keymap = dell_wmi_prepare_new_keymap();
-		if (!keymap) {
-			err = -ENOMEM;
-			goto err_free_dev;
-		}
+	if (dmi_walk(handle_dmi_entry, &dmi_results)) {
+		/*
+		 * Historically, dell-wmi ignored dmi_walk errors.  A failure
+		 * is certainly surprising, but it probably just indicates
+		 * a very old laptop.
+		 */
+		pr_warn("no DMI; using the old-style hotkey interface\n");
+	}
+
+	if (dmi_results.err) {
+		err = dmi_results.err;
+		goto err_free_dev;
+	}
+
+	if (dmi_results.keymap) {
+		dell_new_hk_type = true;
 
-		err = sparse_keymap_setup(dell_wmi_input_dev, keymap, NULL);
+		err = sparse_keymap_setup(dell_wmi_input_dev,
+					  dmi_results.keymap, NULL);
 
 		/*
 		 * Sparse keymap library makes a copy of keymap so we
 		 * don't need the original one that was allocated.
 		 */
-		kfree(keymap);
+		kfree(dmi_results.keymap);
 	} else {
 		err = sparse_keymap_setup(dell_wmi_input_dev,
 					  dell_wmi_legacy_keymap, NULL);
@@ -412,15 +441,6 @@ static void dell_wmi_input_destroy(void)
 	input_unregister_device(dell_wmi_input_dev);
 }
 
-static void __init find_hk_type(const struct dmi_header *dm, void *dummy)
-{
-	if (dm->type == 0xb2 && dm->length > 6) {
-		dell_new_hk_type = true;
-		dell_bios_hotkey_table =
-			container_of(dm, struct dell_bios_hotkey_table, header);
-	}
-}
-
 static int __init dell_wmi_init(void)
 {
 	int err;
@@ -431,8 +451,6 @@ static int __init dell_wmi_init(void)
 		return -ENODEV;
 	}
 
-	dmi_walk(find_hk_type, NULL);
-
 	err = dell_wmi_input_setup();
 	if (err)
 		return err;
-- 
2.5.0

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH v3 2/3] dell-wmi, dell-laptop: select DMI
  2016-01-19 19:07 [PATCH v3 0/3] dell-wmi: DMI misuse fixes Andy Lutomirski
  2016-01-19 19:07 ` [PATCH v3 1/3] dell-wmi: Stop storing pointers to DMI tables Andy Lutomirski
@ 2016-01-19 19:07 ` Andy Lutomirski
  2016-01-19 19:07 ` [PATCH v3 3/3] dell-wmi: Clean up hotkey table size check Andy Lutomirski
  2 siblings, 0 replies; 4+ messages in thread
From: Andy Lutomirski @ 2016-01-19 19:07 UTC (permalink / raw)
  To: Pali Rohár, platform-driver-x86, Jean Delvare
  Cc: linux-kernel, Andy Lutomirski

dell-wmi and dell-laptop will compile but won't work right if DMI
isn't selected.

Signed-off-by: Andy Lutomirski <luto@kernel.org>
---

Changes from v1:
 - New patch.

drivers/platform/x86/Kconfig | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index f37821f004f9..a2f3dd525559 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -102,6 +102,7 @@ config DELL_LAPTOP
 	select POWER_SUPPLY
 	select LEDS_CLASS
 	select NEW_LEDS
+	select DMI
 	default n
 	---help---
 	This driver adds support for rfkill and backlight control to Dell
@@ -113,6 +114,7 @@ config DELL_WMI
 	depends on INPUT
 	depends on ACPI_VIDEO || ACPI_VIDEO = n
 	select INPUT_SPARSEKMAP
+	select DMI
 	---help---
 	  Say Y here if you want to support WMI-based hotkeys on Dell laptops.
 
-- 
2.5.0

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH v3 3/3] dell-wmi: Clean up hotkey table size check
  2016-01-19 19:07 [PATCH v3 0/3] dell-wmi: DMI misuse fixes Andy Lutomirski
  2016-01-19 19:07 ` [PATCH v3 1/3] dell-wmi: Stop storing pointers to DMI tables Andy Lutomirski
  2016-01-19 19:07 ` [PATCH v3 2/3] dell-wmi, dell-laptop: select DMI Andy Lutomirski
@ 2016-01-19 19:07 ` Andy Lutomirski
  2 siblings, 0 replies; 4+ messages in thread
From: Andy Lutomirski @ 2016-01-19 19:07 UTC (permalink / raw)
  To: Pali Rohár, platform-driver-x86, Jean Delvare
  Cc: linux-kernel, Andy Lutomirski

Checking the table for a minimum size of 7 bytes makes no sense: any valid
hotkey table has a size that's a multiple of 4.

Clean this up: replace the hardcoded header length with a sizeof and
change the check to ignore an empty hotkey table.  The only behavior
change is that a 7-byte table (which is nonsensical) will now be
treated as absent instead of as valid but empty.

Reported-by: Jean Delvare <jdelvare@suse.de>
Signed-off-by: Andy Lutomirski <luto@kernel.org>
---

Changes from v2:
 - Total rewrite.

drivers/platform/x86/dell-wmi.c | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c
index 5f5b321062a4..ae1e643e3464 100644
--- a/drivers/platform/x86/dell-wmi.c
+++ b/drivers/platform/x86/dell-wmi.c
@@ -329,13 +329,24 @@ static void __init handle_dmi_entry(const struct dmi_header *dm,
 	if (results->err || results->keymap)
 		return;		/* We already found the hotkey table. */
 
-	if (dm->type != 0xb2 || dm->length <= 6)
+	if (dm->type != 0xb2)
 		return;
 
 	table = container_of(dm, struct dell_bios_hotkey_table, header);
 
-	hotkey_num = (table->header.length - 4) /
+	hotkey_num = (table->header.length -
+		      sizeof(struct dell_bios_hotkey_table)) /
 				sizeof(struct dell_bios_keymap_entry);
+	if (hotkey_num < 1) {
+		/*
+		 * Historically, dell-wmi would ignore a DMI entry of
+		 * fewer than 7 bytes.  Sizes between 4 and 8 bytes are
+		 * nonsensical (both the header and all entries are 4
+		 * bytes), so we approximate the old behavior by
+		 * ignoring tables with fewer than one entry.
+		 */
+		return;
+	}
 
 	keymap = kcalloc(hotkey_num + 1, sizeof(struct key_entry), GFP_KERNEL);
 	if (!keymap) {
-- 
2.5.0

^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2016-01-19 19:07 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-01-19 19:07 [PATCH v3 0/3] dell-wmi: DMI misuse fixes Andy Lutomirski
2016-01-19 19:07 ` [PATCH v3 1/3] dell-wmi: Stop storing pointers to DMI tables Andy Lutomirski
2016-01-19 19:07 ` [PATCH v3 2/3] dell-wmi, dell-laptop: select DMI Andy Lutomirski
2016-01-19 19:07 ` [PATCH v3 3/3] dell-wmi: Clean up hotkey table size check Andy Lutomirski

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox