diff options
author | Mike Waychison <mikew@google.com> | 2011-02-25 18:41:49 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2011-02-25 19:10:03 -0500 |
commit | 66245ad025e02fe9e727c03d43308bb24e346bb6 (patch) | |
tree | 9597235bf126cde0d4d5e0a6d51a58bcbe8d15ca /drivers/firmware | |
parent | 9effd8221fc109e5d33e417e3eaaf8e475003e2d (diff) |
firmware: Fix unaligned memory accesses in dmi-sysfs
DMI entries are arranged in memory back to back with no alignment
guarantees. This means that the struct dmi_header passed to callbacks
from dmi_walk() itself isn't byte aligned. This causes problems on
architectures that expect aligned data, such as IA64.
The dmi-sysfs patchset introduced structure member accesses through this
passed in dmi_header. Fix this by memcpy()ing the structures to
temporary locations on stack when inspecting/copying them.
Signed-off-by: Mike Waychison <mikew@google.com>
Tested-by: Tony Luck <tony.luck@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/firmware')
-rw-r--r-- | drivers/firmware/dmi-sysfs.c | 28 |
1 files changed, 13 insertions, 15 deletions
diff --git a/drivers/firmware/dmi-sysfs.c b/drivers/firmware/dmi-sysfs.c index a5afd805e66f..eb26d62e5188 100644 --- a/drivers/firmware/dmi-sysfs.c +++ b/drivers/firmware/dmi-sysfs.c | |||
@@ -263,20 +263,16 @@ struct dmi_system_event_log { | |||
263 | u8 supported_log_type_descriptos[0]; | 263 | u8 supported_log_type_descriptos[0]; |
264 | } __packed; | 264 | } __packed; |
265 | 265 | ||
266 | static const struct dmi_system_event_log *to_sel(const struct dmi_header *dh) | ||
267 | { | ||
268 | return (const struct dmi_system_event_log *)dh; | ||
269 | } | ||
270 | |||
271 | #define DMI_SYSFS_SEL_FIELD(_field) \ | 266 | #define DMI_SYSFS_SEL_FIELD(_field) \ |
272 | static ssize_t dmi_sysfs_sel_##_field(struct dmi_sysfs_entry *entry, \ | 267 | static ssize_t dmi_sysfs_sel_##_field(struct dmi_sysfs_entry *entry, \ |
273 | const struct dmi_header *dh, \ | 268 | const struct dmi_header *dh, \ |
274 | char *buf) \ | 269 | char *buf) \ |
275 | { \ | 270 | { \ |
276 | const struct dmi_system_event_log *sel = to_sel(dh); \ | 271 | struct dmi_system_event_log sel; \ |
277 | if (sizeof(*sel) > dmi_entry_length(dh)) \ | 272 | if (sizeof(sel) > dmi_entry_length(dh)) \ |
278 | return -EIO; \ | 273 | return -EIO; \ |
279 | return sprintf(buf, "%u\n", sel->_field); \ | 274 | memcpy(&sel, dh, sizeof(sel)); \ |
275 | return sprintf(buf, "%u\n", sel._field); \ | ||
280 | } \ | 276 | } \ |
281 | static DMI_SYSFS_MAPPED_ATTR(sel, _field) | 277 | static DMI_SYSFS_MAPPED_ATTR(sel, _field) |
282 | 278 | ||
@@ -403,26 +399,28 @@ static ssize_t dmi_sel_raw_read_helper(struct dmi_sysfs_entry *entry, | |||
403 | void *_state) | 399 | void *_state) |
404 | { | 400 | { |
405 | struct dmi_read_state *state = _state; | 401 | struct dmi_read_state *state = _state; |
406 | const struct dmi_system_event_log *sel = to_sel(dh); | 402 | struct dmi_system_event_log sel; |
407 | 403 | ||
408 | if (sizeof(*sel) > dmi_entry_length(dh)) | 404 | if (sizeof(sel) > dmi_entry_length(dh)) |
409 | return -EIO; | 405 | return -EIO; |
410 | 406 | ||
411 | switch (sel->access_method) { | 407 | memcpy(&sel, dh, sizeof(sel)); |
408 | |||
409 | switch (sel.access_method) { | ||
412 | case DMI_SEL_ACCESS_METHOD_IO8: | 410 | case DMI_SEL_ACCESS_METHOD_IO8: |
413 | case DMI_SEL_ACCESS_METHOD_IO2x8: | 411 | case DMI_SEL_ACCESS_METHOD_IO2x8: |
414 | case DMI_SEL_ACCESS_METHOD_IO16: | 412 | case DMI_SEL_ACCESS_METHOD_IO16: |
415 | return dmi_sel_raw_read_io(entry, sel, state->buf, | 413 | return dmi_sel_raw_read_io(entry, &sel, state->buf, |
416 | state->pos, state->count); | 414 | state->pos, state->count); |
417 | case DMI_SEL_ACCESS_METHOD_PHYS32: | 415 | case DMI_SEL_ACCESS_METHOD_PHYS32: |
418 | return dmi_sel_raw_read_phys32(entry, sel, state->buf, | 416 | return dmi_sel_raw_read_phys32(entry, &sel, state->buf, |
419 | state->pos, state->count); | 417 | state->pos, state->count); |
420 | case DMI_SEL_ACCESS_METHOD_GPNV: | 418 | case DMI_SEL_ACCESS_METHOD_GPNV: |
421 | pr_info("dmi-sysfs: GPNV support missing.\n"); | 419 | pr_info("dmi-sysfs: GPNV support missing.\n"); |
422 | return -EIO; | 420 | return -EIO; |
423 | default: | 421 | default: |
424 | pr_info("dmi-sysfs: Unknown access method %02x\n", | 422 | pr_info("dmi-sysfs: Unknown access method %02x\n", |
425 | sel->access_method); | 423 | sel.access_method); |
426 | return -EIO; | 424 | return -EIO; |
427 | } | 425 | } |
428 | } | 426 | } |
@@ -595,7 +593,7 @@ static void __init dmi_sysfs_register_handle(const struct dmi_header *dh, | |||
595 | } | 593 | } |
596 | 594 | ||
597 | /* Set the key */ | 595 | /* Set the key */ |
598 | entry->dh = *dh; | 596 | memcpy(&entry->dh, dh, sizeof(*dh)); |
599 | entry->instance = instance_counts[dh->type]++; | 597 | entry->instance = instance_counts[dh->type]++; |
600 | entry->position = position_count++; | 598 | entry->position = position_count++; |
601 | 599 | ||