|
|
/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
sandbox.c
Abstract:
Utilities to run code in isolated processes (sandbox apis).
Author:
Jim Schmidt (jimschm) 31-Jan-2000
Revision History:
--*/
//
// Includes
//
#include "pch.h"
#include "utilsp.h"
#define DBG_SANDBOX "Sandbox"
//
// Strings
//
// None
//
// Constants
//
#define S_SBCLASS TEXT("SandboxHost")
//
// Macros
//
// None
//
// Types
//
typedef struct { BOOL Win32; HANDLE Mapping; HANDLE Ack; UINT Instance; TCHAR WindowTitle[64];
} IPCDATA, *PIPCDATA;
typedef struct { DWORD Command; DWORD Result; DWORD TechnicalLogId; DWORD GuiLogId; DWORD DataSize; BYTE Data[]; } MAPDATA, *PMAPDATA;
//
// Globals
//
static PCTSTR g_Mode; static BOOL g_Sandbox; static TCHAR g_ExePath16[MAX_TCHAR_PATH] = TEXT("sandbx16.exe"); static TCHAR g_ExePath32[MAX_TCHAR_PATH] = TEXT("sandbx32.exe");
//
// Macro expansion list
//
// None
//
// Private function prototypes
//
LRESULT CALLBACK pIpcMessageProc ( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
BOOL pCreateExchangeThread ( IN UINT Instance );
//
// Macro expansion definition
//
// None
//
// Code
//
BOOL SbInitialize ( IN BOOL SandboxProcess ) { WNDCLASS wc;
//
// Set the globals
//
g_Sandbox = SandboxProcess; g_Mode = SandboxProcess ? TEXT("Sandbox") : TEXT("HostProc"); g_ProcessHandle = NULL;
//
// Register the window class for message passing
//
ZeroMemory (&wc, sizeof (wc));
wc.lpfnWndProc = pIpcMessageProc; wc.hInstance = g_hInst; wc.lpszClassName = S_SBCLASS;
RegisterClass (&wc);
return TRUE; }
VOID pCloseIpcData ( IN OUT PIPCDATA IpcData ) { if (IpcData->Ack) { CloseHandle (IpcData->Ack); }
if (IpcData->Mapping) { CloseHandle (IpcData->Mapping); }
if (IpcData->ProcessHandle) { CloseHandle (IpcData->ProcessHandle); }
if (IpcData->File && IpcData->File != INVALID_HANDLE_VALUE) { CloseHandle (IpcData->File); }
if (IpcData->HostProcHwnd) { DestroyWindow (ipcData->HostProcHwnd); }
ZeroMemory (IpcData, sizeof (IPCDATA)); }
DWORD WINAPI pAckThread ( PVOID Arg ) { PIPCDATA ipcData = (PIPCDATA) Arg; MSG msg; HWND hwnd;
//
// Create a message-only hwnd
//
hwnd = CreateWindow ( S_SBCLASS, ipcData->WindowTitle, WS_POPUP, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, g_hInst, ipcData->Instance );
if (!hwnd) { LOG ((LOG_ERROR, "Failed to create host message window")); return 0; }
//
// Loop until the window is destroyed
//
while (GetMessage (&msg, hwnd, 0, 0)) {
DispatchMessage (&msg);
if (msg.message == WM_NCDESTROY) { break; } }
return 1; }
SBHANDLE SbCreateSandboxA ( IN PCSTR DllPath, IN PCSTR WorkingDir OPTIONAL ) { PSECURITY_DESCRIPTOR psd = NULL; SECURITY_ATTRIBUTES sa, *psa; BOOL result = FALSE; PIPCDATA ipcData = NULL; static UINT instance = 0; TCHAR objectName[64]; TCHAR cmdLine[MAX_TCHAR_PATH * 2]; BOOL win32; STARTUPINFOA si; PROCESS_INFORMATION pi; BOOL processResult; HANDLE objectArray[2]; UINT u; DWORD rc; TCHAR tempPath[MAX_TCHAR_PATH]; TCHAR tempFile[MAX_TCHAR_PATH];
__try { //
// TODO - need mutex to guard instance variable
// TODO - need to test instance variable against window title
// TODO - need to detect dll type
//
win32 = TRUE;
//
// Allocate an IPCDATA struct, then fill it in
//
ipcData = (PIPCDATA) MemAlloc (g_hHeap, HEAP_ZERO_MEMORY, sizeof (IPCDATA));
ipcData.Win32 = win32; ipcData.Instance = instance;
if (ISNT()) { //
// Create nul DACL for NT
//
ZeroMemory (&sa, sizeof (sa));
psd = (PSECURITY_DESCRIPTOR) MemAlloc (g_hHeap, 0, SECURITY_DESCRIPTOR_MIN_LENGTH);
if (!InitializeSecurityDescriptor (psd, SECURITY_DESCRIPTOR_REVISION)) { __leave; }
if (!SetSecurityDescriptorDacl (psd, TRUE, (PACL) NULL, FALSE)) { __leave; }
sa.nLength = sizeof (sa); sa.lpSecurityDescriptor = psd;
psa = &sa;
} else { psa = NULL; }
//
// Create the IPC objects: an event and a memory mapped file
//
ipcData->Ack = CreateEvent (psa, FALSE, FALSE, NULL);
wsprintf (objectName, TEXT("Sandbox%u.IpcData"), instance); ipcData->Mapping = CreateFileMapping ( INVALID_HANDLE_VALUE, psa, PAGE_READWRITE, 0, 0x10000, objectName );
if (!ipcData->Ack || !ipcData->Mapping) { LOG ((LOG_ERROR, "Can't create IPC objects")); __leave; }
//
// Create the ack window proc thread and have it wait for messages
//
wsprintf (ipcData->WindowTitle, TEXT("SandboxHost%u"), instance);
if (!pCreateExchangeThread()) { LOG ((LOG_ERROR, "Can't create ack thread")); __leave; }
//
// Launch the sandbox process
//
wsprintfA ( cmdLine, "\"%s\" -i:%u", win32 ? g_ExePath32 : g_ExePath16, instance );
ZeroMemory (&si, sizeof (si)); si.cb = sizeof (si); si.dwFlags = STARTF_FORCEOFFFEEDBACK;
processResult = CreateProcessA ( NULL, cmdLine, NULL, NULL, FALSE, CREATE_DEFAULT_ERROR_MODE, NULL, WorkingDir, &si, &pi );
if (!processResult) { LOG ((LOG_ERROR, "Cannot start %s", cmdLine)); __leave; }
CloseHandle (pi.hThread); ipcData->ProcessHandle = pi.hProcess;
//
// Wait for process to fail or wait for it to send an ack
//
objectArray[0] = ipcData->Ack; objectArray[1] = pi.hProcess; rc = WaitForMultipleObjects (2, objectArray, FALSE, 60000);
if (rc != WAIT_OBJECT_0) { DEBUGMSG (( DBG_WARNING, "Process %x did not signal 'ready'. Wait timed out. (%s)", g_ProcessHandle, g_Mode ));
LOG ((LOG_ERROR, "Failed to launch sandbox.")); __leave; }
//
// Launch was successful -- sandbox is now waiting for a command
//
DEBUGMSG ((DBG_SANDBOX, "Process %s is running (%s)", cmdLine, g_Mode));
instance++; result = TRUE; } __finally { //
// Cleanup code
//
PushError();
if (!result) { if (ipcData) { pCloseIpcData (ipcData); MemFree (g_hHeap, 0, ipcData); } }
if (psd) { MemFree (g_hHeap, 0, psd); }
PopError(); }
return result ? (SBHANDLE) ipcData : NULL; }
VOID SbDestroySandbox ( IN SBHANDLE SandboxHandle ) { PIPCDATA ipcData = (PIPCDATA) SandboxHandle; DWORD rc; COPYDATA copyData;
if (ipcData) { //
// Tell sandbox to close
//
if (ipcData->Win32) { //
// Turn off the ready event
//
MYASSERT (WAIT_OBJECT_0 == WaitForSingleObject (ipcData->ReadyEvent, 0));
ResetEvent (ipcData->ReadyEvent);
//
// Wait for the sandbox to close, kill it if necessary
//
rc = WaitForSingleObject (ipcData->ProcessHandle, 10000);
if (rc != WAIT_OBJECT_0) { TerminateProcess (ipcData->ProcessHandle, 0); }
} else {
//
// Send a shutdown message to the sandbox
//
ZeroMemory (©Data, sizeof (copyData));
copyData.dwData = SB_CLOSE;
SendMessage ( ipcData->SandboxHwnd, WM_COPYDATA, ipcData->HostProcHwnd, copyData );
//
// Wait for the sandbox to close, kill it if necessary
//
rc = WaitForSingleObject (ipcData->ProcessHandle, 10000);
if (rc != WAIT_OBJECT_0) { TerminateProcess (ipcData->ProcessHandle, 0); } }
//
// Clean up resources
//
pCloseIpcData (ipcData); MemFree (g_hHeap, 0, ipcData); } }
LRESULT CALLBACK pIpcMessageProc ( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { COPYDATASTRUCT *p;
switch (uMsg) {
case WM_COPYDATA: p = (COPYDATASTRUCT *) lParam; break; }
return DefWindowProc (hwnd, uMsg, wParam, lParam); }
BOOL pCreateExchangeThread ( IN UINT Instance ) { HANDLE thread;
thread = StartThread (pAckThread, (PVOID) Instance);
return thread != NULL; }
|