diff --git a/src/glibc/lind_syscall/lind_syscall.h b/src/glibc/lind_syscall/lind_syscall.h index 2036a3b4e..deee69e49 100644 --- a/src/glibc/lind_syscall/lind_syscall.h +++ b/src/glibc/lind_syscall/lind_syscall.h @@ -48,4 +48,5 @@ int copy_data_between_cages(uint64_t thiscage, uint64_t targetcage, uint64_t destaddr, uint64_t destcage, uint64_t len, uint64_t copytype); +int copy_handler_table_to_cage(uint64_t srccage, uint64_t targetcage); #endif // _LIND_SYSCALL_H diff --git a/src/rawposix/src/sys_calls.rs b/src/rawposix/src/sys_calls.rs index 48676911a..d6da14d9b 100644 --- a/src/rawposix/src/sys_calls.rs +++ b/src/rawposix/src/sys_calls.rs @@ -163,9 +163,9 @@ pub extern "C" fn fork_syscall( // syscall implementation threei::copy_handler_table_to_cage( UNUSED_ARG, - child_cageid, + UNUSED_ARG, parent_cageid, - UNUSED_ID, + child_cageid, UNUSED_ARG, UNUSED_ID, UNUSED_ARG, diff --git a/src/threei/src/handler_table/dashmap_impl.rs b/src/threei/src/handler_table/dashmap_impl.rs index 486523965..400277dbb 100644 --- a/src/threei/src/handler_table/dashmap_impl.rs +++ b/src/threei/src/handler_table/dashmap_impl.rs @@ -234,8 +234,6 @@ pub fn register_handler_impl( /// Actual implementation of copy_handler_table_to_cage. /// See comments in threei.rs for details. pub fn copy_handler_table_to_cage_impl(srccage: u64, targetcage: u64) -> u64 { - // Clone the source call map snapshot so we don't hold a long-lived reference - // while mutating the destination. DashMap::clone clones the structure and keys/values. let src_snapshot: CallnumMap = if let Some(src_entry) = HANDLERTABLE.get(&srccage) { let snap = src_entry.value().clone(); drop(src_entry); @@ -248,10 +246,12 @@ pub fn copy_handler_table_to_cage_impl(srccage: u64, targetcage: u64) -> u64 { return threei_const::ELINDAPIABORTED; }; - let dst_call_map_ref = HANDLERTABLE.entry(targetcage).or_insert_with(DashMap::new); + // Overwrite the entire target handler table. + HANDLERTABLE.insert(targetcage, DashMap::new()); + + let dst_call_map_ref = HANDLERTABLE.get(&targetcage).unwrap(); let dst_call_map: &CallnumMap = &*dst_call_map_ref; - // Copy without overwriting existing destination handlers. for src_call_entry in src_snapshot.iter() { let callnum = *src_call_entry.key(); let src_target_map: &TargetCageMap = src_call_entry.value(); @@ -263,8 +263,7 @@ pub fn copy_handler_table_to_cage_impl(srccage: u64, targetcage: u64) -> u64 { let handlefunccage = *src_target_entry.key(); let addr = *src_target_entry.value(); - // Insert only if absent, preserving any existing destination mapping. - dst_target_map.entry(handlefunccage).or_insert(addr); + dst_target_map.insert(handlefunccage, addr); } } diff --git a/src/threei/src/handler_table/hashmap_impl.rs b/src/threei/src/handler_table/hashmap_impl.rs index 553e80a67..1e2bd2f3d 100644 --- a/src/threei/src/handler_table/hashmap_impl.rs +++ b/src/threei/src/handler_table/hashmap_impl.rs @@ -226,9 +226,10 @@ pub fn copy_handler_table_to_cage_impl(srccage: u64, targetcage: u64) -> u64 { let mut handler_table = HANDLERTABLE.lock().unwrap(); // If srccage has a handler table, clones its contents into targetcage. - // Does not overwrite any existing handlers in the target. + // Overwrites any existing handlers in the target. if let Some(src_entry) = handler_table.get(&srccage).cloned() { - let target_entry = handler_table.entry(targetcage).or_insert_with(HashMap::new); + handler_table.insert(targetcage, HashMap::new()); // overwrite whole target + let target_entry = handler_table.get_mut(&targetcage).unwrap(); for (callnum, callnum_map) in src_entry { let target_callnum_map = target_entry.entry(callnum).or_insert_with(HashMap::new); for (handlefunc, handlefunccage) in callnum_map { diff --git a/src/threei/src/threei.rs b/src/threei/src/threei.rs index 45bb02ba8..71e0646c6 100644 --- a/src/threei/src/threei.rs +++ b/src/threei/src/threei.rs @@ -329,18 +329,18 @@ pub fn register_handler( /// interposable. /// /// ## Arguments: -/// - targetcage: The ID of the cage receiving the copied handler mappings. /// - srccage: The ID of the cage whose handler mappings are being copied. +/// - targetcage: The ID of the cage receiving the copied handler mappings. /// /// ## Returns: /// - 0 on success. /// - `ELINDESRCH` if either source or target cage is in the EXITING state. /// - `ELINDAPIABORTED` if srccage has no existing handler table. pub fn copy_handler_table_to_cage( - _callnum: u64, - targetcage: u64, + _thiscage: u64, + _targetcage: u64, srccage: u64, - _arg1cage: u64, + targetcage: u64, _arg2: u64, _arg2cage: u64, _arg3: u64, diff --git a/tests/grate-tests/simple-tests/copy-handler-table.c b/tests/grate-tests/simple-tests/copy-handler-table.c new file mode 100644 index 000000000..c5ad1badd --- /dev/null +++ b/tests/grate-tests/simple-tests/copy-handler-table.c @@ -0,0 +1,70 @@ +#include +#include +#include +#include +#include +#include + +#define EXPECTED_EUID 123 + +int main(void) { + int parent_euid = geteuid(); + if (parent_euid != EXPECTED_EUID) { + fprintf(stderr, + "[Cage|copy-handler-table] FAIL: parent expected " + "geteuid=%d, got %d\n", + EXPECTED_EUID, parent_euid); + assert(0); + } + + pid_t pid = fork(); + if (pid < 0) { + perror("fork failed"); + assert(0); + } + + if (pid == 0) { + int child_euid = geteuid(); + if (child_euid != EXPECTED_EUID) { + fprintf(stderr, + "[Cage|copy-handler-table] FAIL: child " + "expected inherited geteuid=%d, got %d\n", + EXPECTED_EUID, child_euid); + assert(0); + } + + int ret = copy_handler_table_to_cage(1, getpid()); + if (ret != 0) { + fprintf(stderr, + "[Cage|copy-handler-table] FAIL: " + "copy_handler_table_to_cage returned %d\n", + ret); + assert(0); + } + + child_euid = geteuid(); + if (child_euid == EXPECTED_EUID) { + fprintf(stderr, + "[Cage|copy-handler-table] FAIL: geteuid still " + "returned inherited handler value %d after " + "table overwrite\n", + child_euid); + assert(0); + } + + printf("[Cage|copy-handler-table] PASS: child inherited " + "handler, then overwrite changed geteuid to %d\n", + child_euid); + return 0; + } + + int status = 0; + pid_t waited_pid = waitpid(pid, &status, 0); + assert(waited_pid == pid); + assert(WIFEXITED(status)); + assert(WEXITSTATUS(status) == 0); + + printf("[Cage|copy-handler-table] PASS: parent=%d child_exit=%d\n", + parent_euid, WEXITSTATUS(status)); + return 0; +} diff --git a/tests/grate-tests/simple-tests/copy-handler-table_grate.c b/tests/grate-tests/simple-tests/copy-handler-table_grate.c new file mode 100644 index 000000000..102cc6481 --- /dev/null +++ b/tests/grate-tests/simple-tests/copy-handler-table_grate.c @@ -0,0 +1,79 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define GETEUID_SYSCALL_NUM 107 +#define EXPECTED_EUID 123 + +int pass_fptr_to_wt(uint64_t fn_ptr_uint, uint64_t cageid, uint64_t arg1, + uint64_t arg1cage, uint64_t arg2, uint64_t arg2cage, + uint64_t arg3, uint64_t arg3cage, uint64_t arg4, + uint64_t arg4cage, uint64_t arg5, uint64_t arg5cage, + uint64_t arg6, uint64_t arg6cage) { + if (fn_ptr_uint == 0) { + fprintf(stderr, "[Grate|copy-handler-table] Invalid function ptr\n"); + assert(0); + } + + int (*fn)(uint64_t) = (int (*)(uint64_t))(uintptr_t)fn_ptr_uint; + return fn(cageid); +} + +int geteuid_grate(uint64_t cageid) { + printf("[Grate|copy-handler-table] geteuid handler invoked for cage %llu\n", + cageid); + return EXPECTED_EUID; +} + +int main(int argc, char *argv[]) { + if (argc < 2) { + fprintf(stderr, "Usage: %s \n", argv[0]); + assert(0); + } + + int grateid = getpid(); + + pid_t pid = fork(); + if (pid < 0) { + perror("fork failed"); + assert(0); + } else if (pid == 0) { + int cageid = getpid(); + uint64_t fn_ptr_addr = (uint64_t)(uintptr_t)&geteuid_grate; + + printf("[Grate|copy-handler-table] Registering geteuid handler for cage %d in grate %d\n", + cageid, grateid); + + int ret = register_handler(cageid, GETEUID_SYSCALL_NUM, grateid, fn_ptr_addr); + if (ret != 0) { + fprintf(stderr, + "[Grate|copy-handler-table] FAIL: register_handler returned %d\n", + ret); + assert(0); + } + + if (execv(argv[1], &argv[1]) == -1) { + perror("execv failed"); + assert(0); + } + } + + int status = 0; + while (wait(&status) > 0) { + if (status != 0) { + fprintf(stderr, + "[Grate|copy-handler-table] FAIL: child exited with status %d\n", + status); + assert(0); + } + } + + printf("[Grate|copy-handler-table] PASS\n"); + return 0; +}