Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1312449 > unrolled thread
| Started by | Andy Lutomirski <luto@kernel.org> |
|---|---|
| First post | 2016-01-19 20:10 +0100 |
| Last post | 2016-01-19 20:10 +0100 |
| Articles | 4 — 1 participant |
Back to article view | Back to linux.kernel
[PATCH v3 0/3] dell-wmi: DMI misuse fixes Andy Lutomirski <luto@kernel.org> - 2016-01-19 20:10 +0100
[PATCH v3 1/3] dell-wmi: Stop storing pointers to DMI tables Andy Lutomirski <luto@kernel.org> - 2016-01-19 20:10 +0100
[PATCH v3 3/3] dell-wmi: Clean up hotkey table size check Andy Lutomirski <luto@kernel.org> - 2016-01-19 20:10 +0100
[PATCH v3 2/3] dell-wmi, dell-laptop: select DMI Andy Lutomirski <luto@kernel.org> - 2016-01-19 20:10 +0100
| From | Andy Lutomirski <luto@kernel.org> |
|---|---|
| Date | 2016-01-19 20:10 +0100 |
| Subject | [PATCH v3 0/3] dell-wmi: DMI misuse fixes |
| Message-ID | <qSJPb-3EO-1@gated-at.bofh.it> |
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
[toc] | [next] | [standalone]
| From | Andy Lutomirski <luto@kernel.org> |
|---|---|
| Date | 2016-01-19 20:10 +0100 |
| Subject | [PATCH v3 1/3] dell-wmi: Stop storing pointers to DMI tables |
| Message-ID | <qSJPc-3EO-3@gated-at.bofh.it> |
| In reply to | #1312449 |
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
[toc] | [prev] | [next] | [standalone]
| From | Andy Lutomirski <luto@kernel.org> |
|---|---|
| Date | 2016-01-19 20:10 +0100 |
| Subject | [PATCH v3 3/3] dell-wmi: Clean up hotkey table size check |
| Message-ID | <qSJPc-3EO-17@gated-at.bofh.it> |
| In reply to | #1312449 |
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
[toc] | [prev] | [next] | [standalone]
| From | Andy Lutomirski <luto@kernel.org> |
|---|---|
| Date | 2016-01-19 20:10 +0100 |
| Subject | [PATCH v3 2/3] dell-wmi, dell-laptop: select DMI |
| Message-ID | <qSJPc-3EO-23@gated-at.bofh.it> |
| In reply to | #1312449 |
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
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web