From f8a86cffd8f1d5a1ec5d5ad509122aea413b3939 Mon Sep 17 00:00:00 2001 From: "ananta@chromium.org" Date: Fri, 25 Oct 2013 18:46:20 +0000 Subject: [PATCH] Attempt3 at landing this. The previous attempt failed on Windows XP because the \Sessions\Session id\BaseNamedObjects path does not always exist on Windows XP. It only exists for terminal server sessions. Relanding this with fixes for the SyncPolicyTest.TestEvent and SyncPolicyTest.TestEventReadOnly tests. Replace the CreateEvent/OpenEvent patches with their Nt counterparts like NtOpenEvent and NtCreateEvent. Reason being :- We patch these APIS via the Export table patch which does not work with bound imports. This results in our patched functions never getting called. This should fix the GPU process hang with the XP presentation path. The change from the previous patch is to resolve the BaseNamedObjects path via the \Sessions\BNOLinks directory which contains the BaseNamedObjects symbolic links for the running sessions BUG=305815 R=cpu@chromium.org, rvargas@chromium.org, cpu, rvargas Review URL: https://codereview.chromium.org/41193002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@231063 0039d316-1c4b-4281-b951-d872f2087c98 --- sandbox/win/src/interceptors.h | 6 +- sandbox/win/src/interceptors_64.cc | 43 ++--- sandbox/win/src/interceptors_64.h | 26 ++- sandbox/win/src/nt_internals.h | 26 +++ sandbox/win/src/sync_dispatcher.cc | 36 ++--- sandbox/win/src/sync_dispatcher.h | 5 +- sandbox/win/src/sync_interception.cc | 234 ++++++++++++--------------- sandbox/win/src/sync_interception.h | 75 +++------ sandbox/win/src/sync_policy.cc | 169 +++++++++++++++++-- sandbox/win/src/sync_policy.h | 3 +- 10 files changed, 350 insertions(+), 273 deletions(-) diff --git a/sandbox/win/src/interceptors.h b/sandbox/win/src/interceptors.h index 2e6dc8ddcb0bf3..43126d005ac85e 100644 --- a/sandbox/win/src/interceptors.h +++ b/sandbox/win/src/interceptors.h @@ -39,10 +39,8 @@ enum InterceptorId { OPEN_KEY_ID, OPEN_KEY_EX_ID, // Sync dispatcher: - CREATE_EVENTW_ID, - CREATE_EVENTA_ID, - OPEN_EVENTW_ID, - OPEN_EVENTA_ID, + CREATE_EVENT_ID, + OPEN_EVENT_ID, // CSRSS bypasses for HandleCloser: CREATE_THREAD_ID, GET_USER_DEFAULT_LCID_ID, diff --git a/sandbox/win/src/interceptors_64.cc b/sandbox/win/src/interceptors_64.cc index a36373279a6c5e..c71d5a2803dc1f 100644 --- a/sandbox/win/src/interceptors_64.cc +++ b/sandbox/win/src/interceptors_64.cc @@ -249,36 +249,23 @@ SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtOpenKeyEx64( // ----------------------------------------------------------------------- -SANDBOX_INTERCEPT HANDLE WINAPI TargetCreateEventW64( - LPSECURITY_ATTRIBUTES security_attributes, BOOL manual_reset, - BOOL initial_state, LPCWSTR name) { - CreateEventWFunction orig_fn = reinterpret_cast< - CreateEventWFunction>(g_originals[CREATE_EVENTW_ID]); - return TargetCreateEventW(orig_fn, security_attributes, manual_reset, - initial_state, name); +SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtCreateEvent64( + PHANDLE event_handle, ACCESS_MASK desired_access, + POBJECT_ATTRIBUTES object_attributes, EVENT_TYPE event_type, + BOOLEAN initial_state) { + NtCreateEventFunction orig_fn = reinterpret_cast< + NtCreateEventFunction>(g_originals[CREATE_EVENT_ID]); + return TargetNtCreateEvent(orig_fn, event_handle, desired_access, + object_attributes, event_type, initial_state); } -SANDBOX_INTERCEPT HANDLE WINAPI TargetCreateEventA64( - LPSECURITY_ATTRIBUTES security_attributes, BOOL manual_reset, - BOOL initial_state, LPCSTR name) { - CreateEventAFunction orig_fn = reinterpret_cast< - CreateEventAFunction>(g_originals[CREATE_EVENTA_ID]); - return TargetCreateEventA(orig_fn, security_attributes, manual_reset, - initial_state, name); -} - -SANDBOX_INTERCEPT HANDLE WINAPI TargetOpenEventW64( - DWORD desired_access, BOOL inherit_handle, LPCWSTR name) { - OpenEventWFunction orig_fn = reinterpret_cast< - OpenEventWFunction>(g_originals[OPEN_EVENTW_ID]); - return TargetOpenEventW(orig_fn, desired_access, inherit_handle, name); -} - -SANDBOX_INTERCEPT HANDLE WINAPI TargetOpenEventA64( - DWORD desired_access, BOOL inherit_handle, LPCSTR name) { - OpenEventAFunction orig_fn = reinterpret_cast< - OpenEventAFunction>(g_originals[OPEN_EVENTA_ID]); - return TargetOpenEventA(orig_fn, desired_access, inherit_handle, name); +SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtOpenEvent64( + PHANDLE event_handle, ACCESS_MASK desired_access, + POBJECT_ATTRIBUTES object_attributes) { + NtOpenEventFunction orig_fn = reinterpret_cast< + NtOpenEventFunction>(g_originals[OPEN_EVENT_ID]); + return TargetNtOpenEvent(orig_fn, event_handle, desired_access, + object_attributes); } } // namespace sandbox diff --git a/sandbox/win/src/interceptors_64.h b/sandbox/win/src/interceptors_64.h index 717fb6d6365409..ef2c10d412c3ad 100644 --- a/sandbox/win/src/interceptors_64.h +++ b/sandbox/win/src/interceptors_64.h @@ -153,23 +153,15 @@ SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtOpenKeyEx64( // ----------------------------------------------------------------------- // Interceptors handled by the sync dispatcher. -// Interception of CreateEventW on the child process. -SANDBOX_INTERCEPT HANDLE WINAPI TargetCreateEventW64( - LPSECURITY_ATTRIBUTES security_attributes, BOOL manual_reset, - BOOL initial_state, LPCWSTR name); - -// Interception of CreateEventA on the child process. -SANDBOX_INTERCEPT HANDLE WINAPI TargetCreateEventA64( - LPSECURITY_ATTRIBUTES security_attributes, BOOL manual_reset, - BOOL initial_state, LPCSTR name); - -// Interception of OpenEventW on the child process. -SANDBOX_INTERCEPT HANDLE WINAPI TargetOpenEventW64( - DWORD desired_access, BOOL inherit_handle, LPCWSTR name); - -// Interception of OpenEventA on the child process. -SANDBOX_INTERCEPT HANDLE WINAPI TargetOpenEventA64( - DWORD desired_access, BOOL inherit_handle, LPCSTR name); +// Interception of NtCreateEvent/NtOpenEvent on the child process. +SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtCreateEvent64( + PHANDLE event_handle, ACCESS_MASK desired_access, + POBJECT_ATTRIBUTES object_attributes, EVENT_TYPE event_type, + BOOLEAN initial_state); + +SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtOpenEvent64( + PHANDLE event_handle, ACCESS_MASK desired_access, + POBJECT_ATTRIBUTES object_attributes); } // extern "C" diff --git a/sandbox/win/src/nt_internals.h b/sandbox/win/src/nt_internals.h index c9aaf92732815e..1423be4937db7a 100644 --- a/sandbox/win/src/nt_internals.h +++ b/sandbox/win/src/nt_internals.h @@ -615,5 +615,31 @@ typedef VOID (WINAPI *RtlInitUnicodeStringFunction) ( IN OUT PUNICODE_STRING DestinationString, IN PCWSTR SourceString); +typedef enum _EVENT_TYPE { + NotificationEvent, + SynchronizationEvent +} EVENT_TYPE, *PEVENT_TYPE; + +typedef NTSTATUS (WINAPI* NtOpenDirectoryObjectFunction) ( + PHANDLE DirectoryHandle, + ACCESS_MASK DesiredAccess, + POBJECT_ATTRIBUTES ObjectAttributes); + +typedef NTSTATUS (WINAPI* NtQuerySymbolicLinkObjectFunction) ( + HANDLE LinkHandle, + PUNICODE_STRING LinkTarget, + PULONG ReturnedLength); + +typedef NTSTATUS (WINAPI* NtOpenSymbolicLinkObjectFunction) ( + PHANDLE LinkHandle, + ACCESS_MASK DesiredAccess, + POBJECT_ATTRIBUTES ObjectAttributes); + +#define DIRECTORY_QUERY 0x0001 +#define DIRECTORY_TRAVERSE 0x0002 +#define DIRECTORY_CREATE_OBJECT 0x0004 +#define DIRECTORY_CREATE_SUBDIRECTORY 0x0008 +#define DIRECTORY_ALL_ACCESS 0x000F + #endif // SANDBOX_WIN_SRC_NT_INTERNALS_H__ diff --git a/sandbox/win/src/sync_dispatcher.cc b/sandbox/win/src/sync_dispatcher.cc index 6897daccc319af..3769fc6c67db42 100644 --- a/sandbox/win/src/sync_dispatcher.cc +++ b/sandbox/win/src/sync_dispatcher.cc @@ -25,7 +25,7 @@ SyncDispatcher::SyncDispatcher(PolicyBase* policy_base) }; static const IPCCall open_params = { - {IPC_OPENEVENT_TAG, WCHAR_TYPE, ULONG_TYPE, ULONG_TYPE}, + {IPC_OPENEVENT_TAG, WCHAR_TYPE, ULONG_TYPE}, reinterpret_cast(&SyncDispatcher::OpenEvent) }; @@ -35,33 +35,16 @@ SyncDispatcher::SyncDispatcher(PolicyBase* policy_base) bool SyncDispatcher::SetupService(InterceptionManager* manager, int service) { - bool ret = false; - // We need to intercept kernelbase.dll on Windows 7 and beyond and - // kernel32.dll for earlier versions. - static const wchar_t* kWin32SyncDllName = - base::win::GetVersion() >= base::win::VERSION_WIN7 ? kKernelBasedllName : - kKerneldllName; - if (IPC_CREATEEVENT_TAG == service) { - ret = INTERCEPT_EAT(manager, kWin32SyncDllName, CreateEventW, - CREATE_EVENTW_ID, 20); - if (ret) { - ret = INTERCEPT_EAT(manager, kWin32SyncDllName, CreateEventA, - CREATE_EVENTA_ID, 20); - } + return INTERCEPT_NT(manager, NtCreateEvent, CREATE_EVENT_ID, 24); } else if (IPC_OPENEVENT_TAG == service) { - ret = INTERCEPT_EAT(manager, kWin32SyncDllName, OpenEventW, OPEN_EVENTW_ID, - 16); - if (ret) { - ret = INTERCEPT_EAT(manager, kWin32SyncDllName, OpenEventA, - OPEN_EVENTA_ID, 16); - } + return INTERCEPT_NT(manager, NtOpenEvent, OPEN_EVENT_ID, 16); } - return ret; + return false; } bool SyncDispatcher::CreateEvent(IPCInfo* ipc, std::wstring* name, - DWORD manual_reset, DWORD initial_state) { + DWORD event_type, DWORD initial_state) { const wchar_t* event_name = name->c_str(); CountedParameterSet params; params[NameBased::NAME] = ParamPickerMake(event_name); @@ -70,16 +53,16 @@ bool SyncDispatcher::CreateEvent(IPCInfo* ipc, std::wstring* name, params.GetBase()); HANDLE handle = NULL; DWORD ret = SyncPolicy::CreateEventAction(result, *ipc->client_info, *name, - manual_reset, initial_state, + event_type, initial_state, &handle); // Return operation status on the IPC. - ipc->return_info.win32_result = ret; + ipc->return_info.nt_status = ret; ipc->return_info.handle = handle; return true; } bool SyncDispatcher::OpenEvent(IPCInfo* ipc, std::wstring* name, - DWORD desired_access, DWORD inherit_handle) { + DWORD desired_access) { const wchar_t* event_name = name->c_str(); CountedParameterSet params; @@ -90,8 +73,7 @@ bool SyncDispatcher::OpenEvent(IPCInfo* ipc, std::wstring* name, params.GetBase()); HANDLE handle = NULL; DWORD ret = SyncPolicy::OpenEventAction(result, *ipc->client_info, *name, - desired_access, inherit_handle, - &handle); + desired_access, &handle); // Return operation status on the IPC. ipc->return_info.win32_result = ret; ipc->return_info.handle = handle; diff --git a/sandbox/win/src/sync_dispatcher.h b/sandbox/win/src/sync_dispatcher.h index 13c8b9d31a0aec..1d1b978c9ad552 100644 --- a/sandbox/win/src/sync_dispatcher.h +++ b/sandbox/win/src/sync_dispatcher.h @@ -22,12 +22,11 @@ class SyncDispatcher : public Dispatcher { private: // Processes IPC requests coming from calls to CreateEvent in the target. - bool CreateEvent(IPCInfo* ipc, std::wstring* name, DWORD manual_reset, + bool CreateEvent(IPCInfo* ipc, std::wstring* name, DWORD event_type, DWORD initial_state); // Processes IPC requests coming from calls to OpenEvent in the target. - bool OpenEvent(IPCInfo* ipc, std::wstring* name, DWORD desired_access, - DWORD inherit_handle); + bool OpenEvent(IPCInfo* ipc, std::wstring* name, DWORD desired_access); PolicyBase* policy_base_; DISALLOW_COPY_AND_ASSIGN(SyncDispatcher); diff --git a/sandbox/win/src/sync_interception.cc b/sandbox/win/src/sync_interception.cc index ddbcc054407897..cafbcb0cc5a760 100644 --- a/sandbox/win/src/sync_interception.cc +++ b/sandbox/win/src/sync_interception.cc @@ -17,33 +17,25 @@ namespace sandbox { ResultCode ProxyCreateEvent(LPCWSTR name, BOOL initial_state, - BOOL manual_reset, + EVENT_TYPE event_type, + void* ipc_memory, CrossCallReturn* answer) { - void* memory = GetGlobalIPCMemory(); - if (!memory) - return SBOX_ERROR_GENERIC; - CountedParameterSet params; params[NameBased::NAME] = ParamPickerMake(name); if (!QueryBroker(IPC_CREATEEVENT_TAG, params.GetBase())) return SBOX_ERROR_GENERIC; - SharedMemIPCClient ipc(memory); - ResultCode code = CrossCall(ipc, IPC_CREATEEVENT_TAG, name, manual_reset, + SharedMemIPCClient ipc(ipc_memory); + ResultCode code = CrossCall(ipc, IPC_CREATEEVENT_TAG, name, event_type, initial_state, answer); return code; } ResultCode ProxyOpenEvent(LPCWSTR name, ACCESS_MASK desired_access, - BOOL inherit_handle, + void* ipc_memory, CrossCallReturn* answer) { - void* memory = GetGlobalIPCMemory(); - if (!memory) - return SBOX_ERROR_GENERIC; - - uint32 inherit_handle_ipc = inherit_handle; CountedParameterSet params; params[OpenEventParams::NAME] = ParamPickerMake(name); params[OpenEventParams::ACCESS] = ParamPickerMake(desired_access); @@ -51,135 +43,119 @@ ResultCode ProxyOpenEvent(LPCWSTR name, if (!QueryBroker(IPC_OPENEVENT_TAG, params.GetBase())) return SBOX_ERROR_GENERIC; - SharedMemIPCClient ipc(memory); + SharedMemIPCClient ipc(ipc_memory); ResultCode code = CrossCall(ipc, IPC_OPENEVENT_TAG, name, desired_access, - inherit_handle_ipc, answer); + answer); return code; } -HANDLE WINAPI TargetCreateEventW(CreateEventWFunction orig_CreateEvent, - LPSECURITY_ATTRIBUTES security_attributes, - BOOL manual_reset, - BOOL initial_state, - LPCWSTR name) { - // Check if the process can create it first. - HANDLE handle = orig_CreateEvent(security_attributes, manual_reset, - initial_state, name); - if (handle || !name) - return handle; - - // We don't trust that the IPC can work this early. - if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled()) - return NULL; - - DWORD original_error = ::GetLastError(); - - CrossCallReturn answer = {0}; - ResultCode code = ProxyCreateEvent(name, initial_state, manual_reset, - &answer); - - if (code == SBOX_ALL_OK) { - ::SetLastError(answer.win32_result); - return answer.handle; - } - ::SetLastError(original_error); - return NULL; -} - -HANDLE WINAPI TargetCreateEventA(CreateEventAFunction orig_CreateEvent, - LPSECURITY_ATTRIBUTES security_attributes, - BOOL manual_reset, - BOOL initial_state, - LPCSTR name) { - // Check if the process can create it first. - HANDLE handle = orig_CreateEvent(security_attributes, manual_reset, - initial_state, name); - if (handle || !name) - return handle; - - // We don't trust that the IPC can work this early. - if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled()) - return NULL; - - DWORD original_error = ::GetLastError(); - - UNICODE_STRING* wide_name = AnsiToUnicode(name); - if (!wide_name) - return NULL; - - CrossCallReturn answer = {0}; - ResultCode code = ProxyCreateEvent(wide_name->Buffer, initial_state, - manual_reset, &answer); - operator delete(wide_name, NT_ALLOC); - - if (code == SBOX_ALL_OK) { - ::SetLastError(answer.win32_result); - return answer.handle; - } - ::SetLastError(original_error); - return NULL; -} - -// Interception of OpenEventW on the child process. -// It should never be called directly -HANDLE WINAPI TargetOpenEventW(OpenEventWFunction orig_OpenEvent, - DWORD desired_access, - BOOL inherit_handle, - LPCWSTR name) { - // Check if the process can open it first. - HANDLE handle = orig_OpenEvent(desired_access, inherit_handle, name); - if (handle || !name) - return handle; +NTSTATUS WINAPI TargetNtCreateEvent(NtCreateEventFunction orig_CreateEvent, + PHANDLE event_handle, + ACCESS_MASK desired_access, + POBJECT_ATTRIBUTES object_attributes, + EVENT_TYPE event_type, + BOOLEAN initial_state) { + NTSTATUS status = orig_CreateEvent(event_handle, desired_access, + object_attributes, event_type, + initial_state); + if (status != STATUS_ACCESS_DENIED || !object_attributes) + return status; // We don't trust that the IPC can work this early. if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled()) - return NULL; - - DWORD original_error = ::GetLastError(); - - CrossCallReturn answer = {0}; - - ResultCode code = ProxyOpenEvent(name, desired_access, inherit_handle, - &answer); - if (code == SBOX_ALL_OK) { - ::SetLastError(answer.win32_result); - return answer.handle; - } - ::SetLastError(original_error); - return NULL; + return status; + + do { + if (!ValidParameter(event_handle, sizeof(HANDLE), WRITE)) + break; + + void* memory = GetGlobalIPCMemory(); + if (memory == NULL) + break; + + OBJECT_ATTRIBUTES object_attribs_copy = *object_attributes; + // The RootDirectory points to BaseNamedObjects. We can ignore it. + object_attribs_copy.RootDirectory = NULL; + + wchar_t* name = NULL; + uint32 attributes = 0; + NTSTATUS ret = AllocAndCopyName(&object_attribs_copy, &name, &attributes, + NULL); + if (!NT_SUCCESS(ret) || name == NULL) + break; + + CrossCallReturn answer = {0}; + answer.nt_status = status; + ResultCode code = ProxyCreateEvent(name, initial_state, event_type, memory, + &answer); + operator delete(name, NT_ALLOC); + + if (code != SBOX_ALL_OK) { + status = answer.nt_status; + break; + } + __try { + *event_handle = answer.handle; + status = STATUS_SUCCESS; + } __except(EXCEPTION_EXECUTE_HANDLER) { + break; + } + } while (false); + + return status; } -HANDLE WINAPI TargetOpenEventA(OpenEventAFunction orig_OpenEvent, - DWORD desired_access, - BOOL inherit_handle, - LPCSTR name) { - // Check if the process can open it first. - HANDLE handle = orig_OpenEvent(desired_access, inherit_handle, name); - if (handle || !name) - return handle; +NTSTATUS WINAPI TargetNtOpenEvent(NtOpenEventFunction orig_OpenEvent, + PHANDLE event_handle, + ACCESS_MASK desired_access, + POBJECT_ATTRIBUTES object_attributes) { + NTSTATUS status = orig_OpenEvent(event_handle, desired_access, + object_attributes); + if (status != STATUS_ACCESS_DENIED || !object_attributes) + return status; // We don't trust that the IPC can work this early. if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled()) - return NULL; - - DWORD original_error = ::GetLastError(); - - UNICODE_STRING* wide_name = AnsiToUnicode(name); - if (!wide_name) - return NULL; - - CrossCallReturn answer = {0}; - ResultCode code = ProxyOpenEvent(wide_name->Buffer, desired_access, - inherit_handle, &answer); - operator delete(wide_name, NT_ALLOC); - - if (code == SBOX_ALL_OK) { - ::SetLastError(answer.win32_result); - return answer.handle; - } - ::SetLastError(original_error); - return NULL; + return status; + + do { + if (!ValidParameter(event_handle, sizeof(HANDLE), WRITE)) + break; + + void* memory = GetGlobalIPCMemory(); + if (memory == NULL) + break; + + OBJECT_ATTRIBUTES object_attribs_copy = *object_attributes; + // The RootDirectory points to BaseNamedObjects. We can ignore it. + object_attribs_copy.RootDirectory = NULL; + + wchar_t* name = NULL; + uint32 attributes = 0; + NTSTATUS ret = AllocAndCopyName(&object_attribs_copy, &name, &attributes, + NULL); + if (!NT_SUCCESS(ret) || name == NULL) + break; + + CrossCallReturn answer = {0}; + answer.nt_status = status; + ResultCode code = ProxyOpenEvent(name, desired_access, memory, &answer); + operator delete(name, NT_ALLOC); + + if (code != SBOX_ALL_OK) { + status = answer.nt_status; + break; + } + __try { + *event_handle = answer.handle; + status = STATUS_SUCCESS; + } __except(EXCEPTION_EXECUTE_HANDLER) { + break; + } + } while (false); + + return status; } } // namespace sandbox diff --git a/sandbox/win/src/sync_interception.h b/sandbox/win/src/sync_interception.h index 19790f7cdfc122..0f985a8edc852a 100644 --- a/sandbox/win/src/sync_interception.h +++ b/sandbox/win/src/sync_interception.h @@ -12,55 +12,32 @@ namespace sandbox { extern "C" { -typedef HANDLE (WINAPI *CreateEventWFunction) ( - LPSECURITY_ATTRIBUTES lpEventAttributes, - BOOL bManualReset, - BOOL bInitialState, - LPCWSTR lpName); - -typedef HANDLE (WINAPI *CreateEventAFunction) ( - LPSECURITY_ATTRIBUTES lpEventAttributes, - BOOL bManualReset, - BOOL bInitialState, - LPCSTR lpName); - -typedef HANDLE (WINAPI *OpenEventWFunction) ( - DWORD dwDesiredAccess, - BOOL bInitialState, - LPCWSTR lpName); - -typedef HANDLE (WINAPI *OpenEventAFunction) ( - DWORD dwDesiredAccess, - BOOL bInheritHandle, - LPCSTR lpName); - -// Interceptors for CreateEventW/A -SANDBOX_INTERCEPT HANDLE WINAPI TargetCreateEventW( - CreateEventWFunction orig_CreateEvent, - LPSECURITY_ATTRIBUTES security_attributes, - BOOL manual_reset, - BOOL initial_state, - LPCWSTR name); - -SANDBOX_INTERCEPT HANDLE WINAPI TargetCreateEventA( - CreateEventAFunction orig_CreateEvent, - LPSECURITY_ATTRIBUTES security_attributes, - BOOL manual_reset, - BOOL initial_state, - LPCSTR name); - -// Interceptors for OpenEventW/A -SANDBOX_INTERCEPT HANDLE WINAPI TargetOpenEventW( - OpenEventWFunction orig_OpenEvent, - DWORD desired_access, - BOOL inherit_handle, - LPCWSTR name); - -SANDBOX_INTERCEPT HANDLE WINAPI TargetOpenEventA( - OpenEventAFunction orig_OpenEvent, - DWORD desired_access, - BOOL inherit_handle, - LPCSTR name); +typedef NTSTATUS (WINAPI* NtCreateEventFunction) ( + PHANDLE EventHandle, + ACCESS_MASK DesiredAccess, + POBJECT_ATTRIBUTES ObjectAttributes, + EVENT_TYPE EventType, + BOOLEAN InitialState); + +typedef NTSTATUS (WINAPI *NtOpenEventFunction) ( + PHANDLE EventHandle, + ACCESS_MASK DesiredAccess, + POBJECT_ATTRIBUTES ObjectAttributes); + +// Interceptors for NtCreateEvent/NtOpenEvent +SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtCreateEvent( + NtCreateEventFunction orig_CreateEvent, + PHANDLE event_handle, + ACCESS_MASK desired_access, + POBJECT_ATTRIBUTES object_attributes, + EVENT_TYPE event_type, + BOOLEAN initial_state); + +SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtOpenEvent( + NtOpenEventFunction orig_OpenEvent, + PHANDLE event_handle, + ACCESS_MASK desired_access, + POBJECT_ATTRIBUTES object_attributes); } // extern "C" diff --git a/sandbox/win/src/sync_policy.cc b/sandbox/win/src/sync_policy.cc index 87ef0bdd15a2ec..e3b6530a143ddd 100644 --- a/sandbox/win/src/sync_policy.cc +++ b/sandbox/win/src/sync_policy.cc @@ -7,14 +7,129 @@ #include "sandbox/win/src/sync_policy.h" #include "base/logging.h" +#include "base/strings/stringprintf.h" #include "sandbox/win/src/ipc_tags.h" +#include "sandbox/win/src/nt_internals.h" #include "sandbox/win/src/policy_engine_opcodes.h" #include "sandbox/win/src/policy_params.h" #include "sandbox/win/src/sandbox_types.h" #include "sandbox/win/src/sandbox_utils.h" +#include "sandbox/win/src/sync_interception.h" +#include "sandbox/win/src/win_utils.h" namespace sandbox { +// Provides functionality to resolve a symbolic link within the object +// directory passed in. +NTSTATUS ResolveSymbolicLink(const std::wstring& directory_name, + const std::wstring& name, + std::wstring* target) { + NtOpenDirectoryObjectFunction NtOpenDirectoryObject = NULL; + ResolveNTFunctionPtr("NtOpenDirectoryObject", &NtOpenDirectoryObject); + + NtQuerySymbolicLinkObjectFunction NtQuerySymbolicLinkObject = NULL; + ResolveNTFunctionPtr("NtQuerySymbolicLinkObject", + &NtQuerySymbolicLinkObject); + + NtOpenSymbolicLinkObjectFunction NtOpenSymbolicLinkObject = NULL; + ResolveNTFunctionPtr("NtOpenSymbolicLinkObject", &NtOpenSymbolicLinkObject); + + NtCloseFunction NtClose = NULL; + ResolveNTFunctionPtr("NtClose", &NtClose); + + OBJECT_ATTRIBUTES symbolic_link_directory_attributes = {}; + UNICODE_STRING symbolic_link_directory_string = {}; + InitObjectAttribs(directory_name, OBJ_CASE_INSENSITIVE, NULL, + &symbolic_link_directory_attributes, + &symbolic_link_directory_string); + + HANDLE symbolic_link_directory = NULL; + NTSTATUS status = NtOpenDirectoryObject(&symbolic_link_directory, + DIRECTORY_QUERY, + &symbolic_link_directory_attributes); + if (status != STATUS_SUCCESS) { + DLOG(ERROR) << "Failed to open symbolic link directory. Error: " + << status; + return status; + } + + OBJECT_ATTRIBUTES symbolic_link_attributes = {}; + UNICODE_STRING name_string = {}; + InitObjectAttribs(name, OBJ_CASE_INSENSITIVE, symbolic_link_directory, + &symbolic_link_attributes, &name_string); + + HANDLE symbolic_link = NULL; + status = NtOpenSymbolicLinkObject(&symbolic_link, GENERIC_READ, + &symbolic_link_attributes); + NtClose(symbolic_link_directory); + if (status != STATUS_SUCCESS) { + DLOG(ERROR) << "Failed to open symbolic link Error: " << status; + return status; + } + + UNICODE_STRING target_path = {}; + unsigned long target_length = 0; + status = NtQuerySymbolicLinkObject(symbolic_link, &target_path, + &target_length); + if (status != STATUS_BUFFER_TOO_SMALL) { + NtClose(symbolic_link); + DLOG(ERROR) << "Failed to get length for symbolic link target. Error: " + << status; + return status; + } + + target_path.Buffer = new wchar_t[target_length + 1]; + target_path.Length = 0; + target_path.MaximumLength = target_length; + status = NtQuerySymbolicLinkObject(symbolic_link, &target_path, + &target_length); + if (status == STATUS_SUCCESS) { + target->assign(target_path.Buffer, target_length); + } else { + DLOG(ERROR) << "Failed to resolve symbolic link. Error: " << status; + } + + NtClose(symbolic_link); + delete[] target_path.Buffer; + return status; +} + +NTSTATUS GetBaseNamedObjectsDirectory(HANDLE* directory) { + static HANDLE base_named_objects_handle = NULL; + if (base_named_objects_handle) { + *directory = base_named_objects_handle; + return STATUS_SUCCESS; + } + + NtOpenDirectoryObjectFunction NtOpenDirectoryObject = NULL; + ResolveNTFunctionPtr("NtOpenDirectoryObject", &NtOpenDirectoryObject); + + DWORD session_id = 0; + ProcessIdToSessionId(::GetCurrentProcessId(), &session_id); + + std::wstring base_named_objects_path; + + NTSTATUS status = ResolveSymbolicLink(L"\\Sessions\\BNOLINKS", + base::StringPrintf(L"%d", session_id), + &base_named_objects_path); + if (status != STATUS_SUCCESS) { + DLOG(ERROR) << "Failed to resolve BaseNamedObjects path. Error: " + << status; + return status; + } + + UNICODE_STRING directory_name = {}; + OBJECT_ATTRIBUTES object_attributes = {}; + InitObjectAttribs(base_named_objects_path, OBJ_CASE_INSENSITIVE, NULL, + &object_attributes, &directory_name); + status = NtOpenDirectoryObject(&base_named_objects_handle, + DIRECTORY_ALL_ACCESS, + &object_attributes); + if (status == STATUS_SUCCESS) + *directory = base_named_objects_handle; + return status; +} + bool SyncPolicy::GenerateRules(const wchar_t* name, TargetPolicy::Semantics semantics, LowLevelPolicy* policy) { @@ -64,49 +179,75 @@ bool SyncPolicy::GenerateRules(const wchar_t* name, DWORD SyncPolicy::CreateEventAction(EvalResult eval_result, const ClientInfo& client_info, const std::wstring &event_name, - uint32 manual_reset, + uint32 event_type, uint32 initial_state, HANDLE *handle) { + NtCreateEventFunction NtCreateEvent = NULL; + ResolveNTFunctionPtr("NtCreateEvent", &NtCreateEvent); + // The only action supported is ASK_BROKER which means create the requested // file as specified. if (ASK_BROKER != eval_result) return false; - HANDLE local_handle = ::CreateEvent(NULL, manual_reset, initial_state, - event_name.c_str()); + HANDLE object_directory = NULL; + NTSTATUS status = GetBaseNamedObjectsDirectory(&object_directory); + if (status != STATUS_SUCCESS) + return status; + + UNICODE_STRING unicode_event_name = {}; + OBJECT_ATTRIBUTES object_attributes = {}; + InitObjectAttribs(event_name, OBJ_CASE_INSENSITIVE, object_directory, + &object_attributes, &unicode_event_name); + + HANDLE local_handle = NULL; + status = NtCreateEvent(&local_handle, EVENT_ALL_ACCESS, &object_attributes, + static_cast(event_type), initial_state); if (NULL == local_handle) - return ::GetLastError(); + return status; if (!::DuplicateHandle(::GetCurrentProcess(), local_handle, client_info.process, handle, 0, FALSE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) { - return ERROR_ACCESS_DENIED; + return STATUS_ACCESS_DENIED; } - return ERROR_SUCCESS; + return status; } DWORD SyncPolicy::OpenEventAction(EvalResult eval_result, const ClientInfo& client_info, const std::wstring &event_name, uint32 desired_access, - uint32 inherit_handle, HANDLE *handle) { + NtOpenEventFunction NtOpenEvent = NULL; + ResolveNTFunctionPtr("NtOpenEvent", &NtOpenEvent); + // The only action supported is ASK_BROKER which means create the requested - // file as specified. + // event as specified. if (ASK_BROKER != eval_result) return false; - HANDLE local_handle = ::OpenEvent(desired_access, FALSE, - event_name.c_str()); + HANDLE object_directory = NULL; + NTSTATUS status = GetBaseNamedObjectsDirectory(&object_directory); + if (status != STATUS_SUCCESS) + return status; + + UNICODE_STRING unicode_event_name = {}; + OBJECT_ATTRIBUTES object_attributes = {}; + InitObjectAttribs(event_name, OBJ_CASE_INSENSITIVE, object_directory, + &object_attributes, &unicode_event_name); + + HANDLE local_handle = NULL; + status = NtOpenEvent(&local_handle, desired_access, &object_attributes); if (NULL == local_handle) - return ::GetLastError(); + return status; if (!::DuplicateHandle(::GetCurrentProcess(), local_handle, - client_info.process, handle, 0, inherit_handle, + client_info.process, handle, 0, FALSE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) { - return ERROR_ACCESS_DENIED; + return STATUS_ACCESS_DENIED; } - return ERROR_SUCCESS; + return status; } } // namespace sandbox diff --git a/sandbox/win/src/sync_policy.h b/sandbox/win/src/sync_policy.h index 2b8b4227025963..93aef64af607d0 100644 --- a/sandbox/win/src/sync_policy.h +++ b/sandbox/win/src/sync_policy.h @@ -35,14 +35,13 @@ class SyncPolicy { static DWORD CreateEventAction(EvalResult eval_result, const ClientInfo& client_info, const std::wstring &event_name, - uint32 manual_reset, + uint32 event_type, uint32 initial_state, HANDLE *handle); static DWORD OpenEventAction(EvalResult eval_result, const ClientInfo& client_info, const std::wstring &event_name, uint32 desired_access, - uint32 inherit_handle, HANDLE *handle); };