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 a5afd805e66..eb26d62e518 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 | ||
