windows-nt/Source/XPSP1/NT/windows/winstate/cobra/utils/sandbox/sandbox.c

520 lines
9.8 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
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 (&copyData, 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;
}