From b3d92e940b9a904fc2c311482fd9531cecc4429a Mon Sep 17 00:00:00 2001 From: Frances Wingerter Date: Thu, 16 Feb 2023 17:42:46 -0500 Subject: [PATCH] add pad-tls tool --- CMakeLists.txt | 1 + pad-tls/CMakeLists.txt | 6 +++ pad-tls/pad-tls.c | 109 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 116 insertions(+) create mode 100644 pad-tls/CMakeLists.txt create mode 100644 pad-tls/pad-tls.c diff --git a/CMakeLists.txt b/CMakeLists.txt index e2cbd95dab..62fc5770b7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,3 +9,4 @@ set(EXTERNAL_DIR ${PROJECT_SOURCE_DIR}/external) add_subdirectory(libia2) add_subdirectory(header-rewriter) add_subdirectory(partition-alloc) +add_subdirectory(pad-tls) diff --git a/pad-tls/CMakeLists.txt b/pad-tls/CMakeLists.txt new file mode 100644 index 0000000000..4bddb920bb --- /dev/null +++ b/pad-tls/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required(VERSION 3.12) +project(PadTls) + +add_executable(pad-tls + pad-tls.c + ) diff --git a/pad-tls/pad-tls.c b/pad-tls/pad-tls.c new file mode 100644 index 0000000000..bbcbf267ca --- /dev/null +++ b/pad-tls/pad-tls.c @@ -0,0 +1,109 @@ +/* pad-tls: tool to pad TLS segment of ELF files so that a given compartment's +TLS variables will only possibly share a page with another compartment's +padding, not its TLS variables */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +enum patch_result { + PATCH_SUCCESS, + BAD_MAGIC, + WRONG_ARCH, + NO_TLS, +}; + +static const char *patch_errors[] = { + "invalid ELF magic number", + "ELF architecture is not x86-64", + "no TLS segment in ELF program headers", +}; + +enum patch_result patch_tls(void *elf, int64_t delta, uint64_t *size_out) { + Elf64_Ehdr *ehdr = elf; + + if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) { + return BAD_MAGIC; + } + + if (ehdr->e_machine != EM_X86_64) { + return WRONG_ARCH; + } + + char *ph_addr = ((char *)elf) + ehdr->e_phoff; + for (int i = 0; i < ehdr->e_phnum; i++) { + Elf64_Phdr *phdr = (Elf64_Phdr *)ph_addr; + + if (phdr->p_type == PT_TLS) { + phdr->p_memsz += delta; + if (size_out) { + *size_out = phdr->p_memsz; + } + return PATCH_SUCCESS; + } + + ph_addr += ehdr->e_phentsize; + } + + return NO_TLS; +} + +const int64_t delta = 4096; + +void usage(char **argv) { + fprintf( + stderr, + "usage: %s [--allow-no-tls] : adds %ld bytes to TLS segment size of ELF binary\n", + basename(argv[0]), delta); +} + +int main(int argc, char **argv) { + char *filename; + bool allow_no_tls = false; + + if (argc > 2 && !strcmp(argv[1], "--allow-no-tls")) { + allow_no_tls = true; + filename = argv[2]; + } else if (argc == 2) { + filename = argv[1]; + } else { + usage(argv); + return 1; + } + + int fd = open(filename, O_RDWR); + if (fd < 0) { + fprintf(stderr, "%s: could not be opened: %s\n", filename, strerror(errno)); + return 1; + } + + struct stat stat; + fstat(fd, &stat); + size_t size = (size_t)stat.st_size; + + void *elf = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (elf == MAP_FAILED) { + fprintf(stderr, "%s: could not mmap: %s\n", filename, strerror(errno)); + return 1; + } + + uint64_t new_size = 0; + enum patch_result result = patch_tls(elf, delta, &new_size); + if (result != PATCH_SUCCESS) { + if (allow_no_tls && result == NO_TLS) { + return 0; + } + fprintf(stderr, "%s: %s\n", filename, patch_errors[result - 1]); + return (int)result; + } + + printf("%s: TLS size now 0x%lx\n", filename, new_size); + return 0; +}