From b1b11e922b3de18b7e226da6fe6d87fa17564bde Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Thu, 17 Sep 2020 07:44:53 +0930 Subject: [PATCH] PR26569, R_RISCV_RVC_JUMP results in buffer overflow This patch corrects "size" and "bitsize" in R_RISCV_RVC_* reloc howtos so that elfnn-riscv.c:perform_relocation doesn't access past the end of a section. I've also corrected "size" in the R_RISCV_CALL* reloc howtos since these relocs apply to two consecutive instructions. That caused fallout in the assembler with complaints about "fixup not contained within frag" due to tc-riscv.c:append_insn finishing off a frag after the auipc insn making up a "call" macro. Which is a little rude since the CALL reloc also relocates the following jalr. Fixed by changing the frag handling a little. I've also changed R_RISCV_ALIGN and R_RISCV_TPREL_ADD marker reloc howtos to look like R_RISCV_NONE, and corrected dst_mask for numerous relocs, not that it matters very much. bfd/ PR 26569 * elfxx-riscv.c (howto_table): Correct size and bitsize of R_RISCV_RVC_BRANCH, R_RISCV_RVC_JUMP, and R_RISCV_RVC_LUI. Correct size for R_RISCV_TLS_DTPMOD32, R_RISCV_TLS_DTPREL32, R_RISCV_CALL, and R_RISCV_CALL_PLT. Make R_RISCV_TPREL_ADD and R_RISCV_ALIGN like R_RISCV_NONE. Correct dst_mask many relocs. gas/ * config/tc-riscv.c (append_insn): Don't tie off frags at CALL relocs. (riscv_call): Tie them off after the jalr. (md_apply_fix): Zero fx_size of RELAX fixup. --- bfd/ChangeLog | 9 +++++++ bfd/elfxx-riscv.c | 60 +++++++++++++++++++++---------------------- gas/ChangeLog | 8 ++++++ gas/config/tc-riscv.c | 10 +++++--- 4 files changed, 54 insertions(+), 33 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 66463bdbabe..608e3c796c0 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,12 @@ +2020-09-21 Alan Modra + + PR 26569 + * elfxx-riscv.c (howto_table): Correct size and bitsize of + R_RISCV_RVC_BRANCH, R_RISCV_RVC_JUMP, and R_RISCV_RVC_LUI. + Correct size for R_RISCV_TLS_DTPMOD32, R_RISCV_TLS_DTPREL32, + R_RISCV_CALL, and R_RISCV_CALL_PLT. Make R_RISCV_TPREL_ADD and + R_RISCV_ALIGN like R_RISCV_NONE. Correct dst_mask many relocs. + 2020-09-17 Mikael Pettersson PR ld/18808 diff --git a/bfd/elfxx-riscv.c b/bfd/elfxx-riscv.c index cfdd867e0de..e5adea57b12 100644 --- a/bfd/elfxx-riscv.c +++ b/bfd/elfxx-riscv.c @@ -69,7 +69,7 @@ static reloc_howto_type howto_table[] = "R_RISCV_32", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ - MINUS_ONE, /* dst_mask */ + 0xffffffff, /* dst_mask */ FALSE), /* pcrel_offset */ /* 64 bit relocation. */ @@ -99,7 +99,7 @@ static reloc_howto_type howto_table[] = "R_RISCV_RELATIVE", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ - MINUS_ONE, /* dst_mask */ + 0xffffffff, /* dst_mask */ FALSE), /* pcrel_offset */ HOWTO (R_RISCV_COPY, /* type */ @@ -133,7 +133,7 @@ static reloc_howto_type howto_table[] = /* Dynamic TLS relocations. */ HOWTO (R_RISCV_TLS_DTPMOD32, /* type */ 0, /* rightshift */ - 4, /* size */ + 2, /* size */ 32, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ @@ -142,7 +142,7 @@ static reloc_howto_type howto_table[] = "R_RISCV_TLS_DTPMOD32", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ - MINUS_ONE, /* dst_mask */ + 0xffffffff, /* dst_mask */ FALSE), /* pcrel_offset */ HOWTO (R_RISCV_TLS_DTPMOD64, /* type */ @@ -161,7 +161,7 @@ static reloc_howto_type howto_table[] = HOWTO (R_RISCV_TLS_DTPREL32, /* type */ 0, /* rightshift */ - 4, /* size */ + 2, /* size */ 32, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ @@ -170,7 +170,7 @@ static reloc_howto_type howto_table[] = "R_RISCV_TLS_DTPREL32", /* name */ TRUE, /* partial_inplace */ 0, /* src_mask */ - MINUS_ONE, /* dst_mask */ + 0xffffffff, /* dst_mask */ FALSE), /* pcrel_offset */ HOWTO (R_RISCV_TLS_DTPREL64, /* type */ @@ -198,7 +198,7 @@ static reloc_howto_type howto_table[] = "R_RISCV_TLS_TPREL32", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ - MINUS_ONE, /* dst_mask */ + 0xffffffff, /* dst_mask */ FALSE), /* pcrel_offset */ HOWTO (R_RISCV_TLS_TPREL64, /* type */ @@ -254,7 +254,7 @@ static reloc_howto_type howto_table[] = /* 32-bit PC-relative function call (AUIPC/JALR). */ HOWTO (R_RISCV_CALL, /* type */ 0, /* rightshift */ - 2, /* size */ + 4, /* size */ 64, /* bitsize */ TRUE, /* pc_relative */ 0, /* bitpos */ @@ -270,7 +270,7 @@ static reloc_howto_type howto_table[] = /* Like R_RISCV_CALL, but not locally binding. */ HOWTO (R_RISCV_CALL_PLT, /* type */ 0, /* rightshift */ - 2, /* size */ + 4, /* size */ 64, /* bitsize */ TRUE, /* pc_relative */ 0, /* bitpos */ @@ -466,14 +466,14 @@ static reloc_howto_type howto_table[] = /* TLS LE thread pointer usage. May be relaxed. */ HOWTO (R_RISCV_TPREL_ADD, /* type */ 0, /* rightshift */ - 2, /* size */ - 32, /* bitsize */ + 3, /* size */ + 0, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_RISCV_TPREL_ADD", /* name */ - TRUE, /* partial_inplace */ + FALSE, /* partial_inplace */ 0, /* src_mask */ 0, /* dst_mask */ FALSE), /* pcrel_offset */ @@ -490,7 +490,7 @@ static reloc_howto_type howto_table[] = "R_RISCV_ADD8", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ - MINUS_ONE, /* dst_mask */ + 0xff, /* dst_mask */ FALSE), /* pcrel_offset */ /* 16-bit in-place addition, for local label subtraction. */ @@ -505,7 +505,7 @@ static reloc_howto_type howto_table[] = "R_RISCV_ADD16", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ - MINUS_ONE, /* dst_mask */ + 0xffff, /* dst_mask */ FALSE), /* pcrel_offset */ /* 32-bit in-place addition, for local label subtraction. */ @@ -520,7 +520,7 @@ static reloc_howto_type howto_table[] = "R_RISCV_ADD32", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ - MINUS_ONE, /* dst_mask */ + 0xffffffff, /* dst_mask */ FALSE), /* pcrel_offset */ /* 64-bit in-place addition, for local label subtraction. */ @@ -550,7 +550,7 @@ static reloc_howto_type howto_table[] = "R_RISCV_SUB8", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ - MINUS_ONE, /* dst_mask */ + 0xff, /* dst_mask */ FALSE), /* pcrel_offset */ /* 16-bit in-place addition, for local label subtraction. */ @@ -565,7 +565,7 @@ static reloc_howto_type howto_table[] = "R_RISCV_SUB16", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ - MINUS_ONE, /* dst_mask */ + 0xffff, /* dst_mask */ FALSE), /* pcrel_offset */ /* 32-bit in-place addition, for local label subtraction. */ @@ -580,7 +580,7 @@ static reloc_howto_type howto_table[] = "R_RISCV_SUB32", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ - MINUS_ONE, /* dst_mask */ + 0xffffffff, /* dst_mask */ FALSE), /* pcrel_offset */ /* 64-bit in-place addition, for local label subtraction. */ @@ -633,7 +633,7 @@ static reloc_howto_type howto_table[] = addend rounded up to the next power of two. */ HOWTO (R_RISCV_ALIGN, /* type */ 0, /* rightshift */ - 2, /* size */ + 3, /* size */ 0, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ @@ -643,13 +643,13 @@ static reloc_howto_type howto_table[] = FALSE, /* partial_inplace */ 0, /* src_mask */ 0, /* dst_mask */ - TRUE), /* pcrel_offset */ + FALSE), /* pcrel_offset */ /* 8-bit PC-relative branch offset. */ HOWTO (R_RISCV_RVC_BRANCH, /* type */ 0, /* rightshift */ - 2, /* size */ - 32, /* bitsize */ + 1, /* size */ + 16, /* bitsize */ TRUE, /* pc_relative */ 0, /* bitpos */ complain_overflow_signed, /* complain_on_overflow */ @@ -663,8 +663,8 @@ static reloc_howto_type howto_table[] = /* 11-bit PC-relative jump offset. */ HOWTO (R_RISCV_RVC_JUMP, /* type */ 0, /* rightshift */ - 2, /* size */ - 32, /* bitsize */ + 1, /* size */ + 16, /* bitsize */ TRUE, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ @@ -678,8 +678,8 @@ static reloc_howto_type howto_table[] = /* High 6 bits of 18-bit absolute address. */ HOWTO (R_RISCV_RVC_LUI, /* type */ 0, /* rightshift */ - 2, /* size */ - 32, /* bitsize */ + 1, /* size */ + 16, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ @@ -807,7 +807,7 @@ static reloc_howto_type howto_table[] = "R_RISCV_SET8", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ - MINUS_ONE, /* dst_mask */ + 0xff, /* dst_mask */ FALSE), /* pcrel_offset */ /* 16-bit in-place setting, for local label subtraction. */ @@ -822,7 +822,7 @@ static reloc_howto_type howto_table[] = "R_RISCV_SET16", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ - MINUS_ONE, /* dst_mask */ + 0xffff, /* dst_mask */ FALSE), /* pcrel_offset */ /* 32-bit in-place setting, for local label subtraction. */ @@ -837,7 +837,7 @@ static reloc_howto_type howto_table[] = "R_RISCV_SET32", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ - MINUS_ONE, /* dst_mask */ + 0xffffffff, /* dst_mask */ FALSE), /* pcrel_offset */ /* 32-bit PC relative. */ @@ -852,7 +852,7 @@ static reloc_howto_type howto_table[] = "R_RISCV_32_PCREL", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ - MINUS_ONE, /* dst_mask */ + 0xffffffff, /* dst_mask */ FALSE), /* pcrel_offset */ }; diff --git a/gas/ChangeLog b/gas/ChangeLog index cad6b5c57c1..ff8fa2201c5 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,11 @@ +2020-09-21 Alan Modra + + PR 26569 + * config/tc-riscv.c (append_insn): Don't tie off frags at CALL + relocs. + (riscv_call): Tie them off after the jalr. + (md_apply_fix): Zero fx_size of RELAX fixup. + 2020-09-018 David Faust * testsuite/gas/bpf/alu-xbpf.d: New file. diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c index 9df6d3f4156..eb31e42a2e7 100644 --- a/gas/config/tc-riscv.c +++ b/gas/config/tc-riscv.c @@ -1133,9 +1133,7 @@ append_insn (struct riscv_cl_insn *ip, expressionS *address_expr, optimized away or compressed by the linker during relaxation, to prevent the assembler from computing static offsets across such an instruction. This is necessary to get correct EH info. */ - if (reloc_type == BFD_RELOC_RISCV_CALL - || reloc_type == BFD_RELOC_RISCV_CALL_PLT - || reloc_type == BFD_RELOC_RISCV_HI20 + if (reloc_type == BFD_RELOC_RISCV_HI20 || reloc_type == BFD_RELOC_RISCV_PCREL_HI20 || reloc_type == BFD_RELOC_RISCV_TPREL_HI20 || reloc_type == BFD_RELOC_RISCV_TPREL_ADD) @@ -1311,8 +1309,13 @@ static void riscv_call (int destreg, int tempreg, expressionS *ep, bfd_reloc_code_real_type reloc) { + /* Ensure the jalr is emitted to the same frag as the auipc. */ + frag_grow (8); macro_build (ep, "auipc", "d,u", tempreg, reloc); macro_build (NULL, "jalr", "d,s", destreg, tempreg); + /* See comment at end of append_insn. */ + frag_wane (frag_now); + frag_new (0); } /* Load an integer constant into a register. */ @@ -3031,6 +3034,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) fixP->fx_next = xmemdup (fixP, sizeof (*fixP), sizeof (*fixP)); fixP->fx_next->fx_addsy = fixP->fx_next->fx_subsy = NULL; fixP->fx_next->fx_r_type = BFD_RELOC_RISCV_RELAX; + fixP->fx_next->fx_size = 0; } } -- 2.30.2