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
7 changes: 6 additions & 1 deletion mk/config.mk
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ BUILD_DIR := build
ELFUSE_BIN := $(BUILD_DIR)/elfuse
VERSION ?= $(shell git describe --tags --always --dirty 2>/dev/null || echo "unknown")

# Private pseudo-syscall number used by translated guests to invoke the
# embedder HVC 6 hook. This is not a Linux syscall number.
ELFUSE_NR_EMBEDDER_HVC6 ?= 999
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make ELFUSE_NR_EMBEDDER_HVC6= lets an empty value override ?=, then CFLAGS picks up -DELFUSE_NR_EMBEDDER_HVC6= and the C hook becomes if (nr == ) -- syntax error. Either skip the -D when the value is empty, or guard the C side with a numeric check:

#if defined(ELFUSE_NR_EMBEDDER_HVC6) && (ELFUSE_NR_EMBEDDER_HVC6 + 0 > 0)


# Test binary directory: either pre-built via GUEST_TEST_BINARIES,
# auto-detected from build/bin, or locally cross-compiled via $(CROSS_COMPILE)gcc.
ifeq ($(origin GUEST_TEST_BINARIES), undefined)
Expand Down Expand Up @@ -50,4 +54,5 @@ RESET := \033[0m
CFLAGS := -O2 -Wall -Wextra -Wpedantic \
-Wshadow -Wstrict-prototypes -Wmissing-prototypes \
-Wformat=2 -Wimplicit-fallthrough -Wundef \
-Wnull-dereference -Wno-unused-parameter
-Wnull-dereference -Wno-unused-parameter \
-DELFUSE_NR_EMBEDDER_HVC6=$(ELFUSE_NR_EMBEDDER_HVC6)
34 changes: 34 additions & 0 deletions src/syscall/syscall.c
Original file line number Diff line number Diff line change
Expand Up @@ -1818,6 +1818,40 @@ int syscall_dispatch(hv_vcpu_t vcpu, guest_t *g, int *exit_code, bool verbose)
slow_path:
entry = RANGE_CHECK(nr, 0, SC_TABLE_SIZE) ? &syscall_table[nr] : NULL;

/* Custom Embedder Syscall Hook:
* Guests running on translated user-space architectures (e.g., x86_64
* via Apple Rosetta 2) execute at EL0 and cannot compile or execute
* native AArch64 'hvc' instructions.
*
* To allow such guests to invoke the embedder extension hooks (like the
* graphics bridge), we intercept a custom system call number
* (ELFUSE_NR_EMBEDDER_HVC6) as the x86_64 guest counterpart to AArch64
* 'hvc 6'.
*
* Syscall layout:
* nr = ELFUSE_NR_EMBEDDER_HVC6
* X0 = call number
* X1 = guest virtual address of the uint64_t args[8] array
*/
#ifdef ELFUSE_NR_EMBEDDER_HVC6
if (nr == ELFUSE_NR_EMBEDDER_HVC6) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Four concerns on this hook:

  1. No g->is_rosetta gate. A native aarch64 EL0 program issuing svc #0; x8=999 reaches g->hvc6_handler, bypassing the HVC Bound static-bin smoke tests with per-test timeout #6 trusted-shim path at src/syscall/proc.c:1825. If embedders (e.g., a graphics bridge) implicitly trust their caller, this blurs the privilege boundary. Either gate on g->is_rosetta, or document the contract at src/core/guest.h:502 so embedders allowlist call_nr.

  2. The Rosetta translation premise is unverified. Apple's Rosetta-for-Linux is closed-source; it may translate via a per-syscall table and ENOSYS an unknown nr like 999 at the translator before the SVC ever reaches elfuse. A working graphics-bridge demo from a real x86_64 guest would close this.

  3. Future Linux generic syscall range collision (today ~462). Add _Static_assert(ELFUSE_NR_EMBEDDER_HVC6 > SC_TABLE_SIZE); here so a future syscall-table growth fails the build instead of silently shadowing the embedder.

  4. No test. The hook sits on the syscall_dispatch hot path; the next refactor can break the embedder ABI silently. A ~50-line native-aarch64 test that registers a stub hvc6_handler, issues syscall(999, 42, &args), asserts call_nr and args[], and covers EFAULT + NULL-handler fallback would lock it in.

Style nits: leading comment block at column 0 should be 4-space indented to match function body; "we intercept" should be third-person per spec.md ("elfuse intercepts" or imperative).

if (g->hvc6_handler) {
uint64_t call_nr = 0;
uint64_t args_gva = 0;
hv_vcpu_get_reg(vcpu, HV_REG_X0, &call_nr);
hv_vcpu_get_reg(vcpu, HV_REG_X1, &args_gva);
uint64_t guest_args[8] = {0};
if (guest_read_small(g, args_gva, guest_args, sizeof(guest_args)) <
0) {
result = -LINUX_EFAULT;
} else {
result = g->hvc6_handler(call_nr, guest_args, g->hvc6_userdata);
}
goto fast_done;
}
}
#endif

hv_vcpu_get_reg(vcpu, HV_REG_X0, &x0);
hv_vcpu_get_reg(vcpu, HV_REG_X1, &x1);
hv_vcpu_get_reg(vcpu, HV_REG_X2, &x2);
Expand Down
Loading