You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
122 lines
4.1 KiB
122 lines
4.1 KiB
4 years ago
|
diff -rup a/ltrace-elf.c b/ltrace-elf.c
|
||
|
--- a/ltrace-elf.c 2019-02-28 17:32:49.873659818 -0500
|
||
|
+++ b/ltrace-elf.c 2019-02-28 17:36:32.426779439 -0500
|
||
|
@@ -639,7 +639,21 @@ ltelf_read_elf(struct ltelf *lte, const
|
||
|
}
|
||
|
} else if (shdr.sh_type == SHT_PROGBITS
|
||
|
|| shdr.sh_type == SHT_NOBITS) {
|
||
|
- if (strcmp(name, ".plt") == 0) {
|
||
|
+ if (strcmp(name, ".plt") == 0
|
||
|
+ && lte->second_plt_seen == 0) {
|
||
|
+ lte->plt_addr = shdr.sh_addr;
|
||
|
+ lte->plt_size = shdr.sh_size;
|
||
|
+ lte->plt_data = elf_loaddata(scn, &shdr);
|
||
|
+ if (lte->plt_data == NULL)
|
||
|
+ fprintf(stderr,
|
||
|
+ "Can't load .plt data\n");
|
||
|
+ lte->plt_flags = shdr.sh_flags;
|
||
|
+ }
|
||
|
+ /* An Intel CET binary has two PLTs; the
|
||
|
+ initial PLTGOT points to the second
|
||
|
+ one. */
|
||
|
+ else if (strcmp(name, ".plt.sec") == 0) {
|
||
|
+ lte->second_plt_seen = 1;
|
||
|
lte->plt_addr = shdr.sh_addr;
|
||
|
lte->plt_size = shdr.sh_size;
|
||
|
lte->plt_data = elf_loaddata(scn, &shdr);
|
||
|
diff -rup a/ltrace-elf.h b/ltrace-elf.h
|
||
|
--- a/ltrace-elf.h 2019-02-28 17:32:49.874660328 -0500
|
||
|
+++ b/ltrace-elf.h 2019-02-28 17:36:32.428779868 -0500
|
||
|
@@ -45,6 +45,7 @@ struct ltelf {
|
||
|
Elf_Data *dynsym;
|
||
|
size_t dynsym_count;
|
||
|
const char *dynstr;
|
||
|
+ int second_plt_seen;
|
||
|
GElf_Addr plt_addr;
|
||
|
GElf_Word plt_flags;
|
||
|
size_t plt_size;
|
||
|
diff -rup a/sysdeps/linux-gnu/x86/plt.c b/sysdeps/linux-gnu/x86/plt.c
|
||
|
--- a/sysdeps/linux-gnu/x86/plt.c 2019-02-28 17:32:49.991720041 -0500
|
||
|
+++ b/sysdeps/linux-gnu/x86/plt.c 2019-02-28 17:36:32.429780083 -0500
|
||
|
@@ -28,18 +28,18 @@
|
||
|
#include "trace.h"
|
||
|
|
||
|
static GElf_Addr
|
||
|
-x86_plt_offset(uint32_t i)
|
||
|
+x86_plt_offset(struct ltelf *lte, uint32_t i)
|
||
|
{
|
||
|
/* Skip the first PLT entry, which contains a stub to call the
|
||
|
* resolver. */
|
||
|
- return (i + 1) * 16;
|
||
|
+ return (i + (lte->second_plt_seen ? 0 : 1)) * 16;
|
||
|
}
|
||
|
|
||
|
GElf_Addr
|
||
|
arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela *rela)
|
||
|
{
|
||
|
uint32_t i = *VECT_ELEMENT(<e->arch.plt_map, uint32_t, ndx);
|
||
|
- return x86_plt_offset(i) + lte->plt_addr;
|
||
|
+ return x86_plt_offset(lte, i) + lte->plt_addr;
|
||
|
}
|
||
|
|
||
|
void *
|
||
|
@@ -116,6 +116,13 @@ arch_elf_init(struct ltelf *lte, struct
|
||
|
* 400426: 68 00 00 00 00 pushq $0x0
|
||
|
* 40042b: e9 e0 ff ff ff jmpq 400410 <_init+0x18>
|
||
|
*
|
||
|
+ * For CET binaries it is the following:
|
||
|
+ *
|
||
|
+ * 13d0: f3 0f 1e fa endbr64
|
||
|
+ * 13d4: 68 27 00 00 00 pushq $0x27 <-- index
|
||
|
+ * 13d9: f2 e9 71 fd ff ff bnd jmpq 1150 <.plt>
|
||
|
+ * 13df: 90 nop
|
||
|
+ *
|
||
|
* On i386, the argument to push is an offset of relocation to
|
||
|
* use. The first PLT slot has an offset of 0x0, the second
|
||
|
* 0x8, etc. On x86_64, it's directly the index that we are
|
||
|
@@ -128,11 +135,33 @@ arch_elf_init(struct ltelf *lte, struct
|
||
|
unsigned int i, sz = vect_size(<e->plt_relocs);
|
||
|
for (i = 0; i < sz; ++i) {
|
||
|
|
||
|
- GElf_Addr offset = x86_plt_offset(i);
|
||
|
+ GElf_Addr offset = x86_plt_offset(lte, i);
|
||
|
+ uint32_t reloc_arg;
|
||
|
|
||
|
uint8_t byte;
|
||
|
- if (elf_read_next_u8(lte->plt_data, &offset, &byte) < 0
|
||
|
- || byte != 0xff
|
||
|
+ if (elf_read_next_u8(lte->plt_data, &offset, &byte) < 0)
|
||
|
+ continue;
|
||
|
+
|
||
|
+
|
||
|
+ if (byte == 0xf3
|
||
|
+ && elf_read_next_u8(lte->plt_data, &offset, &byte) >= 0
|
||
|
+ && byte == 0x0f
|
||
|
+ && elf_read_next_u8(lte->plt_data, &offset, &byte) >= 0
|
||
|
+ && byte == 0x1e
|
||
|
+ && elf_read_next_u8(lte->plt_data, &offset, &byte) >= 0
|
||
|
+ && byte == 0xfa
|
||
|
+ && elf_read_next_u8(lte->plt_data, &offset, &byte) >= 0
|
||
|
+ && byte == 0x68
|
||
|
+ && elf_read_next_u32(lte->plt_data,
|
||
|
+ &offset, &reloc_arg) >= 0)
|
||
|
+ {
|
||
|
+ /* CET */
|
||
|
+ fprintf(stderr, "%d: reloc_arg is %lx\n", i, (long)reloc_arg);
|
||
|
+ *VECT_ELEMENT(<e->arch.plt_map, unsigned int, reloc_arg) = i;
|
||
|
+ continue;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (byte != 0xff
|
||
|
|| elf_read_next_u8(lte->plt_data, &offset, &byte) < 0
|
||
|
|| (byte != 0xa3 && byte != 0x25))
|
||
|
continue;
|
||
|
@@ -140,7 +169,6 @@ arch_elf_init(struct ltelf *lte, struct
|
||
|
/* Skip immediate argument in the instruction. */
|
||
|
offset += 4;
|
||
|
|
||
|
- uint32_t reloc_arg;
|
||
|
if (elf_read_next_u8(lte->plt_data, &offset, &byte) < 0
|
||
|
|| byte != 0x68
|
||
|
|| elf_read_next_u32(lte->plt_data,
|