Skip to content
Draft
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
27 changes: 27 additions & 0 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
63 changes: 59 additions & 4 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
#include <sys/stat.h>
#include <unistd.h>

#ifdef __FreeBSD__
#if defined(__FreeBSD__) || defined(__NetBSD__)
#define PROCFS_MAP "/proc/self/map"
#else
#define PROCFS_MAP "/proc/self/maps"
Expand All @@ -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) {
Expand Down Expand Up @@ -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");

/*
Expand All @@ -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 */
Expand Down Expand Up @@ -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"

Expand All @@ -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"

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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) {
Expand Down