summaryrefslogtreecommitdiffhomepage
path: root/src/process
diff options
context:
space:
mode:
Diffstat (limited to 'src/process')
-rw-r--r--src/process/ntapi_tt_spawn_native_process.c319
1 files changed, 319 insertions, 0 deletions
diff --git a/src/process/ntapi_tt_spawn_native_process.c b/src/process/ntapi_tt_spawn_native_process.c
new file mode 100644
index 0000000..f072426
--- /dev/null
+++ b/src/process/ntapi_tt_spawn_native_process.c
@@ -0,0 +1,319 @@
+/********************************************************/
+/* ntapi: Native API core library */
+/* Copyright (C) 2013--2016 Z. Gilboa */
+/* Released under GPLv2 and GPLv3; see COPYING.NTAPI. */
+/********************************************************/
+
+#include <psxtypes/psxtypes.h>
+#include <pemagine/pemagine.h>
+#include <ntapi/nt_status.h>
+#include <ntapi/nt_object.h>
+#include <ntapi/nt_thread.h>
+#include <ntapi/nt_process.h>
+#include <ntapi/nt_string.h>
+#include <ntapi/ntapi.h>
+#include "ntapi_impl.h"
+
+static int32_t __stdcall __tt_spawn_return(
+ nt_runtime_data_block * rtblock,
+ void * hprocess,
+ void * hthread,
+ int32_t status)
+{
+ nt_runtime_data * rtdata;
+
+ rtdata = (nt_runtime_data *)rtblock->addr;
+
+ if (hprocess) {
+ __ntapi->zw_terminate_process(
+ hprocess,status);
+
+ __ntapi->zw_close(hprocess);
+ __ntapi->zw_close(hthread);
+ }
+
+ if (rtdata->hready)
+ __ntapi->zw_close(
+ rtdata->hready);
+
+ __ntapi->zw_free_virtual_memory(
+ NT_CURRENT_PROCESS_HANDLE,
+ &rtblock->addr,
+ &rtblock->size,
+ NT_MEM_RELEASE);
+
+ return status;
+}
+
+int32_t __stdcall __ntapi_tt_spawn_native_process(nt_spawn_process_params * sparams)
+{
+ int32_t status;
+ nt_create_process_params cparams;
+ nt_tty_session_info session;
+ nt_runtime_data_block rtblock;
+ nt_runtime_data_block crtblock;
+ nt_runtime_data * rtctx;
+ nt_runtime_data * rdata;
+ nt_unicode_string * imgname;
+ nt_peb * peb;
+ char * patharg;
+ void * hat;
+ void * hfile;
+ char ** parg;
+ char ** rargv;
+ char ** renvp;
+ wchar16_t ** pwarg;
+ wchar16_t * wch;
+ void * hchild[2];
+ uint32_t written;
+ wchar16_t * imgbuf;
+
+ /* rtctx (convenience) */
+ rtctx = sparams->rtctx;
+
+ /* validation */
+ if (!sparams->himage && !sparams->patharg)
+ return NT_STATUS_OBJECT_PATH_INVALID;
+
+ if (rtctx->argc || rtctx->argv || rtctx->envc || rtctx->envp)
+ return NT_STATUS_INVALID_PARAMETER;
+
+ if (rtctx->hready || rtctx->hsession)
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+
+ if (!(peb = (nt_peb *)pe_get_peb_address()))
+ return NT_STATUS_INTERNAL_ERROR;
+
+ if (!peb->process_params)
+ return NT_STATUS_INTERNAL_ERROR;
+
+ /* hat */
+ hat = (rtctx->hroot && (sparams->argv[0][0] == '/'))
+ ? rtctx->hroot
+ : rtctx->hcwd
+ ? rtctx->hcwd
+ : peb->process_params->cwd_handle;
+
+ /* patharg */
+ patharg = (sparams->patharg[0] == '/')
+ ? (sparams->patharg[1] == '?')
+ ? &sparams->patharg[0]
+ : &sparams->patharg[1]
+ : &sparams->patharg[0];
+
+ /* rtblock, rdata */
+ rtblock.addr = 0;
+ rtblock.size = 0x20000;
+ rtblock.remote_addr = 0;
+ rtblock.remote_size = 0;
+ rtblock.flags = 0;
+
+ if ((status = __ntapi->zw_allocate_virtual_memory(
+ NT_CURRENT_PROCESS_HANDLE,
+ &rtblock.addr,0,
+ &rtblock.size,
+ NT_MEM_COMMIT,
+ NT_PAGE_READWRITE)))
+ return status;
+
+ __ntapi->tt_aligned_block_memset(
+ rtblock.addr,0,rtblock.size);
+
+ __ntapi->tt_aligned_block_memcpy(
+ (uintptr_t *)(rdata = (nt_runtime_data *)rtblock.addr),
+ (const uintptr_t *)rtctx,
+ sizeof(*rtctx));
+
+ /* imgbuf */
+ imgbuf = (wchar16_t *)rtblock.addr;
+ imgbuf += 0x10000 / sizeof(*imgbuf);
+
+ /* hfile */
+ if (sparams->himage)
+ hfile = sparams->himage;
+ else if ((status = __ntapi_tt_open_file_utf8(
+ &hfile,hat,patharg,1,
+ imgbuf,0x2000)))
+ return status;
+
+ /* imgname */
+ if ((status = __ntapi->zw_query_object(
+ hfile,
+ NT_OBJECT_NAME_INFORMATION,
+ imgbuf,0x10000,&written)))
+ return __tt_spawn_return(
+ &rtblock,0,0,status);
+
+ imgname = (nt_unicode_string *)imgbuf;
+
+ /* argv, envp */
+ if ((status = __ntapi->tt_array_copy_utf8(
+ &rdata->argc,
+ (const char **)sparams->argv,
+ (const char **)sparams->envp,
+ sparams->image,
+ sparams->interpreter,
+ sparams->optarg,
+ rtblock.addr,
+ rdata->buffer,
+ rtblock.size - sizeof(*rdata),
+ &rtblock.remote_size)))
+ return __tt_spawn_return(
+ &rtblock,0,0,status);
+
+ rdata->argv = (char **)&((nt_runtime_data *)0)->buffer;
+ rdata->envp = rdata->argv + rdata->argc + 1;
+
+ rdata->wargv = (wchar16_t **)(rdata->buffer + (rtblock.remote_size / sizeof(uintptr_t)) + 1);
+ rdata->wenvp = rdata->wargv + rdata->argc + 1;
+
+ rargv = rdata->argv + ((uintptr_t)rtblock.addr / sizeof(char *));
+ renvp = rdata->envp + ((uintptr_t)rtblock.addr / sizeof(char *));
+
+ for (rdata->envc=0, parg=sparams->envp; *parg; parg++)
+ rdata->envc++;
+
+ pwarg = rdata->wenvp + rdata->envc + 1;
+ wch = (wchar16_t *)pwarg;
+
+ if ((status = __ntapi->tt_array_convert_utf8_to_utf16(
+ rargv,
+ rdata->wargv,
+ rdata,
+ wch,
+ rtblock.size - sizeof(wchar16_t)*(wch-(wchar16_t *)rdata->buffer),
+ &rtblock.remote_size)))
+ return __tt_spawn_return(
+ &rtblock,0,0,status);
+
+ wch += rtblock.remote_size/sizeof(wchar16_t);
+
+ if ((status = __ntapi->tt_array_convert_utf8_to_utf16(
+ renvp,
+ rdata->wenvp,
+ rdata,
+ wch,
+ rtblock.size - sizeof(wchar16_t)*(wch-(wchar16_t *)rdata->buffer),
+ &rtblock.remote_size)))
+ return __tt_spawn_return(
+ &rtblock,0,0,status);
+
+ rdata->wargv -= (uintptr_t)rtblock.addr / sizeof(wchar16_t *);
+ rdata->wenvp -= (uintptr_t)rtblock.addr / sizeof(wchar16_t *);
+
+ /* session */
+ if (sparams->hready) {
+ if ((status = __ntapi->zw_duplicate_object(
+ NT_CURRENT_PROCESS_HANDLE,
+ sparams->hready,
+ NT_CURRENT_PROCESS_HANDLE,
+ &rdata->hready,
+ 0,0,
+ NT_DUPLICATE_SAME_ACCESS|NT_DUPLICATE_SAME_ATTRIBUTES)))
+ return __tt_spawn_return(
+ &rtblock,0,0,status);
+ } else {
+ if ((status = __ntapi->tt_create_inheritable_event(
+ &rdata->hready,
+ NT_NOTIFICATION_EVENT,
+ NT_EVENT_NOT_SIGNALED)))
+ return __tt_spawn_return(
+ &rtblock,0,0,status);
+ }
+
+ /* cparams */
+ __ntapi->tt_aligned_block_memset(
+ &cparams,0,sizeof(cparams));
+
+ __ntapi->tt_generic_memcpy(
+ &crtblock,&rtblock,sizeof(rtblock));
+
+ cparams.image_name = imgname->buffer;
+ cparams.creation_flags_process = NT_PROCESS_CREATE_FLAGS_INHERIT_HANDLES;
+ cparams.creation_flags_thread = NT_PROCESS_CREATE_FLAGS_CREATE_THREAD_SUSPENDED;
+
+ crtblock.size = 0x10000;
+ cparams.rtblock = &crtblock;
+
+ /* hoppla */
+ if ((status = __ntapi->tt_create_native_process(&cparams)))
+ return __tt_spawn_return(
+ &rtblock,0,0,status);
+
+ /* tty session (optional) */
+ if (sparams->hsession) {
+ if ((status = __ntapi->tty_client_process_register(
+ sparams->hsession,
+ cparams.pbi.unique_process_id,
+ 0,NT_TTY_INHERIT_HANDLES,0)))
+ return __tt_spawn_return(
+ &rtblock,
+ cparams.hprocess,
+ cparams.hthread,
+ status);
+
+ session.pid = rtctx->alt_cid_self.pid;
+ session.pgid = rtctx->alt_cid_self.pgid;
+ session.sid = rtctx->alt_cid_self.sid;
+ session.syspid = cparams.pbi.unique_process_id;
+
+ if ((status = __ntapi->tty_client_session_set(0,&session)))
+ return __tt_spawn_return(
+ &rtblock,
+ cparams.hprocess,
+ cparams.hthread,
+ status);
+ }
+
+ /* output */
+ sparams->hprocess = cparams.hprocess;
+ sparams->hthread = cparams.hthread;
+ sparams->rdata = crtblock.remote_addr;
+
+ sparams->cid.process_id = cparams.pbi.unique_process_id;
+ sparams->cid.thread_id = cparams.cid.thread_id;
+
+ __ntapi->tt_generic_memcpy(
+ &sparams->pbi,
+ &cparams.pbi,
+ sizeof(nt_pbi));
+
+ /* create suspended? */
+ if (sparams->fsuspended)
+ return __tt_spawn_return(
+ &rtblock,0,0,NT_STATUS_SUCCESS);
+
+ /* tada */
+ if ((status = __ntapi->zw_resume_thread(cparams.hthread,0)))
+ return __tt_spawn_return(
+ &rtblock,
+ cparams.hprocess,
+ cparams.hthread,
+ status);
+
+ /* hready */
+ hchild[1] = cparams.hprocess;
+ hchild[0] = rdata->hready;
+
+ __ntapi->zw_wait_for_multiple_objects(
+ 2,hchild,
+ NT_WAIT_ANY,
+ NT_SYNC_NON_ALERTABLE,
+ sparams->timeout);
+
+ if ((status = __ntapi->zw_query_event(
+ rdata->hready,
+ NT_EVENT_BASIC_INFORMATION,
+ &sparams->eready,
+ sizeof(sparams->eready),
+ &(size_t){0})))
+ return __tt_spawn_return(
+ &rtblock,
+ cparams.hprocess,
+ cparams.hthread,
+ status);
+
+ /* all done */
+ return __tt_spawn_return(
+ &rtblock,0,0,NT_STATUS_SUCCESS);
+}