Skip to content

Commit 1e392bb

Browse files
authored
Merge pull request #93 from sysprog21/chown
Track virtual file ownership through chown EPERM
2 parents a2fb25a + c0e6de9 commit 1e392bb

13 files changed

Lines changed: 974 additions & 53 deletions

Makefile

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ SRCS := \
4040
syscall/path.c \
4141
syscall/fuse.c \
4242
syscall/sidecar.c \
43+
syscall/chown-overlay.c \
4344
syscall/fs.c \
4445
syscall/fs-stat.c \
4546
syscall/fs-xattr.c \
@@ -142,6 +143,14 @@ $(BUILD_DIR)/test-tlbi-encoder-host: $(BUILD_DIR)/test-tlbi-encoder-host.o \
142143
@echo " LD $@"
143144
$(Q)$(CC) $(CFLAGS) -o $@ $^
144145

146+
## Build the fork IPC protocol identity unit test (native macOS binary).
147+
# Pure C; no HVF entitlement needed. Pins the first header word as the
148+
# cross-version protocol discriminator after IPC_VERSION removal.
149+
$(BUILD_DIR)/test-fork-ipc-protocol-host: \
150+
$(BUILD_DIR)/test-fork-ipc-protocol-host.o | $(BUILD_DIR)
151+
@echo " LD $@"
152+
$(Q)$(CC) $(CFLAGS) -o $@ $^
153+
145154
## Build the proctitle argv-tail regression test (native macOS binary)
146155
# Links against the project-built proctitle.o so the exact in-tree code is
147156
# exercised; no HVF entitlement is needed because the test only manipulates

mk/config.mk

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ endif
2020

2121
# Exclude native macOS test files from cross-compilation
2222
NATIVE_TESTS := tests/test-multi-vcpu.c tests/test-rwx.c \
23-
tests/test-tlbi-encoder-host.c
23+
tests/test-tlbi-encoder-host.c \
24+
tests/test-fork-ipc-protocol-host.c
2425
SPECIAL_TEST_SRCS := tests/test-lowbase-mem.c
2526
SPECIAL_TEST_BINS := $(BUILD_DIR)/test-lowbase-mem-200000 $(BUILD_DIR)/test-lowbase-mem-300000
2627

mk/tests.mk

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
test-matrix test-matrix-elfuse-aarch64 test-matrix-qemu-aarch64 \
1111
test-full test-multi-vcpu test-rwx test-sysroot-rename \
1212
test-case-collision test-case-collision-fallback test-getdents64-overlong \
13-
test-sysroot-create-paths \
13+
test-sysroot-create-paths test-fork-ipc-protocol-host \
1414
test-proctitle-host test-proctitle-low-stack \
1515
test-sysroot-procfs-exec test-timeout-disable test-fuse-alpine \
1616
test-sysroot-nofollow test-sysroot-chdir perf
@@ -37,10 +37,13 @@ endef
3737

3838
## Run the unit test suite plus busybox applet validation
3939
check: $(ELFUSE_BIN) $(TEST_DEPS) check-syscall-coverage \
40-
$(BUILD_DIR)/test-tlbi-encoder-host
40+
$(BUILD_DIR)/test-tlbi-encoder-host \
41+
$(BUILD_DIR)/test-fork-ipc-protocol-host
4142
@bash tests/driver.sh -e $(ELFUSE_BIN) -d $(TEST_DIR) -v
4243
@printf "\n$(BLUE)━━━ TLBI RVAE1IS encoder unit test ━━━$(RESET)\n"
4344
@$(BUILD_DIR)/test-tlbi-encoder-host
45+
@printf "\n$(BLUE)━━━ fork IPC protocol identity unit test ━━━$(RESET)\n"
46+
@$(BUILD_DIR)/test-fork-ipc-protocol-host
4447
@printf "\n$(BLUE)━━━ proctitle argv-tail regression ━━━$(RESET)\n"
4548
@$(MAKE) --no-print-directory test-proctitle-host
4649
@printf "\n$(BLUE)━━━ proctitle low-stack regression ━━━$(RESET)\n"
@@ -569,6 +572,11 @@ test-multi-vcpu: $(BUILD_DIR)/test-multi-vcpu
569572
test-rwx: $(BUILD_DIR)/test-rwx
570573
$(BUILD_DIR)/test-rwx
571574

575+
# Fork IPC protocol identity regression
576+
## Run the fork IPC protocol identity unit test
577+
test-fork-ipc-protocol-host: $(BUILD_DIR)/test-fork-ipc-protocol-host
578+
$(BUILD_DIR)/test-fork-ipc-protocol-host
579+
572580
# Proctitle argv-tail regression
573581
## Run the deterministic argv-tail overshoot guard test
574582
test-proctitle-host: $(BUILD_DIR)/test-proctitle-host

src/runtime/fork-state.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ int fork_ipc_write_all(int fd, const void *buf, size_t len)
3636
continue;
3737
return -1;
3838
}
39+
3940
if (n == 0) {
4041
/* Defensive: an unexpected zero return on a blocking socket would
4142
* otherwise spin forever, since p and len stay at the same offset.

src/runtime/fork-state.h

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,18 @@
1515
#include "syscall/abi.h"
1616
#include "syscall/signal.h"
1717

18-
/* Magic values for IPC frame delimiters */
19-
#define IPC_MAGIC_HEADER 0x454C464BU /* "ELFK" */
20-
#define IPC_MAGIC_SENTINEL 0x454C4F4BU /* "ELOK" */
21-
/* Bumped to 11 when regions_tracker_stale was added to process state so forked
22-
* children preserve mprotect fast-path correctness.
23-
*
24-
* Bumped to 10 when the rosetta placement / kbuf / ttbr1 tuple was added so a
25-
* rosetta-aware child rejects an older parent's header instead of trying to
26-
* interpret unknown trailing fields.
18+
/* Fork IPC protocol identity. Bump this whenever the header layout or ordered
19+
* fork payload changes incompatibly.
2720
*/
28-
#define IPC_VERSION 11
21+
#define FORK_IPC_PROTOCOL_MAGIC 0x454C464CU /* "ELFL" */
22+
23+
#define IPC_MAGIC_HEADER FORK_IPC_PROTOCOL_MAGIC
24+
#define IPC_MAGIC_SENTINEL 0x454C4F4BU /* "ELOK" */
2925

3026
typedef struct {
3127
uint32_t magic;
32-
uint32_t version;
3328
uint32_t ipa_bits;
34-
uint32_t has_shm;
29+
bool has_shm;
3530
int64_t child_pid, parent_pid;
3631
uint64_t guest_size;
3732
uint64_t elf_load_min;
@@ -46,14 +41,14 @@ typedef struct {
4641
uint32_t _pad;
4742
uint64_t absock_namespace_id;
4843
int64_t sid, pgid;
44+
4945
/* Rosetta placement fields. All zero for aarch64 guests; populated when the
5046
* parent is_rosetta. The child rebuilds the TTBR1 kbuf tree from the PT
5147
* pool that came across in the memory transfer; rosetta_guest_base /
5248
* va_base / size pin the segments at the same primary-buffer location so
5349
* the non-identity page-table mapping remains coherent across the fork.
5450
*/
55-
uint32_t is_rosetta;
56-
uint32_t _rosetta_pad;
51+
bool is_rosetta;
5752
uint64_t rosetta_guest_base;
5853
uint64_t rosetta_va_base;
5954
uint64_t rosetta_size;

src/runtime/forkipc.c

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include "runtime/futex.h"
3838

3939
#include "syscall/abi.h"
40+
#include "syscall/chown-overlay.h"
4041
#include "syscall/internal.h"
4142
#include "syscall/mem.h"
4243
#include "syscall/net.h" /* absock namespace IPC state */
@@ -101,8 +102,8 @@ int fork_child_main(int ipc_fd,
101102
proc_init();
102103
fork_child_vfork_notify_fd = vfork_notify_fd;
103104

104-
/* The header fixes the IPC protocol version and the guest identity before
105-
* any variable-length state is trusted.
105+
/* The header magic identifies the fork IPC protocol before any
106+
* variable-length state is trusted.
106107
*/
107108
ipc_header_t hdr;
108109
if (fork_ipc_read_all(ipc_fd, &hdr, sizeof(hdr)) < 0) {
@@ -113,14 +114,6 @@ int fork_child_main(int ipc_fd,
113114
log_error("fork-child: bad magic 0x%x", hdr.magic);
114115
return 1;
115116
}
116-
if (hdr.version != IPC_VERSION) {
117-
log_error(
118-
"fork-child: IPC version mismatch "
119-
"(got %u, expected %u)",
120-
hdr.version, IPC_VERSION);
121-
return 1;
122-
}
123-
124117
log_debug("fork-child: pid=%lld ppid=%lld", (long long) hdr.child_pid,
125118
(long long) hdr.parent_pid);
126119

@@ -241,7 +234,7 @@ int fork_child_main(int ipc_fd,
241234
* primary buffer and is copied by the region transfer below, so the child
242235
* can reuse it without rebuilding the tree.
243236
*/
244-
g.is_rosetta = (hdr.is_rosetta != 0);
237+
g.is_rosetta = hdr.is_rosetta;
245238
proc_set_rosetta_active(g.is_rosetta);
246239
g.rosetta_guest_base = hdr.rosetta_guest_base;
247240
g.rosetta_va_base = hdr.rosetta_va_base;
@@ -288,6 +281,12 @@ int fork_child_main(int ipc_fd,
288281
return 1;
289282
}
290283

284+
if (chown_overlay_recv(ipc_fd) < 0) {
285+
log_error("fork-child: failed to receive chown overlay");
286+
guest_destroy(&g);
287+
return 1;
288+
}
289+
291290
/* POSIX: "Signals pending to the parent shall not be pending to the child."
292291
* Clear pending bitmask and RT queue before applying state.
293292
* signal_set_state() is deferred until after thread_register_main() so that
@@ -1521,9 +1520,8 @@ int64_t sys_clone(hv_vcpu_t vcpu,
15211520
/* Header */
15221521
ipc_header_t hdr = {
15231522
.magic = IPC_MAGIC_HEADER,
1524-
.version = IPC_VERSION,
15251523
.ipa_bits = g->ipa_bits,
1526-
.has_shm = (uint32_t) use_shm,
1524+
.has_shm = use_shm,
15271525
.child_pid = child_guest_pid,
15281526
.parent_pid = proc_get_pid(),
15291527
.guest_size = g->guest_size,
@@ -1548,7 +1546,7 @@ int64_t sys_clone(hv_vcpu_t vcpu,
15481546
.absock_namespace_id = absock_get_namespace_id(),
15491547
.sid = proc_get_sid(),
15501548
.pgid = proc_get_pgid(),
1551-
.is_rosetta = g->is_rosetta ? 1 : 0,
1549+
.is_rosetta = g->is_rosetta,
15521550
.rosetta_guest_base = g->rosetta_guest_base,
15531551
.rosetta_va_base = g->rosetta_va_base,
15541552
.rosetta_size = g->rosetta_size,
@@ -1652,6 +1650,11 @@ int64_t sys_clone(hv_vcpu_t vcpu,
16521650
goto fail_snapshot;
16531651
}
16541652

1653+
if (chown_overlay_send(ipc_sock) < 0) {
1654+
log_error("clone: failed to send chown overlay");
1655+
goto fail_snapshot;
1656+
}
1657+
16551658
/* The process-state payload includes the SCM_RIGHTS handoff for region
16561659
* backing fds. Keep siblings quiesced until that send completes so a
16571660
* concurrent munmap/remap cannot close or recycle the captured fd numbers.

0 commit comments

Comments
 (0)