mirror of
https://github.com/darlinghq/darlingserver.git
synced 2024-11-23 12:29:41 +00:00
Add a ton of RPC calls
This commit adds a bunch of RPC calls, mostly XNU trap calls (calls that go directly to duct-taped XNU Mach trap calls). The wrapper generator can now automatically generate server-side wrapper/boilerplate code these XNU trap calls. These calls have not yet been tested and some (most of the non-IPC calls) probably require functions that haven't been implemented yet.
This commit is contained in:
parent
a5627fddf1
commit
89e7afe22e
@ -322,6 +322,7 @@ add_library(darlingserver_duct_tape
|
||||
|
||||
target_include_directories(darlingserver_duct_tape PRIVATE
|
||||
internal-include
|
||||
${CMAKE_CURRENT_BINARY_DIR}/../internal-include
|
||||
)
|
||||
|
||||
target_include_directories(darlingserver_duct_tape PUBLIC
|
||||
@ -330,6 +331,7 @@ target_include_directories(darlingserver_duct_tape PUBLIC
|
||||
|
||||
add_dependencies(darlingserver_duct_tape
|
||||
kernel_mig_generate
|
||||
generate_dserver_rpc_wrappers
|
||||
)
|
||||
|
||||
target_link_libraries(darlingserver_duct_tape PUBLIC
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <libsimple/lock.h>
|
||||
#include <darlingserver/rpc.internal.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -70,8 +71,10 @@ uint32_t dtape_task_self_trap(void);
|
||||
uint32_t dtape_host_self_trap(void);
|
||||
uint32_t dtape_thread_self_trap(void);
|
||||
uint32_t dtape_mach_reply_port(void);
|
||||
int dtape_mach_msg_overwrite(uintptr_t msg, int32_t option, uint32_t send_size, uint32_t rcv_size, uint32_t rcv_name, uint32_t timeout, uint32_t notify, uintptr_t rcv_msg, uint32_t rcv_limit);
|
||||
int dtape_mach_port_deallocate(uint32_t task_name_right, uint32_t port_name_right);
|
||||
uint32_t dtape_thread_get_special_reply_port(void);
|
||||
uint32_t dtape_mk_timer_create(void);
|
||||
|
||||
DSERVER_DTAPE_DECLS;
|
||||
|
||||
/**
|
||||
* The threshold beyond which thread IDs are considered IDs for kernel threads.
|
||||
@ -106,6 +109,14 @@ void dtape_thread_destroy(dtape_thread_handle_t thread);
|
||||
void dtape_thread_entering(dtape_thread_handle_t thread);
|
||||
void dtape_thread_exiting(dtape_thread_handle_t thread);
|
||||
void dtape_thread_set_handles(dtape_thread_handle_t thread, uintptr_t pthread_handle, uintptr_t dispatch_qaddr);
|
||||
/**
|
||||
* Returns the thread corresponding to the given thread port.
|
||||
*
|
||||
* @warning It is VERY important that the caller ensures the thread cannot die while we're looking it up.
|
||||
* This can be accomplished, for example, by locking the global thread list before the call.
|
||||
*/
|
||||
dtape_thread_handle_t dtape_thread_for_port(uint32_t thread_port);
|
||||
void* dtape_thread_context(dtape_thread_handle_t thread);
|
||||
|
||||
void dtape_task_uidgid(dtape_task_handle_t task, int new_uid, int new_gid, int* old_uid, int* old_gid);
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <ipc/ipc_importance.h>
|
||||
#include <kern/restartable.h>
|
||||
#include <kern/sync_sema.h>
|
||||
#include <mach/mach_traps.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
@ -333,6 +334,18 @@ kern_return_t task_unregister_dyld_image_infos(task_t task, dyld_kernel_image_in
|
||||
dtape_stub_unsafe();
|
||||
};
|
||||
|
||||
kern_return_t task_for_pid(struct task_for_pid_args* args) {
|
||||
dtape_stub_unsafe();
|
||||
};
|
||||
|
||||
kern_return_t task_name_for_pid(struct task_name_for_pid_args* args) {
|
||||
dtape_stub_unsafe();
|
||||
};
|
||||
|
||||
kern_return_t pid_for_task(struct pid_for_task_args* args) {
|
||||
dtape_stub_unsafe();
|
||||
};
|
||||
|
||||
// <copied from="xnu://7195.141.2/osfmk/kern/task_policy.c">
|
||||
|
||||
/*
|
||||
|
@ -112,6 +112,24 @@ void dtape_thread_set_handles(dtape_thread_handle_t thread_handle, uintptr_t pth
|
||||
thread->dispatch_qaddr = dispatch_qaddr;
|
||||
};
|
||||
|
||||
dtape_thread_handle_t dtape_thread_for_port(uint32_t thread_port) {
|
||||
thread_t xnu_thread = port_name_to_thread(thread_port, PORT_TO_THREAD_NONE);
|
||||
if (!xnu_thread) {
|
||||
return xnu_thread;
|
||||
}
|
||||
// port_name_to_thread returns a reference on the thread upon success.
|
||||
// because we cannot take a reference on the duct-taped thread owner,
|
||||
// this reference is meaningless. therefore, we drop it.
|
||||
// we entrust our caller with the responsibility of ensuring it remains alive.
|
||||
thread_deallocate(xnu_thread);
|
||||
return dtape_thread_for_xnu_thread(xnu_thread);
|
||||
};
|
||||
|
||||
void* dtape_thread_context(dtape_thread_handle_t thread_handle) {
|
||||
dtape_thread_t* thread = thread_handle;
|
||||
return thread->context;
|
||||
};
|
||||
|
||||
thread_t current_thread(void) {
|
||||
dtape_thread_t* thread = dtape_hooks->current_thread();
|
||||
return &thread->xnu_thread;
|
||||
@ -352,6 +370,14 @@ kern_return_t thread_wire(host_priv_t host_priv, thread_t thread, boolean_t wire
|
||||
dtape_stub_unsafe();
|
||||
};
|
||||
|
||||
void thread_handoff_parameter(thread_t thread, thread_continue_t continuation, void *parameter, thread_handoff_option_t option) {
|
||||
dtape_stub_unsafe();
|
||||
};
|
||||
|
||||
wait_result_t thread_handoff_deallocate(thread_t thread, thread_handoff_option_t option) {
|
||||
dtape_stub_unsafe();
|
||||
};
|
||||
|
||||
// ignore the lock timeout
|
||||
#define LockTimeOutUsec UINT32_MAX
|
||||
|
||||
|
@ -18,25 +18,12 @@ uint32_t dtape_mach_reply_port(void) {
|
||||
return mach_reply_port(NULL);
|
||||
};
|
||||
|
||||
int dtape_mach_msg_overwrite(uintptr_t msg, int32_t option, uint32_t send_size, uint32_t rcv_size, uint32_t rcv_name, uint32_t timeout, uint32_t notify, uintptr_t rcv_msg, uint32_t rcv_limit) {
|
||||
struct mach_msg_overwrite_trap_args args = {
|
||||
.msg = msg,
|
||||
.option = option,
|
||||
.send_size = send_size,
|
||||
.rcv_size = rcv_size,
|
||||
.rcv_name = rcv_name,
|
||||
.timeout = timeout,
|
||||
.priority = notify,
|
||||
.rcv_msg = rcv_msg,
|
||||
// no rcv_limit
|
||||
};
|
||||
return mach_msg_overwrite_trap(&args);
|
||||
uint32_t dtape_thread_get_special_reply_port(void) {
|
||||
return thread_get_special_reply_port(NULL);
|
||||
};
|
||||
|
||||
int dtape_mach_port_deallocate(uint32_t task_name_right, uint32_t port_name_right) {
|
||||
struct _kernelrpc_mach_port_deallocate_args args = {
|
||||
.target = task_name_right,
|
||||
.name = port_name_right,
|
||||
};
|
||||
return _kernelrpc_mach_port_deallocate_trap(&args);
|
||||
uint32_t dtape_mk_timer_create(void) {
|
||||
return mk_timer_create_trap(NULL);
|
||||
};
|
||||
|
||||
DSERVER_DTAPE_DEFS;
|
||||
|
@ -40,7 +40,7 @@ namespace DarlingServer {
|
||||
private:
|
||||
std::unordered_map<typename Entry::ID, std::shared_ptr<Entry>> _map;
|
||||
std::unordered_map<typename Entry::NSID, std::shared_ptr<Entry>> _nsmap;
|
||||
std::shared_mutex _rwlock;
|
||||
mutable std::shared_mutex _rwlock;
|
||||
|
||||
// sometimes, the factory used with registerIfAbsent needs to be able to look up other entries
|
||||
// (and the factory is called with the lock held, so trying to acquire the lock again would be a deadlock)
|
||||
@ -176,6 +176,34 @@ namespace DarlingServer {
|
||||
|
||||
return (*it2).second;
|
||||
};
|
||||
|
||||
/**
|
||||
* Locks the registry, preventing new entries from being added and old ones from being removed.
|
||||
*
|
||||
* This should be used very sparingly; you almost certainly don't want to use this.
|
||||
* The primary use case for this is preventing an entry from being removed while it is being used
|
||||
* in a situation where taking its shared_ptr is not possible.
|
||||
*
|
||||
* Every call to this method MUST be balanced with a call to unlock().
|
||||
*/
|
||||
void lock() const {
|
||||
_rwlock.lock();
|
||||
};
|
||||
|
||||
void unlock() const {
|
||||
_rwlock.unlock();
|
||||
};
|
||||
|
||||
using ScopedLock = std::unique_lock<std::shared_mutex>;
|
||||
|
||||
/**
|
||||
* Locks the registry like lock(), but employs the RAII idiom to automatically unlock it at the end of the scope.
|
||||
*
|
||||
* Scoped locks can also be manually unlocked earlier.
|
||||
*/
|
||||
ScopedLock scopedLock() const {
|
||||
return ScopedLock(_rwlock);
|
||||
};
|
||||
};
|
||||
|
||||
Registry<Process>& processRegistry();
|
||||
|
@ -118,6 +118,13 @@ namespace DarlingServer {
|
||||
void setThreadHandles(uintptr_t pthreadHandle, uintptr_t dispatchQueueAddress);
|
||||
|
||||
static std::shared_ptr<Thread> currentThread();
|
||||
|
||||
/**
|
||||
* Returns the Thread that corresponds to the given thread port in the current port space.
|
||||
*
|
||||
* @note This function may only be called from a microthread context.
|
||||
*/
|
||||
static std::shared_ptr<Thread> threadForPort(uint32_t thread_port);
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -6,22 +6,31 @@ from collections import OrderedDict
|
||||
import textwrap
|
||||
from datetime import datetime
|
||||
|
||||
XNU_TRAP_CALL = 1 << 0
|
||||
XNU_TRAP_NOPREFIX = 1 << 1
|
||||
XNU_TRAP_NOSUFFIX = 1 << 2
|
||||
XNU_TRAP_NOSUFFIX_ARGS = 1 << 3
|
||||
|
||||
# NOTE: in Python 3.7+, we can rely on dictionaries having their items in insertion order.
|
||||
# unfortunately, we can't expect everyone building Darling to have Python 3.7+ installed.
|
||||
calls = [
|
||||
#
|
||||
# FORMAT:
|
||||
# tuple with 3 members:
|
||||
# tuple with either 3 or 4 members:
|
||||
# 1. call name: the name of the remote procedure
|
||||
# 2. call parameters: the set of parameters callers are expected to provide arguments for.
|
||||
# 3. return parameters: the set of parameters the procedure is expected to return values for.
|
||||
# 4. flags: an optional set of flags that modify how this call is processed and wrapped.
|
||||
# if the set of flags (4) is omitted, it defaults to 0.
|
||||
#
|
||||
# PARAMETERS:
|
||||
# each parameter (both for calls and returns) is a tuple with either 2 or 3 members:
|
||||
# 1. parameter name: the name of the parameter (duh)
|
||||
# 2. public type: the type used in the public RPC wrappers
|
||||
# 3. (optional) private type: the type used internally for serialization and for the server implementation.
|
||||
# if the private type (3) is omitted, it is the same as the public type.
|
||||
#
|
||||
# TYPES:
|
||||
# the types that can be used are normal C types. however, to be more architecture-agnostic,
|
||||
# it is recommended to use `stdint.h` types whenever possible (e.g. `int32_t` instead of `int`,
|
||||
# `uint64_t` instead of `unsigned long`, etc.).
|
||||
@ -30,11 +39,16 @@ calls = [
|
||||
# that is wide enough to accommodate pointers for all architectures. a good choice is `uint64_t`;
|
||||
# NOT `uintptr_t`, as its size varies according to the architecture.
|
||||
#
|
||||
# SPECIAL TYPES:
|
||||
# one special type that is supported is `@fd`. this type indicates that the parameter specifies a file descriptor.
|
||||
# it will be treated as an `int` type-wise, but the RPC wrappers will perform some additional work on it
|
||||
# to serialize it across the connection. this works bi-directionally (i.e. both the client and server can send and receive FDs).
|
||||
# the resulting descriptor received on the other end (in either client or server) will behave like a `dup()`ed descriptor.
|
||||
#
|
||||
# FLAGS:
|
||||
# currently, the only flag that can be passed is XNU_TRAP_CALL. this indicates that the given call is actually an XNU trap.
|
||||
# this enables more advanced wrappers to be generated for that call and avoid unnecessary boilerplate code on the server side.
|
||||
#
|
||||
# TODO: we should probably add a class for these calls (so it's more readable).
|
||||
# we could even create a DSL (à-la-MIG), but that's probably overkill since
|
||||
# we only use our RPC for darlingserver calls.
|
||||
@ -56,22 +70,6 @@ calls = [
|
||||
('length', 'uint64_t'),
|
||||
]),
|
||||
|
||||
('task_self_trap', [], [
|
||||
('port_name', 'uint32_t'),
|
||||
]),
|
||||
|
||||
('host_self_trap', [], [
|
||||
('port_name', 'uint32_t'),
|
||||
]),
|
||||
|
||||
('thread_self_trap', [], [
|
||||
('port_name', 'uint32_t'),
|
||||
]),
|
||||
|
||||
('mach_reply_port', [], [
|
||||
('port_name', 'uint32_t'),
|
||||
]),
|
||||
|
||||
('kprintf', [
|
||||
('string', 'const char*', 'uint64_t'),
|
||||
('string_length', 'uint64_t'),
|
||||
@ -85,23 +83,6 @@ calls = [
|
||||
('tracer', 'uint32_t'),
|
||||
]),
|
||||
|
||||
('mach_msg_overwrite', [
|
||||
('msg', 'void*', 'uint64_t'),
|
||||
('option', 'int32_t'),
|
||||
('send_size', 'uint32_t'),
|
||||
('rcv_size', 'uint32_t'),
|
||||
('rcv_name', 'uint32_t'),
|
||||
('timeout', 'uint32_t'),
|
||||
('notify', 'uint32_t'),
|
||||
('rcv_msg', 'void*', 'uint64_t'),
|
||||
('rcv_limit', 'uint32_t'),
|
||||
], []),
|
||||
|
||||
('mach_port_deallocate', [
|
||||
('task_right_name', 'uint32_t'),
|
||||
('port_right_name', 'uint32_t'),
|
||||
], []),
|
||||
|
||||
('uidgid', [
|
||||
('new_uid', 'int32_t'),
|
||||
('new_gid', 'int32_t'),
|
||||
@ -125,6 +106,246 @@ calls = [
|
||||
], [
|
||||
('length', 'uint64_t'),
|
||||
]),
|
||||
|
||||
#
|
||||
# pthread cancelation
|
||||
#
|
||||
|
||||
('pthread_kill', [
|
||||
('thread_port', 'uint32_t'),
|
||||
('signal', 'int32_t'),
|
||||
], []),
|
||||
|
||||
('pthread_canceled', [
|
||||
('action', 'int32_t'),
|
||||
], []),
|
||||
|
||||
('pthread_markcancel', [
|
||||
('thread_port', 'uint32_t'),
|
||||
], []),
|
||||
|
||||
#
|
||||
# Mach IPC traps
|
||||
#
|
||||
|
||||
('task_self_trap', [], [
|
||||
('port_name', 'uint32_t'),
|
||||
]),
|
||||
|
||||
('host_self_trap', [], [
|
||||
('port_name', 'uint32_t'),
|
||||
]),
|
||||
|
||||
('thread_self_trap', [], [
|
||||
('port_name', 'uint32_t'),
|
||||
]),
|
||||
|
||||
('mach_reply_port', [], [
|
||||
('port_name', 'uint32_t'),
|
||||
]),
|
||||
|
||||
('thread_get_special_reply_port', [], [
|
||||
('port_name', 'uint32_t'),
|
||||
]),
|
||||
|
||||
('mach_msg_overwrite', [
|
||||
('msg', 'void*', 'uint64_t'),
|
||||
('option', 'int32_t'),
|
||||
('send_size', 'uint32_t'),
|
||||
('rcv_size', 'uint32_t'),
|
||||
('rcv_name', 'uint32_t'),
|
||||
('timeout', 'uint32_t'),
|
||||
('priority', 'uint32_t'),
|
||||
('rcv_msg', 'void*', 'uint64_t'),
|
||||
], [], XNU_TRAP_CALL | XNU_TRAP_NOPREFIX),
|
||||
|
||||
('mach_port_deallocate', [
|
||||
('target', 'uint32_t'),
|
||||
('name', 'uint32_t'),
|
||||
], [], XNU_TRAP_CALL | XNU_TRAP_NOSUFFIX_ARGS),
|
||||
|
||||
('mach_port_allocate', [
|
||||
('target', 'uint32_t'),
|
||||
('right', 'int32_t'),
|
||||
|
||||
# this would be better as a return parameter,
|
||||
# but due to the way darlingserver handles Mach IPC calls,
|
||||
# we need a pointer into the calling process's memory
|
||||
('name', 'uint32_t*', 'uint64_t'),
|
||||
], [], XNU_TRAP_CALL | XNU_TRAP_NOSUFFIX_ARGS),
|
||||
|
||||
('mach_port_mod_refs', [
|
||||
('target', 'uint32_t'),
|
||||
('name', 'uint32_t'),
|
||||
('right', 'int32_t'),
|
||||
('delta', 'int32_t'),
|
||||
], [], XNU_TRAP_CALL | XNU_TRAP_NOSUFFIX_ARGS),
|
||||
|
||||
('mach_port_move_member', [
|
||||
('target', 'uint32_t'),
|
||||
('member', 'uint32_t'),
|
||||
('after', 'uint32_t'),
|
||||
], [], XNU_TRAP_CALL | XNU_TRAP_NOSUFFIX_ARGS),
|
||||
|
||||
('mach_port_insert_right', [
|
||||
('target', 'uint32_t'),
|
||||
('name', 'uint32_t'),
|
||||
('poly', 'uint32_t'),
|
||||
('polyPoly', 'int32_t'),
|
||||
], [], XNU_TRAP_CALL | XNU_TRAP_NOSUFFIX_ARGS),
|
||||
|
||||
('mach_port_insert_member', [
|
||||
('target', 'uint32_t'),
|
||||
('name', 'uint32_t'),
|
||||
('pset', 'uint32_t'),
|
||||
], [], XNU_TRAP_CALL | XNU_TRAP_NOSUFFIX_ARGS),
|
||||
|
||||
('mach_port_extract_member', [
|
||||
('target', 'uint32_t'),
|
||||
('name', 'uint32_t'),
|
||||
('pset', 'uint32_t'),
|
||||
], [], XNU_TRAP_CALL | XNU_TRAP_NOSUFFIX_ARGS),
|
||||
|
||||
('mach_port_construct', [
|
||||
('target', 'uint32_t'),
|
||||
('options', 'void*', 'uint64_t'),
|
||||
('context', 'uint64_t'),
|
||||
('name', 'uint32_t*', 'uint64_t'),
|
||||
], [], XNU_TRAP_CALL | XNU_TRAP_NOSUFFIX_ARGS),
|
||||
|
||||
('mach_port_destruct', [
|
||||
('target', 'uint32_t'),
|
||||
('name', 'uint32_t'),
|
||||
('srdelta', 'int32_t'),
|
||||
('guard', 'uint64_t'),
|
||||
], [], XNU_TRAP_CALL | XNU_TRAP_NOSUFFIX_ARGS),
|
||||
|
||||
('mach_port_guard', [
|
||||
('target', 'uint32_t'),
|
||||
('name', 'uint32_t'),
|
||||
('guard', 'uint64_t'),
|
||||
('strict', 'bool'),
|
||||
], [], XNU_TRAP_CALL | XNU_TRAP_NOSUFFIX_ARGS),
|
||||
|
||||
('mach_port_unguard', [
|
||||
('target', 'uint32_t'),
|
||||
('name', 'uint32_t'),
|
||||
('guard', 'uint64_t'),
|
||||
], [], XNU_TRAP_CALL | XNU_TRAP_NOSUFFIX_ARGS),
|
||||
|
||||
('mach_port_request_notification', [
|
||||
('target', 'uint32_t'),
|
||||
('name', 'uint32_t'),
|
||||
('msgid', 'int32_t'),
|
||||
('sync', 'uint32_t'),
|
||||
('notify', 'uint32_t'),
|
||||
('notifyPoly', 'uint32_t'),
|
||||
('previous', 'uint32_t*', 'uint64_t'),
|
||||
], [], XNU_TRAP_CALL | XNU_TRAP_NOSUFFIX_ARGS),
|
||||
|
||||
('mach_port_get_attributes', [
|
||||
('target', 'uint32_t'),
|
||||
('name', 'uint32_t'),
|
||||
('flavor', 'int32_t'),
|
||||
('info', 'void*', 'uint64_t'),
|
||||
('count', 'uint32_t*', 'uint64_t'),
|
||||
], [], XNU_TRAP_CALL | XNU_TRAP_NOSUFFIX_ARGS),
|
||||
|
||||
('mach_port_type', [
|
||||
('target', 'uint32_t'),
|
||||
('name', 'uint32_t'),
|
||||
('ptype', 'uint32_t*', 'uint64_t'),
|
||||
], [], XNU_TRAP_CALL | XNU_TRAP_NOSUFFIX_ARGS),
|
||||
|
||||
('task_for_pid', [
|
||||
('target_tport', 'uint32_t'),
|
||||
('pid', 'int32_t'),
|
||||
('t', 'uint32_t*', 'uint64_t'),
|
||||
], [], XNU_TRAP_CALL | XNU_TRAP_NOPREFIX | XNU_TRAP_NOSUFFIX),
|
||||
|
||||
('task_name_for_pid', [
|
||||
('target_tport', 'uint32_t'),
|
||||
('pid', 'int32_t'),
|
||||
('t', 'uint32_t*', 'uint64_t'),
|
||||
], [], XNU_TRAP_CALL | XNU_TRAP_NOPREFIX | XNU_TRAP_NOSUFFIX),
|
||||
|
||||
('pid_for_task', [
|
||||
('t', 'uint32_t'),
|
||||
('pid', 'int32_t*', 'uint64_t'),
|
||||
], [], XNU_TRAP_CALL | XNU_TRAP_NOPREFIX | XNU_TRAP_NOSUFFIX),
|
||||
|
||||
#
|
||||
# Mach VM traps
|
||||
#
|
||||
|
||||
('mach_vm_allocate', [
|
||||
('target', 'uint32_t'),
|
||||
('addr', 'uint64_t*', 'uint64_t'),
|
||||
('size', 'uint64_t'),
|
||||
('flags', 'int32_t'),
|
||||
], [], XNU_TRAP_CALL),
|
||||
|
||||
('mach_vm_deallocate', [
|
||||
('target', 'uint32_t'),
|
||||
('address', 'uint64_t'),
|
||||
('size', 'uint64_t'),
|
||||
], [], XNU_TRAP_CALL | XNU_TRAP_NOSUFFIX_ARGS),
|
||||
|
||||
#
|
||||
# Mach semaphore traps
|
||||
#
|
||||
|
||||
('semaphore_signal', [
|
||||
('signal_name', 'uint32_t'),
|
||||
], [], XNU_TRAP_CALL | XNU_TRAP_NOPREFIX),
|
||||
|
||||
('semaphore_signal_all', [
|
||||
('signal_name', 'uint32_t'),
|
||||
], [], XNU_TRAP_CALL | XNU_TRAP_NOPREFIX),
|
||||
|
||||
('semaphore_wait', [
|
||||
('wait_name', 'uint32_t'),
|
||||
], [], XNU_TRAP_CALL | XNU_TRAP_NOPREFIX),
|
||||
|
||||
('semaphore_wait_signal', [
|
||||
('wait_name', 'uint32_t'),
|
||||
('signal_name', 'uint32_t'),
|
||||
], [], XNU_TRAP_CALL | XNU_TRAP_NOPREFIX),
|
||||
|
||||
('semaphore_timedwait', [
|
||||
('wait_name', 'uint32_t'),
|
||||
('sec', 'uint32_t'),
|
||||
('nsec', 'uint32_t'),
|
||||
], [], XNU_TRAP_CALL | XNU_TRAP_NOPREFIX),
|
||||
|
||||
('semaphore_timedwait_signal', [
|
||||
('wait_name', 'uint32_t'),
|
||||
('signal_name', 'uint32_t'),
|
||||
('sec', 'uint32_t'),
|
||||
('nsec', 'uint32_t'),
|
||||
], [], XNU_TRAP_CALL | XNU_TRAP_NOPREFIX),
|
||||
|
||||
#
|
||||
# mk_timer traps
|
||||
#
|
||||
|
||||
('mk_timer_create', [], [
|
||||
('port_name', 'uint32_t'),
|
||||
]),
|
||||
|
||||
('mk_timer_destroy', [
|
||||
('name', 'uint32_t'),
|
||||
], [], XNU_TRAP_CALL | XNU_TRAP_NOPREFIX),
|
||||
|
||||
('mk_timer_arm', [
|
||||
('name', 'uint32_t'),
|
||||
('expire_time', 'uint64_t'),
|
||||
], [], XNU_TRAP_CALL | XNU_TRAP_NOPREFIX),
|
||||
|
||||
('mk_timer_cancel', [
|
||||
('name', 'uint32_t'),
|
||||
('result_time', 'uint64_t*', 'uint64_t'),
|
||||
], [], XNU_TRAP_CALL | XNU_TRAP_NOPREFIX),
|
||||
]
|
||||
|
||||
def parse_type(param_tuple, is_public):
|
||||
@ -411,6 +632,112 @@ for call in calls:
|
||||
internal_header.write("\t}; \\\n")
|
||||
internal_header.write("\n")
|
||||
|
||||
internal_header.write("#define DSERVER_CLASS_SOURCE_DEFS \\\n")
|
||||
for call in calls:
|
||||
call_name = call[0]
|
||||
call_parameters = call[1]
|
||||
reply_parameters = call[2]
|
||||
flags = call[3] if len(call) >= 4 else 0
|
||||
camel_name = to_camel_case(call_name)
|
||||
|
||||
if (flags & XNU_TRAP_CALL) == 0:
|
||||
continue
|
||||
|
||||
# XNU traps return values by writing directly to the calling process's memory at the addresses given as regular call parameters
|
||||
if len(reply_parameters) > 0:
|
||||
raise RuntimeError("Call marked as an XNU trap has reply parameters")
|
||||
|
||||
internal_header.write("\tvoid DarlingServer::Call::{0}::processCall() {{ \\\n".format(camel_name))
|
||||
internal_header.write("\t\t_sendReply(dtape_{0}(".format(call_name))
|
||||
|
||||
is_first = True
|
||||
for param in call_parameters:
|
||||
param_name = param[0]
|
||||
|
||||
if is_first:
|
||||
is_first = False
|
||||
else:
|
||||
internal_header.write(", ")
|
||||
|
||||
internal_header.write("_body.{0}".format(param_name))
|
||||
|
||||
internal_header.write(")); \\\n")
|
||||
internal_header.write("\t}; \\\n")
|
||||
internal_header.write("\n")
|
||||
|
||||
internal_header.write("#define DSERVER_DTAPE_DECLS \\\n")
|
||||
for call in calls:
|
||||
call_name = call[0]
|
||||
call_parameters = call[1]
|
||||
flags = call[3] if len(call) >= 4 else 0
|
||||
camel_name = to_camel_case(call_name)
|
||||
|
||||
if (flags & XNU_TRAP_CALL) == 0:
|
||||
continue
|
||||
|
||||
internal_header.write("\tint dtape_{0}(".format(call_name))
|
||||
|
||||
is_first = True
|
||||
for param in call_parameters:
|
||||
param_name = param[0]
|
||||
|
||||
if is_first:
|
||||
is_first = False
|
||||
else:
|
||||
internal_header.write(", ")
|
||||
|
||||
internal_header.write("{0} {1}".format(parse_type(param, False), param_name))
|
||||
|
||||
internal_header.write("); \\\n")
|
||||
internal_header.write("\n")
|
||||
|
||||
internal_header.write("#define DSERVER_DTAPE_DEFS \\\n")
|
||||
for call in calls:
|
||||
call_name = call[0]
|
||||
call_parameters = call[1]
|
||||
flags = call[3] if len(call) >= 4 else 0
|
||||
camel_name = to_camel_case(call_name)
|
||||
|
||||
if (flags & XNU_TRAP_CALL) == 0:
|
||||
continue
|
||||
|
||||
trap_name = call_name
|
||||
if (flags & XNU_TRAP_NOPREFIX) == 0:
|
||||
trap_name = "_kernelrpc_" + trap_name
|
||||
if (flags & XNU_TRAP_NOSUFFIX) == 0:
|
||||
trap_name = trap_name + "_trap"
|
||||
|
||||
trap_args_name = call_name
|
||||
if (flags & XNU_TRAP_NOPREFIX) == 0:
|
||||
trap_args_name = "_kernelrpc_" + trap_args_name
|
||||
if (flags & (XNU_TRAP_NOSUFFIX | XNU_TRAP_NOSUFFIX_ARGS)) == 0:
|
||||
trap_args_name = trap_args_name + "_trap"
|
||||
|
||||
internal_header.write("\tint dtape_{0}(".format(call_name))
|
||||
|
||||
is_first = True
|
||||
for param in call_parameters:
|
||||
param_name = param[0]
|
||||
|
||||
if is_first:
|
||||
is_first = False
|
||||
else:
|
||||
internal_header.write(", ")
|
||||
|
||||
internal_header.write("{0} {1}".format(parse_type(param, False), param_name))
|
||||
|
||||
internal_header.write(") { \\\n")
|
||||
internal_header.write("\t\tstruct {0}_args args = {{ \\\n".format(trap_args_name))
|
||||
|
||||
for param in call_parameters:
|
||||
param_name = param[0]
|
||||
internal_header.write("\t\t\t.{0} = {0}, \\\n".format(param_name))
|
||||
|
||||
internal_header.write("\t\t}; \\\n")
|
||||
internal_header.write("\t\treturn {0}(&args); \\\n".format(trap_name))
|
||||
internal_header.write("\t}; \\\n")
|
||||
internal_header.write("\n")
|
||||
|
||||
for call in calls:
|
||||
call_name = call[0]
|
||||
call_parameters = call[1]
|
||||
|
59
src/call.cpp
59
src/call.cpp
@ -26,6 +26,7 @@
|
||||
#include <darlingserver/duct-tape.h>
|
||||
#include <darlingserver/config.hpp>
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
static DarlingServer::Log callLog("calls");
|
||||
|
||||
@ -373,14 +374,6 @@ void DarlingServer::Call::GetTracer::processCall() {
|
||||
_sendReply(code, tracer);
|
||||
};
|
||||
|
||||
void DarlingServer::Call::MachMsgOverwrite::processCall() {
|
||||
_sendReply(dtape_mach_msg_overwrite(_body.msg, _body.option, _body.send_size, _body.rcv_size, _body.rcv_name, _body.timeout, _body.notify, _body.rcv_msg, _body.rcv_limit));
|
||||
};
|
||||
|
||||
void DarlingServer::Call::MachPortDeallocate::processCall() {
|
||||
_sendReply(dtape_mach_port_deallocate(_body.task_right_name, _body.port_right_name));
|
||||
};
|
||||
|
||||
void DarlingServer::Call::Uidgid::processCall() {
|
||||
int code = 0;
|
||||
int uid = -1;
|
||||
@ -461,3 +454,53 @@ void DarlingServer::Call::MldrPath::processCall() {
|
||||
|
||||
_sendReply(code, fullLength);
|
||||
};
|
||||
|
||||
void DarlingServer::Call::ThreadGetSpecialReplyPort::processCall() {
|
||||
_sendReply(0, dtape_thread_get_special_reply_port());
|
||||
};
|
||||
|
||||
void DarlingServer::Call::MkTimerCreate::processCall() {
|
||||
_sendReply(0, dtape_mk_timer_create());
|
||||
};
|
||||
|
||||
void DarlingServer::Call::PthreadKill::processCall() {
|
||||
int code = 0;
|
||||
|
||||
if (auto targetThread = Thread::threadForPort(_body.thread_port)) {
|
||||
if (auto targetProcess = targetThread->process()) {
|
||||
if (syscall(SYS_tgkill, targetProcess->id(), targetThread->id(), _body.signal) < 0) {
|
||||
code = -errno;
|
||||
}
|
||||
} else {
|
||||
code = -ESRCH;
|
||||
}
|
||||
} else {
|
||||
code = -ESRCH;
|
||||
}
|
||||
|
||||
_sendReply(code);
|
||||
};
|
||||
|
||||
void DarlingServer::Call::PthreadCanceled::processCall() {
|
||||
int code = 0;
|
||||
|
||||
callLog.error() << "TODO: " << __PRETTY_FUNCTION__ << callLog.endLog;
|
||||
code = -ENOSYS;
|
||||
|
||||
_sendReply(code);
|
||||
};
|
||||
|
||||
void DarlingServer::Call::PthreadMarkcancel::processCall() {
|
||||
int code = 0;
|
||||
|
||||
if (auto targetThread = Thread::threadForPort(_body.thread_port)) {
|
||||
callLog.error() << "TODO: " << __PRETTY_FUNCTION__ << callLog.endLog;
|
||||
code = -ENOSYS;
|
||||
} else {
|
||||
code = -ESRCH;
|
||||
}
|
||||
|
||||
_sendReply(code);
|
||||
};
|
||||
|
||||
DSERVER_CLASS_SOURCE_DEFS;
|
||||
|
@ -77,6 +77,8 @@ DarlingServer::Process::Process(ID id, NSID nsid):
|
||||
|
||||
// NOTE: see thread.cpp for why it's okay to use `this` here
|
||||
_dtapeTask = dtape_task_create(parentProcess ? parentProcess->_dtapeTask : nullptr, _nspid, this);
|
||||
|
||||
processLog.info() << "New process created with ID " << _pid << " and NSID " << _nspid;
|
||||
};
|
||||
|
||||
DarlingServer::Process::Process(KernelProcessConstructorTag tag):
|
||||
|
@ -49,6 +49,8 @@ static thread_local libsimple_lock_t* unlockMeWhenSuspending = nullptr;
|
||||
*/
|
||||
static thread_local uint64_t interruptDisableCount = 0;
|
||||
|
||||
static DarlingServer::Log threadLog("thread");
|
||||
|
||||
DarlingServer::Thread::Thread(std::shared_ptr<Process> process, NSID nsid):
|
||||
_nstid(nsid),
|
||||
_process(process)
|
||||
@ -96,6 +98,8 @@ DarlingServer::Thread::Thread(std::shared_ptr<Process> process, NSID nsid):
|
||||
|
||||
// NOTE: it's okay to use raw `this` without a shared pointer because the duct-taped thread will always live for less time than this Thread instance
|
||||
_dtapeThread = dtape_thread_create(process->_dtapeTask, _nstid, this);
|
||||
|
||||
threadLog.info() << "New thread created with ID " << _tid << " and NSID " << _nstid << " for process with ID " << (process ? process->id() : -1) << " and NSID " << (process ? process->nsid() : -1);
|
||||
};
|
||||
|
||||
DarlingServer::Thread::Thread(KernelThreadConstructorTag tag):
|
||||
@ -448,3 +452,20 @@ void DarlingServer::Thread::_kernelAsync(std::function<void()> fn) {
|
||||
runnerThread->resume(); // resume the runner (it's most likely suspended waiting for work)
|
||||
libsimple_lock_unlock(&kernelAsyncRunnerQueueLock);
|
||||
};
|
||||
|
||||
std::shared_ptr<DarlingServer::Thread> DarlingServer::Thread::threadForPort(uint32_t thread_port) {
|
||||
// prevent the target thread from dying by taking the global thread registry lock
|
||||
auto registryLock = threadRegistry().scopedLock();
|
||||
|
||||
dtape_thread_handle_t thread_handle = dtape_thread_for_port(thread_port);
|
||||
if (!thread_handle) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Thread* thread = static_cast<Thread*>(dtape_thread_context(thread_handle));
|
||||
if (!thread) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return thread->shared_from_this();
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user