From b37026af03827e6a380f0706c87e98a8a016c050 Mon Sep 17 00:00:00 2001 From: Ray Redondo Date: Fri, 17 Jun 2022 23:18:21 -0500 Subject: [PATCH] add mach_vm_msync --- .../include/darlingserver/duct-tape/hooks.h | 2 ++ duct-tape/src/memory.c | 8 +++-- include/darlingserver/rpc-supplement.h | 15 ++++++++ internal-include/darlingserver/process.hpp | 1 + internal-include/darlingserver/thread.hpp | 2 ++ src/process.cpp | 10 ++++++ src/server.cpp | 10 ++++++ src/thread.cpp | 35 +++++++++++++++++++ 8 files changed, 81 insertions(+), 2 deletions(-) diff --git a/duct-tape/include/darlingserver/duct-tape/hooks.h b/duct-tape/include/darlingserver/duct-tape/hooks.h index 052436f..e701920 100644 --- a/duct-tape/include/darlingserver/duct-tape/hooks.h +++ b/duct-tape/include/darlingserver/duct-tape/hooks.h @@ -52,6 +52,7 @@ typedef int (*dtape_hook_task_free_pages_f)(void* task_context, uintptr_t addres typedef uintptr_t (*dtape_hook_task_map_file_f)(void* task_context, int fd, size_t page_count, int protection, uintptr_t address_hint, size_t page_offset, dtape_memory_flags_t flags); typedef uintptr_t (*dtape_hook_task_get_next_region_f)(void* task_context, uintptr_t address); typedef bool (*dtape_hook_task_change_protection_f)(void* task_context, uintptr_t address, size_t page_count, int protection); +typedef bool (*dtape_hook_task_sync_memory_f)(void* task_context, uintptr_t address, size_t size, int sync_flags); typedef void (*dtape_hook_task_context_dispose_f)(void* task_context); #if DSERVER_EXTENDED_DEBUG @@ -97,6 +98,7 @@ typedef struct dtape_hooks { dtape_hook_task_map_file_f task_map_file; dtape_hook_task_get_next_region_f task_get_next_region; dtape_hook_task_change_protection_f task_change_protection; + dtape_hook_task_sync_memory_f task_sync_memory; dtape_hook_task_context_dispose_f task_context_dispose; #if DSERVER_EXTENDED_DEBUG diff --git a/duct-tape/src/memory.c b/duct-tape/src/memory.c index 390ac32..5af695a 100644 --- a/duct-tape/src/memory.c +++ b/duct-tape/src/memory.c @@ -594,8 +594,12 @@ kern_return_t mach_vm_map_external(vm_map_t target_map, mach_vm_offset_t* addres dtape_stub_unsafe(); }; -kern_return_t mach_vm_msync(vm_map_t map, mach_vm_address_t address, mach_vm_size_t size, vm_sync_t sync_flags) { - dtape_stub_unsafe(); +kern_return_t mach_vm_msync(vm_map_t map, mach_vm_offset_t address, mach_vm_size_t size, vm_sync_t sync_flags) { + if (!dtape_hooks->task_change_protection(map->dtape_task->context, address, size, sync_flags)) { + return KERN_FAILURE; + } + + return KERN_SUCCESS; }; kern_return_t mach_vm_page_info(vm_map_t map, mach_vm_address_t address, vm_page_info_flavor_t flavor, vm_page_info_t info, mach_msg_type_number_t* count) { diff --git a/include/darlingserver/rpc-supplement.h b/include/darlingserver/rpc-supplement.h index 6cd0542..db3b804 100644 --- a/include/darlingserver/rpc-supplement.h +++ b/include/darlingserver/rpc-supplement.h @@ -149,6 +149,7 @@ enum dserver_s2c_msgnum { dserver_s2c_msgnum_mmap, dserver_s2c_msgnum_munmap, dserver_s2c_msgnum_mprotect, + dserver_s2c_msgnum_msync, }; typedef enum dserver_s2c_msgnum dserver_s2c_msgnum_t; @@ -207,10 +208,24 @@ typedef struct dserver_s2c_reply_mprotect { int errno_result; } dserver_s2c_reply_mprotect_t; +typedef struct dserver_s2c_call_msync { + dserver_s2c_callhdr_t header; + uint64_t address; + uint64_t size; + int sync_flags; +} dserver_s2c_call_msync_t; + +typedef struct dserver_s2c_reply_msync { + dserver_s2c_replyhdr_t header; + int return_value; + int errno_result; +} dserver_s2c_reply_msync_t; + typedef union dserver_s2c_call { dserver_s2c_call_mmap_t mmap; dserver_s2c_call_munmap_t munmap; dserver_s2c_call_mprotect_t mprotect; + dserver_s2c_call_msync_t msync; } dserver_s2c_call_t; #if __cplusplus diff --git a/internal-include/darlingserver/process.hpp b/internal-include/darlingserver/process.hpp index 1f477a9..56d1342 100644 --- a/internal-include/darlingserver/process.hpp +++ b/internal-include/darlingserver/process.hpp @@ -180,6 +180,7 @@ namespace DarlingServer { void freePages(uintptr_t address, size_t pageCount); uintptr_t mapFile(int fd, size_t pageCount, int protection, uintptr_t addressHint, size_t pageOffset, bool fixed, bool overwrite); void changeProtection(uintptr_t address, size_t pageCount, int protection); + void syncMemory(uintptr_t address, size_t size, int sync_flags); uintptr_t getNextRegion(uintptr_t address) const; diff --git a/internal-include/darlingserver/thread.hpp b/internal-include/darlingserver/thread.hpp index 6dddc6a..c0870cf 100644 --- a/internal-include/darlingserver/thread.hpp +++ b/internal-include/darlingserver/thread.hpp @@ -126,6 +126,7 @@ namespace DarlingServer { uintptr_t _mmap(uintptr_t address, size_t length, int protection, int flags, int fd, off_t offset, int& outErrno); int _munmap(uintptr_t address, size_t length, int& outErrno); int _mprotect(uintptr_t address, size_t length, int protection, int& outErrno); + int _msync(uintptr_t address, size_t size, int sync_flags, int& outErrno); void _deferLocked(bool wait, std::unique_lock& lock); void _undeferLocked(std::unique_lock& lock); @@ -235,6 +236,7 @@ namespace DarlingServer { void freePages(uintptr_t address, size_t pageCount); uintptr_t mapFile(int fd, size_t pageCount, int protection, uintptr_t addressHint, size_t pageOffset, bool fixed, bool overwrite); void changeProtection(uintptr_t address, size_t pageCount, int protection); + void syncMemory(uintptr_t address, size_t size, int sync_flags); void defer(bool wait = false); void undefer(); diff --git a/src/process.cpp b/src/process.cpp index 5f70f49..79201a3 100644 --- a/src/process.cpp +++ b/src/process.cpp @@ -633,6 +633,16 @@ void DarlingServer::Process::changeProtection(uintptr_t address, size_t pageCoun return thread->changeProtection(address, pageCount, protection); }; +void DarlingServer::Process::syncMemory(uintptr_t address, size_t size, int sync_flags) { + auto thread = _pickS2CThread(); + + if (!thread) { + throw std::system_error(ESRCH, std::generic_category()); + } + + return thread->syncMemory(address, size, sync_flags); +}; + static const std::regex memoryRegionEntryAddressRegex("([0-9a-fA-F]+)\\-([0-9a-fA-F]+)"); uintptr_t DarlingServer::Process::getNextRegion(uintptr_t address) const { diff --git a/src/server.cpp b/src/server.cpp index 3491065..3e4a6dd 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -297,6 +297,15 @@ struct DTapeHooks { } }; + static bool dtape_hook_task_sync_memory(void* task_context, uintptr_t address, size_t size, int sync_flags) { + try { + static_cast(task_context)->syncMemory(address, size, sync_flags); + return true; + } catch (std::system_error e) { + return false; + } + }; + static void dtape_hook_task_context_dispose(void* task_context) { static_cast(task_context)->_dispose(); }; @@ -358,6 +367,7 @@ struct DTapeHooks { .task_map_file = dtape_hook_task_map_file, .task_get_next_region = dtape_hook_task_get_next_region, .task_change_protection = dtape_hook_task_change_protection, + .task_sync_memory = dtape_hook_task_sync_memory, .task_context_dispose = dtape_hook_task_context_dispose, #if DSERVER_EXTENDED_DEBUG diff --git a/src/thread.cpp b/src/thread.cpp index 048a822..0d876da 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -1171,6 +1171,34 @@ int DarlingServer::Thread::_mprotect(uintptr_t address, size_t length, int prote return reply->return_value; }; +int DarlingServer::Thread::_msync(uintptr_t address, size_t size, int sync_flags, int& outErrno) { + Message callMessage(sizeof(dserver_s2c_call_msync_t), 0); + auto call = reinterpret_cast(callMessage.data().data()); + + call->header.call_number = dserver_callnum_s2c; + call->header.s2c_number = dserver_s2c_msgnum_msync; + call->address = address; + call->size = size; + call->sync_flags = sync_flags; + + s2cLog.debug() << "Performing _msync with address=" << call->address << ", size=" << call->size << ", sync_flags=" << call->sync_flags << s2cLog.endLog; + + auto maybeReplyMessage = _s2cPerform(std::move(callMessage), dserver_s2c_msgnum_msync, sizeof(dserver_s2c_reply_msync_t)); + if (!maybeReplyMessage) { + s2cLog.debug() << "_msync call interrupted" << s2cLog.endLog; + outErrno = EINTR; + return -1; + } + + auto replyMessage = std::move(*maybeReplyMessage); + auto reply = reinterpret_cast(replyMessage.data().data()); + + s2cLog.debug() << "_msync returned return_value=" << reply->return_value << ", errno_result=" << reply->errno_result << s2cLog.endLog; + + outErrno = reply->errno_result; + return reply->return_value; +}; + uintptr_t DarlingServer::Thread::allocatePages(size_t pageCount, int protection, uintptr_t addressHint, bool fixed, bool overwrite) { int err = 0; int flags = MAP_PRIVATE | MAP_ANONYMOUS; @@ -1215,6 +1243,13 @@ void DarlingServer::Thread::changeProtection(uintptr_t address, size_t pageCount } }; +void DarlingServer::Thread::syncMemory(uintptr_t address, size_t size, int sync_flags) { + int err = 0; + if (_msync(address, size, sync_flags, err) < 0) { + throw std::system_error(err, std::generic_category(), "S2C msync call failed"); + } +}; + void DarlingServer::Thread::waitUntilRunning() { std::shared_lock lock(_rwlock); _runningCondvar.wait(lock, [&]() {