mirror of
https://github.com/rapid7/metasploit-payloads
synced 2025-03-30 22:19:17 +02:00
Fix up POSIX to match channel changes
POSIX was out of whack with Windows as a result of the changes made around channels. The schedular in posix was very different, and this commit brings it into line. Other than the obvious issues, a non-obvious issue with the changes was that the channel was being freed up on close prior to the thread terminating. This doesn't appear to be an issue on Windows, but was causing crashes on close in POSIX. The changes go quite deep. This changeset requires a lot of testing.
This commit is contained in:
parent
a89d79d139
commit
2f200d4fa1
c/meterpreter
6
c/meterpreter/.gitignore
vendored
6
c/meterpreter/.gitignore
vendored
@ -43,6 +43,12 @@ source/jpeg-8/Backup/*
|
||||
|
||||
# ignore posix temp stuff
|
||||
posix-meterp-build-tmp/*
|
||||
data/meterpreter/*
|
||||
source/server/rtld/elf2bin
|
||||
source/server/rtld/lib*
|
||||
source/server/rtld/msflinker
|
||||
source/server/rtld/msflinker.bin
|
||||
source/server/rtld/rtldtest
|
||||
|
||||
# Doxygen output
|
||||
docs/*
|
||||
|
@ -1,317 +1,310 @@
|
||||
#include "queue.h"
|
||||
#include "common.h"
|
||||
#include <poll.h>
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
typedef struct _WaitableEntry
|
||||
{
|
||||
HANDLE waitable;
|
||||
LPVOID context;
|
||||
WaitableNotifyRoutine routine;
|
||||
LIST_ENTRY(_WaitableEntry) link;
|
||||
} WaitableEntry;
|
||||
|
||||
int nentries = 0;
|
||||
int ntableentries = 0;
|
||||
struct pollfd *polltable;
|
||||
LIST_HEAD(_WaitableEntryHead, _WaitableEntry) WEHead;
|
||||
|
||||
THREAD *scheduler_thread;
|
||||
|
||||
/*
|
||||
* If there are no waitables in the queue, we wait
|
||||
* for a conditional broadcast to start it.
|
||||
*/
|
||||
|
||||
pthread_mutex_t scheduler_mutex;
|
||||
pthread_cond_t scheduler_cond;
|
||||
|
||||
DWORD scheduler_run(THREAD *thread);
|
||||
|
||||
DWORD scheduler_destroy( VOID )
|
||||
{
|
||||
WaitableEntry *current, *tmp;
|
||||
|
||||
dprintf("Shutdown of scheduler requested");
|
||||
|
||||
if(scheduler_thread)
|
||||
{
|
||||
dprintf("sigterm'ing thread");
|
||||
thread_sigterm(scheduler_thread);
|
||||
|
||||
// wake up the thread if needed
|
||||
pthread_cond_signal(&scheduler_cond);
|
||||
|
||||
// can delay execution up to 2 sec give or take
|
||||
thread_join(scheduler_thread);
|
||||
|
||||
// free up memory
|
||||
thread_destroy(scheduler_thread);
|
||||
scheduler_thread = NULL;
|
||||
|
||||
dprintf("thread joined .. going for polltable");
|
||||
|
||||
if(polltable)
|
||||
{
|
||||
free(polltable);
|
||||
polltable = NULL;
|
||||
nentries = ntableentries = 0;
|
||||
}
|
||||
|
||||
dprintf("Now for the fun part, iterating through list and removing items");
|
||||
|
||||
LIST_FOREACH_SAFE(current, &WEHead, link, tmp)
|
||||
{
|
||||
// can't call close function due to no remote struct
|
||||
// will segfault if we try
|
||||
// XXX could steal from scheduler_thread->parameter1 ?
|
||||
|
||||
dprintf("current: %08x, current->routine: %08x", current, current->routine);
|
||||
|
||||
LIST_REMOVE(current, link);
|
||||
close(current->waitable);
|
||||
free(current->context);
|
||||
free(current);
|
||||
}
|
||||
|
||||
dprintf("All done. Leaving");
|
||||
|
||||
}
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
DWORD scheduler_initialize( Remote * remote )
|
||||
{
|
||||
if(scheduler_thread) {
|
||||
dprintf("Hmmm. scheduler_initialize() called twice?");
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
pthread_mutex_init(&scheduler_mutex, NULL);
|
||||
pthread_cond_init(&scheduler_cond, NULL);
|
||||
|
||||
scheduler_thread = thread_create(scheduler_run, remote, NULL);
|
||||
if(! scheduler_thread) {
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
thread_run(scheduler_thread);
|
||||
|
||||
dprintf("Initialized scheduler thread and started it running");
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert a waitable object for checking and processing
|
||||
*/
|
||||
DWORD
|
||||
scheduler_insert_waitable(HANDLE waitable, LPVOID context,
|
||||
WaitableNotifyRoutine routine)
|
||||
{
|
||||
DWORD retcode = ERROR_SUCCESS;
|
||||
|
||||
WaitableEntry *current;
|
||||
struct pollfd *polltableprev;
|
||||
|
||||
pthread_mutex_lock(&scheduler_mutex);
|
||||
|
||||
//dprintf("Handle: %d, context: 0x%08x, routine: 0x%08x. nentries = %d, polltable = 0x%08x",
|
||||
// waitable, context, routine, nentries, polltable);
|
||||
|
||||
do {
|
||||
if ((current = malloc(sizeof(WaitableEntry))) == NULL) {
|
||||
retcode = ENOMEM;
|
||||
break;
|
||||
}
|
||||
|
||||
nentries++;
|
||||
|
||||
if (nentries > ntableentries) {
|
||||
polltableprev = polltable;
|
||||
|
||||
// We do *2 because reallocating every scheduler_insert_waitable
|
||||
// is slower than need be.
|
||||
|
||||
polltable = malloc((nentries*2)*sizeof(struct pollfd));
|
||||
|
||||
if (polltable == NULL) {
|
||||
nentries--;
|
||||
polltable = polltableprev;
|
||||
free(current);
|
||||
|
||||
retcode = ENOMEM;
|
||||
break;
|
||||
}
|
||||
|
||||
if (polltableprev != NULL)
|
||||
free(polltableprev);
|
||||
|
||||
ntableentries = (nentries*2);
|
||||
}
|
||||
current->waitable = waitable;
|
||||
current->context = context;
|
||||
current->routine = routine;
|
||||
|
||||
LIST_INSERT_HEAD(&WEHead, current, link);
|
||||
|
||||
|
||||
} while(0);
|
||||
|
||||
|
||||
dprintf("WEHead: %08x, Now nentries = %d, and polltable = 0x%08x. LIST_EMPTY: %d", &WEHead, nentries, polltable, LIST_EMPTY(&WEHead));
|
||||
/*
|
||||
LIST_FOREACH(current, &WEHead, link)
|
||||
dprintf("current->waitable: %d, current->context: %08x, current->routine: %08x",
|
||||
current->waitable, current->context, current->routine);
|
||||
*/
|
||||
|
||||
pthread_mutex_unlock(&scheduler_mutex);
|
||||
|
||||
// wake up scheduler if needed.
|
||||
pthread_cond_signal(&scheduler_cond);
|
||||
|
||||
return retcode;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove a waitable object
|
||||
*/
|
||||
DWORD
|
||||
scheduler_remove_waitable(HANDLE waitable)
|
||||
{
|
||||
DWORD retcode = ERROR_SUCCESS;
|
||||
WaitableEntry *current;
|
||||
|
||||
dprintf("Handle: %d", waitable);
|
||||
|
||||
pthread_mutex_lock(&scheduler_mutex);
|
||||
|
||||
do {
|
||||
LIST_FOREACH(current, &WEHead, link)
|
||||
if (current->waitable == waitable)
|
||||
break;
|
||||
|
||||
if (current == NULL) {
|
||||
retcode = ENOENT;
|
||||
break;
|
||||
}
|
||||
|
||||
LIST_REMOVE(current, link);
|
||||
free(current);
|
||||
nentries--;
|
||||
} while(0);
|
||||
|
||||
pthread_mutex_unlock(&scheduler_mutex);
|
||||
|
||||
return retcode;
|
||||
}
|
||||
|
||||
/*
|
||||
* Runs the scheduler, checking waitable objects for data
|
||||
*/
|
||||
DWORD
|
||||
scheduler_run(THREAD *thread)
|
||||
{
|
||||
Remote *remote;
|
||||
remote = (Remote *) thread->parameter1;
|
||||
WaitableEntry *current, *tmp;
|
||||
int ret, i, found, idx;
|
||||
int timeout;
|
||||
|
||||
timeout = 1000;
|
||||
|
||||
// see if we can modify this code to use waitable as the index into polltable
|
||||
// and waitable events. saves time looking up in exchange for more memory use.
|
||||
|
||||
pthread_mutex_lock(&scheduler_mutex);
|
||||
|
||||
dprintf("Beginning loop");
|
||||
|
||||
while( event_poll(thread->sigterm, 0) == FALSE )
|
||||
{
|
||||
// scheduler_mutex is held upon entry and execution of the loop
|
||||
|
||||
idx = 0;
|
||||
|
||||
while(event_poll(thread->sigterm, 0) == FALSE && (LIST_EMPTY(&WEHead) || polltable == NULL)) {
|
||||
// XXX I'd prefer to use pthread_cond_timedwait, but it's broken in bionic and just
|
||||
// chews cpu
|
||||
|
||||
//dprintf(" Waiting for conditional (%08x). %d vs %d",
|
||||
// &scheduler_cond, LIST_EMPTY(&WEHead), polltable == NULL);
|
||||
|
||||
pthread_cond_wait(&scheduler_cond, &scheduler_mutex);
|
||||
|
||||
// pthread_cond_wait still chews CPU in some cases, usleep to yield
|
||||
// processor so we don't just spin.
|
||||
usleep(1000);
|
||||
}
|
||||
|
||||
LIST_FOREACH(current, &WEHead, link) {
|
||||
dprintf("current->waitable: %d, current->context: %08x, current->routine: %08x",
|
||||
current->waitable, current->context, current->routine);
|
||||
polltable[idx].fd = current->waitable;
|
||||
polltable[idx].events = POLLRDNORM;
|
||||
polltable[idx].revents = 0;
|
||||
idx++;
|
||||
}
|
||||
|
||||
dprintf("Created a polltable of %d", idx);
|
||||
|
||||
pthread_mutex_unlock(&scheduler_mutex);
|
||||
|
||||
ret = poll(polltable, idx, timeout);
|
||||
|
||||
pthread_mutex_lock(&scheduler_mutex);
|
||||
|
||||
if(ret == 0) continue;
|
||||
if(ret == -1) {
|
||||
if(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
dprintf("poll() failed, errno: %d (%s). Sleeping 1 second and retrying", errno, strerror(errno));
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (found = i = 0; i < idx && found < ret; i++)
|
||||
{
|
||||
if (polltable[i].revents)
|
||||
{
|
||||
LIST_FOREACH(current, &WEHead, link)
|
||||
if (current->waitable == polltable[i].fd)
|
||||
break;
|
||||
|
||||
if(current)
|
||||
{
|
||||
ret = current->routine(remote, current->context);
|
||||
if(ret != ERROR_SUCCESS)
|
||||
{
|
||||
// could call close due to remote, but it would deadlock
|
||||
// if it calls remove waitable
|
||||
// could make a separate list to handle when we are not locking
|
||||
// unlink and let rest deal with it ?
|
||||
|
||||
dprintf("current->routine (%08x / %08x) returned an error message. destroying", current->routine, current->context);
|
||||
|
||||
LIST_REMOVE(current, link);
|
||||
close(current->waitable);
|
||||
channel_close((Channel *)current->context, remote, NULL, 0, NULL);
|
||||
free(current);
|
||||
|
||||
nentries--;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dprintf("Ending loop");
|
||||
|
||||
pthread_mutex_unlock(&scheduler_mutex);
|
||||
}
|
||||
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include <poll.h>
|
||||
|
||||
typedef struct _WaitableEntry
|
||||
{
|
||||
Remote * remote;
|
||||
HANDLE waitable;
|
||||
EVENT* pause;
|
||||
EVENT* resume;
|
||||
LPVOID context;
|
||||
BOOL running;
|
||||
WaitableNotifyRoutine routine;
|
||||
WaitableDestroyRoutine destroy;
|
||||
} WaitableEntry;
|
||||
|
||||
/*
|
||||
* The list of all currenltly running threads in the scheduler subsystem.
|
||||
*/
|
||||
LIST * schedulerThreadList = NULL;
|
||||
|
||||
/*
|
||||
* The Remote that is associated with the scheduler subsystem
|
||||
*/
|
||||
Remote * schedulerRemote = NULL;
|
||||
|
||||
/*
|
||||
* Initialize the scheduler subsystem. Must be called before any calls to scheduler_insert_waitable.
|
||||
*/
|
||||
DWORD scheduler_initialize( Remote * remote )
|
||||
{
|
||||
DWORD result = ERROR_SUCCESS;
|
||||
|
||||
dprintf( "[SCHEDULER] entering scheduler_initialize." );
|
||||
|
||||
if( remote == NULL )
|
||||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
schedulerThreadList = list_create();
|
||||
if( schedulerThreadList == NULL )
|
||||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
schedulerRemote = remote;
|
||||
|
||||
dprintf( "[SCHEDULER] leaving scheduler_initialize." );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroy the scheduler subsystem. All waitable threads at signaled to terminate.
|
||||
* this function blocks untill all waitable threads have terminated.
|
||||
*/
|
||||
DWORD scheduler_destroy( VOID )
|
||||
{
|
||||
DWORD result = ERROR_SUCCESS;
|
||||
DWORD index = 0;
|
||||
DWORD count = 0;
|
||||
LIST * jlist = list_create();
|
||||
THREAD * thread = NULL;
|
||||
WaitableEntry * entry = NULL;
|
||||
|
||||
dprintf( "[SCHEDULER] entering scheduler_destroy." );
|
||||
|
||||
lock_acquire( schedulerThreadList->lock );
|
||||
|
||||
count = list_count( schedulerThreadList );
|
||||
|
||||
for( index=0 ; index < count ; index++ )
|
||||
{
|
||||
thread = (THREAD *)list_get( schedulerThreadList, index );
|
||||
if( thread == NULL )
|
||||
continue;
|
||||
|
||||
list_push( jlist, thread );
|
||||
|
||||
entry = (WaitableEntry *)thread->parameter1;
|
||||
|
||||
if( !entry->running )
|
||||
event_signal( entry->resume );
|
||||
|
||||
thread_sigterm( thread );
|
||||
}
|
||||
|
||||
lock_release( schedulerThreadList->lock );
|
||||
|
||||
dprintf( "[SCHEDULER] scheduler_destroy, joining all waitable threads..." );
|
||||
|
||||
while( TRUE )
|
||||
{
|
||||
dprintf( "[SCHEDULER] scheduler_destroy, popping off another item from thread liat..." );
|
||||
|
||||
thread = (THREAD *)list_pop( jlist );
|
||||
if( thread == NULL )
|
||||
break;
|
||||
|
||||
dprintf( "[SCHEDULER] scheduler_destroy, joining thread 0x%08X...", thread );
|
||||
|
||||
thread_join( thread );
|
||||
}
|
||||
|
||||
dprintf( "[SCHEDULER] scheduler_destroy, destroying lists..." );
|
||||
|
||||
list_destroy( jlist );
|
||||
|
||||
list_destroy( schedulerThreadList );
|
||||
|
||||
schedulerThreadList = NULL;
|
||||
|
||||
dprintf( "[SCHEDULER] leaving scheduler_destroy." );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert a new waitable thread for checking and processing.
|
||||
*/
|
||||
DWORD scheduler_insert_waitable( HANDLE waitable, LPVOID entryContext, LPVOID threadContext, WaitableNotifyRoutine routine, WaitableDestroyRoutine destroy )
|
||||
{
|
||||
DWORD result = ERROR_SUCCESS;
|
||||
THREAD * swt = NULL;
|
||||
|
||||
WaitableEntry * entry = (WaitableEntry *)malloc( sizeof( WaitableEntry ) );
|
||||
if( entry == NULL )
|
||||
return ERROR_NOT_ENOUGH_MEMORY;
|
||||
|
||||
dprintf( "[SCHEDULER] entering scheduler_insert_waitable( 0x%08X, 0x%08X, 0x%08X, 0x%08X, 0x%08X )",
|
||||
waitable, entryContext, threadContext, routine, destroy );
|
||||
|
||||
memset( entry, 0, sizeof( WaitableEntry ) );
|
||||
|
||||
entry->remote = schedulerRemote;
|
||||
entry->waitable = waitable;
|
||||
entry->destroy = destroy;
|
||||
entry->context = entryContext;
|
||||
entry->routine = routine;
|
||||
entry->pause = event_create();
|
||||
entry->resume = event_create();
|
||||
|
||||
swt = thread_create( scheduler_waitable_thread, entry, threadContext );
|
||||
if( swt != NULL )
|
||||
{
|
||||
dprintf( "[SCHEDULER] created scheduler_waitable_thread 0x%08X", swt );
|
||||
thread_run( swt );
|
||||
}
|
||||
else
|
||||
{
|
||||
free( entry );
|
||||
result = ERROR_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
dprintf( "[SCHEDULER] leaving scheduler_insert_waitable" );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Signal a waitable object.
|
||||
*/
|
||||
DWORD scheduler_signal_waitable( HANDLE waitable, SchedularSignal signal )
|
||||
{
|
||||
DWORD index = 0;
|
||||
DWORD count = 0;
|
||||
THREAD * thread = NULL;
|
||||
WaitableEntry * entry = NULL;
|
||||
DWORD result = ERROR_NOT_FOUND;
|
||||
|
||||
dprintf( "[SCHEDULER] entering scheduler_signal_waitable( 0x%08X )", waitable );
|
||||
|
||||
if( schedulerThreadList == NULL || waitable == NULL )
|
||||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
lock_acquire( schedulerThreadList->lock );
|
||||
|
||||
count = list_count( schedulerThreadList );
|
||||
|
||||
for( index=0 ; index < count ; index++ )
|
||||
{
|
||||
thread = (THREAD *)list_get( schedulerThreadList, index );
|
||||
if( thread == NULL )
|
||||
continue;
|
||||
|
||||
entry = (WaitableEntry *)thread->parameter1;
|
||||
if( entry == NULL )
|
||||
continue;
|
||||
|
||||
if( entry->waitable == waitable )
|
||||
{
|
||||
dprintf( "[SCHEDULER] scheduler_signal_waitable: signaling waitable = 0x%08X, thread = 0x%08X", waitable, thread );
|
||||
if( signal == Pause )
|
||||
{
|
||||
if( entry->running ) {
|
||||
dprintf( "[SCHEDULER] scheduler_signal_waitable: thread running, pausing. waitable = 0x%08X, thread = 0x%08X, handle = 0x%X", waitable, thread, entry->pause->handle );
|
||||
event_signal( entry->pause );
|
||||
} else {
|
||||
dprintf( "[SCHEDULER] scheduler_signal_waitable: thread already paused. waitable = 0x%08X, thread = 0x%08X", waitable, thread );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( !entry->running ) {
|
||||
dprintf( "[SCHEDULER] scheduler_signal_waitable: thread paused, resuming. waitable = 0x%08X, thread = 0x%08X, handle = 0x%X", waitable, thread, entry->resume->handle );
|
||||
event_signal( entry->resume );
|
||||
}
|
||||
|
||||
if( signal == Stop ) {
|
||||
dprintf( "[SCHEDULER] scheduler_signal_waitable: stopping thread. waitable = 0x%08X, thread = 0x%08X, handle = 0x%X", waitable, thread, thread->sigterm->handle );
|
||||
thread_sigterm( thread );
|
||||
} else {
|
||||
dprintf( "[SCHEDULER] scheduler_signal_waitable: thread already running. waitable = 0x%08X, thread = 0x%08X", waitable, thread );
|
||||
}
|
||||
}
|
||||
|
||||
result = ERROR_SUCCESS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
lock_release( schedulerThreadList->lock );
|
||||
|
||||
dprintf( "[SCHEDULER] leaving scheduler_signal_waitable" );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* The schedulers waitable thread. Each scheduled item will have its own thread which
|
||||
* waits for either data to process or the threads signal to terminate.
|
||||
*/
|
||||
DWORD THREADCALL scheduler_waitable_thread( THREAD * thread )
|
||||
{
|
||||
struct pollfd pollDetail = {0};
|
||||
WaitableEntry * entry = NULL;
|
||||
DWORD result = 0;
|
||||
BOOL terminate = FALSE;
|
||||
UINT signalIndex = 0;
|
||||
|
||||
if( thread == NULL )
|
||||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
entry = (WaitableEntry *)thread->parameter1;
|
||||
if( entry == NULL )
|
||||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
if( entry->routine == NULL )
|
||||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
if( schedulerThreadList == NULL )
|
||||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
list_add( schedulerThreadList, thread );
|
||||
|
||||
pollDetail.fd = entry->waitable;
|
||||
pollDetail.events = POLLRDNORM;
|
||||
pollDetail.revents = 0;
|
||||
|
||||
dprintf( "[SCHEDULER] entering scheduler_waitable_thread( 0x%08X )", thread );
|
||||
|
||||
|
||||
entry->running = TRUE;
|
||||
while( !terminate )
|
||||
{
|
||||
if( event_poll( thread->sigterm, 0 ) ) {
|
||||
dprintf( "[SCHEDULER] scheduler_waitable_thread( 0x%08X ), signaled to terminate...", thread );
|
||||
terminate = TRUE;
|
||||
}
|
||||
else if( event_poll( entry->pause, 0 ) ) {
|
||||
dprintf( "[SCHEDULER] scheduler_waitable_thread( 0x%08X ), signaled to pause...", thread );
|
||||
entry->running = FALSE;
|
||||
while( !event_poll( entry->resume, 1000 ) );
|
||||
entry->running = TRUE;
|
||||
dprintf( "[SCHEDULER] scheduler_waitable_thread( 0x%08X ), signaled to resume...", thread );
|
||||
}
|
||||
else if( poll( &pollDetail, 1, 100 ) == POLLIN ) {
|
||||
//dprintf( "[SCHEDULER] scheduler_waitable_thread( 0x%08X ), signaled on waitable...", thread );
|
||||
entry->routine( entry->remote, entry->context, (LPVOID)thread->parameter2 );
|
||||
}
|
||||
}
|
||||
|
||||
dprintf( "[SCHEDULER] leaving scheduler_waitable_thread( 0x%08X )", thread );
|
||||
|
||||
// we acquire the lock for this block as we are freeing 'entry' which may be accessed
|
||||
// in a second call to scheduler_signal_waitable for this thread (unlikely but best practice).
|
||||
dprintf( "[SCHEDULER] attempting to remove thread( 0x%08X )", thread );
|
||||
lock_acquire( schedulerThreadList->lock );
|
||||
if( list_remove( schedulerThreadList, thread ) )
|
||||
{
|
||||
if( entry->destroy ) {
|
||||
dprintf( "[SCHEDULER] destroying thread( 0x%08X )", thread );
|
||||
entry->destroy( entry->waitable, entry->context, (LPVOID)thread->parameter2 );
|
||||
dprintf( "[SCHEDULER] destroyed thread( 0x%08X )", thread );
|
||||
}
|
||||
else if( entry->waitable ) {
|
||||
dprintf( "[SCHEDULER] scheduler_waitable_thread( 0x%08X ) closing handle 0x%08X", thread, entry->waitable);
|
||||
close( entry->waitable );
|
||||
}
|
||||
|
||||
dprintf( "[SCHEDULER] cleaning up resume thread( 0x%08X )", thread );
|
||||
event_destroy( entry->resume );
|
||||
dprintf( "[SCHEDULER] cleaning up pause thread( 0x%08X )", thread );
|
||||
event_destroy( entry->pause );
|
||||
dprintf( "[SCHEDULER] cleaning up thread( 0x%08X )", thread );
|
||||
thread_destroy( thread );
|
||||
dprintf( "[SCHEDULER] cleaning up entry( 0x%08X )", thread );
|
||||
free( entry );
|
||||
}
|
||||
lock_release( schedulerThreadList->lock );
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
@ -565,9 +565,10 @@ DWORD remote_request_core_channel_interact(Remote *remote, Packet *packet)
|
||||
NativeChannelOps *native = (NativeChannelOps *)&channel->ops;
|
||||
|
||||
// Check to see if this channel has a registered interact handler
|
||||
if (native->interact)
|
||||
result = native->interact(channel, packet, native->context,
|
||||
interact);
|
||||
dprintf( "[DISPATCH] attempting to set interactive: %d context 0x%p", interact, native->context );
|
||||
if (native->interact) {
|
||||
result = native->interact(channel, packet, native->context, interact);
|
||||
}
|
||||
}
|
||||
|
||||
// Set the channel's interactive state
|
||||
|
@ -159,6 +159,7 @@ VOID channel_destroy(Channel *channel, Packet *request)
|
||||
lock_destroy( channel->lock );
|
||||
|
||||
// Destroy the channel context
|
||||
dprintf( "[CHANNEL] Free up the channel context 0x%p", channel );
|
||||
free(channel);
|
||||
}
|
||||
|
||||
@ -445,13 +446,16 @@ DWORD _channel_packet_completion_routine(Remote *remote, Packet *packet,
|
||||
length);
|
||||
}
|
||||
else if ((!strcmp(method, "core_channel_close")) &&
|
||||
(comp->routine.close))
|
||||
(comp->routine.close)) {
|
||||
dprintf( "[CHANNEL] freeing up the completion context" );
|
||||
res = comp->routine.close(remote, channel, comp->context, result);
|
||||
}
|
||||
else if ((!strcmp(method, "core_channel_interact")) &&
|
||||
(comp->routine.interact))
|
||||
res = comp->routine.interact(remote, channel, comp->context, result);
|
||||
|
||||
// Deallocate the completion context
|
||||
dprintf( "[CHANNEL] freeing up the completion context" );
|
||||
free(comp);
|
||||
|
||||
return res;
|
||||
|
@ -44,7 +44,7 @@ int current_unix_timestamp(void) {
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
int debugging_enabled;
|
||||
int debugging_enabled = 1;
|
||||
|
||||
/*
|
||||
*/
|
||||
|
@ -11,12 +11,12 @@ typedef enum
|
||||
Stop = 3
|
||||
} SchedularSignal;
|
||||
|
||||
typedef DWORD (*WaitableNotifyRoutine)(Remote *remote, LPVOID context);
|
||||
typedef DWORD (*WaitableDestroyRoutine)(HANDLE waitable, LPVOID context);
|
||||
typedef DWORD (*WaitableNotifyRoutine)(Remote *remote, LPVOID entryContext, LPVOID threadContext);
|
||||
typedef DWORD (*WaitableDestroyRoutine)(HANDLE waitable, LPVOID entryContext, LPVOID threadContext);
|
||||
|
||||
LINKAGE DWORD scheduler_initialize( Remote * remote );
|
||||
LINKAGE DWORD scheduler_destroy( VOID );
|
||||
LINKAGE DWORD scheduler_insert_waitable( HANDLE waitable, LPVOID context, WaitableNotifyRoutine routine, WaitableDestroyRoutine destroy );
|
||||
LINKAGE DWORD scheduler_insert_waitable( HANDLE waitable, LPVOID entryContext, LPVOID threadContext, WaitableNotifyRoutine routine, WaitableDestroyRoutine destroy );
|
||||
LINKAGE DWORD scheduler_signal_waitable( HANDLE waitable, SchedularSignal signal );
|
||||
LINKAGE DWORD THREADCALL scheduler_waitable_thread( THREAD * thread );
|
||||
|
||||
|
@ -156,21 +156,26 @@ BOOL event_signal( EVENT * event )
|
||||
*/
|
||||
BOOL event_poll( EVENT * event, DWORD timeout )
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if( event == NULL )
|
||||
return FALSE;
|
||||
|
||||
#ifdef _WIN32
|
||||
if( WaitForSingleObject( event->handle, timeout ) == WAIT_OBJECT_0 )
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
#else
|
||||
BOOL result = FALSE;
|
||||
|
||||
// DWORD WINAPI WaitForSingleObject(
|
||||
// __in HANDLE hHandle,
|
||||
// __in DWORD dwMilliseconds
|
||||
// );
|
||||
// http://msdn.microsoft.com/en-us/library/ms687032(VS.85).aspx
|
||||
|
||||
if( event == NULL )
|
||||
return FALSE;
|
||||
|
||||
if(timeout) {
|
||||
struct timespec ts;
|
||||
|
||||
@ -191,7 +196,12 @@ BOOL event_poll( EVENT * event, DWORD timeout )
|
||||
__futex_wait(&(event->handle), 0, &ts);
|
||||
}
|
||||
|
||||
return event->handle ? TRUE : FALSE;
|
||||
// We should behave like an auto-reset event
|
||||
result = event->handle ? TRUE : FALSE;
|
||||
if( result )
|
||||
event->handle = (HANDLE)0;
|
||||
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -328,7 +328,7 @@ DWORD create_tcp_client_channel(Remote *remote, LPCSTR remoteHost, USHORT remote
|
||||
WSAEventSelect(ctx->fd, ctx->notify, FD_READ|FD_CLOSE);
|
||||
dprintf( "[TCP] create_tcp_client_channel. host=%s, port=%d created the notify %.8x", remoteHost, remotePort, ctx->notify );
|
||||
|
||||
scheduler_insert_waitable( ctx->notify, ctx, (WaitableNotifyRoutine)tcp_channel_client_local_notify, NULL);
|
||||
scheduler_insert_waitable( ctx->notify, ctx, NULL, (WaitableNotifyRoutine)tcp_channel_client_local_notify, NULL);
|
||||
}
|
||||
|
||||
} while (0);
|
||||
|
@ -105,7 +105,7 @@ TcpClientContext * tcp_channel_server_create_client( TcpServerContext * serverct
|
||||
if( !clientctx->channel )
|
||||
BREAK_WITH_ERROR( "[TCP-SERVER] tcp_channel_server_create_client. clientctx->channel == NULL", ERROR_INVALID_HANDLE );
|
||||
|
||||
dwResult = scheduler_insert_waitable( clientctx->notify, clientctx, (WaitableNotifyRoutine)tcp_channel_client_local_notify, NULL );
|
||||
dwResult = scheduler_insert_waitable( clientctx->notify, clientctx, NULL, (WaitableNotifyRoutine)tcp_channel_client_local_notify, NULL );
|
||||
|
||||
} while( 0 );
|
||||
|
||||
@ -266,7 +266,7 @@ DWORD request_net_tcp_server_channel_open( Remote * remote, Packet * packet )
|
||||
if( !ctx->channel )
|
||||
BREAK_WITH_ERROR( "[TCP-SERVER] request_net_tcp_server_channel_open. channel_create_stream failed", ERROR_INVALID_HANDLE );
|
||||
|
||||
scheduler_insert_waitable( ctx->notify, ctx, (WaitableNotifyRoutine)tcp_channel_server_notify, NULL );
|
||||
scheduler_insert_waitable( ctx->notify, ctx, NULL, (WaitableNotifyRoutine)tcp_channel_server_notify, NULL );
|
||||
|
||||
packet_add_tlv_uint( response, TLV_TYPE_CHANNEL_ID, channel_get_id(ctx->channel) );
|
||||
|
||||
|
@ -323,7 +323,7 @@ DWORD request_net_udp_channel_open( Remote * remote, Packet * packet )
|
||||
if( !ctx->sock.channel )
|
||||
BREAK_WITH_ERROR( "[UDP] request_net_udp_channel_open. channel_create_stream failed", ERROR_INVALID_HANDLE );
|
||||
|
||||
scheduler_insert_waitable( ctx->sock.notify, ctx, (WaitableNotifyRoutine)udp_channel_notify, NULL );
|
||||
scheduler_insert_waitable( ctx->sock.notify, ctx, NULL, (WaitableNotifyRoutine)udp_channel_notify, NULL );
|
||||
|
||||
packet_add_tlv_uint( response, TLV_TYPE_CHANNEL_ID, channel_get_id(ctx->sock.channel) );
|
||||
|
||||
|
@ -270,6 +270,7 @@ DWORD request_sys_process_execute(Remote *remote, Packet *packet)
|
||||
memset(&chops, 0, sizeof(PoolChannelOps));
|
||||
|
||||
// Initialize the channel operations
|
||||
dprintf( "[PROCESS] context address 0x%p", ctx );
|
||||
chops.native.context = ctx;
|
||||
chops.native.write = process_channel_write;
|
||||
chops.native.close = process_channel_close;
|
||||
@ -570,6 +571,7 @@ DWORD request_sys_process_execute(Remote *remote, Packet *packet)
|
||||
int idx, i;
|
||||
pid_t pid;
|
||||
int have_pty = -1;
|
||||
ProcessChannelContext * ctx = NULL;
|
||||
|
||||
int hidden = (flags & PROCESS_EXECUTE_FLAG_HIDDEN);
|
||||
|
||||
@ -620,7 +622,6 @@ DWORD request_sys_process_execute(Remote *remote, Packet *packet)
|
||||
// such that input can be directed to and from the remote endpoint
|
||||
if (flags & PROCESS_EXECUTE_FLAG_CHANNELIZED)
|
||||
{
|
||||
ProcessChannelContext * ctx = NULL;
|
||||
PoolChannelOps chops;
|
||||
Channel *newChannel;
|
||||
|
||||
@ -634,6 +635,7 @@ DWORD request_sys_process_execute(Remote *remote, Packet *packet)
|
||||
memset(&chops, 0, sizeof(PoolChannelOps));
|
||||
|
||||
// Initialize the channel operations
|
||||
dprintf( "[PROCESS] context address 0x%p", ctx );
|
||||
chops.native.context = ctx;
|
||||
chops.native.write = process_channel_write;
|
||||
chops.native.close = process_channel_close;
|
||||
@ -758,6 +760,7 @@ DWORD request_sys_process_execute(Remote *remote, Packet *packet)
|
||||
if(have_pty) {
|
||||
dprintf("child channelized\n");
|
||||
close(slave);
|
||||
ctx->pProcess = (HANDLE)pid;
|
||||
} else {
|
||||
close(in[0]);
|
||||
close(out[1]);
|
||||
@ -1073,11 +1076,14 @@ DWORD process_channel_close( Channel *channel, Packet *request, LPVOID context )
|
||||
return result;
|
||||
}
|
||||
|
||||
DWORD process_channel_interact_destroy( HANDLE waitable, Channel* channel )
|
||||
DWORD process_channel_interact_destroy( HANDLE waitable, LPVOID entryContext, LPVOID threadContext )
|
||||
{
|
||||
ProcessChannelContext *ctx = (ProcessChannelContext *)threadContext;
|
||||
DWORD dwResult = ERROR_SUCCESS;
|
||||
|
||||
dprintf( "[PROCESS] terminating context 0x%p", ctx );
|
||||
|
||||
#ifdef _WIN32
|
||||
ProcessChannelContext *ctx = (ProcessChannelContext *)channel->ops.stream.native.context;
|
||||
|
||||
CloseHandle( ctx->pStdin );
|
||||
CloseHandle( ctx->pStdout );
|
||||
@ -1087,8 +1093,16 @@ DWORD process_channel_interact_destroy( HANDLE waitable, Channel* channel )
|
||||
TerminateProcess( ctx->pProcess, 0 );
|
||||
}
|
||||
#else
|
||||
close( ctx->pStdin );
|
||||
close( ctx->pStdout );
|
||||
//dprintf( "[PROCESS] closing stdin 0x%x", ctx->pStdin );
|
||||
//close( ctx->pStdin );
|
||||
//dprintf( "[PROCESS] closing stdout 0x%x", ctx->pStdout );
|
||||
//close( ctx->pStdout );
|
||||
|
||||
dprintf( "[PROCESS] pid %u", ctx->pProcess );
|
||||
if( ctx->pProcess ) {
|
||||
dprintf( "[PROCESS] terminating pid %u", ctx->pProcess );
|
||||
kill( (pid_t)ctx->pProcess, 9 );
|
||||
}
|
||||
#endif
|
||||
|
||||
free( ctx );
|
||||
@ -1100,10 +1114,10 @@ DWORD process_channel_interact_destroy( HANDLE waitable, Channel* channel )
|
||||
* Callback for when data is available on the standard output handle of
|
||||
* a process channel that is interactive mode
|
||||
*/
|
||||
DWORD process_channel_interact_notify(Remote *remote, Channel *channel)
|
||||
DWORD process_channel_interact_notify(Remote *remote, LPVOID entryContext, LPVOID threadContext)
|
||||
{
|
||||
|
||||
ProcessChannelContext *ctx = (ProcessChannelContext *)channel->ops.stream.native.context;
|
||||
Channel *channel = (Channel*)entryContext;
|
||||
ProcessChannelContext *ctx = (ProcessChannelContext *)threadContext;
|
||||
DWORD bytesRead, bytesAvail = 0;
|
||||
CHAR buffer[16384];
|
||||
DWORD result = ERROR_SUCCESS;
|
||||
@ -1174,7 +1188,7 @@ DWORD process_channel_interact(Channel *channel, Packet *request, LPVOID context
|
||||
if (interact) {
|
||||
// try to resume it first, if it's not there, we can create a new entry
|
||||
if( (result = scheduler_signal_waitable( ctx->pStdout, Resume )) == ERROR_NOT_FOUND ) {
|
||||
result = scheduler_insert_waitable( ctx->pStdout, channel,
|
||||
result = scheduler_insert_waitable( ctx->pStdout, channel, context,
|
||||
(WaitableNotifyRoutine)process_channel_interact_notify,
|
||||
(WaitableDestroyRoutine)process_channel_interact_destroy );
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user