Skip to content

Commit

Permalink
firmware: Fix unaligned memory accesses in dmi-sysfs
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
waych authored and gregkh committed Feb 26, 2011
1 parent 9effd82 commit 66245ad
Showing 1 changed file with 13 additions and 15 deletions.
28 changes: 13 additions & 15 deletions drivers/firmware/dmi-sysfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -263,20 +263,16 @@ struct dmi_system_event_log {
u8 supported_log_type_descriptos[0];
} __packed;

static const struct dmi_system_event_log *to_sel(const struct dmi_header *dh)
{
return (const struct dmi_system_event_log *)dh;
}

#define DMI_SYSFS_SEL_FIELD(_field) \
static ssize_t dmi_sysfs_sel_##_field(struct dmi_sysfs_entry *entry, \
const struct dmi_header *dh, \
char *buf) \
{ \
const struct dmi_system_event_log *sel = to_sel(dh); \
if (sizeof(*sel) > dmi_entry_length(dh)) \
struct dmi_system_event_log sel; \
if (sizeof(sel) > dmi_entry_length(dh)) \
return -EIO; \
return sprintf(buf, "%u\n", sel->_field); \
memcpy(&sel, dh, sizeof(sel)); \
return sprintf(buf, "%u\n", sel._field); \
} \
static DMI_SYSFS_MAPPED_ATTR(sel, _field)

Expand Down Expand Up @@ -403,26 +399,28 @@ static ssize_t dmi_sel_raw_read_helper(struct dmi_sysfs_entry *entry,
void *_state)
{
struct dmi_read_state *state = _state;
const struct dmi_system_event_log *sel = to_sel(dh);
struct dmi_system_event_log sel;

if (sizeof(*sel) > dmi_entry_length(dh))
if (sizeof(sel) > dmi_entry_length(dh))
return -EIO;

switch (sel->access_method) {
memcpy(&sel, dh, sizeof(sel));

switch (sel.access_method) {
case DMI_SEL_ACCESS_METHOD_IO8:
case DMI_SEL_ACCESS_METHOD_IO2x8:
case DMI_SEL_ACCESS_METHOD_IO16:
return dmi_sel_raw_read_io(entry, sel, state->buf,
return dmi_sel_raw_read_io(entry, &sel, state->buf,
state->pos, state->count);
case DMI_SEL_ACCESS_METHOD_PHYS32:
return dmi_sel_raw_read_phys32(entry, sel, state->buf,
return dmi_sel_raw_read_phys32(entry, &sel, state->buf,
state->pos, state->count);
case DMI_SEL_ACCESS_METHOD_GPNV:
pr_info("dmi-sysfs: GPNV support missing.\n");
return -EIO;
default:
pr_info("dmi-sysfs: Unknown access method %02x\n",
sel->access_method);
sel.access_method);
return -EIO;
}
}
Expand Down Expand Up @@ -595,7 +593,7 @@ static void __init dmi_sysfs_register_handle(const struct dmi_header *dh,
}

/* Set the key */
entry->dh = *dh;
memcpy(&entry->dh, dh, sizeof(*dh));
entry->instance = instance_counts[dh->type]++;
entry->position = position_count++;

Expand Down

0 comments on commit 66245ad

Please sign in to comment.