All of lore.kernel.org
 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:08 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.