520 lines
9.8 KiB
C
520 lines
9.8 KiB
C
|
/*++
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
|