From ef5c674f89c4c4f34c5db5f742ba7f4edd7afe04 Mon Sep 17 00:00:00 2001 From: Samuel Herts Date: Thu, 26 Feb 2026 11:47:11 -0500 Subject: [PATCH 01/14] Enhance CI workflow for ARM64 support Added support for ARM64 architecture in CI workflow. --- .github/workflows/ci.yml | 47 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2e0e07d5..68ab7968 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,6 +1,7 @@ name: ci on: + workflow_dispatch: push: branches: - devel @@ -17,7 +18,7 @@ concurrency: cancel-in-progress: true jobs: - spindle-serial-ubuntu: + spindle-serial-ubuntu_x86: name: Testsuite (Serial, Ubuntu) environment: Spindle CI runs-on: ubuntu-latest @@ -60,6 +61,50 @@ jobs: run: | cd containers/spindle-serial-ubuntu docker compose down + + spindle-serial-ubuntu_arm64: + name: Testsuite (Serial, Ubuntu, arm64) + environment: Spindle CI + runs-on: ubuntu-24.04-arm + timeout-minutes: 30 + steps: + - name: Check out Spindle + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + + - name: Setup Docker Compose + uses: docker/setup-compose-action@364cc21a5de5b1ee4a7f5f9d3fa374ce0ccde746 + with: + version: latest + + - name: Build spindle-serial-ubuntu image + id: serial-ubuntu-build + run: | + cd containers/spindle-serial-ubuntu + docker compose --progress=plain build + + - name: Bring spindle-serial-ubuntu up + id: serial-ubuntu-up + run: | + cd containers/spindle-serial-ubuntu + docker compose up -d + + - name: Verify munge works in spindle-serial-ubuntu + id: serial-ubuntu-munge + run: | + docker exec spindlenode bash -c 'munge -n | unmunge' + + - name: Run spindle-serial-ubuntu testsuite + id: serial-ubuntu-testsuite + run: | + docker exec spindlenode bash -c 'cd Spindle-build/testsuite && ./runTests' + + - name: Bring spindle-serial-ubuntu down + id: serial-ubuntu-down + if: ${{ always() }} + continue-on-error: true + run: | + cd containers/spindle-serial-ubuntu + docker compose down spindle-flux-ubuntu: name: Testsuite (Flux, Ubuntu) From 7c19a5e0f0be7bc72d9fa6a81c3a08ede1d2a386 Mon Sep 17 00:00:00 2001 From: Samuel Herts Date: Thu, 26 Feb 2026 11:52:05 -0500 Subject: [PATCH 02/14] Add arm64_CI branch to pull request workflow --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 68ab7968..d6c3c8b2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,6 +8,7 @@ on: pull_request: branches: - devel + - arm64_CI permissions: contents: read From 449c0610582dcdeaa4d1ea0cd49f2f4e00b8f816 Mon Sep 17 00:00:00 2001 From: Samuel Herts Date: Thu, 26 Feb 2026 12:13:26 -0500 Subject: [PATCH 03/14] Add aarch64 to architecture check for rel type --- testsuite/symbind_test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testsuite/symbind_test.c b/testsuite/symbind_test.c index 67c3af1d..f6cba01c 100644 --- a/testsuite/symbind_test.c +++ b/testsuite/symbind_test.c @@ -133,7 +133,7 @@ static int dso_at_address(ElfW(Addr) addr, char **name) return 0; } -#if defined(__x86_64) +#if defined(__x86_64) || definted(__aarch64__) #define REL_TYPE ElfW(Rela) #else #error Need rel type for architecture From 4e290898de969c8bef20e8b9985ef99db2ea2946 Mon Sep 17 00:00:00 2001 From: Samuel Herts Date: Thu, 26 Feb 2026 12:17:01 -0500 Subject: [PATCH 04/14] Fix typo in architecture check for symbind_test --- testsuite/symbind_test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testsuite/symbind_test.c b/testsuite/symbind_test.c index f6cba01c..8d5553b9 100644 --- a/testsuite/symbind_test.c +++ b/testsuite/symbind_test.c @@ -133,7 +133,7 @@ static int dso_at_address(ElfW(Addr) addr, char **name) return 0; } -#if defined(__x86_64) || definted(__aarch64__) +#if defined(__x86_64) || defined(__aarch64__) #define REL_TYPE ElfW(Rela) #else #error Need rel type for architecture From 79c2d13e10cd13a666fdce7a3e73741eff910eef Mon Sep 17 00:00:00 2001 From: Samuel Herts Date: Thu, 26 Feb 2026 14:09:36 -0500 Subject: [PATCH 05/14] Add functions to auditclient_aarch64.c to match auditclient_x86_64.c but with necessary arch changes --- src/client/auditclient/auditclient_aarch64.c | 132 ++++++++++++++++++- 1 file changed, 127 insertions(+), 5 deletions(-) diff --git a/src/client/auditclient/auditclient_aarch64.c b/src/client/auditclient/auditclient_aarch64.c index 1f1df68a..b07e23c0 100644 --- a/src/client/auditclient/auditclient_aarch64.c +++ b/src/client/auditclient/auditclient_aarch64.c @@ -18,20 +18,32 @@ Place, Suite 330, Boston, MA 02111-1307 USA #define _GNU_SOURCE #endif -#include -#include "client.h" #include "auditclient.h" #include "spindle_debug.h" +#include "writablegot.h" +#include "client.h" + +#include +#include +#include +#include + -Elf64_Addr la_aarch64_gnu_pltenter(Elf64_Sym *sym, unsigned int ndx, + +/*Elf64_Addr la_aarch64_gnu_pltenter(Elf64_Sym *sym, unsigned int ndx, uintptr_t *refcook, uintptr_t *defcook, La_aarch64_regs *regs, unsigned int *flags, const char *symname, - long int *framesizep) AUDIT_EXPORT; + long int *framesizep) AUDIT_EXPORT;*/ + +uintptr_t la_symbind64(Elf64_Sym *sym, unsigned int ndx, + uintptr_t *refcook, uintptr_t *defcook, + unsigned int *flags, const char *symname) AUDIT_EXPORT; -Elf64_Addr la_aarch64_gnu_pltenter (Elf64_Sym *sym, unsigned int ndx, +Elf64_Addr la_aarch64_gnu_pltenter (Elf64_Sym *sym, + unsigned int ndx, uintptr_t *refcook, uintptr_t *defcook, La_aarch64_regs *regs, @@ -48,3 +60,113 @@ Elf64_Addr la_aarch64_gnu_pltenter (Elf64_Sym *sym, unsigned int ndx, return doPermanentBinding_noidx(refcook, defcook, target, symname, sp, (void *) regs); } + +uintptr_t la_symbind64(Elf64_Sym *sym, unsigned int ndx, + uintptr_t *refcook, uintptr_t *defcook, + unsigned int *flags, const char *symname) +{ + (void)ndx; + (void)refcook; + (void)defcook; + updateDataBindingQueue(0); + Elf64_Addr target = client_call_binding(symname, sym->st_value); + *flags = 0; + return target; +} + +static int bind_global_relocations(struct link_map *map, Elf64_Rela *relocs, Elf64_Addr base, unsigned long num_relocs, + Elf64_Sym *symtable, const char *strtable, int has_pltrelocs) +{ + unsigned long i; + unsigned long symidx; + Elf64_Addr symvalue, target; + Elf64_Sym *sym; + const char *symname; + Elf64_Addr *got_entry; + int made_reloc_table_writable = 0, result, error; + Elf64_Addr reloc_table_pagebase = 0; + size_t reloc_table_size = 0; + + for (i = 0; i < num_relocs; i++) { + Elf64_Rela *r = relocs+i; + if (ELF64_R_TYPE(r->r_info) != R_AARCH64_GLOB_DAT) + continue; + symidx = ELF64_R_SYM(r->r_info); + sym = symtable + symidx; + symname = strtable + sym->st_name; + symvalue = sym->st_value; + target = client_call_binding(symname, symvalue); + if (target == symvalue) + continue; + got_entry = (Elf64_Addr *) (r->r_offset + base); + if (has_pltrelocs) { + //Queue up any data-type symbols that need to be relocated and apply them + // when we do the function-type symbols in la_symbind64 + addToDataBindingQueue(map, target, got_entry); + } + else { + //This DSO has no function-type relocations. So we won't get a symbind callback. + //We'll do the bindings for the data-type relocations now. To prevent ld.so from + //overwriting these later, we'll also change the relocation type to make it a NULL + //operation. This has the unfortunate side effect of modifying the binary, which + //some programs may notice if they checksum themselves. It's a trade-off between + //this or messing up data-variable bindings. + //Spindle's libsymbind_g.so test triggers this. + debug_printf2("Unusal, have to do data symbol bindings in a DSO without PLT\n"); + make_got_writable(got_entry, map); + *got_entry = target; + if (!made_reloc_table_writable) { + reloc_table_pagebase = ((Elf64_Addr) relocs) & ~((Elf64_Addr) (getpagesize()-1)); + reloc_table_size = ((num_relocs + 1) * sizeof(Elf64_Rela)) - 1 + (((Elf64_Addr) relocs) - reloc_table_pagebase); + debug_printf3("mprotect(%p, %lu, PROT_READ|PROT_WRITE|PROT_EXEC) making GOT table writiable\n", (void *) reloc_table_pagebase, reloc_table_size); + result = mprotect((void *) reloc_table_pagebase, reloc_table_size, PROT_READ | PROT_WRITE | PROT_EXEC); + if (result == -1) { + error = errno; + err_printf("Could not mprotect for write to relocs 0x%lx +%lu: %s\n", + reloc_table_pagebase, reloc_table_size, strerror(error)); + continue; + } + made_reloc_table_writable = 1; + } + r->r_info &= ~((Elf64_Xword) 0xffffffff); + r->r_info |= R_AARCH64_NONE; + } + } + + return 0; +} + +int do_global_bindings(struct link_map *map) +{ + Elf64_Dyn *dyn; + Elf64_Rela *rels = NULL; + unsigned long num_rels = 0; + Elf64_Sym *syms = NULL; + const char *strtable = NULL; + int has_pltrelocs = 0; + + dyn = map->l_ld; + if (!dyn) { + debug_printf2("DSO %s does not have dynamic section\n", map->l_name); + return 0; + } + for (; dyn->d_tag != DT_NULL; dyn++) { + if (dyn->d_tag == DT_SYMTAB) + syms = (Elf64_Sym *) dyn->d_un.d_ptr; + else if (dyn->d_tag == DT_STRTAB) + strtable = (char *) dyn->d_un.d_ptr; + else if (dyn->d_tag == DT_RELA) + rels = (Elf64_Rela *) dyn->d_un.d_ptr; + else if (dyn->d_tag == DT_RELASZ) + num_rels = dyn->d_un.d_val / sizeof(Elf64_Rela); + else if (dyn->d_tag == DT_JMPREL) + has_pltrelocs = 1; + } + if (!syms || !strtable || !rels || !num_rels) { + debug_printf2("DSO %s is missing sections needed for variable binding (%p %p %p %lu)\n", map->l_name, + syms, strtable, rels, num_rels); + return 0; + } + + return bind_global_relocations(map, rels, map->l_addr, num_rels, syms, strtable, has_pltrelocs); +} From 3b54236fa564cf017efd2a5e884900eb9a2bbf33 Mon Sep 17 00:00:00 2001 From: Samuel Herts Date: Thu, 26 Feb 2026 14:09:56 -0500 Subject: [PATCH 06/14] whitespace fixes --- src/client/auditclient/auditclient_x86_64.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/client/auditclient/auditclient_x86_64.c b/src/client/auditclient/auditclient_x86_64.c index 9ad39718..20721a0f 100644 --- a/src/client/auditclient/auditclient_x86_64.c +++ b/src/client/auditclient/auditclient_x86_64.c @@ -82,7 +82,7 @@ static int bind_global_relocations(struct link_map *map, Elf64_Rela *relocs, Elf for (i = 0; i < num_relocs; i++) { Elf64_Rela *r = relocs+i; if (ELF64_R_TYPE(r->r_info) != R_X86_64_GLOB_DAT) - continue; + continue; symidx = ELF64_R_SYM(r->r_info); sym = symtable + symidx; symname = strtable + sym->st_name; @@ -120,7 +120,6 @@ static int bind_global_relocations(struct link_map *map, Elf64_Rela *relocs, Elf } made_reloc_table_writable = 1; } - r->r_info &= ~((Elf64_Xword) 0xffffffff); r->r_info |= R_X86_64_NONE; } @@ -144,7 +143,7 @@ int do_global_bindings(struct link_map *map) return 0; } for (; dyn->d_tag != DT_NULL; dyn++) { - if (dyn->d_tag == DT_SYMTAB) + if (dyn->d_tag == DT_SYMTAB) syms = (Elf64_Sym *) dyn->d_un.d_ptr; else if (dyn->d_tag == DT_STRTAB) strtable = (char *) dyn->d_un.d_ptr; From 48b395fc023130f5c791be3b182da786a2a3410b Mon Sep 17 00:00:00 2001 From: Samuel Herts Date: Thu, 26 Feb 2026 14:51:25 -0500 Subject: [PATCH 07/14] Move arch defines to header for visibility --- src/client/auditclient/writablegot.c | 5 ++--- src/client/auditclient/writablegot.h | 12 ++++++++++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/client/auditclient/writablegot.c b/src/client/auditclient/writablegot.c index 8170ece3..64c7c202 100644 --- a/src/client/auditclient/writablegot.c +++ b/src/client/auditclient/writablegot.c @@ -44,18 +44,17 @@ static signed int gots_last_entry; static signed int gots_size; #define GOTS_INITIAL_SIZE 32 +#include "writablegot.h" + #if defined(arch_x86_64) #define DEFAULT_RELENTSZ 24 #define EXTRA_GOT_ENTRIES 3 -#define DATA_GOT_TYPE R_X86_64_GLOB_DAT #elif defined(arch_ppc64) || defined(arch_ppc64le) #define DEFAULT_RELENTSZ 24 #define EXTRA_GOT_ENTRIES 2 -#define DATA_GOT_TYPE R_PPC64_GLOB_DAT #elif defined(arch_aarch64) #define DEFAULT_RELENTSZ 24 #define EXTRA_GOT_ENTRIES 4 -#define DATA_GOT_TYPE R_AARCH64_GLOB_DAT #else #error Need to fill in got info #endif diff --git a/src/client/auditclient/writablegot.h b/src/client/auditclient/writablegot.h index d0a66e88..7736f4a9 100644 --- a/src/client/auditclient/writablegot.h +++ b/src/client/auditclient/writablegot.h @@ -21,7 +21,19 @@ Place, Suite 330, Boston, MA 02111-1307 USA #define _GNU_SOURCE #endif +#include "config.h" #include +#include + +#if defined(arch_x86_64) +#define DATA_GOT_TYPE R_X86_64_GLOB_DAT +#elif defined(arch_ppc64) || defined(arch_ppc64le) +#define DATA_GOT_TYPE R_PPC64_GLOB_DAT +#elif defined(arch_aarch64) +#define DATA_GOT_TYPE R_AARCH64_GLOB_DAT +#else +#error Need to define DATA_GOT_TYPE for this architecture +#endif int add_wgot_library(struct link_map *map); int rm_wgot_library(struct link_map *map); From f6efe8864769f02378689a3c3b9208bdad9f76e5 Mon Sep 17 00:00:00 2001 From: Samuel Herts Date: Thu, 26 Feb 2026 14:52:07 -0500 Subject: [PATCH 08/14] Add auditclient functions to common since they are identical across arch --- src/client/auditclient/auditclient_common.c | 110 +++++++++++++++++++- 1 file changed, 109 insertions(+), 1 deletion(-) diff --git a/src/client/auditclient/auditclient_common.c b/src/client/auditclient/auditclient_common.c index de24d62b..b82fbb9b 100644 --- a/src/client/auditclient/auditclient_common.c +++ b/src/client/auditclient/auditclient_common.c @@ -18,13 +18,15 @@ Place, Suite 330, Boston, MA 02111-1307 USA in platform files like auditclient_x86_64.c */ -#include "client.h" #include "auditclient.h" #include "ldcs_api.h" #include "intercept.h" #include "writablegot.h" #include +#include #include +#include +#include #include static uintptr_t *firstcookie = NULL; @@ -163,3 +165,109 @@ unsigned int la_objclose (uintptr_t *cookie) return spindle_la_objclose(cookie); } +uintptr_t la_symbind64(Elf64_Sym *sym, unsigned int ndx, + uintptr_t *refcook, uintptr_t *defcook, + unsigned int *flags, const char *symname) AUDIT_EXPORT; + +uintptr_t la_symbind64(Elf64_Sym *sym, unsigned int ndx, + uintptr_t *refcook, uintptr_t *defcook, + unsigned int *flags, const char *symname) +{ + (void)ndx; + (void)refcook; + (void)defcook; + updateDataBindingQueue(0); + Elf64_Addr target = client_call_binding(symname, sym->st_value); + *flags = 0; + return target; +} + +static int bind_global_relocations(struct link_map *map, Elf64_Rela *relocs, Elf64_Addr base, + unsigned long num_relocs, Elf64_Sym *symtable, + const char *strtable, int has_pltrelocs) +{ + unsigned long i; + unsigned long symidx; + Elf64_Addr symvalue, target; + Elf64_Sym *sym; + const char *symname; + Elf64_Addr *got_entry; + int made_reloc_table_writable = 0, result, error; + Elf64_Addr reloc_table_pagebase = 0; + size_t reloc_table_size = 0; + + for (i = 0; i < num_relocs; i++) { + Elf64_Rela *r = relocs+i; + if (ELF64_R_TYPE(r->r_info) != DATA_GOT_TYPE) + continue; + symidx = ELF64_R_SYM(r->r_info); + sym = symtable + symidx; + symname = strtable + sym->st_name; + symvalue = sym->st_value; + target = client_call_binding(symname, symvalue); + if (target == symvalue) + continue; + got_entry = (Elf64_Addr *) (r->r_offset + base); + if (has_pltrelocs) { + addToDataBindingQueue(map, target, got_entry); + } + else { + debug_printf2("Unusal, have to do data symbol bindings in a DSO without PLT\n"); + make_got_writable(got_entry, map); + *got_entry = target; + if (!made_reloc_table_writable) { + reloc_table_pagebase = ((Elf64_Addr) relocs) & ~((Elf64_Addr) (getpagesize()-1)); + reloc_table_size = ((num_relocs + 1) * sizeof(Elf64_Rela)) - 1 + (((Elf64_Addr) relocs) - reloc_table_pagebase); + debug_printf3("mprotect(%p, %lu, PROT_READ|PROT_WRITE|PROT_EXEC) making GOT table writiable\n", + (void *) reloc_table_pagebase, reloc_table_size); + result = mprotect((void *) reloc_table_pagebase, reloc_table_size, PROT_READ | PROT_WRITE | PROT_EXEC); + if (result == -1) { + error = errno; + err_printf("Could not mprotect for write to relocs 0x%lx +%lu: %s\n", + reloc_table_pagebase, reloc_table_size, strerror(error)); + continue; + } + made_reloc_table_writable = 1; + } + r->r_info &= ~((Elf64_Xword) 0xffffffff); + r->r_info |= 0; /* R_*_NONE is 0 on all supported architectures */ + } + } + + return 0; +} + +int do_global_bindings(struct link_map *map) +{ + Elf64_Dyn *dyn; + Elf64_Rela *rels = NULL; + unsigned long num_rels = 0; + Elf64_Sym *syms = NULL; + const char *strtable = NULL; + int has_pltrelocs = 0; + + dyn = map->l_ld; + if (!dyn) { + debug_printf2("DSO %s does not have dynamic section\n", map->l_name); + return 0; + } + for (; dyn->d_tag != DT_NULL; dyn++) { + if (dyn->d_tag == DT_SYMTAB) + syms = (Elf64_Sym *) dyn->d_un.d_ptr; + else if (dyn->d_tag == DT_STRTAB) + strtable = (char *) dyn->d_un.d_ptr; + else if (dyn->d_tag == DT_RELA) + rels = (Elf64_Rela *) dyn->d_un.d_ptr; + else if (dyn->d_tag == DT_RELASZ) + num_rels = dyn->d_un.d_val / sizeof(Elf64_Rela); + else if (dyn->d_tag == DT_JMPREL) + has_pltrelocs = 1; + } + if (!syms || !strtable || !rels || !num_rels) { + debug_printf2("DSO %s is missing sections needed for variable binding (%p %p %p %lu)\n", map->l_name, + syms, strtable, rels, num_rels); + return 0; + } + + return bind_global_relocations(map, rels, map->l_addr, num_rels, syms, strtable, has_pltrelocs); +} From aa2b95a6d4f22654fe8fdb981f984dd2d730b1d9 Mon Sep 17 00:00:00 2001 From: Samuel Herts Date: Thu, 26 Feb 2026 14:53:15 -0500 Subject: [PATCH 09/14] Remove redundant functions from auditclient_x86_64.c since they are arch independent. Also reformat function definition --- src/client/auditclient/auditclient_x86_64.c | 134 ++------------------ 1 file changed, 8 insertions(+), 126 deletions(-) diff --git a/src/client/auditclient/auditclient_x86_64.c b/src/client/auditclient/auditclient_x86_64.c index 20721a0f..2add291d 100644 --- a/src/client/auditclient/auditclient_x86_64.c +++ b/src/client/auditclient/auditclient_x86_64.c @@ -16,21 +16,15 @@ Place, Suite 330, Boston, MA 02111-1307 USA #include "auditclient.h" #include "spindle_debug.h" -#include "writablegot.h" -#include -#include -#include -#include - -/*Elf64_Addr la_x86_64_gnu_pltenter(Elf64_Sym *sym, unsigned int ndx, - uintptr_t *refcook, uintptr_t *defcook, - La_x86_64_regs *regs, unsigned int *flags, - const char *symname, long int *framesizep) AUDIT_EXPORT;*/ - -uintptr_t la_symbind64(Elf64_Sym *sym, unsigned int ndx, - uintptr_t *refcook, uintptr_t *defcook, - unsigned int *flags, const char *symname) AUDIT_EXPORT; +Elf64_Addr la_x86_64_gnu_pltenter(Elf64_Sym *sym, + unsigned int ndx, + uintptr_t *refcook, + uintptr_t *defcook, + La_x86_64_regs *regs, + unsigned int *flags, + const char *symname, + long int *framesizep) AUDIT_EXPORT; Elf64_Addr la_x86_64_gnu_pltenter(Elf64_Sym *sym, unsigned int ndx, @@ -50,115 +44,3 @@ Elf64_Addr la_x86_64_gnu_pltenter(Elf64_Sym *sym, Elf64_Addr target = client_call_binding(symname, sym->st_value); return doPermanentBinding_idx(map, reloc_index, target, symname); } - -uintptr_t la_symbind64(Elf64_Sym *sym, unsigned int ndx, - uintptr_t *refcook, uintptr_t *defcook, - unsigned int *flags, const char *symname) -{ -// struct link_map *rmap = get_linkmap_from_cookie(refcook); -// struct link_map *dmap = get_linkmap_from_cookie(defcook); - (void)ndx; - (void)refcook; - (void)defcook; - updateDataBindingQueue(0); - Elf64_Addr target = client_call_binding(symname, sym->st_value); - *flags = 0; - return target; -} - -static int bind_global_relocations(struct link_map *map, Elf64_Rela *relocs, Elf64_Addr base, unsigned long num_relocs, - Elf64_Sym *symtable, const char *strtable, int has_pltrelocs) -{ - unsigned long i; - unsigned long symidx; - Elf64_Addr symvalue, target; - Elf64_Sym *sym; - const char *symname; - Elf64_Addr *got_entry; - int made_reloc_table_writable = 0, result, error; - Elf64_Addr reloc_table_pagebase = 0; - size_t reloc_table_size = 0; - - for (i = 0; i < num_relocs; i++) { - Elf64_Rela *r = relocs+i; - if (ELF64_R_TYPE(r->r_info) != R_X86_64_GLOB_DAT) - continue; - symidx = ELF64_R_SYM(r->r_info); - sym = symtable + symidx; - symname = strtable + sym->st_name; - symvalue = sym->st_value; - target = client_call_binding(symname, symvalue); - if (target == symvalue) - continue; - got_entry = (Elf64_Addr *) (r->r_offset + base); - if (has_pltrelocs) { - //Queue up any data-type symbols that need to be relocated and apply them - // when we do the function-type symbols in la_symbind64 - addToDataBindingQueue(map, target, got_entry); - } - else { - //This DSO has no function-type relocations. So we won't get a symbind callback. - //We'll do the bindings for the data-type relocations now. To prevent ld.so from - //overwriting these later, we'll also change the relocation type to make it a NULL - //operation. This has the unfortunate side effect of modifying the binary, which - //some programs may notice if they checksum themselves. It's a trade-off between - //this or messing up data-variable bindings. - //Spindle's libsymbind_g.so test triggers this. - debug_printf2("Unusal, have to do data symbol bindings in a DSO without PLT\n"); - make_got_writable(got_entry, map); - *got_entry = target; - if (!made_reloc_table_writable) { - reloc_table_pagebase = ((Elf64_Addr) relocs) & ~((Elf64_Addr) (getpagesize()-1)); - reloc_table_size = ((num_relocs + 1) * sizeof(Elf64_Rela)) - 1 + (((Elf64_Addr) relocs) - reloc_table_pagebase); - debug_printf3("mprotect(%p, %lu, PROT_READ|PROT_WRITE|PROT_EXEC) making GOT table writiable\n", (void *) reloc_table_pagebase, reloc_table_size); - result = mprotect((void *) reloc_table_pagebase, reloc_table_size, PROT_READ | PROT_WRITE | PROT_EXEC); - if (result == -1) { - error = errno; - err_printf("Could not mprotect for write to relocs 0x%lx +%lu: %s\n", - reloc_table_pagebase, reloc_table_size, strerror(error)); - continue; - } - made_reloc_table_writable = 1; - } - r->r_info &= ~((Elf64_Xword) 0xffffffff); - r->r_info |= R_X86_64_NONE; - } - } - - return 0; -} - -int do_global_bindings(struct link_map *map) -{ - Elf64_Dyn *dyn; - Elf64_Rela *rels = NULL; - unsigned long num_rels = 0; - Elf64_Sym *syms = NULL; - const char *strtable = NULL; - int has_pltrelocs = 0; - - dyn = map->l_ld; - if (!dyn) { - debug_printf2("DSO %s does not have dynamic section\n", map->l_name); - return 0; - } - for (; dyn->d_tag != DT_NULL; dyn++) { - if (dyn->d_tag == DT_SYMTAB) - syms = (Elf64_Sym *) dyn->d_un.d_ptr; - else if (dyn->d_tag == DT_STRTAB) - strtable = (char *) dyn->d_un.d_ptr; - else if (dyn->d_tag == DT_RELA) - rels = (Elf64_Rela *) dyn->d_un.d_ptr; - else if (dyn->d_tag == DT_RELASZ) - num_rels = dyn->d_un.d_val / sizeof(Elf64_Rela); - else if (dyn->d_tag == DT_JMPREL) - has_pltrelocs = 1; - } - if (!syms || !strtable || !rels || !num_rels) { - debug_printf2("DSO %s is missing sections needed for variable binding (%p %p %p %lu)\n", map->l_name, - syms, strtable, rels, num_rels); - return 0; - } - - return bind_global_relocations(map, rels, map->l_addr, num_rels, syms, strtable, has_pltrelocs); -} From a62f59437b1dbb7679fb92deec8bac316595e12a Mon Sep 17 00:00:00 2001 From: Samuel Herts Date: Thu, 26 Feb 2026 14:55:15 -0500 Subject: [PATCH 10/14] Remove redundant functions from auditclient_aarch64.c since they are arch independent --- src/client/auditclient/auditclient_aarch64.c | 126 +------------------ src/client/auditclient/auditclient_x86_64.c | 4 +- 2 files changed, 4 insertions(+), 126 deletions(-) diff --git a/src/client/auditclient/auditclient_aarch64.c b/src/client/auditclient/auditclient_aarch64.c index b07e23c0..baa4959a 100644 --- a/src/client/auditclient/auditclient_aarch64.c +++ b/src/client/auditclient/auditclient_aarch64.c @@ -20,13 +20,6 @@ Place, Suite 330, Boston, MA 02111-1307 USA #include "auditclient.h" #include "spindle_debug.h" -#include "writablegot.h" -#include "client.h" - -#include -#include -#include -#include @@ -36,14 +29,9 @@ Place, Suite 330, Boston, MA 02111-1307 USA La_aarch64_regs *regs, unsigned int *flags, const char *symname, - long int *framesizep) AUDIT_EXPORT;*/ - -uintptr_t la_symbind64(Elf64_Sym *sym, unsigned int ndx, - uintptr_t *refcook, uintptr_t *defcook, - unsigned int *flags, const char *symname) AUDIT_EXPORT; + long int *framesizep) AUDIT_EXPORT; -Elf64_Addr la_aarch64_gnu_pltenter (Elf64_Sym *sym, - unsigned int ndx, +Elf64_Addr la_aarch64_gnu_pltenter(Elf64_Sym *sym, unsigned int ndx, uintptr_t *refcook, uintptr_t *defcook, La_aarch64_regs *regs, @@ -60,113 +48,3 @@ Elf64_Addr la_aarch64_gnu_pltenter (Elf64_Sym *sym, return doPermanentBinding_noidx(refcook, defcook, target, symname, sp, (void *) regs); } - -uintptr_t la_symbind64(Elf64_Sym *sym, unsigned int ndx, - uintptr_t *refcook, uintptr_t *defcook, - unsigned int *flags, const char *symname) -{ - (void)ndx; - (void)refcook; - (void)defcook; - updateDataBindingQueue(0); - Elf64_Addr target = client_call_binding(symname, sym->st_value); - *flags = 0; - return target; -} - -static int bind_global_relocations(struct link_map *map, Elf64_Rela *relocs, Elf64_Addr base, unsigned long num_relocs, - Elf64_Sym *symtable, const char *strtable, int has_pltrelocs) -{ - unsigned long i; - unsigned long symidx; - Elf64_Addr symvalue, target; - Elf64_Sym *sym; - const char *symname; - Elf64_Addr *got_entry; - int made_reloc_table_writable = 0, result, error; - Elf64_Addr reloc_table_pagebase = 0; - size_t reloc_table_size = 0; - - for (i = 0; i < num_relocs; i++) { - Elf64_Rela *r = relocs+i; - if (ELF64_R_TYPE(r->r_info) != R_AARCH64_GLOB_DAT) - continue; - symidx = ELF64_R_SYM(r->r_info); - sym = symtable + symidx; - symname = strtable + sym->st_name; - symvalue = sym->st_value; - target = client_call_binding(symname, symvalue); - if (target == symvalue) - continue; - got_entry = (Elf64_Addr *) (r->r_offset + base); - if (has_pltrelocs) { - //Queue up any data-type symbols that need to be relocated and apply them - // when we do the function-type symbols in la_symbind64 - addToDataBindingQueue(map, target, got_entry); - } - else { - //This DSO has no function-type relocations. So we won't get a symbind callback. - //We'll do the bindings for the data-type relocations now. To prevent ld.so from - //overwriting these later, we'll also change the relocation type to make it a NULL - //operation. This has the unfortunate side effect of modifying the binary, which - //some programs may notice if they checksum themselves. It's a trade-off between - //this or messing up data-variable bindings. - //Spindle's libsymbind_g.so test triggers this. - debug_printf2("Unusal, have to do data symbol bindings in a DSO without PLT\n"); - make_got_writable(got_entry, map); - *got_entry = target; - if (!made_reloc_table_writable) { - reloc_table_pagebase = ((Elf64_Addr) relocs) & ~((Elf64_Addr) (getpagesize()-1)); - reloc_table_size = ((num_relocs + 1) * sizeof(Elf64_Rela)) - 1 + (((Elf64_Addr) relocs) - reloc_table_pagebase); - debug_printf3("mprotect(%p, %lu, PROT_READ|PROT_WRITE|PROT_EXEC) making GOT table writiable\n", (void *) reloc_table_pagebase, reloc_table_size); - result = mprotect((void *) reloc_table_pagebase, reloc_table_size, PROT_READ | PROT_WRITE | PROT_EXEC); - if (result == -1) { - error = errno; - err_printf("Could not mprotect for write to relocs 0x%lx +%lu: %s\n", - reloc_table_pagebase, reloc_table_size, strerror(error)); - continue; - } - made_reloc_table_writable = 1; - } - r->r_info &= ~((Elf64_Xword) 0xffffffff); - r->r_info |= R_AARCH64_NONE; - } - } - - return 0; -} - -int do_global_bindings(struct link_map *map) -{ - Elf64_Dyn *dyn; - Elf64_Rela *rels = NULL; - unsigned long num_rels = 0; - Elf64_Sym *syms = NULL; - const char *strtable = NULL; - int has_pltrelocs = 0; - - dyn = map->l_ld; - if (!dyn) { - debug_printf2("DSO %s does not have dynamic section\n", map->l_name); - return 0; - } - for (; dyn->d_tag != DT_NULL; dyn++) { - if (dyn->d_tag == DT_SYMTAB) - syms = (Elf64_Sym *) dyn->d_un.d_ptr; - else if (dyn->d_tag == DT_STRTAB) - strtable = (char *) dyn->d_un.d_ptr; - else if (dyn->d_tag == DT_RELA) - rels = (Elf64_Rela *) dyn->d_un.d_ptr; - else if (dyn->d_tag == DT_RELASZ) - num_rels = dyn->d_un.d_val / sizeof(Elf64_Rela); - else if (dyn->d_tag == DT_JMPREL) - has_pltrelocs = 1; - } - if (!syms || !strtable || !rels || !num_rels) { - debug_printf2("DSO %s is missing sections needed for variable binding (%p %p %p %lu)\n", map->l_name, - syms, strtable, rels, num_rels); - return 0; - } - - return bind_global_relocations(map, rels, map->l_addr, num_rels, syms, strtable, has_pltrelocs); -} diff --git a/src/client/auditclient/auditclient_x86_64.c b/src/client/auditclient/auditclient_x86_64.c index 2add291d..bbedb3bf 100644 --- a/src/client/auditclient/auditclient_x86_64.c +++ b/src/client/auditclient/auditclient_x86_64.c @@ -17,14 +17,14 @@ Place, Suite 330, Boston, MA 02111-1307 USA #include "auditclient.h" #include "spindle_debug.h" -Elf64_Addr la_x86_64_gnu_pltenter(Elf64_Sym *sym, +/*Elf64_Addr la_x86_64_gnu_pltenter(Elf64_Sym *sym, unsigned int ndx, uintptr_t *refcook, uintptr_t *defcook, La_x86_64_regs *regs, unsigned int *flags, const char *symname, - long int *framesizep) AUDIT_EXPORT; + long int *framesizep) AUDIT_EXPORT;*/ Elf64_Addr la_x86_64_gnu_pltenter(Elf64_Sym *sym, unsigned int ndx, From b343a40d7457a22d0fcbfb564b13813469bfdfe0 Mon Sep 17 00:00:00 2001 From: Samuel Herts Date: Thu, 26 Feb 2026 14:59:37 -0500 Subject: [PATCH 11/14] Fix comment --- src/client/auditclient/auditclient_aarch64.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/auditclient/auditclient_aarch64.c b/src/client/auditclient/auditclient_aarch64.c index baa4959a..8e06058b 100644 --- a/src/client/auditclient/auditclient_aarch64.c +++ b/src/client/auditclient/auditclient_aarch64.c @@ -29,7 +29,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA La_aarch64_regs *regs, unsigned int *flags, const char *symname, - long int *framesizep) AUDIT_EXPORT; + long int *framesizep) AUDIT_EXPORT;*/ Elf64_Addr la_aarch64_gnu_pltenter(Elf64_Sym *sym, unsigned int ndx, uintptr_t *refcook, From 4718edc6506cff899a5e722d1b73517d0db8ebd8 Mon Sep 17 00:00:00 2001 From: Samuel Herts Date: Fri, 27 Feb 2026 09:42:39 -0500 Subject: [PATCH 12/14] Pass GLibC's LA_VERSION back to ensure Spindle reports appropriate compatibility --- src/client/auditclient/auditclient.c | 4 ++-- src/client/subaudit/subaudit.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/client/auditclient/auditclient.c b/src/client/auditclient/auditclient.c index 2c94e81d..db7d5574 100644 --- a/src/client/auditclient/auditclient.c +++ b/src/client/auditclient/auditclient.c @@ -29,9 +29,9 @@ extern void restore_pathpatch(); unsigned int spindle_la_version(unsigned int version) { - (void)version; + //(void)version; patchDTV_init(); - return 1; + return version; } void spindle_la_activity (uintptr_t *cookie, unsigned int flag) diff --git a/src/client/subaudit/subaudit.c b/src/client/subaudit/subaudit.c index 982ac7ba..1e6b8f4f 100644 --- a/src/client/subaudit/subaudit.c +++ b/src/client/subaudit/subaudit.c @@ -27,7 +27,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA unsigned int spindle_la_version(unsigned int version) { - (void)version; + //(void)version; int result; int binding_offset = 0; @@ -39,7 +39,7 @@ unsigned int spindle_la_version(unsigned int version) debug_printf3("Updating subaudit bindings with offset %d\n", binding_offset); init_plt_binding_func(binding_offset); - return 1; + return version; } static void bind_to_libc() From 2cb5546c7756f2a1bc4ca7bb92f05a966ce4f552 Mon Sep 17 00:00:00 2001 From: Samuel Herts Date: Fri, 27 Feb 2026 09:43:16 -0500 Subject: [PATCH 13/14] Add jetbrains to .gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index dd50dea1..72c87827 100644 --- a/.gitignore +++ b/.gitignore @@ -34,3 +34,5 @@ run_driver run_driver_rm preload_file_list build + +.idea/ From d292d8e5e9510573d2a918bab6eac13078ecf4c3 Mon Sep 17 00:00:00 2001 From: Samuel Herts Date: Tue, 24 Mar 2026 11:27:00 -0400 Subject: [PATCH 14/14] Remove arm64_CI branch from pull request triggers --- .github/workflows/ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c64c6b45..a6f1039a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,7 +8,6 @@ on: pull_request: branches: - devel - - arm64_CI permissions: contents: read