Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

519 lines
9.8 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. sandbox.c
  5. Abstract:
  6. Utilities to run code in isolated processes (sandbox apis).
  7. Author:
  8. Jim Schmidt (jimschm) 31-Jan-2000
  9. Revision History:
  10. --*/
  11. //
  12. // Includes
  13. //
  14. #include "pch.h"
  15. #include "utilsp.h"
  16. #define DBG_SANDBOX "Sandbox"
  17. //
  18. // Strings
  19. //
  20. // None
  21. //
  22. // Constants
  23. //
  24. #define S_SBCLASS TEXT("SandboxHost")
  25. //
  26. // Macros
  27. //
  28. // None
  29. //
  30. // Types
  31. //
  32. typedef struct {
  33. BOOL Win32;
  34. HANDLE Mapping;
  35. HANDLE Ack;
  36. UINT Instance;
  37. TCHAR WindowTitle[64];
  38. } IPCDATA, *PIPCDATA;
  39. typedef struct {
  40. DWORD Command;
  41. DWORD Result;
  42. DWORD TechnicalLogId;
  43. DWORD GuiLogId;
  44. DWORD DataSize;
  45. BYTE Data[];
  46. } MAPDATA, *PMAPDATA;
  47. //
  48. // Globals
  49. //
  50. static PCTSTR g_Mode;
  51. static BOOL g_Sandbox;
  52. static TCHAR g_ExePath16[MAX_TCHAR_PATH] = TEXT("sandbx16.exe");
  53. static TCHAR g_ExePath32[MAX_TCHAR_PATH] = TEXT("sandbx32.exe");
  54. //
  55. // Macro expansion list
  56. //
  57. // None
  58. //
  59. // Private function prototypes
  60. //
  61. LRESULT
  62. CALLBACK
  63. pIpcMessageProc (
  64. HWND hwnd,
  65. UINT uMsg,
  66. WPARAM wParam,
  67. LPARAM lParam
  68. );
  69. BOOL
  70. pCreateExchangeThread (
  71. IN UINT Instance
  72. );
  73. //
  74. // Macro expansion definition
  75. //
  76. // None
  77. //
  78. // Code
  79. //
  80. BOOL
  81. SbInitialize (
  82. IN BOOL SandboxProcess
  83. )
  84. {
  85. WNDCLASS wc;
  86. //
  87. // Set the globals
  88. //
  89. g_Sandbox = SandboxProcess;
  90. g_Mode = SandboxProcess ? TEXT("Sandbox") : TEXT("HostProc");
  91. g_ProcessHandle = NULL;
  92. //
  93. // Register the window class for message passing
  94. //
  95. ZeroMemory (&wc, sizeof (wc));
  96. wc.lpfnWndProc = pIpcMessageProc;
  97. wc.hInstance = g_hInst;
  98. wc.lpszClassName = S_SBCLASS;
  99. RegisterClass (&wc);
  100. return TRUE;
  101. }
  102. VOID
  103. pCloseIpcData (
  104. IN OUT PIPCDATA IpcData
  105. )
  106. {
  107. if (IpcData->Ack) {
  108. CloseHandle (IpcData->Ack);
  109. }
  110. if (IpcData->Mapping) {
  111. CloseHandle (IpcData->Mapping);
  112. }
  113. if (IpcData->ProcessHandle) {
  114. CloseHandle (IpcData->ProcessHandle);
  115. }
  116. if (IpcData->File && IpcData->File != INVALID_HANDLE_VALUE) {
  117. CloseHandle (IpcData->File);
  118. }
  119. if (IpcData->HostProcHwnd) {
  120. DestroyWindow (ipcData->HostProcHwnd);
  121. }
  122. ZeroMemory (IpcData, sizeof (IPCDATA));
  123. }
  124. DWORD
  125. WINAPI
  126. pAckThread (
  127. PVOID Arg
  128. )
  129. {
  130. PIPCDATA ipcData = (PIPCDATA) Arg;
  131. MSG msg;
  132. HWND hwnd;
  133. //
  134. // Create a message-only hwnd
  135. //
  136. hwnd = CreateWindow (
  137. S_SBCLASS,
  138. ipcData->WindowTitle,
  139. WS_POPUP,
  140. CW_USEDEFAULT,
  141. CW_USEDEFAULT,
  142. CW_USEDEFAULT,
  143. CW_USEDEFAULT,
  144. NULL,
  145. NULL,
  146. g_hInst,
  147. ipcData->Instance
  148. );
  149. if (!hwnd) {
  150. LOG ((LOG_ERROR, "Failed to create host message window"));
  151. return 0;
  152. }
  153. //
  154. // Loop until the window is destroyed
  155. //
  156. while (GetMessage (&msg, hwnd, 0, 0)) {
  157. DispatchMessage (&msg);
  158. if (msg.message == WM_NCDESTROY) {
  159. break;
  160. }
  161. }
  162. return 1;
  163. }
  164. SBHANDLE
  165. SbCreateSandboxA (
  166. IN PCSTR DllPath,
  167. IN PCSTR WorkingDir OPTIONAL
  168. )
  169. {
  170. PSECURITY_DESCRIPTOR psd = NULL;
  171. SECURITY_ATTRIBUTES sa, *psa;
  172. BOOL result = FALSE;
  173. PIPCDATA ipcData = NULL;
  174. static UINT instance = 0;
  175. TCHAR objectName[64];
  176. TCHAR cmdLine[MAX_TCHAR_PATH * 2];
  177. BOOL win32;
  178. STARTUPINFOA si;
  179. PROCESS_INFORMATION pi;
  180. BOOL processResult;
  181. HANDLE objectArray[2];
  182. UINT u;
  183. DWORD rc;
  184. TCHAR tempPath[MAX_TCHAR_PATH];
  185. TCHAR tempFile[MAX_TCHAR_PATH];
  186. __try {
  187. //
  188. // TODO - need mutex to guard instance variable
  189. // TODO - need to test instance variable against window title
  190. // TODO - need to detect dll type
  191. //
  192. win32 = TRUE;
  193. //
  194. // Allocate an IPCDATA struct, then fill it in
  195. //
  196. ipcData = (PIPCDATA) MemAlloc (g_hHeap, HEAP_ZERO_MEMORY, sizeof (IPCDATA));
  197. ipcData.Win32 = win32;
  198. ipcData.Instance = instance;
  199. if (ISNT()) {
  200. //
  201. // Create nul DACL for NT
  202. //
  203. ZeroMemory (&sa, sizeof (sa));
  204. psd = (PSECURITY_DESCRIPTOR) MemAlloc (g_hHeap, 0, SECURITY_DESCRIPTOR_MIN_LENGTH);
  205. if (!InitializeSecurityDescriptor (psd, SECURITY_DESCRIPTOR_REVISION)) {
  206. __leave;
  207. }
  208. if (!SetSecurityDescriptorDacl (psd, TRUE, (PACL) NULL, FALSE)) {
  209. __leave;
  210. }
  211. sa.nLength = sizeof (sa);
  212. sa.lpSecurityDescriptor = psd;
  213. psa = &sa;
  214. } else {
  215. psa = NULL;
  216. }
  217. //
  218. // Create the IPC objects: an event and a memory mapped file
  219. //
  220. ipcData->Ack = CreateEvent (psa, FALSE, FALSE, NULL);
  221. wsprintf (objectName, TEXT("Sandbox%u.IpcData"), instance);
  222. ipcData->Mapping = CreateFileMapping (
  223. INVALID_HANDLE_VALUE,
  224. psa,
  225. PAGE_READWRITE,
  226. 0,
  227. 0x10000,
  228. objectName
  229. );
  230. if (!ipcData->Ack || !ipcData->Mapping) {
  231. LOG ((LOG_ERROR, "Can't create IPC objects"));
  232. __leave;
  233. }
  234. //
  235. // Create the ack window proc thread and have it wait for messages
  236. //
  237. wsprintf (ipcData->WindowTitle, TEXT("SandboxHost%u"), instance);
  238. if (!pCreateExchangeThread()) {
  239. LOG ((LOG_ERROR, "Can't create ack thread"));
  240. __leave;
  241. }
  242. //
  243. // Launch the sandbox process
  244. //
  245. wsprintfA (
  246. cmdLine,
  247. "\"%s\" -i:%u",
  248. win32 ? g_ExePath32 : g_ExePath16,
  249. instance
  250. );
  251. ZeroMemory (&si, sizeof (si));
  252. si.cb = sizeof (si);
  253. si.dwFlags = STARTF_FORCEOFFFEEDBACK;
  254. processResult = CreateProcessA (
  255. NULL,
  256. cmdLine,
  257. NULL,
  258. NULL,
  259. FALSE,
  260. CREATE_DEFAULT_ERROR_MODE,
  261. NULL,
  262. WorkingDir,
  263. &si,
  264. &pi
  265. );
  266. if (!processResult) {
  267. LOG ((LOG_ERROR, "Cannot start %s", cmdLine));
  268. __leave;
  269. }
  270. CloseHandle (pi.hThread);
  271. ipcData->ProcessHandle = pi.hProcess;
  272. //
  273. // Wait for process to fail or wait for it to send an ack
  274. //
  275. objectArray[0] = ipcData->Ack;
  276. objectArray[1] = pi.hProcess;
  277. rc = WaitForMultipleObjects (2, objectArray, FALSE, 60000);
  278. if (rc != WAIT_OBJECT_0) {
  279. DEBUGMSG ((
  280. DBG_WARNING,
  281. "Process %x did not signal 'ready'. Wait timed out. (%s)",
  282. g_ProcessHandle,
  283. g_Mode
  284. ));
  285. LOG ((LOG_ERROR, "Failed to launch sandbox."));
  286. __leave;
  287. }
  288. //
  289. // Launch was successful -- sandbox is now waiting for a command
  290. //
  291. DEBUGMSG ((DBG_SANDBOX, "Process %s is running (%s)", cmdLine, g_Mode));
  292. instance++;
  293. result = TRUE;
  294. }
  295. __finally {
  296. //
  297. // Cleanup code
  298. //
  299. PushError();
  300. if (!result) {
  301. if (ipcData) {
  302. pCloseIpcData (ipcData);
  303. MemFree (g_hHeap, 0, ipcData);
  304. }
  305. }
  306. if (psd) {
  307. MemFree (g_hHeap, 0, psd);
  308. }
  309. PopError();
  310. }
  311. return result ? (SBHANDLE) ipcData : NULL;
  312. }
  313. VOID
  314. SbDestroySandbox (
  315. IN SBHANDLE SandboxHandle
  316. )
  317. {
  318. PIPCDATA ipcData = (PIPCDATA) SandboxHandle;
  319. DWORD rc;
  320. COPYDATA copyData;
  321. if (ipcData) {
  322. //
  323. // Tell sandbox to close
  324. //
  325. if (ipcData->Win32) {
  326. //
  327. // Turn off the ready event
  328. //
  329. MYASSERT (WAIT_OBJECT_0 == WaitForSingleObject (ipcData->ReadyEvent, 0));
  330. ResetEvent (ipcData->ReadyEvent);
  331. //
  332. // Wait for the sandbox to close, kill it if necessary
  333. //
  334. rc = WaitForSingleObject (ipcData->ProcessHandle, 10000);
  335. if (rc != WAIT_OBJECT_0) {
  336. TerminateProcess (ipcData->ProcessHandle, 0);
  337. }
  338. } else {
  339. //
  340. // Send a shutdown message to the sandbox
  341. //
  342. ZeroMemory (&copyData, sizeof (copyData));
  343. copyData.dwData = SB_CLOSE;
  344. SendMessage (
  345. ipcData->SandboxHwnd,
  346. WM_COPYDATA,
  347. ipcData->HostProcHwnd,
  348. copyData
  349. );
  350. //
  351. // Wait for the sandbox to close, kill it if necessary
  352. //
  353. rc = WaitForSingleObject (ipcData->ProcessHandle, 10000);
  354. if (rc != WAIT_OBJECT_0) {
  355. TerminateProcess (ipcData->ProcessHandle, 0);
  356. }
  357. }
  358. //
  359. // Clean up resources
  360. //
  361. pCloseIpcData (ipcData);
  362. MemFree (g_hHeap, 0, ipcData);
  363. }
  364. }
  365. LRESULT
  366. CALLBACK
  367. pIpcMessageProc (
  368. HWND hwnd,
  369. UINT uMsg,
  370. WPARAM wParam,
  371. LPARAM lParam
  372. )
  373. {
  374. COPYDATASTRUCT *p;
  375. switch (uMsg) {
  376. case WM_COPYDATA:
  377. p = (COPYDATASTRUCT *) lParam;
  378. break;
  379. }
  380. return DefWindowProc (hwnd, uMsg, wParam, lParam);
  381. }
  382. BOOL
  383. pCreateExchangeThread (
  384. IN UINT Instance
  385. )
  386. {
  387. HANDLE thread;
  388. thread = StartThread (pAckThread, (PVOID) Instance);
  389. return thread != NULL;
  390. }