Redesign of the server communication protocol to allow arbitrary sized
data to be exchanged.
Split request and reply structures to make backwards compatibility
easier.
Moved many console functions to dlls/kernel, added code page support,
changed a few requests to behave properly with the new protocol.
diff --git a/server/process.c b/server/process.c
index f02f5b7..5a5241d 100644
--- a/server/process.c
+++ b/server/process.c
@@ -98,7 +98,7 @@
/* set the console and stdio handles for a newly created process */
static int set_process_console( struct process *process, struct process *parent,
- struct startup_info *info, struct init_process_request *req )
+ struct startup_info *info, struct init_process_reply *reply )
{
if (process->create_flags & CREATE_NEW_CONSOLE)
{
@@ -120,35 +120,35 @@
if (!info->inherit_all && !(info->start_flags & STARTF_USESTDHANDLES))
{
/* duplicate the handle from the parent into this process */
- req->hstdin = duplicate_handle( parent, info->hstdin, process,
- 0, TRUE, DUPLICATE_SAME_ACCESS );
- req->hstdout = duplicate_handle( parent, info->hstdout, process,
- 0, TRUE, DUPLICATE_SAME_ACCESS );
- req->hstderr = duplicate_handle( parent, info->hstderr, process,
- 0, TRUE, DUPLICATE_SAME_ACCESS );
+ reply->hstdin = duplicate_handle( parent, info->hstdin, process,
+ 0, TRUE, DUPLICATE_SAME_ACCESS );
+ reply->hstdout = duplicate_handle( parent, info->hstdout, process,
+ 0, TRUE, DUPLICATE_SAME_ACCESS );
+ reply->hstderr = duplicate_handle( parent, info->hstderr, process,
+ 0, TRUE, DUPLICATE_SAME_ACCESS );
}
else
{
- req->hstdin = info->hstdin;
- req->hstdout = info->hstdout;
- req->hstderr = info->hstderr;
+ reply->hstdin = info->hstdin;
+ reply->hstdout = info->hstdout;
+ reply->hstderr = info->hstderr;
}
}
else
{
if (process->console)
{
- req->hstdin = alloc_handle( process, process->console,
- GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, 1 );
- req->hstdout = alloc_handle( process, process->console->active,
- GENERIC_READ | GENERIC_WRITE, 1 );
- req->hstderr = alloc_handle( process, process->console->active,
- GENERIC_READ | GENERIC_WRITE, 1 );
+ reply->hstdin = alloc_handle( process, process->console,
+ GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, 1 );
+ reply->hstdout = alloc_handle( process, process->console->active,
+ GENERIC_READ | GENERIC_WRITE, 1 );
+ reply->hstderr = alloc_handle( process, process->console->active,
+ GENERIC_READ | GENERIC_WRITE, 1 );
}
else
{
/* no parent, let the caller decide what to do */
- req->hstdin = req->hstdout = req->hstderr = 0;
+ reply->hstdin = reply->hstdout = reply->hstderr = 0;
}
}
/* some handles above may have been invalid; this is not an error */
@@ -216,7 +216,7 @@
}
/* initialize the current process and fill in the request */
-static void init_process( int ppid, struct init_process_request *req )
+static void init_process( int ppid, struct init_process_reply *reply )
{
struct process *process = current->process;
struct thread *parent_thread = get_thread_from_pid( ppid );
@@ -251,16 +251,16 @@
if (!process->handles) return;
/* retrieve the main exe file */
- req->exe_file = 0;
+ reply->exe_file = 0;
if (parent && info->exe_file)
{
process->exe.file = (struct file *)grab_object( info->exe_file );
- if (!(req->exe_file = alloc_handle( process, process->exe.file, GENERIC_READ, 0 )))
+ if (!(reply->exe_file = alloc_handle( process, process->exe.file, GENERIC_READ, 0 )))
return;
}
/* set the process console */
- if (!set_process_console( process, parent, info, req )) return;
+ if (!set_process_console( process, parent, info, reply )) return;
if (parent)
{
@@ -277,23 +277,21 @@
if (info)
{
size_t size = strlen(info->filename);
- if (size > get_req_data_size(req)) size = get_req_data_size(req);
- req->start_flags = info->start_flags;
- req->cmd_show = info->cmd_show;
- memcpy( get_req_data(req), info->filename, size );
- set_req_data_size( req, size );
+ if (size > get_reply_max_size()) size = get_reply_max_size();
+ reply->start_flags = info->start_flags;
+ reply->cmd_show = info->cmd_show;
+ set_reply_data( info->filename, size );
info->process = (struct process *)grab_object( process );
info->thread = (struct thread *)grab_object( current );
wake_up( &info->obj, 0 );
}
else
{
- req->start_flags = STARTF_USESTDHANDLES;
- req->cmd_show = 0;
- set_req_data_size( req, 0 );
+ reply->start_flags = STARTF_USESTDHANDLES;
+ reply->cmd_show = 0;
}
- req->create_flags = process->create_flags;
- req->server_start = server_start_ticks;
+ reply->create_flags = process->create_flags;
+ reply->server_start = server_start_ticks;
}
/* destroy a process when its refcount is 0 */
@@ -577,19 +575,19 @@
/* get all information about a process */
-static void get_process_info( struct process *process, struct get_process_info_request *req )
+static void get_process_info( struct process *process, struct get_process_info_reply *reply )
{
- req->pid = process;
- req->debugged = (process->debugger != 0);
- req->exit_code = process->exit_code;
- req->priority = process->priority;
- req->process_affinity = process->affinity;
- req->system_affinity = 1;
+ reply->pid = process;
+ reply->debugged = (process->debugger != 0);
+ reply->exit_code = process->exit_code;
+ reply->priority = process->priority;
+ reply->process_affinity = process->affinity;
+ reply->system_affinity = 1;
}
/* set all information about a process */
static void set_process_info( struct process *process,
- struct set_process_info_request *req )
+ const struct set_process_info_request *req )
{
if (req->mask & SET_PROCESS_INFO_PRIORITY)
process->priority = req->priority;
@@ -601,62 +599,56 @@
}
/* read data from a process memory space */
-/* len is the total size (in ints), max is the size we can actually store in the output buffer */
-/* we read the total size in all cases to check for permissions */
-static void read_process_memory( struct process *process, const int *addr,
- size_t len, size_t max, int *dest )
+/* len is the total size (in ints) */
+static int read_process_memory( struct process *process, const int *addr, size_t len, int *dest )
{
struct thread *thread = process->thread_list;
- if ((unsigned int)addr % sizeof(int)) /* address must be aligned */
- {
- set_error( STATUS_INVALID_PARAMETER );
- return;
- }
+ assert( !((unsigned int)addr % sizeof(int)) ); /* address must be aligned */
+
if (!thread) /* process is dead */
{
set_error( STATUS_ACCESS_DENIED );
- return;
+ return 0;
}
if (suspend_for_ptrace( thread ))
{
- while (len > 0 && max)
+ while (len > 0)
{
- if (read_thread_int( thread, addr++, dest++ ) == -1) goto done;
- max--;
+ if (read_thread_int( thread, addr++, dest++ ) == -1) break;
len--;
}
- /* check the rest for read permission */
- if (len > 0)
- {
- int dummy, page = get_page_size() / sizeof(int);
- while (len >= page)
- {
- addr += page;
- len -= page;
- if (read_thread_int( thread, addr - 1, &dummy ) == -1) goto done;
- }
- if (len && (read_thread_int( thread, addr + len - 1, &dummy ) == -1)) goto done;
- }
- done:
resume_thread( thread );
}
+ return !len;
+}
+
+/* make sure we can write to the whole address range */
+/* len is the total size (in ints) */
+static int check_process_write_access( struct thread *thread, int *addr, size_t len )
+{
+ int page = get_page_size() / sizeof(int);
+
+ for (;;)
+ {
+ if (write_thread_int( thread, addr, 0, 0 ) == -1) return 0;
+ if (len <= page) break;
+ addr += page;
+ len -= page;
+ }
+ return (write_thread_int( thread, addr + len - 1, 0, 0 ) != -1);
}
/* write data to a process memory space */
/* len is the total size (in ints), max is the size we can actually read from the input buffer */
/* we check the total size for write permissions */
static void write_process_memory( struct process *process, int *addr, size_t len,
- size_t max, unsigned int first_mask,
- unsigned int last_mask, const int *src )
+ unsigned int first_mask, unsigned int last_mask, const int *src )
{
struct thread *thread = process->thread_list;
- if (!len || ((unsigned int)addr % sizeof(int))) /* address must be aligned */
- {
- set_error( STATUS_INVALID_PARAMETER );
- return;
- }
+ assert( !((unsigned int)addr % sizeof(int) )); /* address must be aligned */
+
if (!thread) /* process is dead */
{
set_error( STATUS_ACCESS_DENIED );
@@ -664,39 +656,28 @@
}
if (suspend_for_ptrace( thread ))
{
+ if (!check_process_write_access( thread, addr, len ))
+ {
+ set_error( STATUS_ACCESS_DENIED );
+ return;
+ }
/* first word is special */
if (len > 1)
{
if (write_thread_int( thread, addr++, *src++, first_mask ) == -1) goto done;
len--;
- max--;
}
else last_mask &= first_mask;
- while (len > 1 && max)
+ while (len > 1)
{
if (write_thread_int( thread, addr++, *src++, ~0 ) == -1) goto done;
- max--;
len--;
}
- if (max)
- {
- /* last word is special too */
- if (write_thread_int( thread, addr, *src, last_mask ) == -1) goto done;
- }
- else
- {
- /* check the rest for write permission */
- int page = get_page_size() / sizeof(int);
- while (len >= page)
- {
- addr += page;
- len -= page;
- if (write_thread_int( thread, addr - 1, 0, 0 ) == -1) goto done;
- }
- if (len && (write_thread_int( thread, addr + len - 1, 0, 0 ) == -1)) goto done;
- }
+ /* last word is special too */
+ if (write_thread_int( thread, addr, *src, last_mask ) == -1) goto done;
+
done:
resume_thread( thread );
}
@@ -747,7 +728,7 @@
/* create a new process */
DECL_HANDLER(new_process)
{
- size_t len = get_req_data_size( req );
+ size_t len = get_req_data_size();
struct startup_info *info;
if (current->info)
@@ -777,10 +758,10 @@
if (!(info->filename = mem_alloc( len + 1 ))) goto done;
- memcpy( info->filename, get_req_data(req), len );
+ memcpy( info->filename, get_req_data(), len );
info->filename[len] = 0;
current->info = info;
- req->info = alloc_handle( current->process, info, SYNCHRONIZE, FALSE );
+ reply->info = alloc_handle( current->process, info, SYNCHRONIZE, FALSE );
done:
release_object( info );
@@ -791,28 +772,28 @@
{
struct startup_info *info;
- req->event = 0;
+ reply->event = 0;
if ((info = (struct startup_info *)get_handle_obj( current->process, req->info,
0, &startup_info_ops )))
{
- req->pid = get_process_id( info->process );
- req->tid = get_thread_id( info->thread );
- req->phandle = alloc_handle( current->process, info->process,
- PROCESS_ALL_ACCESS, req->pinherit );
- req->thandle = alloc_handle( current->process, info->thread,
- THREAD_ALL_ACCESS, req->tinherit );
+ reply->pid = get_process_id( info->process );
+ reply->tid = get_thread_id( info->thread );
+ reply->phandle = alloc_handle( current->process, info->process,
+ PROCESS_ALL_ACCESS, req->pinherit );
+ reply->thandle = alloc_handle( current->process, info->thread,
+ THREAD_ALL_ACCESS, req->tinherit );
if (info->process->init_event)
- req->event = alloc_handle( current->process, info->process->init_event,
+ reply->event = alloc_handle( current->process, info->process->init_event,
EVENT_ALL_ACCESS, 0 );
release_object( info );
}
else
{
- req->pid = 0;
- req->tid = 0;
- req->phandle = 0;
- req->thandle = 0;
+ reply->pid = 0;
+ reply->tid = 0;
+ reply->phandle = 0;
+ reply->thandle = 0;
}
}
@@ -825,7 +806,7 @@
return;
}
current->process->ldt_copy = req->ldt_copy;
- init_process( req->ppid, req );
+ init_process( req->ppid, reply );
}
/* signal the end of the process initialization */
@@ -852,17 +833,17 @@
process->init_event = NULL;
if (req->gui) process->idle_event = create_event( NULL, 0, 1, 0 );
if (current->suspend + current->process->suspend > 0) stop_thread( current );
- req->debugged = (current->process->debugger != 0);
+ reply->debugged = (current->process->debugger != 0);
}
/* open a handle to a process */
DECL_HANDLER(open_process)
{
struct process *process = get_process_from_id( req->pid );
- req->handle = 0;
+ reply->handle = 0;
if (process)
{
- req->handle = alloc_handle( current->process, process, req->access, req->inherit );
+ reply->handle = alloc_handle( current->process, process, req->access, req->inherit );
release_object( process );
}
}
@@ -874,7 +855,7 @@
if ((process = get_process_from_handle( req->handle, PROCESS_TERMINATE )))
{
- req->self = (current->process == process);
+ reply->self = (current->process == process);
kill_process( process, current, req->exit_code );
release_object( process );
}
@@ -887,7 +868,7 @@
if ((process = get_process_from_handle( req->handle, PROCESS_QUERY_INFORMATION )))
{
- get_process_info( process, req );
+ get_process_info( process, reply );
release_object( process );
}
}
@@ -908,13 +889,28 @@
DECL_HANDLER(read_process_memory)
{
struct process *process;
+ size_t len = get_reply_max_size();
- if ((process = get_process_from_handle( req->handle, PROCESS_VM_READ )))
+ if (!(process = get_process_from_handle( req->handle, PROCESS_VM_READ ))) return;
+
+ if (len)
{
- size_t maxlen = get_req_data_size(req) / sizeof(int);
- read_process_memory( process, req->addr, req->len, maxlen, get_req_data(req) );
- release_object( process );
+ unsigned int start_offset = (unsigned int)req->addr % sizeof(int);
+ unsigned int nb_ints = (len + start_offset + sizeof(int) - 1) / sizeof(int);
+ const int *start = (int *)((char *)req->addr - start_offset);
+ int *buffer = mem_alloc( nb_ints * sizeof(int) );
+ if (buffer)
+ {
+ if (read_process_memory( process, start, nb_ints, buffer ))
+ {
+ /* move start of requested data to start of buffer */
+ if (start_offset) memmove( buffer, (char *)buffer + start_offset, len );
+ set_reply_data_ptr( buffer, len );
+ }
+ else len = 0;
+ }
}
+ release_object( process );
}
/* write data to a process address space */
@@ -924,9 +920,14 @@
if ((process = get_process_from_handle( req->handle, PROCESS_VM_WRITE )))
{
- size_t maxlen = get_req_data_size(req) / sizeof(int);
- write_process_memory( process, req->addr, req->len, maxlen,
- req->first_mask, req->last_mask, get_req_data(req) );
+ size_t len = get_req_data_size();
+ if ((len % sizeof(int)) || ((unsigned int)req->addr % sizeof(int)))
+ set_error( STATUS_INVALID_PARAMETER );
+ else
+ {
+ if (len) write_process_memory( process, req->addr, len / sizeof(int),
+ req->first_mask, req->last_mask, get_req_data() );
+ }
release_object( process );
}
}
@@ -964,12 +965,12 @@
{
struct process *process;
- req->event = 0;
+ reply->event = 0;
if ((process = get_process_from_handle( req->handle, PROCESS_QUERY_INFORMATION )))
{
if (process->idle_event && process != current->process && process->queue != current->queue)
- req->event = alloc_handle( current->process, process->idle_event,
- EVENT_ALL_ACCESS, 0 );
+ reply->event = alloc_handle( current->process, process->idle_event,
+ EVENT_ALL_ACCESS, 0 );
release_object( process );
}
}