Skip to content

Commit fc04ac5

Browse files
committed
Add NetBSD support
1 parent 3835811 commit fc04ac5

File tree

5 files changed

+100
-9
lines changed

5 files changed

+100
-9
lines changed

.github/workflows/build.yaml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,29 @@ jobs:
5555
make fmt
5656
make -C apps/basic fmt
5757
test -z "$(git status --porcelain)"
58+
netbsd-build:
59+
name: NetBSD Build
60+
runs-on: ubuntu-latest
61+
steps:
62+
- name: Code checkout
63+
uses: actions/checkout@v4
64+
with:
65+
fetch-depth: 0
66+
- name: Build on NetBSD
67+
uses: vmactions/netbsd-vm@v1
68+
with:
69+
arch: aarch64
70+
usesh: true
71+
prepare: |
72+
pkg_add clang
73+
run: |
74+
bmake clean
75+
bmake -C apps/basic clean
76+
bmake
77+
bmake -C apps/basic
78+
bmake fmt
79+
bmake -C apps/basic fmt
80+
test -z "$(git status --porcelain)"
5881
android-build:
5982
name: Android Cross Build
6083
runs-on: ubuntu-latest

Makefile

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1-
#!/usr/bin/env make
21
# SPDX-License-Identifier: Apache-2.0
32
# Copyright (C) 2025 Akira Moroo
43

4+
CC ?= clang
55
PROGS = libsvchook.so
66

77
CLANG_FORMAT ?= clang-format
88

99
SYSCALL_RECORD ?= 0
10+
NO_MAN=
1011

1112
CLEANFILES = $(PROGS) *.o *.d
1213

@@ -31,7 +32,7 @@ OBJS = $(C_SRCS:.c=.o)
3132
all: $(PROGS)
3233

3334
$(PROGS): $(OBJS)
34-
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
35+
$(CC) $(CFLAGS) -o $@ $? $(LDFLAGS)
3536

3637
clean:
3738
-@rm -rf $(CLEANFILES)

README.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Read [my blog post (ja)](https://retrage.github.io/2024/07/31/svc-hook.html/) fo
1414

1515
## Target Platform
1616

17-
svc-hook supports ARM64 Linux and FreeBSD.
17+
svc-hook supports ARM64 Linux, FreeBSD and NetBSD.
1818

1919
## Build
2020

@@ -31,6 +31,18 @@ To build a simple hook application `libsvchook_basic.so`, use:
3131
make -C apps/basic
3232
```
3333

34+
35+
### NetBSD Development Environment
36+
37+
You can build and test svc-hook on NetBSD using user mode QEMU. Install
38+
`qemu-user` and `bmake` on your development system:
39+
40+
```shell
41+
sudo apt-get install qemu-user bmake
42+
```
43+
44+
Then build the project with `bmake` or run the NetBSD binaries using
45+
`qemu-aarch64`. The Makefiles are compatible with both GNU Make and BSD Make.
3446
## Usage
3547

3648
You need to set two environment variables:

apps/basic/Makefile

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
#!/usr/bin/env make
21
# SPDX-License-Identifier: Apache-2.0
32
# Copyright (C) 2025 Akira Moroo
43

4+
CC ?= clang
55
PROGS = libsvchook_basic.so
66

77
CLANG_FORMAT ?= clang-format
8+
NO_MAN=
89

910
CLEANFILES = $(PROGS) *.o *.d
1011

@@ -24,7 +25,7 @@ OBJS = $(C_SRCS:.c=.o)
2425
all: $(PROGS)
2526

2627
$(PROGS): $(OBJS)
27-
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LDFLAGS)
28+
$(CC) $(CFLAGS) -o $@ $? $(LDFLAGS)
2829

2930
clean:
3031
-@rm -rf $(CLEANFILES)

main.c

Lines changed: 58 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@
1818
#include <sys/stat.h>
1919
#include <unistd.h>
2020

21-
#ifdef __FreeBSD__
21+
#if defined(__FreeBSD__)
2222
#define PROCFS_MAP "/proc/self/map"
23+
#elif defined(__NetBSD__)
24+
#define PROCFS_MAP "/proc/curproc/map"
2325
#else
2426
#define PROCFS_MAP "/proc/self/maps"
2527
#endif
@@ -120,8 +122,9 @@ void ____asm_impl(void) {
120122
"adrp x6, :got:syscall_table \n\t"
121123
"ldr x6, [x6, #:got_lo12:syscall_table] \n\t"
122124
"ldr x6, [x6] \n\t"
123-
"add x6, x6, xzr, lsl #3 \n\t"
124-
"br x6 \n\t");
125+
"lsl x8, x8, #3 \n\t"
126+
"add x8, x8, x6 \n\t"
127+
"br x8 \n\t");
125128

126129
/*
127130
* asm_syscall_hook is the address where the
@@ -508,7 +511,7 @@ static void scan_exec_code(char *code, size_t code_size, int mem_prot,
508511
close(fd);
509512
}
510513

511-
#ifdef __FreeBSD__
514+
#if defined(__FreeBSD__)
512515
/* entry point for binary scanning on FreeBSD */
513516
static void scan_code(void) {
514517
LIST_INIT(&head);
@@ -559,6 +562,57 @@ static void scan_code(void) {
559562
}
560563
fclose(fp);
561564
}
565+
#elif defined(__NetBSD__)
566+
/* entry point for binary scanning on NetBSD */
567+
static void scan_code(void) {
568+
LIST_INIT(&head);
569+
570+
FILE *fp = NULL;
571+
/* get memory mapping information from procfs */
572+
assert((fp = fopen(PROCFS_MAP, "r")) != NULL);
573+
char buf[4096];
574+
while (fgets(buf, sizeof(buf), fp) != NULL) {
575+
/* we do not touch stack memory */
576+
if (strstr(buf, "[stack]") != NULL) {
577+
continue;
578+
}
579+
int mem_prot = 0;
580+
int i = 0;
581+
char from_addr[65] = {0};
582+
char to_addr[65] = {0};
583+
char *c = strtok(buf, " ");
584+
while (c != NULL) {
585+
switch (i) {
586+
case 0:
587+
strncpy(from_addr, c, sizeof(from_addr) - 1);
588+
break;
589+
case 1:
590+
strncpy(to_addr, c, sizeof(to_addr) - 1);
591+
break;
592+
case 2:
593+
for (size_t j = 0; j < strlen(c); j++) {
594+
if (c[j] == 'r') mem_prot |= PROT_READ;
595+
if (c[j] == 'w') mem_prot |= PROT_WRITE;
596+
if (c[j] == 'x') mem_prot |= PROT_EXEC;
597+
}
598+
break;
599+
case 4:
600+
if (strncmp(c, "COW", 3) == 0) {
601+
int64_t from = strtol(&from_addr[0], NULL, 16);
602+
int64_t to = strtol(&to_addr[0], NULL, 16);
603+
if (mem_prot & PROT_EXEC) {
604+
scan_exec_code((char *)from, (size_t)to - from, mem_prot, NULL);
605+
}
606+
}
607+
break;
608+
}
609+
if (i == 4) break;
610+
c = strtok(NULL, " ");
611+
i++;
612+
}
613+
}
614+
fclose(fp);
615+
}
562616
#else
563617
/* entry point for binary scanning on Linux */
564618
static void scan_code(void) {

0 commit comments

Comments
 (0)