123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746 |
- // Copyright (c) 2012 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "sandbox/win/src/sandbox_nt_util.h"
- #include <stddef.h>
- #include <stdint.h>
- #include <string>
- #include "base/compiler_specific.h"
- #include "base/win/pe_image.h"
- #include "sandbox/win/src/internal_types.h"
- #include "sandbox/win/src/sandbox_factory.h"
- #include "sandbox/win/src/target_services.h"
- namespace sandbox {
- // This is the list of all imported symbols from ntdll.dll.
- SANDBOX_INTERCEPT NtExports g_nt;
- } // namespace sandbox
- namespace {
- #if defined(_WIN64)
- // Align a pointer to the next allocation granularity boundary.
- inline char* AlignToBoundary(void* ptr, size_t increment) {
- const size_t kAllocationGranularity = (64 * 1024) - 1;
- uintptr_t ptr_int = reinterpret_cast<uintptr_t>(ptr);
- uintptr_t ret_ptr =
- (ptr_int + increment + kAllocationGranularity) & ~kAllocationGranularity;
- // Check for overflow.
- if (ret_ptr < ptr_int)
- return nullptr;
- return reinterpret_cast<char*>(ret_ptr);
- }
- // Allocate a memory block somewhere within 2GiB of a specified base address.
- // This is used for the DLL hooking code to get a valid trampoline location
- // which must be within +/- 2GiB of the base. We only consider +2GiB for now.
- void* AllocateNearTo(void* source, size_t size) {
- // 2GiB, maximum upper bound the allocation address must be within.
- const size_t kMaxSize = 0x80000000ULL;
- // We don't support null as a base as this would just pick an arbitrary
- // address when passed to NtAllocateVirtualMemory.
- if (!source)
- return nullptr;
- // Ignore an allocation which is larger than the maximum.
- if (size > kMaxSize)
- return nullptr;
- // Ensure base address is aligned to the allocation granularity boundary.
- char* base = AlignToBoundary(source, 0);
- if (!base)
- return nullptr;
- // Set top address to be base + 2GiB.
- const char* top_address = base + kMaxSize;
- while (base < top_address) {
- // Avoid memset inserted by -ftrivial-auto-var-init=pattern.
- STACK_UNINITIALIZED MEMORY_BASIC_INFORMATION mem_info;
- NTSTATUS status = sandbox::GetNtExports()->QueryVirtualMemory(
- NtCurrentProcess, base, MemoryBasicInformation, &mem_info,
- sizeof(mem_info), nullptr);
- if (!NT_SUCCESS(status))
- break;
- if ((mem_info.State == MEM_FREE) && (mem_info.RegionSize >= size)) {
- // We've found a valid free block, try and allocate it for use.
- // Note that we need to both commit and reserve the block for the
- // allocation to succeed as per Windows virtual memory requirements.
- void* ret_base = mem_info.BaseAddress;
- status = sandbox::GetNtExports()->AllocateVirtualMemory(
- NtCurrentProcess, &ret_base, 0, &size, MEM_COMMIT | MEM_RESERVE,
- PAGE_READWRITE);
- // Shouldn't fail, but if it does we'll just continue and try next block.
- if (NT_SUCCESS(status))
- return ret_base;
- }
- // Update base past current allocation region.
- base = AlignToBoundary(mem_info.BaseAddress, mem_info.RegionSize);
- if (!base)
- break;
- }
- return nullptr;
- }
- #else // defined(_WIN64).
- void* AllocateNearTo(void* source, size_t size) {
- // In 32-bit processes allocations below 512k are predictable, so mark
- // anything in that range as reserved and retry until we get a good address.
- const void* const kMinAddress = reinterpret_cast<void*>(512 * 1024);
- NTSTATUS ret;
- SIZE_T actual_size;
- void* base;
- do {
- base = nullptr;
- actual_size = 64 * 1024;
- ret = sandbox::GetNtExports()->AllocateVirtualMemory(
- NtCurrentProcess, &base, 0, &actual_size, MEM_RESERVE, PAGE_NOACCESS);
- if (!NT_SUCCESS(ret))
- return nullptr;
- } while (base < kMinAddress);
- actual_size = size;
- ret = sandbox::GetNtExports()->AllocateVirtualMemory(
- NtCurrentProcess, &base, 0, &actual_size, MEM_COMMIT, PAGE_READWRITE);
- if (!NT_SUCCESS(ret))
- return nullptr;
- return base;
- }
- #endif // defined(_WIN64).
- template <typename T>
- void InitFunc(const base::win::PEImage& image, T& member, const char* name) {
- member = reinterpret_cast<T>(image.GetProcAddress(name));
- DCHECK(member);
- }
- #define INIT_NT(member) InitFunc(image, sandbox::g_nt.member, "Nt" #member)
- #define INIT_RTL(member) InitFunc(image, sandbox::g_nt.member, #member)
- void InitGlobalNt() {
- HMODULE ntdll = ::GetModuleHandle(sandbox::kNtdllName);
- base::win::PEImage image(ntdll);
- INIT_NT(AllocateVirtualMemory);
- INIT_NT(CreateFile);
- INIT_NT(CreateSection);
- INIT_NT(Close);
- INIT_NT(DuplicateObject);
- INIT_NT(FreeVirtualMemory);
- INIT_NT(MapViewOfSection);
- INIT_NT(OpenFile);
- INIT_NT(OpenThread);
- INIT_NT(OpenProcess);
- INIT_NT(OpenProcessToken);
- INIT_NT(OpenProcessTokenEx);
- INIT_NT(ProtectVirtualMemory);
- INIT_NT(QueryAttributesFile);
- INIT_NT(QueryFullAttributesFile);
- INIT_NT(QueryInformationProcess);
- INIT_NT(QueryObject);
- INIT_NT(QuerySection);
- INIT_NT(QueryVirtualMemory);
- INIT_NT(SetInformationFile);
- INIT_NT(SetInformationProcess);
- INIT_NT(SignalAndWaitForSingleObject);
- INIT_NT(UnmapViewOfSection);
- INIT_NT(WaitForSingleObject);
- INIT_RTL(RtlAllocateHeap);
- INIT_RTL(RtlAnsiStringToUnicodeString);
- INIT_RTL(RtlCompareUnicodeString);
- INIT_RTL(RtlCreateHeap);
- INIT_RTL(RtlCreateUserThread);
- INIT_RTL(RtlDestroyHeap);
- INIT_RTL(RtlFreeHeap);
- INIT_RTL(RtlNtStatusToDosError);
- INIT_RTL(_strnicmp);
- INIT_RTL(strlen);
- INIT_RTL(wcslen);
- INIT_RTL(memcpy);
- sandbox::g_nt.Initialized = true;
- }
- } // namespace.
- namespace sandbox {
- // Handle for our private heap.
- void* g_heap = nullptr;
- SANDBOX_INTERCEPT HANDLE g_shared_section;
- SANDBOX_INTERCEPT size_t g_shared_IPC_size = 0;
- SANDBOX_INTERCEPT size_t g_shared_policy_size = 0;
- void* volatile g_shared_policy_memory = nullptr;
- void* volatile g_shared_IPC_memory = nullptr;
- // Both the IPC and the policy share a single region of memory in which the IPC
- // memory is first and the policy memory is last.
- bool MapGlobalMemory() {
- if (!g_shared_IPC_memory) {
- void* memory = nullptr;
- SIZE_T size = 0;
- // Map the entire shared section from the start.
- NTSTATUS ret = GetNtExports()->MapViewOfSection(
- g_shared_section, NtCurrentProcess, &memory, 0, 0, nullptr, &size,
- ViewUnmap, 0, PAGE_READWRITE);
- if (!NT_SUCCESS(ret) || !memory) {
- NOTREACHED_NT();
- return false;
- }
- if (_InterlockedCompareExchangePointer(&g_shared_IPC_memory, memory,
- nullptr)) {
- // Somebody beat us to the memory setup.
- VERIFY_SUCCESS(
- GetNtExports()->UnmapViewOfSection(NtCurrentProcess, memory));
- }
- DCHECK_NT(g_shared_IPC_size > 0);
- g_shared_policy_memory =
- reinterpret_cast<char*>(g_shared_IPC_memory) + g_shared_IPC_size;
- }
- DCHECK_NT(g_shared_policy_memory);
- DCHECK_NT(g_shared_policy_size > 0);
- return true;
- }
- void* GetGlobalIPCMemory() {
- if (!MapGlobalMemory())
- return nullptr;
- return g_shared_IPC_memory;
- }
- void* GetGlobalPolicyMemory() {
- if (!MapGlobalMemory())
- return nullptr;
- return g_shared_policy_memory;
- }
- const NtExports* GetNtExports() {
- if (!g_nt.Initialized)
- InitGlobalNt();
- return &g_nt;
- }
- bool InitHeap() {
- if (!g_heap) {
- // Create a new heap using default values for everything.
- void* heap = GetNtExports()->RtlCreateHeap(HEAP_GROWABLE, nullptr, 0, 0,
- nullptr, nullptr);
- if (!heap)
- return false;
- if (_InterlockedCompareExchangePointer(&g_heap, heap, nullptr)) {
- // Somebody beat us to the memory setup.
- GetNtExports()->RtlDestroyHeap(heap);
- }
- }
- return !!g_heap;
- }
- // Physically reads or writes from memory to verify that (at this time), it is
- // valid. Returns a dummy value.
- int TouchMemory(void* buffer, size_t size_bytes, RequiredAccess intent) {
- const int kPageSize = 4096;
- int dummy = 0;
- volatile char* start = reinterpret_cast<char*>(buffer);
- volatile char* end = start + size_bytes - 1;
- if (WRITE == intent) {
- for (; start < end; start += kPageSize) {
- *start = *start;
- }
- *end = *end;
- } else {
- for (; start < end; start += kPageSize) {
- dummy += *start;
- }
- dummy += *end;
- }
- return dummy;
- }
- bool ValidParameter(void* buffer, size_t size, RequiredAccess intent) {
- DCHECK_NT(size);
- __try {
- TouchMemory(buffer, size, intent);
- } __except (EXCEPTION_EXECUTE_HANDLER) {
- return false;
- }
- return true;
- }
- NTSTATUS CopyData(void* destination, const void* source, size_t bytes) {
- NTSTATUS ret = STATUS_SUCCESS;
- __try {
- GetNtExports()->memcpy(destination, source, bytes);
- } __except (EXCEPTION_EXECUTE_HANDLER) {
- ret = GetExceptionCode();
- }
- return ret;
- }
- NTSTATUS CopyNameAndAttributes(
- const OBJECT_ATTRIBUTES* in_object,
- std::unique_ptr<wchar_t, NtAllocDeleter>* out_name,
- size_t* out_name_len,
- uint32_t* attributes) {
- if (!InitHeap())
- return STATUS_NO_MEMORY;
- DCHECK_NT(out_name);
- DCHECK_NT(out_name_len);
- NTSTATUS ret = STATUS_UNSUCCESSFUL;
- __try {
- do {
- if (in_object->RootDirectory != nullptr)
- break;
- if (!in_object->ObjectName)
- break;
- if (!in_object->ObjectName->Buffer)
- break;
- size_t size = in_object->ObjectName->Length / sizeof(wchar_t);
- out_name->reset(new (NT_ALLOC) wchar_t[size + 1]);
- if (!*out_name)
- break;
- ret = CopyData(out_name->get(), in_object->ObjectName->Buffer,
- size * sizeof(wchar_t));
- if (!NT_SUCCESS(ret))
- break;
- *out_name_len = size;
- out_name->get()[size] = L'\0';
- if (attributes)
- *attributes = in_object->Attributes;
- ret = STATUS_SUCCESS;
- } while (false);
- } __except (EXCEPTION_EXECUTE_HANDLER) {
- ret = GetExceptionCode();
- }
- if (!NT_SUCCESS(ret) && *out_name)
- out_name->reset(nullptr);
- return ret;
- }
- NTSTATUS GetProcessId(HANDLE process, DWORD* process_id) {
- PROCESS_BASIC_INFORMATION proc_info;
- ULONG bytes_returned;
- NTSTATUS ret = GetNtExports()->QueryInformationProcess(
- process, ProcessBasicInformation, &proc_info, sizeof(proc_info),
- &bytes_returned);
- if (!NT_SUCCESS(ret) || sizeof(proc_info) != bytes_returned)
- return ret;
- *process_id = proc_info.UniqueProcessId;
- return STATUS_SUCCESS;
- }
- bool IsSameProcess(HANDLE process) {
- if (NtCurrentProcess == process)
- return true;
- static DWORD s_process_id = 0;
- if (!s_process_id) {
- NTSTATUS ret = GetProcessId(NtCurrentProcess, &s_process_id);
- if (!NT_SUCCESS(ret))
- return false;
- }
- DWORD process_id;
- NTSTATUS ret = GetProcessId(process, &process_id);
- if (!NT_SUCCESS(ret))
- return false;
- return (process_id == s_process_id);
- }
- bool IsValidImageSection(HANDLE section,
- PVOID* base,
- PLARGE_INTEGER offset,
- PSIZE_T view_size) {
- if (!section || !base || !view_size || offset)
- return false;
- HANDLE query_section;
- NTSTATUS ret = GetNtExports()->DuplicateObject(
- NtCurrentProcess, section, NtCurrentProcess, &query_section,
- SECTION_QUERY, 0, 0);
- if (!NT_SUCCESS(ret))
- return false;
- SECTION_BASIC_INFORMATION basic_info;
- SIZE_T bytes_returned;
- ret = GetNtExports()->QuerySection(query_section, SectionBasicInformation,
- &basic_info, sizeof(basic_info),
- &bytes_returned);
- VERIFY_SUCCESS(GetNtExports()->Close(query_section));
- if (!NT_SUCCESS(ret) || sizeof(basic_info) != bytes_returned)
- return false;
- if (!(basic_info.Attributes & SEC_IMAGE))
- return false;
- // Windows 10 2009+ may open PEs as SEC_IMAGE_NO_EXECUTE in non-dll-loading
- // paths which looks identical to dll-loading unless we check if the section
- // handle has execute rights.
- // Avoid memset inserted by -ftrivial-auto-var-init=pattern.
- STACK_UNINITIALIZED OBJECT_BASIC_INFORMATION obj_info;
- ULONG obj_size_returned;
- ret = GetNtExports()->QueryObject(section, ObjectBasicInformation, &obj_info,
- sizeof(obj_info), &obj_size_returned);
- if (!NT_SUCCESS(ret) || sizeof(obj_info) != obj_size_returned)
- return false;
- if (!(obj_info.GrantedAccess & SECTION_MAP_EXECUTE))
- return false;
- return true;
- }
- UNICODE_STRING* AnsiToUnicode(const char* string) {
- ANSI_STRING ansi_string;
- ansi_string.Length = static_cast<USHORT>(GetNtExports()->strlen(string));
- ansi_string.MaximumLength = ansi_string.Length + 1;
- ansi_string.Buffer = const_cast<char*>(string);
- if (ansi_string.Length > ansi_string.MaximumLength)
- return nullptr;
- size_t name_bytes =
- ansi_string.MaximumLength * sizeof(wchar_t) + sizeof(UNICODE_STRING);
- UNICODE_STRING* out_string =
- reinterpret_cast<UNICODE_STRING*>(new (NT_ALLOC) char[name_bytes]);
- if (!out_string)
- return nullptr;
- out_string->MaximumLength = ansi_string.MaximumLength * sizeof(wchar_t);
- out_string->Buffer = reinterpret_cast<wchar_t*>(&out_string[1]);
- BOOLEAN alloc_destination = false;
- NTSTATUS ret = GetNtExports()->RtlAnsiStringToUnicodeString(
- out_string, &ansi_string, alloc_destination);
- DCHECK_NT(STATUS_BUFFER_OVERFLOW != ret);
- if (!NT_SUCCESS(ret)) {
- operator delete(out_string, NT_ALLOC);
- return nullptr;
- }
- return out_string;
- }
- UNICODE_STRING* GetImageInfoFromModule(HMODULE module, uint32_t* flags) {
- // PEImage's dtor won't be run during SEH unwinding, but that's OK.
- #pragma warning(push)
- #pragma warning(disable : 4509)
- UNICODE_STRING* out_name = nullptr;
- __try {
- do {
- *flags = 0;
- base::win::PEImage pe(module);
- if (!pe.VerifyMagic())
- break;
- *flags |= MODULE_IS_PE_IMAGE;
- PIMAGE_EXPORT_DIRECTORY exports = pe.GetExportDirectory();
- if (exports) {
- char* name = reinterpret_cast<char*>(pe.RVAToAddr(exports->Name));
- out_name = AnsiToUnicode(name);
- }
- PIMAGE_NT_HEADERS headers = pe.GetNTHeaders();
- if (headers) {
- if (headers->OptionalHeader.AddressOfEntryPoint)
- *flags |= MODULE_HAS_ENTRY_POINT;
- if (headers->OptionalHeader.SizeOfCode)
- *flags |= MODULE_HAS_CODE;
- }
- } while (false);
- } __except (EXCEPTION_EXECUTE_HANDLER) {
- }
- return out_name;
- #pragma warning(pop)
- }
- const char* GetAnsiImageInfoFromModule(HMODULE module) {
- // PEImage's dtor won't be run during SEH unwinding, but that's OK.
- #pragma warning(push)
- #pragma warning(disable : 4509)
- const char* out_name = nullptr;
- __try {
- do {
- base::win::PEImage pe(module);
- if (!pe.VerifyMagic())
- break;
- PIMAGE_EXPORT_DIRECTORY exports = pe.GetExportDirectory();
- if (exports)
- out_name = static_cast<const char*>(pe.RVAToAddr(exports->Name));
- } while (false);
- } __except (EXCEPTION_EXECUTE_HANDLER) {
- }
- return out_name;
- #pragma warning(pop)
- }
- UNICODE_STRING* GetBackingFilePath(PVOID address) {
- // We'll start with something close to max_path charactes for the name.
- SIZE_T buffer_bytes = MAX_PATH * 2;
- for (;;) {
- MEMORY_SECTION_NAME* section_name = reinterpret_cast<MEMORY_SECTION_NAME*>(
- new (NT_ALLOC) char[buffer_bytes]);
- if (!section_name)
- return nullptr;
- SIZE_T returned_bytes;
- NTSTATUS ret = GetNtExports()->QueryVirtualMemory(
- NtCurrentProcess, address, MemorySectionName, section_name,
- buffer_bytes, &returned_bytes);
- if (STATUS_BUFFER_OVERFLOW == ret) {
- // Retry the call with the given buffer size.
- operator delete(section_name, NT_ALLOC);
- section_name = nullptr;
- buffer_bytes = returned_bytes;
- continue;
- }
- if (!NT_SUCCESS(ret)) {
- operator delete(section_name, NT_ALLOC);
- return nullptr;
- }
- return reinterpret_cast<UNICODE_STRING*>(section_name);
- }
- }
- UNICODE_STRING* ExtractModuleName(const UNICODE_STRING* module_path) {
- if ((!module_path) || (!module_path->Buffer))
- return nullptr;
- wchar_t* sep = nullptr;
- int start_pos = module_path->Length / sizeof(wchar_t) - 1;
- int ix = start_pos;
- for (; ix >= 0; --ix) {
- if (module_path->Buffer[ix] == L'\\') {
- sep = &module_path->Buffer[ix];
- break;
- }
- }
- // Ends with path separator. Not a valid module name.
- if ((ix == start_pos) && sep)
- return nullptr;
- // No path separator found. Use the entire name.
- if (!sep) {
- sep = &module_path->Buffer[-1];
- }
- // Add one to the size so we can null terminate the string.
- size_t size_bytes = (start_pos - ix + 1) * sizeof(wchar_t);
- // Based on the code above, size_bytes should always be small enough
- // to make the static_cast below safe.
- DCHECK_NT(UINT16_MAX > size_bytes);
- char* str_buffer = new (NT_ALLOC) char[size_bytes + sizeof(UNICODE_STRING)];
- if (!str_buffer)
- return nullptr;
- UNICODE_STRING* out_string = reinterpret_cast<UNICODE_STRING*>(str_buffer);
- out_string->Buffer = reinterpret_cast<wchar_t*>(&out_string[1]);
- out_string->Length = static_cast<USHORT>(size_bytes - sizeof(wchar_t));
- out_string->MaximumLength = static_cast<USHORT>(size_bytes);
- NTSTATUS ret = CopyData(out_string->Buffer, &sep[1], out_string->Length);
- if (!NT_SUCCESS(ret)) {
- operator delete(out_string, NT_ALLOC);
- return nullptr;
- }
- out_string->Buffer[out_string->Length / sizeof(wchar_t)] = L'\0';
- return out_string;
- }
- NTSTATUS AutoProtectMemory::ChangeProtection(void* address,
- size_t bytes,
- ULONG protect) {
- DCHECK_NT(!changed_);
- SIZE_T new_bytes = bytes;
- NTSTATUS ret = GetNtExports()->ProtectVirtualMemory(
- NtCurrentProcess, &address, &new_bytes, protect, &old_protect_);
- if (NT_SUCCESS(ret)) {
- changed_ = true;
- address_ = address;
- bytes_ = new_bytes;
- }
- return ret;
- }
- NTSTATUS AutoProtectMemory::RevertProtection() {
- if (!changed_)
- return STATUS_SUCCESS;
- DCHECK_NT(address_);
- DCHECK_NT(bytes_);
- SIZE_T new_bytes = bytes_;
- NTSTATUS ret = GetNtExports()->ProtectVirtualMemory(
- NtCurrentProcess, &address_, &new_bytes, old_protect_, &old_protect_);
- DCHECK_NT(NT_SUCCESS(ret));
- changed_ = false;
- address_ = nullptr;
- bytes_ = 0;
- old_protect_ = 0;
- return ret;
- }
- bool IsSupportedRenameCall(FILE_RENAME_INFORMATION* file_info,
- DWORD length,
- uint32_t file_info_class) {
- if (FileRenameInformation != file_info_class)
- return false;
- if (length < sizeof(FILE_RENAME_INFORMATION))
- return false;
- // Make sure file name length doesn't exceed the message length
- if (length - offsetof(FILE_RENAME_INFORMATION, FileName) <
- file_info->FileNameLength)
- return false;
- // We don't support a root directory.
- if (file_info->RootDirectory)
- return false;
- static const wchar_t kPathPrefix[] = {L'\\', L'?', L'?', L'\\'};
- // Check if it starts with \\??\\. We don't support relative paths.
- if (file_info->FileNameLength < sizeof(kPathPrefix) ||
- file_info->FileNameLength > UINT16_MAX)
- return false;
- if (file_info->FileName[0] != kPathPrefix[0] ||
- file_info->FileName[1] != kPathPrefix[1] ||
- file_info->FileName[2] != kPathPrefix[2] ||
- file_info->FileName[3] != kPathPrefix[3])
- return false;
- return true;
- }
- bool NtGetPathFromHandle(HANDLE handle,
- std::unique_ptr<wchar_t, NtAllocDeleter>* path) {
- OBJECT_NAME_INFORMATION initial_buffer;
- OBJECT_NAME_INFORMATION* name;
- ULONG size = 0;
- // Query the name information a first time to get the size of the name.
- NTSTATUS status = GetNtExports()->QueryObject(handle, ObjectNameInformation,
- &initial_buffer, size, &size);
- if (!NT_SUCCESS(status) && status != STATUS_INFO_LENGTH_MISMATCH)
- return false;
- std::unique_ptr<BYTE[], NtAllocDeleter> name_ptr;
- if (!size)
- return false;
- name_ptr.reset(new (NT_ALLOC) BYTE[size]);
- name = reinterpret_cast<OBJECT_NAME_INFORMATION*>(name_ptr.get());
- // Query the name information a second time to get the name of the
- // object referenced by the handle.
- status = GetNtExports()->QueryObject(handle, ObjectNameInformation, name,
- size, &size);
- if (STATUS_SUCCESS != status)
- return false;
- size_t num_path_wchars = (name->ObjectName.Length / sizeof(wchar_t)) + 1;
- path->reset(new (NT_ALLOC) wchar_t[num_path_wchars]);
- status =
- CopyData(path->get(), name->ObjectName.Buffer, name->ObjectName.Length);
- path->get()[num_path_wchars - 1] = L'\0';
- if (STATUS_SUCCESS != status)
- return false;
- return true;
- }
- } // namespace sandbox
- void* operator new(size_t size, sandbox::AllocationType type, void* near_to) {
- void* result = nullptr;
- if (type == sandbox::NT_ALLOC) {
- if (sandbox::InitHeap()) {
- // Use default flags for the allocation.
- result =
- sandbox::GetNtExports()->RtlAllocateHeap(sandbox::g_heap, 0, size);
- }
- } else if (type == sandbox::NT_PAGE) {
- result = AllocateNearTo(near_to, size);
- } else {
- NOTREACHED_NT();
- }
- // TODO: Returning nullptr from operator new has undefined behavior, but
- // the Allocate() functions called above can return nullptr. Consider checking
- // for nullptr here and crashing or throwing.
- return result;
- }
- void operator delete(void* memory, sandbox::AllocationType type) {
- if (type == sandbox::NT_ALLOC) {
- // Use default flags.
- VERIFY(sandbox::GetNtExports()->RtlFreeHeap(sandbox::g_heap, 0, memory));
- } else if (type == sandbox::NT_PAGE) {
- void* base = memory;
- SIZE_T size = 0;
- VERIFY_SUCCESS(sandbox::GetNtExports()->FreeVirtualMemory(
- NtCurrentProcess, &base, &size, MEM_RELEASE));
- } else {
- NOTREACHED_NT();
- }
- }
- void operator delete(void* memory,
- sandbox::AllocationType type,
- void* near_to) {
- operator delete(memory, type);
- }
- void* __cdecl operator new(size_t size,
- void* buffer,
- sandbox::AllocationType type) {
- return buffer;
- }
- void __cdecl operator delete(void* memory,
- void* buffer,
- sandbox::AllocationType type) {}
|