mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-22 16:06:04 -05:00
modpost: work around unaligned data access error
With the latest binutils, modpost fails with a bus error on some architectures such as ARM and sparc64. Since binutils commit 1f1b5e506bf0 ("bfd/ELF: restrict file alignment for object files"), the byte offset to each section (sh_offset) in relocatable ELF is no longer guaranteed to be aligned. modpost parses MODULE_DEVICE_TABLE() data structures, which are usually located in the .rodata section. If it is not properly aligned, unaligned access errors may occur. To address the issue, this commit imports the get_unaligned() helper from include/linux/unaligned.h. The get_unaligned_native() helper caters to the endianness in addition to handling the unaligned access. I slightly refactored do_pcmcia_entry() and do_input() to avoid writing back to an unaligned address. (We would need the put_unaligned() helper to do that.) The addend_*_rel() functions need similar adjustments because the .text sections are not aligned either. It seems that the .symtab, .rel.* and .rela.* sections are still aligned. Keep normal pointer access for these sections to avoid unnecessary performance costs. Reported-by: Paulo Pisati <paolo.pisati@canonical.com> Reported-by: Matthias Klose <doko@debian.org> Closes: https://sourceware.org/bugzilla/show_bug.cgi?id=32435 Reported-by: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de> Closes: https://sourceware.org/bugzilla/show_bug.cgi?id=32493 Signed-off-by: Masahiro Yamada <masahiroy@kernel.org> Tested-by: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
This commit is contained in:
parent
e1352d7ead
commit
8fe1a63d3d
3 changed files with 39 additions and 25 deletions
|
@ -132,7 +132,8 @@ struct devtable {
|
||||||
* based at address m.
|
* based at address m.
|
||||||
*/
|
*/
|
||||||
#define DEF_FIELD(m, devid, f) \
|
#define DEF_FIELD(m, devid, f) \
|
||||||
typeof(((struct devid *)0)->f) f = TO_NATIVE(*(typeof(f) *)((m) + OFF_##devid##_##f))
|
typeof(((struct devid *)0)->f) f = \
|
||||||
|
get_unaligned_native((typeof(f) *)((m) + OFF_##devid##_##f))
|
||||||
|
|
||||||
/* Define a variable f that holds the address of field f of struct devid
|
/* Define a variable f that holds the address of field f of struct devid
|
||||||
* based at address m. Due to the way typeof works, for a field of type
|
* based at address m. Due to the way typeof works, for a field of type
|
||||||
|
@ -600,7 +601,7 @@ static void do_pnp_card_entry(struct module *mod, void *symval)
|
||||||
static void do_pcmcia_entry(struct module *mod, void *symval)
|
static void do_pcmcia_entry(struct module *mod, void *symval)
|
||||||
{
|
{
|
||||||
char alias[256] = {};
|
char alias[256] = {};
|
||||||
unsigned int i;
|
|
||||||
DEF_FIELD(symval, pcmcia_device_id, match_flags);
|
DEF_FIELD(symval, pcmcia_device_id, match_flags);
|
||||||
DEF_FIELD(symval, pcmcia_device_id, manf_id);
|
DEF_FIELD(symval, pcmcia_device_id, manf_id);
|
||||||
DEF_FIELD(symval, pcmcia_device_id, card_id);
|
DEF_FIELD(symval, pcmcia_device_id, card_id);
|
||||||
|
@ -609,10 +610,6 @@ static void do_pcmcia_entry(struct module *mod, void *symval)
|
||||||
DEF_FIELD(symval, pcmcia_device_id, device_no);
|
DEF_FIELD(symval, pcmcia_device_id, device_no);
|
||||||
DEF_FIELD_ADDR(symval, pcmcia_device_id, prod_id_hash);
|
DEF_FIELD_ADDR(symval, pcmcia_device_id, prod_id_hash);
|
||||||
|
|
||||||
for (i=0; i<4; i++) {
|
|
||||||
(*prod_id_hash)[i] = TO_NATIVE((*prod_id_hash)[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
ADD(alias, "m", match_flags & PCMCIA_DEV_ID_MATCH_MANF_ID,
|
ADD(alias, "m", match_flags & PCMCIA_DEV_ID_MATCH_MANF_ID,
|
||||||
manf_id);
|
manf_id);
|
||||||
ADD(alias, "c", match_flags & PCMCIA_DEV_ID_MATCH_CARD_ID,
|
ADD(alias, "c", match_flags & PCMCIA_DEV_ID_MATCH_CARD_ID,
|
||||||
|
@ -623,10 +620,14 @@ static void do_pcmcia_entry(struct module *mod, void *symval)
|
||||||
function);
|
function);
|
||||||
ADD(alias, "pfn", match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO,
|
ADD(alias, "pfn", match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO,
|
||||||
device_no);
|
device_no);
|
||||||
ADD(alias, "pa", match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID1, (*prod_id_hash)[0]);
|
ADD(alias, "pa", match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID1,
|
||||||
ADD(alias, "pb", match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID2, (*prod_id_hash)[1]);
|
get_unaligned_native(*prod_id_hash + 0));
|
||||||
ADD(alias, "pc", match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID3, (*prod_id_hash)[2]);
|
ADD(alias, "pb", match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID2,
|
||||||
ADD(alias, "pd", match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID4, (*prod_id_hash)[3]);
|
get_unaligned_native(*prod_id_hash + 1));
|
||||||
|
ADD(alias, "pc", match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID3,
|
||||||
|
get_unaligned_native(*prod_id_hash + 2));
|
||||||
|
ADD(alias, "pd", match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID4,
|
||||||
|
get_unaligned_native(*prod_id_hash + 3));
|
||||||
|
|
||||||
module_alias_printf(mod, true, "pcmcia:%s", alias);
|
module_alias_printf(mod, true, "pcmcia:%s", alias);
|
||||||
}
|
}
|
||||||
|
@ -654,10 +655,9 @@ static void do_input(char *alias,
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
for (i = min / BITS_PER_LONG; i < max / BITS_PER_LONG + 1; i++)
|
|
||||||
arr[i] = TO_NATIVE(arr[i]);
|
|
||||||
for (i = min; i <= max; i++)
|
for (i = min; i <= max; i++)
|
||||||
if (arr[i / BITS_PER_LONG] & (1ULL << (i%BITS_PER_LONG)))
|
if (get_unaligned_native(arr + i / BITS_PER_LONG) &
|
||||||
|
(1ULL << (i % BITS_PER_LONG)))
|
||||||
sprintf(alias + strlen(alias), "%X,*", i);
|
sprintf(alias + strlen(alias), "%X,*", i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1138,9 +1138,9 @@ static Elf_Addr addend_386_rel(uint32_t *location, unsigned int r_type)
|
||||||
{
|
{
|
||||||
switch (r_type) {
|
switch (r_type) {
|
||||||
case R_386_32:
|
case R_386_32:
|
||||||
return TO_NATIVE(*location);
|
return get_unaligned_native(location);
|
||||||
case R_386_PC32:
|
case R_386_PC32:
|
||||||
return TO_NATIVE(*location) + 4;
|
return get_unaligned_native(location) + 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (Elf_Addr)(-1);
|
return (Elf_Addr)(-1);
|
||||||
|
@ -1161,24 +1161,24 @@ static Elf_Addr addend_arm_rel(void *loc, Elf_Sym *sym, unsigned int r_type)
|
||||||
switch (r_type) {
|
switch (r_type) {
|
||||||
case R_ARM_ABS32:
|
case R_ARM_ABS32:
|
||||||
case R_ARM_REL32:
|
case R_ARM_REL32:
|
||||||
inst = TO_NATIVE(*(uint32_t *)loc);
|
inst = get_unaligned_native((uint32_t *)loc);
|
||||||
return inst + sym->st_value;
|
return inst + sym->st_value;
|
||||||
case R_ARM_MOVW_ABS_NC:
|
case R_ARM_MOVW_ABS_NC:
|
||||||
case R_ARM_MOVT_ABS:
|
case R_ARM_MOVT_ABS:
|
||||||
inst = TO_NATIVE(*(uint32_t *)loc);
|
inst = get_unaligned_native((uint32_t *)loc);
|
||||||
offset = sign_extend32(((inst & 0xf0000) >> 4) | (inst & 0xfff),
|
offset = sign_extend32(((inst & 0xf0000) >> 4) | (inst & 0xfff),
|
||||||
15);
|
15);
|
||||||
return offset + sym->st_value;
|
return offset + sym->st_value;
|
||||||
case R_ARM_PC24:
|
case R_ARM_PC24:
|
||||||
case R_ARM_CALL:
|
case R_ARM_CALL:
|
||||||
case R_ARM_JUMP24:
|
case R_ARM_JUMP24:
|
||||||
inst = TO_NATIVE(*(uint32_t *)loc);
|
inst = get_unaligned_native((uint32_t *)loc);
|
||||||
offset = sign_extend32((inst & 0x00ffffff) << 2, 25);
|
offset = sign_extend32((inst & 0x00ffffff) << 2, 25);
|
||||||
return offset + sym->st_value + 8;
|
return offset + sym->st_value + 8;
|
||||||
case R_ARM_THM_MOVW_ABS_NC:
|
case R_ARM_THM_MOVW_ABS_NC:
|
||||||
case R_ARM_THM_MOVT_ABS:
|
case R_ARM_THM_MOVT_ABS:
|
||||||
upper = TO_NATIVE(*(uint16_t *)loc);
|
upper = get_unaligned_native((uint16_t *)loc);
|
||||||
lower = TO_NATIVE(*((uint16_t *)loc + 1));
|
lower = get_unaligned_native((uint16_t *)loc + 1);
|
||||||
offset = sign_extend32(((upper & 0x000f) << 12) |
|
offset = sign_extend32(((upper & 0x000f) << 12) |
|
||||||
((upper & 0x0400) << 1) |
|
((upper & 0x0400) << 1) |
|
||||||
((lower & 0x7000) >> 4) |
|
((lower & 0x7000) >> 4) |
|
||||||
|
@ -1195,8 +1195,8 @@ static Elf_Addr addend_arm_rel(void *loc, Elf_Sym *sym, unsigned int r_type)
|
||||||
* imm11 = lower[10:0]
|
* imm11 = lower[10:0]
|
||||||
* imm32 = SignExtend(S:J2:J1:imm6:imm11:'0')
|
* imm32 = SignExtend(S:J2:J1:imm6:imm11:'0')
|
||||||
*/
|
*/
|
||||||
upper = TO_NATIVE(*(uint16_t *)loc);
|
upper = get_unaligned_native((uint16_t *)loc);
|
||||||
lower = TO_NATIVE(*((uint16_t *)loc + 1));
|
lower = get_unaligned_native((uint16_t *)loc + 1);
|
||||||
|
|
||||||
sign = (upper >> 10) & 1;
|
sign = (upper >> 10) & 1;
|
||||||
j1 = (lower >> 13) & 1;
|
j1 = (lower >> 13) & 1;
|
||||||
|
@ -1219,8 +1219,8 @@ static Elf_Addr addend_arm_rel(void *loc, Elf_Sym *sym, unsigned int r_type)
|
||||||
* I2 = NOT(J2 XOR S)
|
* I2 = NOT(J2 XOR S)
|
||||||
* imm32 = SignExtend(S:I1:I2:imm10:imm11:'0')
|
* imm32 = SignExtend(S:I1:I2:imm10:imm11:'0')
|
||||||
*/
|
*/
|
||||||
upper = TO_NATIVE(*(uint16_t *)loc);
|
upper = get_unaligned_native((uint16_t *)loc);
|
||||||
lower = TO_NATIVE(*((uint16_t *)loc + 1));
|
lower = get_unaligned_native((uint16_t *)loc + 1);
|
||||||
|
|
||||||
sign = (upper >> 10) & 1;
|
sign = (upper >> 10) & 1;
|
||||||
j1 = (lower >> 13) & 1;
|
j1 = (lower >> 13) & 1;
|
||||||
|
@ -1241,7 +1241,7 @@ static Elf_Addr addend_mips_rel(uint32_t *location, unsigned int r_type)
|
||||||
{
|
{
|
||||||
uint32_t inst;
|
uint32_t inst;
|
||||||
|
|
||||||
inst = TO_NATIVE(*location);
|
inst = get_unaligned_native(location);
|
||||||
switch (r_type) {
|
switch (r_type) {
|
||||||
case R_MIPS_LO16:
|
case R_MIPS_LO16:
|
||||||
return inst & 0xffff;
|
return inst & 0xffff;
|
||||||
|
|
|
@ -65,6 +65,20 @@
|
||||||
#define TO_NATIVE(x) \
|
#define TO_NATIVE(x) \
|
||||||
(target_is_big_endian == host_is_big_endian ? x : bswap(x))
|
(target_is_big_endian == host_is_big_endian ? x : bswap(x))
|
||||||
|
|
||||||
|
#define __get_unaligned_t(type, ptr) ({ \
|
||||||
|
const struct { type x; } __attribute__((__packed__)) *__pptr = \
|
||||||
|
(typeof(__pptr))(ptr); \
|
||||||
|
__pptr->x; \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define get_unaligned(ptr) __get_unaligned_t(typeof(*(ptr)), (ptr))
|
||||||
|
|
||||||
|
#define get_unaligned_native(ptr) \
|
||||||
|
({ \
|
||||||
|
typeof(*(ptr)) _val = get_unaligned(ptr); \
|
||||||
|
TO_NATIVE(_val); \
|
||||||
|
})
|
||||||
|
|
||||||
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||||
|
|
||||||
#define strstarts(str, prefix) (strncmp(str, prefix, strlen(prefix)) == 0)
|
#define strstarts(str, prefix) (strncmp(str, prefix, strlen(prefix)) == 0)
|
||||||
|
|
Loading…
Reference in a new issue