Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 46 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
name: ci

on:
workflow_dispatch:
push:
branches:
- devel
Expand All @@ -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
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,5 @@ run_driver
run_driver_rm
preload_file_list
build

.idea/
4 changes: 2 additions & 2 deletions src/client/auditclient/auditclient.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
10 changes: 5 additions & 5 deletions src/client/auditclient/auditclient_aarch64.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,20 @@ Place, Suite 330, Boston, MA 02111-1307 USA
#define _GNU_SOURCE
#endif

#include <stdlib.h>
#include "client.h"
#include "auditclient.h"
#include "spindle_debug.h"

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;*/

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,
Expand Down
110 changes: 109 additions & 1 deletion src/client/auditclient/auditclient_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 <assert.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>

static uintptr_t *firstcookie = NULL;
Expand Down Expand Up @@ -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);
}
135 changes: 8 additions & 127 deletions src/client/auditclient/auditclient_x86_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,15 @@ Place, Suite 330, Boston, MA 02111-1307 USA

#include "auditclient.h"
#include "spindle_debug.h"
#include "writablegot.h"

#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/mman.h>

/*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,
Expand All @@ -50,116 +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);
}
Loading
Loading