diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 6f3319b..9238340 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -55,6 +55,33 @@ jobs: make fmt make -C apps/basic fmt test -z "$(git status --porcelain)" + netbsd-build: + name: NetBSD Build + runs-on: ubuntu-latest + steps: + - name: Code checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Build on NetBSD + uses: vmactions/netbsd-vm@v1 + with: + arch: aarch64 + usesh: true + prepare: | + export PKG_PATH="ftp://ftp.NetBSD.org/pub/pkgsrc/packages/$(uname -s)/$(uname -p)/$(uname -r)/All" + /usr/sbin/pkg_add -U -v pkgin + /usr/pkg/bin/pkgin update + /usr/pkg/bin/pkgin install -y clang + /sbin/sysctl -w security.pax.mprotect.global=0 + run: | + make clean + make -C apps/basic clean + make + make -C apps/basic + make fmt + make -C apps/basic fmt + test -z "$(git status --porcelain)" android-build: name: Android Cross Build runs-on: ubuntu-latest diff --git a/Makefile b/Makefile index 17902da..87de57c 100644 --- a/Makefile +++ b/Makefile @@ -31,7 +31,7 @@ OBJS = $(C_SRCS:.c=.o) all: $(PROGS) $(PROGS): $(OBJS) - $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) + $(CC) $(CFLAGS) -o $@ $(OBJS) $(LDFLAGS) clean: -@rm -rf $(CLEANFILES) diff --git a/README.md b/README.md index a7c046d..28f3a7b 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Read [my blog post (ja)](https://retrage.github.io/2024/07/31/svc-hook.html/) fo ## Target Platform -svc-hook supports ARM64 Linux and FreeBSD. +svc-hook supports ARM64 Linux, FreeBSD and NetBSD. ## Build diff --git a/main.c b/main.c index 1a6842a..e644ba1 100644 --- a/main.c +++ b/main.c @@ -18,7 +18,7 @@ #include #include -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) || defined(__NetBSD__) #define PROCFS_MAP "/proc/self/map" #else #define PROCFS_MAP "/proc/self/maps" @@ -33,7 +33,7 @@ * SUPPLEMENTAL: syscall record without syscalls */ #define BM_BACKING_FILE "/tmp/syscall_record" -#define BM_SIZE (1UL << 9) +#define BM_SIZE (1UL << 16) // svc #imm is 16-bit, so 65536 entries static char *bm_mem = NULL; static void bm_init(void) { @@ -120,7 +120,7 @@ void ____asm_impl(void) { "adrp x6, :got:syscall_table \n\t" "ldr x6, [x6, #:got_lo12:syscall_table] \n\t" "ldr x6, [x6] \n\t" - "add x6, x6, xzr, lsl #3 \n\t" + "add x6, x6, x8, lsl #3 \n\t" "br x6 \n\t"); /* @@ -138,6 +138,7 @@ void ____asm_impl(void) { ".globl asm_syscall_hook \n\t" "asm_syscall_hook: \n\t" +#if defined(__linux__) "cmp x8, #139 \n\t" /* rt_sigreturn */ "b.eq do_rt_sigreturn \n\t" /* bypass hook */ "cmp x8, #220 \n\t" /* clone */ @@ -179,6 +180,7 @@ void ____asm_impl(void) { /* Copy x0-x30 to cl_args->stack + cl_args->stack_size */ SAVE_CONTEXT(x15) "b do_syscall_hook \n\t" +#endif /* defined(__linux__) */ "do_syscall_hook: \n\t" @@ -189,7 +191,9 @@ void ____asm_impl(void) { /* arguments for syscall_hook */ "mov x7, x14 \n\t" /* return address */ +#if !defined(__NetBSD__) "mov x6, x8 \n\t" /* syscall NR */ +#endif /* !defined(__NetBSD__) */ "bl syscall_hook \n\t" @@ -508,7 +512,7 @@ static void scan_exec_code(char *code, size_t code_size, int mem_prot, close(fd); } -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) /* entry point for binary scanning on FreeBSD */ static void scan_code(void) { LIST_INIT(&head); @@ -559,6 +563,57 @@ static void scan_code(void) { } fclose(fp); } +#elif defined(__NetBSD__) +/* entry point for binary scanning on NetBSD */ +static void scan_code(void) { + LIST_INIT(&head); + + FILE *fp = NULL; + /* get memory mapping information from procfs */ + assert((fp = fopen(PROCFS_MAP, "r")) != NULL); + char buf[4096]; + while (fgets(buf, sizeof(buf), fp) != NULL) { + /* we do not touch stack memory */ + if (strstr(buf, "[stack]") != NULL) { + continue; + } + int mem_prot = 0; + int i = 0; + char from_addr[65] = {0}; + char to_addr[65] = {0}; + char *c = strtok(buf, " "); + while (c != NULL) { + switch (i) { + case 0: + strncpy(from_addr, c, sizeof(from_addr) - 1); + break; + case 1: + strncpy(to_addr, c, sizeof(to_addr) - 1); + break; + case 2: + for (size_t j = 0; j < strlen(c); j++) { + if (c[j] == 'r') mem_prot |= PROT_READ; + if (c[j] == 'w') mem_prot |= PROT_WRITE; + if (c[j] == 'x') mem_prot |= PROT_EXEC; + } + break; + case 4: + if (strncmp(c, "COW", 3) == 0) { + int64_t from = strtol(&from_addr[0], NULL, 16); + int64_t to = strtol(&to_addr[0], NULL, 16); + if (mem_prot & PROT_EXEC) { + scan_exec_code((char *)from, (size_t)to - from, mem_prot, NULL); + } + } + break; + } + if (i == 4) break; + c = strtok(NULL, " "); + i++; + } + } + fclose(fp); +} #else /* entry point for binary scanning on Linux */ static void scan_code(void) {