From 874d9283682b99e20173270e06b5ab2841af4dad Mon Sep 17 00:00:00 2001 From: Chun-Hung Tseng Date: Fri, 17 Jul 2026 18:03:26 +0200 Subject: [PATCH] De-dup write_rusage_to_guest code sys_getrusage() open-coded the same macOS-to-Linux rusage translation that write_rusage_to_guest() already implements in proc.c for the ptrace paths: a whole-struct memcpy followed by ru_maxrss conversion from bytes to kilobytes. Carrying two copies risks them drifting apart, especially the layout assertions that gate the fast memcpy path. Expose the existing helper via proc.h and call it from sys_getrusage(), dropping the duplicate. Move the full-size _Static_assert next to the helper in proc.c; sys.c keeps only the ru_maxrss offset check that guards the translation done there. --- src/syscall/proc.c | 4 +--- src/syscall/proc.h | 7 +++++++ src/syscall/sys.c | 12 ++++-------- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/syscall/proc.c b/src/syscall/proc.c index fe2aa533..48e9e629 100644 --- a/src/syscall/proc.c +++ b/src/syscall/proc.c @@ -1074,9 +1074,7 @@ int64_t sys_ptrace(guest_t *g, _Static_assert(sizeof(struct rusage) == sizeof(linux_rusage_t), "host and guest rusage layouts must match on LP64"); -static int write_rusage_to_guest(guest_t *g, - uint64_t gva, - const struct rusage *ru) +int write_rusage_to_guest(guest_t *g, uint64_t gva, const struct rusage *ru) { linux_rusage_t lru; memcpy(&lru, ru, sizeof(lru)); diff --git a/src/syscall/proc.h b/src/syscall/proc.h index b57686c7..03830413 100644 --- a/src/syscall/proc.h +++ b/src/syscall/proc.h @@ -323,6 +323,13 @@ void proc_children_cpu_add(const struct rusage *ru); /* Read the accumulated guest-children CPU time, in microseconds. */ void proc_children_cpu_us(uint64_t *utime_us, uint64_t *stime_us); +/* Write a macOS struct rusage to guest memory as linux_rusage_t. The field + * layout matches on LP64; ru_maxrss is converted from macOS bytes to Linux + * kilobytes. Returns the guest_write_small result (0 on success, negative on + * fault). + */ +int write_rusage_to_guest(guest_t *g, uint64_t gva, const struct rusage *ru); + /* Collect host PIDs of active (non-exited) fork children. Writes up to max_pids * entries into out[]. * diff --git a/src/syscall/sys.c b/src/syscall/sys.c index 09ebe7dd..1abb4ea3 100644 --- a/src/syscall/sys.c +++ b/src/syscall/sys.c @@ -74,8 +74,9 @@ static linux_rlimit64_t guest_nofile_limit = { }; #define RLIMIT_CACHE_SIZE ((int) (ARRAY_SIZE(cached_linux_rlimits))) -_Static_assert(sizeof(struct rusage) == sizeof(linux_rusage_t), - "host and guest rusage layouts must match on LP64"); +/* The full-size assertion lives with write_rusage_to_guest() in proc.c; this + * offset check guards the fast memcpy translation done there. + */ _Static_assert(offsetof(struct rusage, ru_maxrss) == offsetof(linux_rusage_t, ru_maxrss), "ru_maxrss offset must stay aligned for fast translation"); @@ -529,12 +530,7 @@ int64_t sys_getrusage(guest_t *g, int who, uint64_t usage_gva) if (getrusage(who, &mac_usage) < 0) return linux_errno(); - linux_rusage_t lin_usage; - memcpy(&lin_usage, &mac_usage, sizeof(lin_usage)); - lin_usage.ru_maxrss = - mac_usage.ru_maxrss / 1024; /* macOS: bytes -> Linux: KB */ - - if (guest_write_small(g, usage_gva, &lin_usage, sizeof(lin_usage)) < 0) + if (write_rusage_to_guest(g, usage_gva, &mac_usage) < 0) return -LINUX_EFAULT; return 0;