mirror of
https://github.com/rapid7/metasploit-payloads
synced 2025-04-30 13:07:22 +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
|
# ignore posix temp stuff
|
||||||
posix-meterp-build-tmp/*
|
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
|
# Doxygen output
|
||||||
docs/*
|
docs/*
|
||||||
|
@ -1,317 +1,310 @@
|
|||||||
#include "queue.h"
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include <poll.h>
|
|
||||||
|
|
||||||
#include <pthread.h>
|
#include <poll.h>
|
||||||
|
|
||||||
typedef struct _WaitableEntry
|
typedef struct _WaitableEntry
|
||||||
{
|
{
|
||||||
|
Remote * remote;
|
||||||
HANDLE waitable;
|
HANDLE waitable;
|
||||||
|
EVENT* pause;
|
||||||
|
EVENT* resume;
|
||||||
LPVOID context;
|
LPVOID context;
|
||||||
|
BOOL running;
|
||||||
WaitableNotifyRoutine routine;
|
WaitableNotifyRoutine routine;
|
||||||
LIST_ENTRY(_WaitableEntry) link;
|
WaitableDestroyRoutine destroy;
|
||||||
} WaitableEntry;
|
} WaitableEntry;
|
||||||
|
|
||||||
int nentries = 0;
|
/*
|
||||||
int ntableentries = 0;
|
* The list of all currenltly running threads in the scheduler subsystem.
|
||||||
struct pollfd *polltable;
|
*/
|
||||||
LIST_HEAD(_WaitableEntryHead, _WaitableEntry) WEHead;
|
LIST * schedulerThreadList = NULL;
|
||||||
|
|
||||||
THREAD *scheduler_thread;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If there are no waitables in the queue, we wait
|
* The Remote that is associated with the scheduler subsystem
|
||||||
* for a conditional broadcast to start it.
|
|
||||||
*/
|
*/
|
||||||
|
Remote * schedulerRemote = NULL;
|
||||||
|
|
||||||
pthread_mutex_t scheduler_mutex;
|
/*
|
||||||
pthread_cond_t scheduler_cond;
|
* Initialize the scheduler subsystem. Must be called before any calls to scheduler_insert_waitable.
|
||||||
|
*/
|
||||||
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 )
|
DWORD scheduler_initialize( Remote * remote )
|
||||||
{
|
{
|
||||||
if(scheduler_thread) {
|
DWORD result = ERROR_SUCCESS;
|
||||||
dprintf("Hmmm. scheduler_initialize() called twice?");
|
|
||||||
return 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 );
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_init(&scheduler_mutex, NULL);
|
lock_release( schedulerThreadList->lock );
|
||||||
pthread_cond_init(&scheduler_cond, NULL);
|
|
||||||
|
|
||||||
scheduler_thread = thread_create(scheduler_run, remote, NULL);
|
dprintf( "[SCHEDULER] scheduler_destroy, joining all waitable threads..." );
|
||||||
if(! scheduler_thread) {
|
|
||||||
return ENOMEM;
|
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 );
|
||||||
}
|
}
|
||||||
|
|
||||||
thread_run(scheduler_thread);
|
dprintf( "[SCHEDULER] scheduler_destroy, destroying lists..." );
|
||||||
|
|
||||||
dprintf("Initialized scheduler thread and started it running");
|
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;
|
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -565,9 +565,10 @@ DWORD remote_request_core_channel_interact(Remote *remote, Packet *packet)
|
|||||||
NativeChannelOps *native = (NativeChannelOps *)&channel->ops;
|
NativeChannelOps *native = (NativeChannelOps *)&channel->ops;
|
||||||
|
|
||||||
// Check to see if this channel has a registered interact handler
|
// Check to see if this channel has a registered interact handler
|
||||||
if (native->interact)
|
dprintf( "[DISPATCH] attempting to set interactive: %d context 0x%p", interact, native->context );
|
||||||
result = native->interact(channel, packet, native->context,
|
if (native->interact) {
|
||||||
interact);
|
result = native->interact(channel, packet, native->context, interact);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the channel's interactive state
|
// Set the channel's interactive state
|
||||||
|
@ -159,6 +159,7 @@ VOID channel_destroy(Channel *channel, Packet *request)
|
|||||||
lock_destroy( channel->lock );
|
lock_destroy( channel->lock );
|
||||||
|
|
||||||
// Destroy the channel context
|
// Destroy the channel context
|
||||||
|
dprintf( "[CHANNEL] Free up the channel context 0x%p", channel );
|
||||||
free(channel);
|
free(channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -445,13 +446,16 @@ DWORD _channel_packet_completion_routine(Remote *remote, Packet *packet,
|
|||||||
length);
|
length);
|
||||||
}
|
}
|
||||||
else if ((!strcmp(method, "core_channel_close")) &&
|
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);
|
res = comp->routine.close(remote, channel, comp->context, result);
|
||||||
|
}
|
||||||
else if ((!strcmp(method, "core_channel_interact")) &&
|
else if ((!strcmp(method, "core_channel_interact")) &&
|
||||||
(comp->routine.interact))
|
(comp->routine.interact))
|
||||||
res = comp->routine.interact(remote, channel, comp->context, result);
|
res = comp->routine.interact(remote, channel, comp->context, result);
|
||||||
|
|
||||||
// Deallocate the completion context
|
// Deallocate the completion context
|
||||||
|
dprintf( "[CHANNEL] freeing up the completion context" );
|
||||||
free(comp);
|
free(comp);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
|
@ -44,7 +44,7 @@ int current_unix_timestamp(void) {
|
|||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
|
|
||||||
int debugging_enabled;
|
int debugging_enabled = 1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*/
|
*/
|
||||||
|
@ -11,12 +11,12 @@ typedef enum
|
|||||||
Stop = 3
|
Stop = 3
|
||||||
} SchedularSignal;
|
} SchedularSignal;
|
||||||
|
|
||||||
typedef DWORD (*WaitableNotifyRoutine)(Remote *remote, LPVOID context);
|
typedef DWORD (*WaitableNotifyRoutine)(Remote *remote, LPVOID entryContext, LPVOID threadContext);
|
||||||
typedef DWORD (*WaitableDestroyRoutine)(HANDLE waitable, LPVOID context);
|
typedef DWORD (*WaitableDestroyRoutine)(HANDLE waitable, LPVOID entryContext, LPVOID threadContext);
|
||||||
|
|
||||||
LINKAGE DWORD scheduler_initialize( Remote * remote );
|
LINKAGE DWORD scheduler_initialize( Remote * remote );
|
||||||
LINKAGE DWORD scheduler_destroy( VOID );
|
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 scheduler_signal_waitable( HANDLE waitable, SchedularSignal signal );
|
||||||
LINKAGE DWORD THREADCALL scheduler_waitable_thread( THREAD * thread );
|
LINKAGE DWORD THREADCALL scheduler_waitable_thread( THREAD * thread );
|
||||||
|
|
||||||
|
@ -156,21 +156,26 @@ BOOL event_signal( EVENT * event )
|
|||||||
*/
|
*/
|
||||||
BOOL event_poll( EVENT * event, DWORD timeout )
|
BOOL event_poll( EVENT * event, DWORD timeout )
|
||||||
{
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
if( event == NULL )
|
if( event == NULL )
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
if( WaitForSingleObject( event->handle, timeout ) == WAIT_OBJECT_0 )
|
if( WaitForSingleObject( event->handle, timeout ) == WAIT_OBJECT_0 )
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
#else
|
#else
|
||||||
|
BOOL result = FALSE;
|
||||||
|
|
||||||
// DWORD WINAPI WaitForSingleObject(
|
// DWORD WINAPI WaitForSingleObject(
|
||||||
// __in HANDLE hHandle,
|
// __in HANDLE hHandle,
|
||||||
// __in DWORD dwMilliseconds
|
// __in DWORD dwMilliseconds
|
||||||
// );
|
// );
|
||||||
// http://msdn.microsoft.com/en-us/library/ms687032(VS.85).aspx
|
// http://msdn.microsoft.com/en-us/library/ms687032(VS.85).aspx
|
||||||
|
|
||||||
|
if( event == NULL )
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
if(timeout) {
|
if(timeout) {
|
||||||
struct timespec ts;
|
struct timespec ts;
|
||||||
|
|
||||||
@ -191,7 +196,12 @@ BOOL event_poll( EVENT * event, DWORD timeout )
|
|||||||
__futex_wait(&(event->handle), 0, &ts);
|
__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
|
#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);
|
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 );
|
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);
|
} while (0);
|
||||||
|
@ -105,7 +105,7 @@ TcpClientContext * tcp_channel_server_create_client( TcpServerContext * serverct
|
|||||||
if( !clientctx->channel )
|
if( !clientctx->channel )
|
||||||
BREAK_WITH_ERROR( "[TCP-SERVER] tcp_channel_server_create_client. clientctx->channel == NULL", ERROR_INVALID_HANDLE );
|
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 );
|
} while( 0 );
|
||||||
|
|
||||||
@ -266,7 +266,7 @@ DWORD request_net_tcp_server_channel_open( Remote * remote, Packet * packet )
|
|||||||
if( !ctx->channel )
|
if( !ctx->channel )
|
||||||
BREAK_WITH_ERROR( "[TCP-SERVER] request_net_tcp_server_channel_open. channel_create_stream failed", ERROR_INVALID_HANDLE );
|
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) );
|
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 )
|
if( !ctx->sock.channel )
|
||||||
BREAK_WITH_ERROR( "[UDP] request_net_udp_channel_open. channel_create_stream failed", ERROR_INVALID_HANDLE );
|
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) );
|
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));
|
memset(&chops, 0, sizeof(PoolChannelOps));
|
||||||
|
|
||||||
// Initialize the channel operations
|
// Initialize the channel operations
|
||||||
|
dprintf( "[PROCESS] context address 0x%p", ctx );
|
||||||
chops.native.context = ctx;
|
chops.native.context = ctx;
|
||||||
chops.native.write = process_channel_write;
|
chops.native.write = process_channel_write;
|
||||||
chops.native.close = process_channel_close;
|
chops.native.close = process_channel_close;
|
||||||
@ -570,6 +571,7 @@ DWORD request_sys_process_execute(Remote *remote, Packet *packet)
|
|||||||
int idx, i;
|
int idx, i;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
int have_pty = -1;
|
int have_pty = -1;
|
||||||
|
ProcessChannelContext * ctx = NULL;
|
||||||
|
|
||||||
int hidden = (flags & PROCESS_EXECUTE_FLAG_HIDDEN);
|
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
|
// such that input can be directed to and from the remote endpoint
|
||||||
if (flags & PROCESS_EXECUTE_FLAG_CHANNELIZED)
|
if (flags & PROCESS_EXECUTE_FLAG_CHANNELIZED)
|
||||||
{
|
{
|
||||||
ProcessChannelContext * ctx = NULL;
|
|
||||||
PoolChannelOps chops;
|
PoolChannelOps chops;
|
||||||
Channel *newChannel;
|
Channel *newChannel;
|
||||||
|
|
||||||
@ -634,6 +635,7 @@ DWORD request_sys_process_execute(Remote *remote, Packet *packet)
|
|||||||
memset(&chops, 0, sizeof(PoolChannelOps));
|
memset(&chops, 0, sizeof(PoolChannelOps));
|
||||||
|
|
||||||
// Initialize the channel operations
|
// Initialize the channel operations
|
||||||
|
dprintf( "[PROCESS] context address 0x%p", ctx );
|
||||||
chops.native.context = ctx;
|
chops.native.context = ctx;
|
||||||
chops.native.write = process_channel_write;
|
chops.native.write = process_channel_write;
|
||||||
chops.native.close = process_channel_close;
|
chops.native.close = process_channel_close;
|
||||||
@ -758,6 +760,7 @@ DWORD request_sys_process_execute(Remote *remote, Packet *packet)
|
|||||||
if(have_pty) {
|
if(have_pty) {
|
||||||
dprintf("child channelized\n");
|
dprintf("child channelized\n");
|
||||||
close(slave);
|
close(slave);
|
||||||
|
ctx->pProcess = (HANDLE)pid;
|
||||||
} else {
|
} else {
|
||||||
close(in[0]);
|
close(in[0]);
|
||||||
close(out[1]);
|
close(out[1]);
|
||||||
@ -1073,11 +1076,14 @@ DWORD process_channel_close( Channel *channel, Packet *request, LPVOID context )
|
|||||||
return result;
|
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;
|
DWORD dwResult = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
dprintf( "[PROCESS] terminating context 0x%p", ctx );
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
ProcessChannelContext *ctx = (ProcessChannelContext *)channel->ops.stream.native.context;
|
|
||||||
|
|
||||||
CloseHandle( ctx->pStdin );
|
CloseHandle( ctx->pStdin );
|
||||||
CloseHandle( ctx->pStdout );
|
CloseHandle( ctx->pStdout );
|
||||||
@ -1087,8 +1093,16 @@ DWORD process_channel_interact_destroy( HANDLE waitable, Channel* channel )
|
|||||||
TerminateProcess( ctx->pProcess, 0 );
|
TerminateProcess( ctx->pProcess, 0 );
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
close( ctx->pStdin );
|
//dprintf( "[PROCESS] closing stdin 0x%x", ctx->pStdin );
|
||||||
close( ctx->pStdout );
|
//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
|
#endif
|
||||||
|
|
||||||
free( ctx );
|
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
|
* Callback for when data is available on the standard output handle of
|
||||||
* a process channel that is interactive mode
|
* 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)
|
||||||
{
|
{
|
||||||
|
Channel *channel = (Channel*)entryContext;
|
||||||
ProcessChannelContext *ctx = (ProcessChannelContext *)channel->ops.stream.native.context;
|
ProcessChannelContext *ctx = (ProcessChannelContext *)threadContext;
|
||||||
DWORD bytesRead, bytesAvail = 0;
|
DWORD bytesRead, bytesAvail = 0;
|
||||||
CHAR buffer[16384];
|
CHAR buffer[16384];
|
||||||
DWORD result = ERROR_SUCCESS;
|
DWORD result = ERROR_SUCCESS;
|
||||||
@ -1174,7 +1188,7 @@ DWORD process_channel_interact(Channel *channel, Packet *request, LPVOID context
|
|||||||
if (interact) {
|
if (interact) {
|
||||||
// try to resume it first, if it's not there, we can create a new entry
|
// 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 ) {
|
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,
|
(WaitableNotifyRoutine)process_channel_interact_notify,
|
||||||
(WaitableDestroyRoutine)process_channel_interact_destroy );
|
(WaitableDestroyRoutine)process_channel_interact_destroy );
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user