From c86a59a5112c47c6d60c4cbab09a9cc3d479964b Mon Sep 17 00:00:00 2001 From: Rui Ueyama Date: Mon, 23 Oct 2023 12:00:34 +0900 Subject: [PATCH] Fill gaps in executable segments with trap or nop instructions --- elf/elf.h | 17 ++++++++++++++++- elf/output-chunks.cc | 39 +++++++++++++++++++-------------------- 2 files changed, 35 insertions(+), 21 deletions(-) diff --git a/elf/elf.h b/elf/elf.h index cac6506a10..a910d734f9 100644 --- a/elf/elf.h +++ b/elf/elf.h @@ -1868,6 +1868,7 @@ struct X86_64 { static constexpr u32 plt_hdr_size = 32; static constexpr u32 plt_size = 16; static constexpr u32 pltgot_size = 8; + static constexpr u8 filler[] = { 0xcc }; static constexpr u32 R_COPY = R_X86_64_COPY; static constexpr u32 R_GLOB_DAT = R_X86_64_GLOB_DAT; @@ -1892,6 +1893,7 @@ struct I386 { static constexpr u32 plt_hdr_size = 16; static constexpr u32 plt_size = 16; static constexpr u32 pltgot_size = 16; + static constexpr u8 filler[] = { 0xcc }; static constexpr u32 R_COPY = R_386_COPY; static constexpr u32 R_GLOB_DAT = R_386_GLOB_DAT; @@ -1918,6 +1920,7 @@ struct ARM64 { static constexpr u32 pltgot_size = 16; static constexpr u32 thunk_hdr_size = 0; static constexpr u32 thunk_size = 16; + static constexpr u8 filler[] = { 0x00, 0x7d, 0x20, 0xd4 }; static constexpr u32 R_COPY = R_AARCH64_COPY; static constexpr u32 R_GLOB_DAT = R_AARCH64_GLOB_DAT; @@ -1944,6 +1947,7 @@ struct ARM32 { static constexpr u32 pltgot_size = 16; static constexpr u32 thunk_hdr_size = 16; static constexpr u32 thunk_size = 16; + static constexpr u8 filler[] = { 0xff, 0xde }; static constexpr u32 R_COPY = R_ARM_COPY; static constexpr u32 R_GLOB_DAT = R_ARM_GLOB_DAT; @@ -1969,6 +1973,7 @@ struct RV64 { static constexpr u32 plt_hdr_size = 32; static constexpr u32 plt_size = 16; static constexpr u32 pltgot_size = 16; + static constexpr u8 filler[] = { 0x02, 0x90 }; static constexpr u32 R_COPY = R_RISCV_COPY; static constexpr u32 R_GLOB_DAT = R_RISCV_64; @@ -2001,6 +2006,7 @@ struct RV32 { static constexpr u32 plt_hdr_size = 32; static constexpr u32 plt_size = 16; static constexpr u32 pltgot_size = 16; + static constexpr u8 filler[] = { 0x02, 0x90 }; static constexpr u32 R_COPY = R_RISCV_COPY; static constexpr u32 R_GLOB_DAT = R_RISCV_32; @@ -2037,7 +2043,7 @@ struct PPC32 { static constexpr u32 pltgot_size = 36; static constexpr u32 thunk_hdr_size = 0; static constexpr u32 thunk_size = 36; - + static constexpr u8 filler[] = { 0x7f, 0xe0, 0x00, 0x08 }; static constexpr u32 R_COPY = R_PPC_COPY; static constexpr u32 R_GLOB_DAT = R_PPC_GLOB_DAT; @@ -2079,6 +2085,7 @@ struct PPC64V1 : PPC64 { static constexpr u32 pltgot_size = 0; static constexpr u32 thunk_hdr_size = 0; static constexpr u32 thunk_size = 28; + static constexpr u8 filler[] = { 0x7f, 0xe0, 0x00, 0x08 }; }; struct PPC64V2 : PPC64 { @@ -2089,6 +2096,7 @@ struct PPC64V2 : PPC64 { static constexpr u32 pltgot_size = 0; static constexpr u32 thunk_hdr_size = 0; static constexpr u32 thunk_size = 24; + static constexpr u8 filler[] = { 0x08, 0x00, 0xe0, 0x7f }; }; struct S390X { @@ -2101,6 +2109,7 @@ struct S390X { static constexpr u32 plt_hdr_size = 48; static constexpr u32 plt_size = 16; static constexpr u32 pltgot_size = 16; + static constexpr u8 filler[] = { 0x07, 0x00 }; static constexpr u32 R_COPY = R_390_COPY; static constexpr u32 R_GLOB_DAT = R_390_GLOB_DAT; @@ -2124,6 +2133,7 @@ struct SPARC64 { static constexpr u32 plt_hdr_size = 128; static constexpr u32 plt_size = 32; static constexpr u32 pltgot_size = 32; + static constexpr u8 filler[] = { 0x91, 0xd0, 0x20, 0x05 }; static constexpr u32 R_COPY = R_SPARC_COPY; static constexpr u32 R_GLOB_DAT = R_SPARC_GLOB_DAT; @@ -2147,6 +2157,7 @@ struct M68K { static constexpr u32 plt_hdr_size = 18; static constexpr u32 plt_size = 14; static constexpr u32 pltgot_size = 8; + static constexpr u8 filler[] = { 0x4a, 0xfc }; static constexpr u32 R_COPY = R_68K_COPY; static constexpr u32 R_GLOB_DAT = R_68K_GLOB_DAT; @@ -2169,6 +2180,7 @@ struct SH4 { static constexpr u32 plt_hdr_size = 16; static constexpr u32 plt_size = 16; static constexpr u32 pltgot_size = 12; + static constexpr u8 filler[] = { 0x00, 0x00 }; static constexpr u32 R_COPY = R_SH_COPY; static constexpr u32 R_GLOB_DAT = R_SH_GLOB_DAT; @@ -2191,6 +2203,7 @@ struct ALPHA { static constexpr u32 plt_hdr_size = 0; static constexpr u32 plt_size = 0; static constexpr u32 pltgot_size = 0; + static constexpr u8 filler[] = { 0x81, 0x00, 0x00, 0x00 }; static constexpr u32 R_COPY = R_ALPHA_COPY; static constexpr u32 R_GLOB_DAT = R_ALPHA_GLOB_DAT; @@ -2215,6 +2228,7 @@ struct LOONGARCH64 { static constexpr u32 pltgot_size = 16; static constexpr u32 thunk_hdr_size = 0; static constexpr u32 thunk_size = 16; + static constexpr u8 filler[] = { 0x00, 0x00, 0x2a, 0x00 }; static constexpr u32 R_COPY = R_LARCH_COPY; static constexpr u32 R_GLOB_DAT = R_LARCH_64; @@ -2240,6 +2254,7 @@ struct LOONGARCH32 { static constexpr u32 pltgot_size = 16; static constexpr u32 thunk_hdr_size = 0; static constexpr u32 thunk_size = 16; + static constexpr u8 filler[] = { 0x00, 0x00, 0x2a, 0x00 }; static constexpr u32 R_COPY = R_LARCH_COPY; static constexpr u32 R_GLOB_DAT = R_LARCH_32; diff --git a/elf/output-chunks.cc b/elf/output-chunks.cc index 4ee895bd64..88ee1a9f35 100644 --- a/elf/output-chunks.cc +++ b/elf/output-chunks.cc @@ -883,31 +883,30 @@ void OutputSection::copy_buf(Context &ctx) { template void OutputSection::write_to(Context &ctx, u8 *buf) { - auto clear = [&](u8 *loc, i64 size) { - // As a special case, .init and .fini are filled with NOPs for s390x - // because the runtime executes the sections as if they were a single - // function. .init and .fini are superceded by .init_array and - // .fini_array but being actively used only on s390x. - if constexpr (is_s390x) { - if (this->name == ".init" || this->name == ".fini") { - for (i64 i = 0; i < size; i += 2) - *(ub16 *)(loc + i) = 0x0700; // nop - return; - } - } - memset(loc, 0, size); - }; - tbb::parallel_for((i64)0, (i64)members.size(), [&](i64 i) { - // Copy section contents to an output file + // Copy section contents to an output file. InputSection &isec = *members[i]; isec.write_to(ctx, buf + isec.offset); - // Clear trailing padding + // Clear trailing padding. We write trap or nop instructions for + // an executable segment so that a disassembler wouldn't try to + // disassemble garbage as instructions. u64 this_end = isec.offset + isec.sh_size; - u64 next_start = (i == members.size() - 1) ? - (u64)this->shdr.sh_size : members[i + 1]->offset; - clear(buf + this_end, next_start - this_end); + u64 next_start; + if (i + 1 < members.size()) + next_start = members[i + 1]->offset; + else + next_start = this->shdr.sh_size; + + u8 *loc = buf + this_end; + i64 size = next_start - this_end; + + if (this->shdr.sh_flags & SHF_EXECINSTR) { + for (i64 i = 0; i + sizeof(E::filler) <= size; i += sizeof(E::filler)) + memcpy(loc + i, E::filler, sizeof(E::filler)); + } else { + memset(loc, 0, size); + } }); if constexpr (needs_thunk) {