/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ /* vim: set sts=2 sw=2 et tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; if (typeof Components !== "undefined") { /* global OS */ Cc["@mozilla.org/net/osfileconstantsservice;1"] .getService(Ci.nsIOSFileConstantsService) .init(); } /* exported LIBC, Win, createPipe, libc, win32 */ // ctypes is either already available in the chrome worker scope, or defined // in scope via loadSubScript. /* global ctypes */ // This file is loaded into the same scope as subprocess_shared.js. /* import-globals-from subprocess_shared.js */ const LIBC = OS.Constants.libc; const Win = OS.Constants.Win; const LIBC_CHOICES = ["kernel32.dll"]; var win32 = { // On Windows 64, winapi_abi is an alias for default_abi. WINAPI: ctypes.winapi_abi, VOID: ctypes.void_t, BYTE: ctypes.uint8_t, WORD: ctypes.uint16_t, DWORD: ctypes.uint32_t, LONG: ctypes.long, LARGE_INTEGER: ctypes.int64_t, ULONGLONG: ctypes.uint64_t, UINT: ctypes.unsigned_int, UCHAR: ctypes.unsigned_char, BOOL: ctypes.bool, HANDLE: ctypes.voidptr_t, PVOID: ctypes.voidptr_t, LPVOID: ctypes.voidptr_t, CHAR: ctypes.char, WCHAR: ctypes.jschar, ULONG_PTR: ctypes.uintptr_t, SIZE_T: ctypes.size_t, PSIZE_T: ctypes.size_t.ptr, }; Object.assign(win32, { DWORD_PTR: win32.ULONG_PTR, LPSTR: win32.CHAR.ptr, LPWSTR: win32.WCHAR.ptr, LPBYTE: win32.BYTE.ptr, LPDWORD: win32.DWORD.ptr, LPHANDLE: win32.HANDLE.ptr, // This is an opaque type. PROC_THREAD_ATTRIBUTE_LIST: ctypes.char.array(), LPPROC_THREAD_ATTRIBUTE_LIST: ctypes.char.ptr, }); Object.assign(win32, { LPCSTR: win32.LPSTR, LPCWSTR: win32.LPWSTR, LPCVOID: win32.LPVOID, }); Object.assign(win32, { INVALID_HANDLE_VALUE: ctypes.cast(ctypes.int64_t(-1), win32.HANDLE), NULL_HANDLE_VALUE: ctypes.cast(ctypes.uintptr_t(0), win32.HANDLE), CREATE_SUSPENDED: 0x00000004, CREATE_NEW_CONSOLE: 0x00000010, CREATE_UNICODE_ENVIRONMENT: 0x00000400, CREATE_NO_WINDOW: 0x08000000, CREATE_BREAKAWAY_FROM_JOB: 0x01000000, EXTENDED_STARTUPINFO_PRESENT: 0x00080000, STARTF_USESTDHANDLES: 0x0100, DUPLICATE_CLOSE_SOURCE: 0x01, DUPLICATE_SAME_ACCESS: 0x02, ERROR_HANDLE_EOF: 38, ERROR_BROKEN_PIPE: 109, ERROR_INSUFFICIENT_BUFFER: 122, FILE_FLAG_OVERLAPPED: 0x40000000, PIPE_TYPE_BYTE: 0x00, PIPE_ACCESS_INBOUND: 0x01, PIPE_ACCESS_OUTBOUND: 0x02, PIPE_ACCESS_DUPLEX: 0x03, PIPE_WAIT: 0x00, PIPE_NOWAIT: 0x01, STILL_ACTIVE: 259, PROC_THREAD_ATTRIBUTE_HANDLE_LIST: 0x00020002, JobObjectBasicLimitInformation: 2, JobObjectExtendedLimitInformation: 9, JOB_OBJECT_LIMIT_BREAKAWAY_OK: 0x00000800, // These constants are 32-bit unsigned integers, but Windows defines // them as negative integers cast to an unsigned type. STD_INPUT_HANDLE: -10 + 0x100000000, STD_OUTPUT_HANDLE: -11 + 0x100000000, STD_ERROR_HANDLE: -12 + 0x100000000, WAIT_TIMEOUT: 0x00000102, WAIT_FAILED: 0xffffffff, }); Object.assign(win32, { JOBOBJECT_BASIC_LIMIT_INFORMATION: new ctypes.StructType( "JOBOBJECT_BASIC_LIMIT_INFORMATION", [ { PerProcessUserTimeLimit: win32.LARGE_INTEGER }, { PerJobUserTimeLimit: win32.LARGE_INTEGER }, { LimitFlags: win32.DWORD }, { MinimumWorkingSetSize: win32.SIZE_T }, { MaximumWorkingSetSize: win32.SIZE_T }, { ActiveProcessLimit: win32.DWORD }, { Affinity: win32.ULONG_PTR }, { PriorityClass: win32.DWORD }, { SchedulingClass: win32.DWORD }, ] ), IO_COUNTERS: new ctypes.StructType("IO_COUNTERS", [ { ReadOperationCount: win32.ULONGLONG }, { WriteOperationCount: win32.ULONGLONG }, { OtherOperationCount: win32.ULONGLONG }, { ReadTransferCount: win32.ULONGLONG }, { WriteTransferCount: win32.ULONGLONG }, { OtherTransferCount: win32.ULONGLONG }, ]), }); Object.assign(win32, { JOBOBJECT_EXTENDED_LIMIT_INFORMATION: new ctypes.StructType( "JOBOBJECT_EXTENDED_LIMIT_INFORMATION", [ { BasicLimitInformation: win32.JOBOBJECT_BASIC_LIMIT_INFORMATION }, { IoInfo: win32.IO_COUNTERS }, { ProcessMemoryLimit: win32.SIZE_T }, { JobMemoryLimit: win32.SIZE_T }, { PeakProcessMemoryUsed: win32.SIZE_T }, { PeakJobMemoryUsed: win32.SIZE_T }, ] ), OVERLAPPED: new ctypes.StructType("OVERLAPPED", [ { Internal: win32.ULONG_PTR }, { InternalHigh: win32.ULONG_PTR }, { Offset: win32.DWORD }, { OffsetHigh: win32.DWORD }, { hEvent: win32.HANDLE }, ]), PROCESS_INFORMATION: new ctypes.StructType("PROCESS_INFORMATION", [ { hProcess: win32.HANDLE }, { hThread: win32.HANDLE }, { dwProcessId: win32.DWORD }, { dwThreadId: win32.DWORD }, ]), SECURITY_ATTRIBUTES: new ctypes.StructType("SECURITY_ATTRIBUTES", [ { nLength: win32.DWORD }, { lpSecurityDescriptor: win32.LPVOID }, { bInheritHandle: win32.BOOL }, ]), STARTUPINFOW: new ctypes.StructType("STARTUPINFOW", [ { cb: win32.DWORD }, { lpReserved: win32.LPWSTR }, { lpDesktop: win32.LPWSTR }, { lpTitle: win32.LPWSTR }, { dwX: win32.DWORD }, { dwY: win32.DWORD }, { dwXSize: win32.DWORD }, { dwYSize: win32.DWORD }, { dwXCountChars: win32.DWORD }, { dwYCountChars: win32.DWORD }, { dwFillAttribute: win32.DWORD }, { dwFlags: win32.DWORD }, { wShowWindow: win32.WORD }, { cbReserved2: win32.WORD }, { lpReserved2: win32.LPBYTE }, { hStdInput: win32.HANDLE }, { hStdOutput: win32.HANDLE }, { hStdError: win32.HANDLE }, ]), }); Object.assign(win32, { STARTUPINFOEXW: new ctypes.StructType("STARTUPINFOEXW", [ { StartupInfo: win32.STARTUPINFOW }, { lpAttributeList: win32.LPPROC_THREAD_ATTRIBUTE_LIST }, ]), }); var libc = new Library("libc", LIBC_CHOICES, { AssignProcessToJobObject: [ win32.WINAPI, win32.BOOL, win32.HANDLE /* hJob */, win32.HANDLE /* hProcess */, ], CloseHandle: [win32.WINAPI, win32.BOOL, win32.HANDLE /* hObject */], CreateEventW: [ win32.WINAPI, win32.HANDLE, win32.SECURITY_ATTRIBUTES.ptr /* opt lpEventAttributes */, win32.BOOL /* bManualReset */, win32.BOOL /* bInitialState */, win32.LPWSTR /* lpName */, ], CreateFileW: [ win32.WINAPI, win32.HANDLE, win32.LPWSTR /* lpFileName */, win32.DWORD /* dwDesiredAccess */, win32.DWORD /* dwShareMode */, win32.SECURITY_ATTRIBUTES.ptr /* opt lpSecurityAttributes */, win32.DWORD /* dwCreationDisposition */, win32.DWORD /* dwFlagsAndAttributes */, win32.HANDLE /* opt hTemplateFile */, ], CreateJobObjectW: [ win32.WINAPI, win32.HANDLE, win32.SECURITY_ATTRIBUTES.ptr /* opt lpJobAttributes */, win32.LPWSTR /* lpName */, ], CreateNamedPipeW: [ win32.WINAPI, win32.HANDLE, win32.LPWSTR /* lpName */, win32.DWORD /* dwOpenMode */, win32.DWORD /* dwPipeMode */, win32.DWORD /* nMaxInstances */, win32.DWORD /* nOutBufferSize */, win32.DWORD /* nInBufferSize */, win32.DWORD /* nDefaultTimeOut */, win32.SECURITY_ATTRIBUTES.ptr /* opt lpSecurityAttributes */, ], CreatePipe: [ win32.WINAPI, win32.BOOL, win32.LPHANDLE /* out hReadPipe */, win32.LPHANDLE /* out hWritePipe */, win32.SECURITY_ATTRIBUTES.ptr /* opt lpPipeAttributes */, win32.DWORD /* nSize */, ], CreateProcessW: [ win32.WINAPI, win32.BOOL, win32.LPCWSTR /* lpApplicationName */, win32.LPWSTR /* lpCommandLine */, win32.SECURITY_ATTRIBUTES.ptr /* lpProcessAttributes */, win32.SECURITY_ATTRIBUTES.ptr /* lpThreadAttributes */, win32.BOOL /* bInheritHandle */, win32.DWORD /* dwCreationFlags */, win32.LPVOID /* opt lpEnvironment */, win32.LPCWSTR /* opt lpCurrentDirectory */, win32.STARTUPINFOW.ptr /* lpStartupInfo */, win32.PROCESS_INFORMATION.ptr /* out lpProcessInformation */, ], CreateSemaphoreW: [ win32.WINAPI, win32.HANDLE, win32.SECURITY_ATTRIBUTES.ptr /* opt lpSemaphoreAttributes */, win32.LONG /* lInitialCount */, win32.LONG /* lMaximumCount */, win32.LPCWSTR /* opt lpName */, ], DeleteProcThreadAttributeList: [ win32.WINAPI, win32.VOID, win32.LPPROC_THREAD_ATTRIBUTE_LIST /* in/out lpAttributeList */, ], DuplicateHandle: [ win32.WINAPI, win32.BOOL, win32.HANDLE /* hSourceProcessHandle */, win32.HANDLE /* hSourceHandle */, win32.HANDLE /* hTargetProcessHandle */, win32.LPHANDLE /* out lpTargetHandle */, win32.DWORD /* dwDesiredAccess */, win32.BOOL /* bInheritHandle */, win32.DWORD /* dwOptions */, ], FreeEnvironmentStringsW: [ win32.WINAPI, win32.BOOL, win32.LPCWSTR /* lpszEnvironmentBlock */, ], GetCurrentProcess: [win32.WINAPI, win32.HANDLE], GetCurrentProcessId: [win32.WINAPI, win32.DWORD], GetEnvironmentStringsW: [win32.WINAPI, win32.LPCWSTR], GetExitCodeProcess: [ win32.WINAPI, win32.BOOL, win32.HANDLE /* hProcess */, win32.LPDWORD /* lpExitCode */, ], GetOverlappedResult: [ win32.WINAPI, win32.BOOL, win32.HANDLE /* hFile */, win32.OVERLAPPED.ptr /* lpOverlapped */, win32.LPDWORD /* lpNumberOfBytesTransferred */, win32.BOOL /* bWait */, ], GetStdHandle: [win32.WINAPI, win32.HANDLE, win32.DWORD /* nStdHandle */], InitializeProcThreadAttributeList: [ win32.WINAPI, win32.BOOL, win32.LPPROC_THREAD_ATTRIBUTE_LIST /* out opt lpAttributeList */, win32.DWORD /* dwAttributeCount */, win32.DWORD /* dwFlags */, win32.PSIZE_T /* in/out lpSize */, ], ReadFile: [ win32.WINAPI, win32.BOOL, win32.HANDLE /* hFile */, win32.LPVOID /* out lpBuffer */, win32.DWORD /* nNumberOfBytesToRead */, win32.LPDWORD /* opt out lpNumberOfBytesRead */, win32.OVERLAPPED.ptr /* opt in/out lpOverlapped */, ], ReleaseSemaphore: [ win32.WINAPI, win32.BOOL, win32.HANDLE /* hSemaphore */, win32.LONG /* lReleaseCount */, win32.LONG.ptr /* opt out lpPreviousCount */, ], ResumeThread: [win32.WINAPI, win32.DWORD, win32.HANDLE /* hThread */], SetInformationJobObject: [ win32.WINAPI, win32.BOOL, win32.HANDLE /* hJob */, ctypes.int /* JobObjectInfoClass */, win32.LPVOID /* lpJobObjectInfo */, win32.DWORD /* cbJobObjectInfoLengt */, ], TerminateJobObject: [ win32.WINAPI, win32.BOOL, win32.HANDLE /* hJob */, win32.UINT /* uExitCode */, ], TerminateProcess: [ win32.WINAPI, win32.BOOL, win32.HANDLE /* hProcess */, win32.UINT /* uExitCode */, ], UpdateProcThreadAttribute: [ win32.WINAPI, win32.BOOL, win32.LPPROC_THREAD_ATTRIBUTE_LIST /* in/out lpAttributeList */, win32.DWORD /* dwFlags */, win32.DWORD_PTR /* Attribute */, win32.PVOID /* lpValue */, win32.SIZE_T /* cbSize */, win32.PVOID /* out opt lpPreviousValue */, win32.PSIZE_T /* opt lpReturnSize */, ], WaitForMultipleObjects: [ win32.WINAPI, win32.DWORD, win32.DWORD /* nCount */, win32.HANDLE.ptr /* hHandles */, win32.BOOL /* bWaitAll */, win32.DWORD /* dwMilliseconds */, ], WaitForSingleObject: [ win32.WINAPI, win32.DWORD, win32.HANDLE /* hHandle */, win32.BOOL /* bWaitAll */, win32.DWORD /* dwMilliseconds */, ], WriteFile: [ win32.WINAPI, win32.BOOL, win32.HANDLE /* hFile */, win32.LPCVOID /* lpBuffer */, win32.DWORD /* nNumberOfBytesToRead */, win32.LPDWORD /* opt out lpNumberOfBytesWritten */, win32.OVERLAPPED.ptr /* opt in/out lpOverlapped */, ], }); let nextNamedPipeId = 0; win32.Handle = function (handle) { return ctypes.CDataFinalizer(win32.HANDLE(handle), libc.CloseHandle); }; win32.createPipe = function (secAttr, readFlags = 0, writeFlags = 0, size = 0) { readFlags |= win32.PIPE_ACCESS_INBOUND; writeFlags |= Win.FILE_ATTRIBUTE_NORMAL; if (size == 0) { size = 4096; } let pid = libc.GetCurrentProcessId(); let pipeName = String.raw`\\.\Pipe\SubProcessPipe.${pid}.${nextNamedPipeId++}`; let readHandle = libc.CreateNamedPipeW( pipeName, readFlags, win32.PIPE_TYPE_BYTE | win32.PIPE_WAIT, 1 /* number of connections */, size /* output buffer size */, size /* input buffer size */, 0 /* timeout */, secAttr.address() ); let isInvalid = handle => String(handle) == String(win32.HANDLE(Win.INVALID_HANDLE_VALUE)); if (isInvalid(readHandle)) { return []; } let writeHandle = libc.CreateFileW( pipeName, Win.GENERIC_WRITE, 0, secAttr.address(), Win.OPEN_EXISTING, writeFlags, null ); if (isInvalid(writeHandle)) { libc.CloseHandle(readHandle); return []; } return [win32.Handle(readHandle), win32.Handle(writeHandle)]; }; win32.createThreadAttributeList = function (handles) { try { void libc.InitializeProcThreadAttributeList; void libc.DeleteProcThreadAttributeList; void libc.UpdateProcThreadAttribute; } catch (e) { // This is only supported in Windows Vista and later. return null; } let size = win32.SIZE_T(); if ( !libc.InitializeProcThreadAttributeList(null, 1, 0, size.address()) && ctypes.winLastError != win32.ERROR_INSUFFICIENT_BUFFER ) { return null; } let attrList = win32.PROC_THREAD_ATTRIBUTE_LIST(size.value); if (!libc.InitializeProcThreadAttributeList(attrList, 1, 0, size.address())) { return null; } let ok = libc.UpdateProcThreadAttribute( attrList, 0, win32.PROC_THREAD_ATTRIBUTE_HANDLE_LIST, handles, handles.constructor.size, null, null ); if (!ok) { libc.DeleteProcThreadAttributeList(attrList); return null; } return attrList; };