diff options
Diffstat (limited to 'security/sandbox/chromium/base/win')
-rw-r--r-- | security/sandbox/chromium/base/win/pe_image.cc | 580 | ||||
-rw-r--r-- | security/sandbox/chromium/base/win/pe_image.h | 265 | ||||
-rw-r--r-- | security/sandbox/chromium/base/win/scoped_handle.cc | 248 | ||||
-rw-r--r-- | security/sandbox/chromium/base/win/scoped_handle.h | 182 | ||||
-rw-r--r-- | security/sandbox/chromium/base/win/scoped_process_information.cc | 147 | ||||
-rw-r--r-- | security/sandbox/chromium/base/win/scoped_process_information.h | 83 | ||||
-rw-r--r-- | security/sandbox/chromium/base/win/startup_information.cc | 109 | ||||
-rw-r--r-- | security/sandbox/chromium/base/win/startup_information.h | 51 | ||||
-rw-r--r-- | security/sandbox/chromium/base/win/windows_version.cc | 225 | ||||
-rw-r--r-- | security/sandbox/chromium/base/win/windows_version.h | 133 |
10 files changed, 2023 insertions, 0 deletions
diff --git a/security/sandbox/chromium/base/win/pe_image.cc b/security/sandbox/chromium/base/win/pe_image.cc new file mode 100644 index 000000000..4b5d62099 --- /dev/null +++ b/security/sandbox/chromium/base/win/pe_image.cc @@ -0,0 +1,580 @@ +// Copyright (c) 2010 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. + +// This file implements PEImage, a generic class to manipulate PE files. +// This file was adapted from GreenBorder's Code. + +#include <stddef.h> + +#include "base/win/pe_image.h" + +namespace base { +namespace win { + +// Structure to perform imports enumerations. +struct EnumAllImportsStorage { + PEImage::EnumImportsFunction callback; + PVOID cookie; +}; + +namespace { + +// PdbInfo Signature +const DWORD kPdbInfoSignature = 'SDSR'; + +// Compare two strings byte by byte on an unsigned basis. +// if s1 == s2, return 0 +// if s1 < s2, return negative +// if s1 > s2, return positive +// Exception if inputs are invalid. +int StrCmpByByte(LPCSTR s1, LPCSTR s2) { + while (*s1 != '\0' && *s1 == *s2) { + ++s1; + ++s2; + } + + return (*reinterpret_cast<const unsigned char*>(s1) - + *reinterpret_cast<const unsigned char*>(s2)); +} + +struct PdbInfo { + DWORD Signature; + GUID Guid; + DWORD Age; + char PdbFileName[1]; +}; + +} // namespace + +// Callback used to enumerate imports. See EnumImportChunksFunction. +bool ProcessImportChunk(const PEImage &image, LPCSTR module, + PIMAGE_THUNK_DATA name_table, + PIMAGE_THUNK_DATA iat, PVOID cookie) { + EnumAllImportsStorage& storage = + *reinterpret_cast<EnumAllImportsStorage*>(cookie); + + return image.EnumOneImportChunk(storage.callback, module, name_table, iat, + storage.cookie); +} + +// Callback used to enumerate delay imports. See EnumDelayImportChunksFunction. +bool ProcessDelayImportChunk(const PEImage& image, + PImgDelayDescr delay_descriptor, + LPCSTR module, + PIMAGE_THUNK_DATA name_table, + PIMAGE_THUNK_DATA iat, + PVOID cookie) { + EnumAllImportsStorage& storage = + *reinterpret_cast<EnumAllImportsStorage*>(cookie); + + return image.EnumOneDelayImportChunk(storage.callback, delay_descriptor, + module, name_table, iat, storage.cookie); +} + +void PEImage::set_module(HMODULE module) { + module_ = module; +} + +PIMAGE_DOS_HEADER PEImage::GetDosHeader() const { + return reinterpret_cast<PIMAGE_DOS_HEADER>(module_); +} + +PIMAGE_NT_HEADERS PEImage::GetNTHeaders() const { + PIMAGE_DOS_HEADER dos_header = GetDosHeader(); + + return reinterpret_cast<PIMAGE_NT_HEADERS>( + reinterpret_cast<char*>(dos_header) + dos_header->e_lfanew); +} + +PIMAGE_SECTION_HEADER PEImage::GetSectionHeader(UINT section) const { + PIMAGE_NT_HEADERS nt_headers = GetNTHeaders(); + PIMAGE_SECTION_HEADER first_section = IMAGE_FIRST_SECTION(nt_headers); + + if (section < nt_headers->FileHeader.NumberOfSections) + return first_section + section; + else + return NULL; +} + +WORD PEImage::GetNumSections() const { + return GetNTHeaders()->FileHeader.NumberOfSections; +} + +DWORD PEImage::GetImageDirectoryEntrySize(UINT directory) const { + PIMAGE_NT_HEADERS nt_headers = GetNTHeaders(); + + return nt_headers->OptionalHeader.DataDirectory[directory].Size; +} + +PVOID PEImage::GetImageDirectoryEntryAddr(UINT directory) const { + PIMAGE_NT_HEADERS nt_headers = GetNTHeaders(); + + return RVAToAddr( + nt_headers->OptionalHeader.DataDirectory[directory].VirtualAddress); +} + +PIMAGE_SECTION_HEADER PEImage::GetImageSectionFromAddr(PVOID address) const { + PBYTE target = reinterpret_cast<PBYTE>(address); + PIMAGE_SECTION_HEADER section; + + for (UINT i = 0; NULL != (section = GetSectionHeader(i)); i++) { + // Don't use the virtual RVAToAddr. + PBYTE start = reinterpret_cast<PBYTE>( + PEImage::RVAToAddr(section->VirtualAddress)); + + DWORD size = section->Misc.VirtualSize; + + if ((start <= target) && (start + size > target)) + return section; + } + + return NULL; +} + +PIMAGE_SECTION_HEADER PEImage::GetImageSectionHeaderByName( + LPCSTR section_name) const { + if (NULL == section_name) + return NULL; + + PIMAGE_SECTION_HEADER ret = NULL; + int num_sections = GetNumSections(); + + for (int i = 0; i < num_sections; i++) { + PIMAGE_SECTION_HEADER section = GetSectionHeader(i); + if (0 == _strnicmp(reinterpret_cast<LPCSTR>(section->Name), section_name, + sizeof(section->Name))) { + ret = section; + break; + } + } + + return ret; +} + +bool PEImage::GetDebugId(LPGUID guid, LPDWORD age) const { + if (NULL == guid || NULL == age) { + return false; + } + + DWORD debug_directory_size = + GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_DEBUG); + PIMAGE_DEBUG_DIRECTORY debug_directory = + reinterpret_cast<PIMAGE_DEBUG_DIRECTORY>( + GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_DEBUG)); + + size_t directory_count = + debug_directory_size / sizeof(IMAGE_DEBUG_DIRECTORY); + + for (size_t index = 0; index < directory_count; ++index) { + if (debug_directory[index].Type == IMAGE_DEBUG_TYPE_CODEVIEW) { + PdbInfo* pdb_info = reinterpret_cast<PdbInfo*>( + RVAToAddr(debug_directory[index].AddressOfRawData)); + if (pdb_info->Signature != kPdbInfoSignature) { + // Unsupported PdbInfo signature + return false; + } + *guid = pdb_info->Guid; + *age = pdb_info->Age; + return true; + } + } + return false; +} + +PDWORD PEImage::GetExportEntry(LPCSTR name) const { + PIMAGE_EXPORT_DIRECTORY exports = GetExportDirectory(); + + if (NULL == exports) + return NULL; + + WORD ordinal = 0; + if (!GetProcOrdinal(name, &ordinal)) + return NULL; + + PDWORD functions = reinterpret_cast<PDWORD>( + RVAToAddr(exports->AddressOfFunctions)); + + return functions + ordinal - exports->Base; +} + +FARPROC PEImage::GetProcAddress(LPCSTR function_name) const { + PDWORD export_entry = GetExportEntry(function_name); + if (NULL == export_entry) + return NULL; + + PBYTE function = reinterpret_cast<PBYTE>(RVAToAddr(*export_entry)); + + PBYTE exports = reinterpret_cast<PBYTE>( + GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_EXPORT)); + DWORD size = GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_EXPORT); + + // Check for forwarded exports as a special case. + if (exports <= function && exports + size > function) + return reinterpret_cast<FARPROC>(-1); + + return reinterpret_cast<FARPROC>(function); +} + +bool PEImage::GetProcOrdinal(LPCSTR function_name, WORD *ordinal) const { + if (NULL == ordinal) + return false; + + PIMAGE_EXPORT_DIRECTORY exports = GetExportDirectory(); + + if (NULL == exports) + return false; + + if (IsOrdinal(function_name)) { + *ordinal = ToOrdinal(function_name); + } else { + PDWORD names = reinterpret_cast<PDWORD>(RVAToAddr(exports->AddressOfNames)); + PDWORD lower = names; + PDWORD upper = names + exports->NumberOfNames; + int cmp = -1; + + // Binary Search for the name. + while (lower != upper) { + PDWORD middle = lower + (upper - lower) / 2; + LPCSTR name = reinterpret_cast<LPCSTR>(RVAToAddr(*middle)); + + // This may be called by sandbox before MSVCRT dll loads, so can't use + // CRT function here. + cmp = StrCmpByByte(function_name, name); + + if (cmp == 0) { + lower = middle; + break; + } + + if (cmp > 0) + lower = middle + 1; + else + upper = middle; + } + + if (cmp != 0) + return false; + + + PWORD ordinals = reinterpret_cast<PWORD>( + RVAToAddr(exports->AddressOfNameOrdinals)); + + *ordinal = ordinals[lower - names] + static_cast<WORD>(exports->Base); + } + + return true; +} + +bool PEImage::EnumSections(EnumSectionsFunction callback, PVOID cookie) const { + PIMAGE_NT_HEADERS nt_headers = GetNTHeaders(); + UINT num_sections = nt_headers->FileHeader.NumberOfSections; + PIMAGE_SECTION_HEADER section = GetSectionHeader(0); + + for (UINT i = 0; i < num_sections; i++, section++) { + PVOID section_start = RVAToAddr(section->VirtualAddress); + DWORD size = section->Misc.VirtualSize; + + if (!callback(*this, section, section_start, size, cookie)) + return false; + } + + return true; +} + +bool PEImage::EnumExports(EnumExportsFunction callback, PVOID cookie) const { + PVOID directory = GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_EXPORT); + DWORD size = GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_EXPORT); + + // Check if there are any exports at all. + if (NULL == directory || 0 == size) + return true; + + PIMAGE_EXPORT_DIRECTORY exports = reinterpret_cast<PIMAGE_EXPORT_DIRECTORY>( + directory); + UINT ordinal_base = exports->Base; + UINT num_funcs = exports->NumberOfFunctions; + UINT num_names = exports->NumberOfNames; + PDWORD functions = reinterpret_cast<PDWORD>(RVAToAddr( + exports->AddressOfFunctions)); + PDWORD names = reinterpret_cast<PDWORD>(RVAToAddr(exports->AddressOfNames)); + PWORD ordinals = reinterpret_cast<PWORD>(RVAToAddr( + exports->AddressOfNameOrdinals)); + + for (UINT count = 0; count < num_funcs; count++) { + PVOID func = RVAToAddr(functions[count]); + if (NULL == func) + continue; + + // Check for a name. + LPCSTR name = NULL; + UINT hint; + for (hint = 0; hint < num_names; hint++) { + if (ordinals[hint] == count) { + name = reinterpret_cast<LPCSTR>(RVAToAddr(names[hint])); + break; + } + } + + if (name == NULL) + hint = 0; + + // Check for forwarded exports. + LPCSTR forward = NULL; + if (reinterpret_cast<char*>(func) >= reinterpret_cast<char*>(directory) && + reinterpret_cast<char*>(func) <= reinterpret_cast<char*>(directory) + + size) { + forward = reinterpret_cast<LPCSTR>(func); + func = 0; + } + + if (!callback(*this, ordinal_base + count, hint, name, func, forward, + cookie)) + return false; + } + + return true; +} + +bool PEImage::EnumRelocs(EnumRelocsFunction callback, PVOID cookie) const { + PVOID directory = GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_BASERELOC); + DWORD size = GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_BASERELOC); + PIMAGE_BASE_RELOCATION base = reinterpret_cast<PIMAGE_BASE_RELOCATION>( + directory); + + if (!directory) + return true; + + while (size >= sizeof(IMAGE_BASE_RELOCATION) && base->SizeOfBlock && + size >= base->SizeOfBlock) { + PWORD reloc = reinterpret_cast<PWORD>(base + 1); + UINT num_relocs = (base->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / + sizeof(WORD); + + for (UINT i = 0; i < num_relocs; i++, reloc++) { + WORD type = *reloc >> 12; + PVOID address = RVAToAddr(base->VirtualAddress + (*reloc & 0x0FFF)); + + if (!callback(*this, type, address, cookie)) + return false; + } + + size -= base->SizeOfBlock; + base = reinterpret_cast<PIMAGE_BASE_RELOCATION>( + reinterpret_cast<char*>(base) + base->SizeOfBlock); + } + + return true; +} + +bool PEImage::EnumImportChunks(EnumImportChunksFunction callback, + PVOID cookie) const { + DWORD size = GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_IMPORT); + PIMAGE_IMPORT_DESCRIPTOR import = GetFirstImportChunk(); + + if (import == NULL || size < sizeof(IMAGE_IMPORT_DESCRIPTOR)) + return true; + + for (; import->FirstThunk; import++) { + LPCSTR module_name = reinterpret_cast<LPCSTR>(RVAToAddr(import->Name)); + PIMAGE_THUNK_DATA name_table = reinterpret_cast<PIMAGE_THUNK_DATA>( + RVAToAddr(import->OriginalFirstThunk)); + PIMAGE_THUNK_DATA iat = reinterpret_cast<PIMAGE_THUNK_DATA>( + RVAToAddr(import->FirstThunk)); + + if (!callback(*this, module_name, name_table, iat, cookie)) + return false; + } + + return true; +} + +bool PEImage::EnumOneImportChunk(EnumImportsFunction callback, + LPCSTR module_name, + PIMAGE_THUNK_DATA name_table, + PIMAGE_THUNK_DATA iat, PVOID cookie) const { + if (NULL == name_table) + return false; + + for (; name_table && name_table->u1.Ordinal; name_table++, iat++) { + LPCSTR name = NULL; + WORD ordinal = 0; + WORD hint = 0; + + if (IMAGE_SNAP_BY_ORDINAL(name_table->u1.Ordinal)) { + ordinal = static_cast<WORD>(IMAGE_ORDINAL32(name_table->u1.Ordinal)); + } else { + PIMAGE_IMPORT_BY_NAME import = reinterpret_cast<PIMAGE_IMPORT_BY_NAME>( + RVAToAddr(name_table->u1.ForwarderString)); + + hint = import->Hint; + name = reinterpret_cast<LPCSTR>(&import->Name); + } + + if (!callback(*this, module_name, ordinal, name, hint, iat, cookie)) + return false; + } + + return true; +} + +bool PEImage::EnumAllImports(EnumImportsFunction callback, PVOID cookie) const { + EnumAllImportsStorage temp = { callback, cookie }; + return EnumImportChunks(ProcessImportChunk, &temp); +} + +bool PEImage::EnumDelayImportChunks(EnumDelayImportChunksFunction callback, + PVOID cookie) const { + PVOID directory = GetImageDirectoryEntryAddr( + IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT); + DWORD size = GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT); + PImgDelayDescr delay_descriptor = reinterpret_cast<PImgDelayDescr>(directory); + + if (directory == NULL || size == 0) + return true; + + for (; delay_descriptor->rvaHmod; delay_descriptor++) { + PIMAGE_THUNK_DATA name_table; + PIMAGE_THUNK_DATA iat; + LPCSTR module_name; + + // check if VC7-style imports, using RVAs instead of + // VC6-style addresses. + bool rvas = (delay_descriptor->grAttrs & dlattrRva) != 0; + + if (rvas) { + module_name = + reinterpret_cast<LPCSTR>(RVAToAddr(delay_descriptor->rvaDLLName)); + name_table = reinterpret_cast<PIMAGE_THUNK_DATA>( + RVAToAddr(delay_descriptor->rvaINT)); + iat = reinterpret_cast<PIMAGE_THUNK_DATA>( + RVAToAddr(delay_descriptor->rvaIAT)); + } else { + // Values in IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT are 32-bit, even on 64-bit + // platforms. See section 4.8 of PECOFF image spec rev 8.3. + module_name = reinterpret_cast<LPCSTR>( + static_cast<uintptr_t>(delay_descriptor->rvaDLLName)); + name_table = reinterpret_cast<PIMAGE_THUNK_DATA>( + static_cast<uintptr_t>(delay_descriptor->rvaINT)); + iat = reinterpret_cast<PIMAGE_THUNK_DATA>( + static_cast<uintptr_t>(delay_descriptor->rvaIAT)); + } + + if (!callback(*this, delay_descriptor, module_name, name_table, iat, + cookie)) + return false; + } + + return true; +} + +bool PEImage::EnumOneDelayImportChunk(EnumImportsFunction callback, + PImgDelayDescr delay_descriptor, + LPCSTR module_name, + PIMAGE_THUNK_DATA name_table, + PIMAGE_THUNK_DATA iat, + PVOID cookie) const { + for (; name_table->u1.Ordinal; name_table++, iat++) { + LPCSTR name = NULL; + WORD ordinal = 0; + WORD hint = 0; + + if (IMAGE_SNAP_BY_ORDINAL(name_table->u1.Ordinal)) { + ordinal = static_cast<WORD>(IMAGE_ORDINAL32(name_table->u1.Ordinal)); + } else { + PIMAGE_IMPORT_BY_NAME import; + bool rvas = (delay_descriptor->grAttrs & dlattrRva) != 0; + + if (rvas) { + import = reinterpret_cast<PIMAGE_IMPORT_BY_NAME>( + RVAToAddr(name_table->u1.ForwarderString)); + } else { + import = reinterpret_cast<PIMAGE_IMPORT_BY_NAME>( + name_table->u1.ForwarderString); + } + + hint = import->Hint; + name = reinterpret_cast<LPCSTR>(&import->Name); + } + + if (!callback(*this, module_name, ordinal, name, hint, iat, cookie)) + return false; + } + + return true; +} + +bool PEImage::EnumAllDelayImports(EnumImportsFunction callback, + PVOID cookie) const { + EnumAllImportsStorage temp = { callback, cookie }; + return EnumDelayImportChunks(ProcessDelayImportChunk, &temp); +} + +bool PEImage::VerifyMagic() const { + PIMAGE_DOS_HEADER dos_header = GetDosHeader(); + + if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) + return false; + + PIMAGE_NT_HEADERS nt_headers = GetNTHeaders(); + + if (nt_headers->Signature != IMAGE_NT_SIGNATURE) + return false; + + if (nt_headers->FileHeader.SizeOfOptionalHeader != + sizeof(IMAGE_OPTIONAL_HEADER)) + return false; + + if (nt_headers->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC) + return false; + + return true; +} + +bool PEImage::ImageRVAToOnDiskOffset(DWORD rva, DWORD* on_disk_offset) const { + LPVOID address = RVAToAddr(rva); + return ImageAddrToOnDiskOffset(address, on_disk_offset); +} + +bool PEImage::ImageAddrToOnDiskOffset(LPVOID address, + DWORD* on_disk_offset) const { + if (NULL == address) + return false; + + // Get the section that this address belongs to. + PIMAGE_SECTION_HEADER section_header = GetImageSectionFromAddr(address); + if (NULL == section_header) + return false; + + // Don't follow the virtual RVAToAddr, use the one on the base. + DWORD offset_within_section = + static_cast<DWORD>(reinterpret_cast<uintptr_t>(address)) - + static_cast<DWORD>(reinterpret_cast<uintptr_t>( + PEImage::RVAToAddr(section_header->VirtualAddress))); + + *on_disk_offset = section_header->PointerToRawData + offset_within_section; + return true; +} + +PVOID PEImage::RVAToAddr(DWORD rva) const { + if (rva == 0) + return NULL; + + return reinterpret_cast<char*>(module_) + rva; +} + +PVOID PEImageAsData::RVAToAddr(DWORD rva) const { + if (rva == 0) + return NULL; + + PVOID in_memory = PEImage::RVAToAddr(rva); + DWORD disk_offset; + + if (!ImageAddrToOnDiskOffset(in_memory, &disk_offset)) + return NULL; + + return PEImage::RVAToAddr(disk_offset); +} + +} // namespace win +} // namespace base diff --git a/security/sandbox/chromium/base/win/pe_image.h b/security/sandbox/chromium/base/win/pe_image.h new file mode 100644 index 000000000..4c36bcf85 --- /dev/null +++ b/security/sandbox/chromium/base/win/pe_image.h @@ -0,0 +1,265 @@ +// Copyright (c) 2010 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. + +// This file was adapted from GreenBorder's Code. +// To understand what this class is about (for other than well known functions +// as GetProcAddress), a good starting point is "An In-Depth Look into the +// Win32 Portable Executable File Format" by Matt Pietrek: +// http://msdn.microsoft.com/msdnmag/issues/02/02/PE/default.aspx + +#ifndef BASE_WIN_PE_IMAGE_H_ +#define BASE_WIN_PE_IMAGE_H_ + +#include <windows.h> + +#if defined(_WIN32_WINNT_WIN8) +// The Windows 8 SDK defines FACILITY_VISUALCPP in winerror.h. +#undef FACILITY_VISUALCPP +#endif +#include <DelayIMP.h> + +namespace base { +namespace win { + +// This class is a wrapper for the Portable Executable File Format (PE). +// Its main purpose is to provide an easy way to work with imports and exports +// from a file, mapped in memory as image. +class PEImage { + public: + // Callback to enumerate sections. + // cookie is the value passed to the enumerate method. + // Returns true to continue the enumeration. + typedef bool (*EnumSectionsFunction)(const PEImage &image, + PIMAGE_SECTION_HEADER header, + PVOID section_start, DWORD section_size, + PVOID cookie); + + // Callback to enumerate exports. + // function is the actual address of the symbol. If forward is not null, it + // contains the dll and symbol to forward this export to. cookie is the value + // passed to the enumerate method. + // Returns true to continue the enumeration. + typedef bool (*EnumExportsFunction)(const PEImage &image, DWORD ordinal, + DWORD hint, LPCSTR name, PVOID function, + LPCSTR forward, PVOID cookie); + + // Callback to enumerate import blocks. + // name_table and iat point to the imports name table and address table for + // this block. cookie is the value passed to the enumerate method. + // Returns true to continue the enumeration. + typedef bool (*EnumImportChunksFunction)(const PEImage &image, LPCSTR module, + PIMAGE_THUNK_DATA name_table, + PIMAGE_THUNK_DATA iat, PVOID cookie); + + // Callback to enumerate imports. + // module is the dll that exports this symbol. cookie is the value passed to + // the enumerate method. + // Returns true to continue the enumeration. + typedef bool (*EnumImportsFunction)(const PEImage &image, LPCSTR module, + DWORD ordinal, LPCSTR name, DWORD hint, + PIMAGE_THUNK_DATA iat, PVOID cookie); + + // Callback to enumerate dalayed import blocks. + // module is the dll that exports this block of symbols. cookie is the value + // passed to the enumerate method. + // Returns true to continue the enumeration. + typedef bool (*EnumDelayImportChunksFunction)(const PEImage &image, + PImgDelayDescr delay_descriptor, + LPCSTR module, + PIMAGE_THUNK_DATA name_table, + PIMAGE_THUNK_DATA iat, + PVOID cookie); + + // Callback to enumerate relocations. + // cookie is the value passed to the enumerate method. + // Returns true to continue the enumeration. + typedef bool (*EnumRelocsFunction)(const PEImage &image, WORD type, + PVOID address, PVOID cookie); + + explicit PEImage(HMODULE module) : module_(module) {} + explicit PEImage(const void* module) { + module_ = reinterpret_cast<HMODULE>(const_cast<void*>(module)); + } + + virtual ~PEImage() {} + + // Gets the HMODULE for this object. + HMODULE module() const; + + // Sets this object's HMODULE. + void set_module(HMODULE module); + + // Checks if this symbol is actually an ordinal. + static bool IsOrdinal(LPCSTR name); + + // Converts a named symbol to the corresponding ordinal. + static WORD ToOrdinal(LPCSTR name); + + // Returns the DOS_HEADER for this PE. + PIMAGE_DOS_HEADER GetDosHeader() const; + + // Returns the NT_HEADER for this PE. + PIMAGE_NT_HEADERS GetNTHeaders() const; + + // Returns number of sections of this PE. + WORD GetNumSections() const; + + // Returns the header for a given section. + // returns NULL if there is no such section. + PIMAGE_SECTION_HEADER GetSectionHeader(UINT section) const; + + // Returns the size of a given directory entry. + DWORD GetImageDirectoryEntrySize(UINT directory) const; + + // Returns the address of a given directory entry. + PVOID GetImageDirectoryEntryAddr(UINT directory) const; + + // Returns the section header for a given address. + // Use: s = image.GetImageSectionFromAddr(a); + // Post: 's' is the section header of the section that contains 'a' + // or NULL if there is no such section. + PIMAGE_SECTION_HEADER GetImageSectionFromAddr(PVOID address) const; + + // Returns the section header for a given section. + PIMAGE_SECTION_HEADER GetImageSectionHeaderByName(LPCSTR section_name) const; + + // Returns the first block of imports. + PIMAGE_IMPORT_DESCRIPTOR GetFirstImportChunk() const; + + // Returns the exports directory. + PIMAGE_EXPORT_DIRECTORY GetExportDirectory() const; + + // Returns the debug id (guid+age). + bool GetDebugId(LPGUID guid, LPDWORD age) const; + + // Returns a given export entry. + // Use: e = image.GetExportEntry(f); + // Pre: 'f' is either a zero terminated string or ordinal + // Post: 'e' is a pointer to the export directory entry + // that contains 'f's export RVA, or NULL if 'f' + // is not exported from this image + PDWORD GetExportEntry(LPCSTR name) const; + + // Returns the address for a given exported symbol. + // Use: p = image.GetProcAddress(f); + // Pre: 'f' is either a zero terminated string or ordinal. + // Post: if 'f' is a non-forwarded export from image, 'p' is + // the exported function. If 'f' is a forwarded export + // then p is the special value -1. In this case + // RVAToAddr(*GetExportEntry) can be used to resolve + // the string that describes the forward. + FARPROC GetProcAddress(LPCSTR function_name) const; + + // Retrieves the ordinal for a given exported symbol. + // Returns true if the symbol was found. + bool GetProcOrdinal(LPCSTR function_name, WORD *ordinal) const; + + // Enumerates PE sections. + // cookie is a generic cookie to pass to the callback. + // Returns true on success. + bool EnumSections(EnumSectionsFunction callback, PVOID cookie) const; + + // Enumerates PE exports. + // cookie is a generic cookie to pass to the callback. + // Returns true on success. + bool EnumExports(EnumExportsFunction callback, PVOID cookie) const; + + // Enumerates PE imports. + // cookie is a generic cookie to pass to the callback. + // Returns true on success. + bool EnumAllImports(EnumImportsFunction callback, PVOID cookie) const; + + // Enumerates PE import blocks. + // cookie is a generic cookie to pass to the callback. + // Returns true on success. + bool EnumImportChunks(EnumImportChunksFunction callback, PVOID cookie) const; + + // Enumerates the imports from a single PE import block. + // cookie is a generic cookie to pass to the callback. + // Returns true on success. + bool EnumOneImportChunk(EnumImportsFunction callback, LPCSTR module_name, + PIMAGE_THUNK_DATA name_table, PIMAGE_THUNK_DATA iat, + PVOID cookie) const; + + + // Enumerates PE delay imports. + // cookie is a generic cookie to pass to the callback. + // Returns true on success. + bool EnumAllDelayImports(EnumImportsFunction callback, PVOID cookie) const; + + // Enumerates PE delay import blocks. + // cookie is a generic cookie to pass to the callback. + // Returns true on success. + bool EnumDelayImportChunks(EnumDelayImportChunksFunction callback, + PVOID cookie) const; + + // Enumerates imports from a single PE delay import block. + // cookie is a generic cookie to pass to the callback. + // Returns true on success. + bool EnumOneDelayImportChunk(EnumImportsFunction callback, + PImgDelayDescr delay_descriptor, + LPCSTR module_name, + PIMAGE_THUNK_DATA name_table, + PIMAGE_THUNK_DATA iat, + PVOID cookie) const; + + // Enumerates PE relocation entries. + // cookie is a generic cookie to pass to the callback. + // Returns true on success. + bool EnumRelocs(EnumRelocsFunction callback, PVOID cookie) const; + + // Verifies the magic values on the PE file. + // Returns true if all values are correct. + bool VerifyMagic() const; + + // Converts an rva value to the appropriate address. + virtual PVOID RVAToAddr(DWORD rva) const; + + // Converts an rva value to an offset on disk. + // Returns true on success. + bool ImageRVAToOnDiskOffset(DWORD rva, DWORD *on_disk_offset) const; + + // Converts an address to an offset on disk. + // Returns true on success. + bool ImageAddrToOnDiskOffset(LPVOID address, DWORD *on_disk_offset) const; + + private: + HMODULE module_; +}; + +// This class is an extension to the PEImage class that allows working with PE +// files mapped as data instead of as image file. +class PEImageAsData : public PEImage { + public: + explicit PEImageAsData(HMODULE hModule) : PEImage(hModule) {} + + PVOID RVAToAddr(DWORD rva) const override; +}; + +inline bool PEImage::IsOrdinal(LPCSTR name) { + return reinterpret_cast<uintptr_t>(name) <= 0xFFFF; +} + +inline WORD PEImage::ToOrdinal(LPCSTR name) { + return static_cast<WORD>(reinterpret_cast<intptr_t>(name)); +} + +inline HMODULE PEImage::module() const { + return module_; +} + +inline PIMAGE_IMPORT_DESCRIPTOR PEImage::GetFirstImportChunk() const { + return reinterpret_cast<PIMAGE_IMPORT_DESCRIPTOR>( + GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_IMPORT)); +} + +inline PIMAGE_EXPORT_DIRECTORY PEImage::GetExportDirectory() const { + return reinterpret_cast<PIMAGE_EXPORT_DIRECTORY>( + GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_EXPORT)); +} + +} // namespace win +} // namespace base + +#endif // BASE_WIN_PE_IMAGE_H_ diff --git a/security/sandbox/chromium/base/win/scoped_handle.cc b/security/sandbox/chromium/base/win/scoped_handle.cc new file mode 100644 index 000000000..9c21603a0 --- /dev/null +++ b/security/sandbox/chromium/base/win/scoped_handle.cc @@ -0,0 +1,248 @@ +// 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 "base/win/scoped_handle.h" + +#include <stddef.h> + +#include <unordered_map> + +#include "base/debug/alias.h" +#include "base/hash.h" +#include "base/lazy_instance.h" +#include "base/logging.h" +#include "base/macros.h" +#include "base/synchronization/lock_impl.h" + +extern "C" { +__declspec(dllexport) void* GetHandleVerifier(); +typedef void* (*GetHandleVerifierFn)(); +} + +namespace { + +struct HandleHash { + size_t operator()(const HANDLE& handle) const { + char buffer[sizeof(handle)]; + memcpy(buffer, &handle, sizeof(handle)); + return base::Hash(buffer, sizeof(buffer)); + } +}; + +struct Info { + const void* owner; + const void* pc1; + const void* pc2; + DWORD thread_id; +}; +typedef std::unordered_map<HANDLE, Info, HandleHash> HandleMap; + +// g_lock protects the handle map and setting g_active_verifier. +typedef base::internal::LockImpl NativeLock; +base::LazyInstance<NativeLock>::Leaky g_lock = LAZY_INSTANCE_INITIALIZER; + +bool CloseHandleWrapper(HANDLE handle) { + if (!::CloseHandle(handle)) + CHECK(false); + return true; +} + +// Simple automatic locking using a native critical section so it supports +// recursive locking. +class AutoNativeLock { + public: + explicit AutoNativeLock(NativeLock& lock) : lock_(lock) { + lock_.Lock(); + } + + ~AutoNativeLock() { + lock_.Unlock(); + } + + private: + NativeLock& lock_; + DISALLOW_COPY_AND_ASSIGN(AutoNativeLock); +}; + +// Implements the actual object that is verifying handles for this process. +// The active instance is shared across the module boundary but there is no +// way to delete this object from the wrong side of it (or any side, actually). +class ActiveVerifier { + public: + explicit ActiveVerifier(bool enabled) + : enabled_(enabled), closing_(false), lock_(g_lock.Pointer()) { + } + + // Retrieves the current verifier. + static ActiveVerifier* Get(); + + // The methods required by HandleTraits. They are virtual because we need to + // forward the call execution to another module, instead of letting the + // compiler call the version that is linked in the current module. + virtual bool CloseHandle(HANDLE handle); + virtual void StartTracking(HANDLE handle, const void* owner, + const void* pc1, const void* pc2); + virtual void StopTracking(HANDLE handle, const void* owner, + const void* pc1, const void* pc2); + virtual void Disable(); + virtual void OnHandleBeingClosed(HANDLE handle); + + private: + ~ActiveVerifier(); // Not implemented. + + static void InstallVerifier(); + + bool enabled_; + bool closing_; + NativeLock* lock_; + HandleMap map_; + DISALLOW_COPY_AND_ASSIGN(ActiveVerifier); +}; +ActiveVerifier* g_active_verifier = NULL; + +// static +ActiveVerifier* ActiveVerifier::Get() { + if (!g_active_verifier) + ActiveVerifier::InstallVerifier(); + + return g_active_verifier; +} + +// static +void ActiveVerifier::InstallVerifier() { +#if defined(COMPONENT_BUILD) + AutoNativeLock lock(g_lock.Get()); + g_active_verifier = new ActiveVerifier(true); +#else + // If you are reading this, wondering why your process seems deadlocked, take + // a look at your DllMain code and remove things that should not be done + // there, like doing whatever gave you that nice windows handle you are trying + // to store in a ScopedHandle. + HMODULE main_module = ::GetModuleHandle(NULL); + GetHandleVerifierFn get_handle_verifier = + reinterpret_cast<GetHandleVerifierFn>(::GetProcAddress( + main_module, "GetHandleVerifier")); + + if (!get_handle_verifier) { + g_active_verifier = new ActiveVerifier(false); + return; + } + + ActiveVerifier* verifier = + reinterpret_cast<ActiveVerifier*>(get_handle_verifier()); + + // This lock only protects against races in this module, which is fine. + AutoNativeLock lock(g_lock.Get()); + g_active_verifier = verifier ? verifier : new ActiveVerifier(true); +#endif +} + +bool ActiveVerifier::CloseHandle(HANDLE handle) { + if (!enabled_) + return CloseHandleWrapper(handle); + + AutoNativeLock lock(*lock_); + closing_ = true; + CloseHandleWrapper(handle); + closing_ = false; + + return true; +} + +void ActiveVerifier::StartTracking(HANDLE handle, const void* owner, + const void* pc1, const void* pc2) { + if (!enabled_) + return; + + // Grab the thread id before the lock. + DWORD thread_id = GetCurrentThreadId(); + + AutoNativeLock lock(*lock_); + + Info handle_info = { owner, pc1, pc2, thread_id }; + std::pair<HANDLE, Info> item(handle, handle_info); + std::pair<HandleMap::iterator, bool> result = map_.insert(item); + if (!result.second) { + Info other = result.first->second; + base::debug::Alias(&other); + CHECK(false); + } +} + +void ActiveVerifier::StopTracking(HANDLE handle, const void* owner, + const void* pc1, const void* pc2) { + if (!enabled_) + return; + + AutoNativeLock lock(*lock_); + HandleMap::iterator i = map_.find(handle); + if (i == map_.end()) + CHECK(false); + + Info other = i->second; + if (other.owner != owner) { + base::debug::Alias(&other); + CHECK(false); + } + + map_.erase(i); +} + +void ActiveVerifier::Disable() { + enabled_ = false; +} + +void ActiveVerifier::OnHandleBeingClosed(HANDLE handle) { + if (!enabled_) + return; + + AutoNativeLock lock(*lock_); + if (closing_) + return; + + HandleMap::iterator i = map_.find(handle); + if (i == map_.end()) + return; + + Info other = i->second; + base::debug::Alias(&other); + CHECK(false); +} + +} // namespace + +void* GetHandleVerifier() { + return g_active_verifier; +} + +namespace base { +namespace win { + +// Static. +bool HandleTraits::CloseHandle(HANDLE handle) { + return ActiveVerifier::Get()->CloseHandle(handle); +} + +// Static. +void VerifierTraits::StartTracking(HANDLE handle, const void* owner, + const void* pc1, const void* pc2) { + return ActiveVerifier::Get()->StartTracking(handle, owner, pc1, pc2); +} + +// Static. +void VerifierTraits::StopTracking(HANDLE handle, const void* owner, + const void* pc1, const void* pc2) { + return ActiveVerifier::Get()->StopTracking(handle, owner, pc1, pc2); +} + +void DisableHandleVerifier() { + return ActiveVerifier::Get()->Disable(); +} + +void OnHandleBeingClosed(HANDLE handle) { + return ActiveVerifier::Get()->OnHandleBeingClosed(handle); +} + +} // namespace win +} // namespace base diff --git a/security/sandbox/chromium/base/win/scoped_handle.h b/security/sandbox/chromium/base/win/scoped_handle.h new file mode 100644 index 000000000..404ab6693 --- /dev/null +++ b/security/sandbox/chromium/base/win/scoped_handle.h @@ -0,0 +1,182 @@ +// 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. + +#ifndef BASE_WIN_SCOPED_HANDLE_H_ +#define BASE_WIN_SCOPED_HANDLE_H_ + +#include <windows.h> + +#include "base/base_export.h" +#include "base/location.h" +#include "base/logging.h" +#include "base/macros.h" +#include "base/move.h" + +// TODO(rvargas): remove this with the rest of the verifier. +#if defined(COMPILER_MSVC) +#include <intrin.h> +#define BASE_WIN_GET_CALLER _ReturnAddress() +#elif defined(COMPILER_GCC) +#define BASE_WIN_GET_CALLER __builtin_extract_return_addr(\\ + __builtin_return_address(0)) +#endif + +namespace base { +namespace win { + +// Generic wrapper for raw handles that takes care of closing handles +// automatically. The class interface follows the style of +// the ScopedFILE class with two additions: +// - IsValid() method can tolerate multiple invalid handle values such as NULL +// and INVALID_HANDLE_VALUE (-1) for Win32 handles. +// - Set() (and the constructors and assignment operators that call it) +// preserve the Windows LastError code. This ensures that GetLastError() can +// be called after stashing a handle in a GenericScopedHandle object. Doing +// this explicitly is necessary because of bug 528394 and VC++ 2015. +template <class Traits, class Verifier> +class GenericScopedHandle { + MOVE_ONLY_TYPE_FOR_CPP_03(GenericScopedHandle) + + public: + typedef typename Traits::Handle Handle; + + GenericScopedHandle() : handle_(Traits::NullHandle()) {} + + explicit GenericScopedHandle(Handle handle) : handle_(Traits::NullHandle()) { + Set(handle); + } + + GenericScopedHandle(GenericScopedHandle&& other) + : handle_(Traits::NullHandle()) { + Set(other.Take()); + } + + ~GenericScopedHandle() { + Close(); + } + + bool IsValid() const { + return Traits::IsHandleValid(handle_); + } + + GenericScopedHandle& operator=(GenericScopedHandle&& other) { + DCHECK_NE(this, &other); + Set(other.Take()); + return *this; + } + + void Set(Handle handle) { + if (handle_ != handle) { + // Preserve old LastError to avoid bug 528394. + auto last_error = ::GetLastError(); + Close(); + + if (Traits::IsHandleValid(handle)) { + handle_ = handle; + Verifier::StartTracking(handle, this, BASE_WIN_GET_CALLER, + tracked_objects::GetProgramCounter()); + } + ::SetLastError(last_error); + } + } + + Handle Get() const { + return handle_; + } + + // Transfers ownership away from this object. + Handle Take() { + Handle temp = handle_; + handle_ = Traits::NullHandle(); + if (Traits::IsHandleValid(temp)) { + Verifier::StopTracking(temp, this, BASE_WIN_GET_CALLER, + tracked_objects::GetProgramCounter()); + } + return temp; + } + + // Explicitly closes the owned handle. + void Close() { + if (Traits::IsHandleValid(handle_)) { + Verifier::StopTracking(handle_, this, BASE_WIN_GET_CALLER, + tracked_objects::GetProgramCounter()); + + Traits::CloseHandle(handle_); + handle_ = Traits::NullHandle(); + } + } + + private: + Handle handle_; +}; + +#undef BASE_WIN_GET_CALLER + +// The traits class for Win32 handles that can be closed via CloseHandle() API. +class HandleTraits { + public: + typedef HANDLE Handle; + + // Closes the handle. + static bool BASE_EXPORT CloseHandle(HANDLE handle); + + // Returns true if the handle value is valid. + static bool IsHandleValid(HANDLE handle) { + return handle != NULL && handle != INVALID_HANDLE_VALUE; + } + + // Returns NULL handle value. + static HANDLE NullHandle() { + return NULL; + } + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(HandleTraits); +}; + +// Do-nothing verifier. +class DummyVerifierTraits { + public: + typedef HANDLE Handle; + + static void StartTracking(HANDLE handle, const void* owner, + const void* pc1, const void* pc2) {} + static void StopTracking(HANDLE handle, const void* owner, + const void* pc1, const void* pc2) {} + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(DummyVerifierTraits); +}; + +// Performs actual run-time tracking. +class BASE_EXPORT VerifierTraits { + public: + typedef HANDLE Handle; + + static void StartTracking(HANDLE handle, const void* owner, + const void* pc1, const void* pc2); + static void StopTracking(HANDLE handle, const void* owner, + const void* pc1, const void* pc2); + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(VerifierTraits); +}; + +typedef GenericScopedHandle<HandleTraits, VerifierTraits> ScopedHandle; + +// This function may be called by the embedder to disable the use of +// VerifierTraits at runtime. It has no effect if DummyVerifierTraits is used +// for ScopedHandle. +void BASE_EXPORT DisableHandleVerifier(); + +// This should be called whenever the OS is closing a handle, if extended +// verification of improper handle closing is desired. If |handle| is being +// tracked by the handle verifier and ScopedHandle is not the one closing it, +// a CHECK is generated. +void BASE_EXPORT OnHandleBeingClosed(HANDLE handle); + +} // namespace win +} // namespace base + +#endif // BASE_WIN_SCOPED_HANDLE_H_ diff --git a/security/sandbox/chromium/base/win/scoped_process_information.cc b/security/sandbox/chromium/base/win/scoped_process_information.cc new file mode 100644 index 000000000..634a538ee --- /dev/null +++ b/security/sandbox/chromium/base/win/scoped_process_information.cc @@ -0,0 +1,147 @@ +// 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 "base/win/scoped_process_information.h" + +#include "base/logging.h" +#include "base/win/scoped_handle.h" +#include "base/win/windows_version.h" + +namespace base { +namespace win { + +namespace { + +// Duplicates source into target, returning true upon success. |target| is +// guaranteed to be untouched in case of failure. Succeeds with no side-effects +// if source is NULL. +bool CheckAndDuplicateHandle(HANDLE source, ScopedHandle* target) { + if (!source) + return true; + + HANDLE temp = NULL; + + // TODO(shrikant): Remove following code as soon as we gather some + // information regarding AppContainer related DuplicateHandle failures that + // only seem to happen on certain machine and only random launches (normally + // renderer launches seem to succeed even on those machines.) + if (base::win::GetVersion() == base::win::VERSION_WIN8 || + base::win::GetVersion() == base::win::VERSION_WIN8_1) { + typedef LONG (WINAPI *NtDuplicateObject)( + IN HANDLE SourceProcess, + IN HANDLE SourceHandle, + IN HANDLE TargetProcess, + OUT PHANDLE TargetHandle, + IN ACCESS_MASK DesiredAccess, + IN ULONG Attributes, + IN ULONG Options); + + typedef ULONG (WINAPI *RtlNtStatusToDosError)(IN LONG Status); + + NtDuplicateObject nt_duplicate_object = + reinterpret_cast<NtDuplicateObject>(::GetProcAddress( + GetModuleHandle(L"ntdll.dll"), "NtDuplicateObject")); + if (nt_duplicate_object != NULL) { + LONG status = nt_duplicate_object(::GetCurrentProcess(), source, + ::GetCurrentProcess(), &temp, + 0, FALSE, DUPLICATE_SAME_ACCESS); + if (status < 0) { + DPLOG(ERROR) << "Failed to duplicate a handle."; + RtlNtStatusToDosError ntstatus_to_doserror = + reinterpret_cast<RtlNtStatusToDosError>(::GetProcAddress( + GetModuleHandle(L"ntdll.dll"), "RtlNtStatusToDosError")); + if (ntstatus_to_doserror != NULL) { + ::SetLastError(ntstatus_to_doserror(status)); + } + return false; + } + } + } else { + if (!::DuplicateHandle(::GetCurrentProcess(), source, + ::GetCurrentProcess(), &temp, 0, FALSE, + DUPLICATE_SAME_ACCESS)) { + DPLOG(ERROR) << "Failed to duplicate a handle."; + return false; + } + } + target->Set(temp); + return true; +} + +} // namespace + +ScopedProcessInformation::ScopedProcessInformation() + : process_id_(0), thread_id_(0) { +} + +ScopedProcessInformation::ScopedProcessInformation( + const PROCESS_INFORMATION& process_info) : process_id_(0), thread_id_(0) { + Set(process_info); +} + +ScopedProcessInformation::~ScopedProcessInformation() { + Close(); +} + +bool ScopedProcessInformation::IsValid() const { + return process_id_ || process_handle_.Get() || + thread_id_ || thread_handle_.Get(); +} + +void ScopedProcessInformation::Close() { + process_handle_.Close(); + thread_handle_.Close(); + process_id_ = 0; + thread_id_ = 0; +} + +void ScopedProcessInformation::Set(const PROCESS_INFORMATION& process_info) { + if (IsValid()) + Close(); + + process_handle_.Set(process_info.hProcess); + thread_handle_.Set(process_info.hThread); + process_id_ = process_info.dwProcessId; + thread_id_ = process_info.dwThreadId; +} + +bool ScopedProcessInformation::DuplicateFrom( + const ScopedProcessInformation& other) { + DCHECK(!IsValid()) << "target ScopedProcessInformation must be NULL"; + DCHECK(other.IsValid()) << "source ScopedProcessInformation must be valid"; + + if (CheckAndDuplicateHandle(other.process_handle(), &process_handle_) && + CheckAndDuplicateHandle(other.thread_handle(), &thread_handle_)) { + process_id_ = other.process_id(); + thread_id_ = other.thread_id(); + return true; + } + + return false; +} + +PROCESS_INFORMATION ScopedProcessInformation::Take() { + PROCESS_INFORMATION process_information = {}; + process_information.hProcess = process_handle_.Take(); + process_information.hThread = thread_handle_.Take(); + process_information.dwProcessId = process_id(); + process_information.dwThreadId = thread_id(); + process_id_ = 0; + thread_id_ = 0; + + return process_information; +} + +HANDLE ScopedProcessInformation::TakeProcessHandle() { + process_id_ = 0; + return process_handle_.Take(); +} + +HANDLE ScopedProcessInformation::TakeThreadHandle() { + thread_id_ = 0; + return thread_handle_.Take(); +} + +} // namespace win +} // namespace base diff --git a/security/sandbox/chromium/base/win/scoped_process_information.h b/security/sandbox/chromium/base/win/scoped_process_information.h new file mode 100644 index 000000000..01df861f0 --- /dev/null +++ b/security/sandbox/chromium/base/win/scoped_process_information.h @@ -0,0 +1,83 @@ +// 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. + +#ifndef BASE_WIN_SCOPED_PROCESS_INFORMATION_H_ +#define BASE_WIN_SCOPED_PROCESS_INFORMATION_H_ + +#include <windows.h> + +#include "base/base_export.h" +#include "base/macros.h" +#include "base/win/scoped_handle.h" + +namespace base { +namespace win { + +// Manages the closing of process and thread handles from PROCESS_INFORMATION +// structures. Allows clients to take ownership of either handle independently. +class BASE_EXPORT ScopedProcessInformation { + public: + ScopedProcessInformation(); + explicit ScopedProcessInformation(const PROCESS_INFORMATION& process_info); + ~ScopedProcessInformation(); + + // Returns true iff this instance is holding a thread and/or process handle. + bool IsValid() const; + + // Closes the held thread and process handles, if any. + void Close(); + + // Populates this instance with the provided |process_info|. + void Set(const PROCESS_INFORMATION& process_info); + + // Populates this instance with duplicate handles and the thread/process IDs + // from |other|. Returns false in case of failure, in which case this instance + // will be completely unpopulated. + bool DuplicateFrom(const ScopedProcessInformation& other); + + // Transfers ownership of the held PROCESS_INFORMATION, if any, away from this + // instance. + PROCESS_INFORMATION Take(); + + // Transfers ownership of the held process handle, if any, away from this + // instance. Note that the related process_id will also be cleared. + HANDLE TakeProcessHandle(); + + // Transfers ownership of the held thread handle, if any, away from this + // instance. Note that the related thread_id will also be cleared. + HANDLE TakeThreadHandle(); + + // Returns the held process handle, if any, while retaining ownership. + HANDLE process_handle() const { + return process_handle_.Get(); + } + + // Returns the held thread handle, if any, while retaining ownership. + HANDLE thread_handle() const { + return thread_handle_.Get(); + } + + // Returns the held process id, if any. + DWORD process_id() const { + return process_id_; + } + + // Returns the held thread id, if any. + DWORD thread_id() const { + return thread_id_; + } + + private: + ScopedHandle process_handle_; + ScopedHandle thread_handle_; + DWORD process_id_; + DWORD thread_id_; + + DISALLOW_COPY_AND_ASSIGN(ScopedProcessInformation); +}; + +} // namespace win +} // namespace base + +#endif // BASE_WIN_SCOPED_PROCESS_INFORMATION_H_ diff --git a/security/sandbox/chromium/base/win/startup_information.cc b/security/sandbox/chromium/base/win/startup_information.cc new file mode 100644 index 000000000..aff52eb79 --- /dev/null +++ b/security/sandbox/chromium/base/win/startup_information.cc @@ -0,0 +1,109 @@ +// 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 "base/win/startup_information.h" + +#include "base/logging.h" +#include "base/win/windows_version.h" + +namespace { + +typedef BOOL (WINAPI *InitializeProcThreadAttributeListFunction)( + LPPROC_THREAD_ATTRIBUTE_LIST attribute_list, + DWORD attribute_count, + DWORD flags, + PSIZE_T size); +static InitializeProcThreadAttributeListFunction + initialize_proc_thread_attribute_list; + +typedef BOOL (WINAPI *UpdateProcThreadAttributeFunction)( + LPPROC_THREAD_ATTRIBUTE_LIST attribute_list, + DWORD flags, + DWORD_PTR attribute, + PVOID value, + SIZE_T size, + PVOID previous_value, + PSIZE_T return_size); +static UpdateProcThreadAttributeFunction update_proc_thread_attribute_list; + +typedef VOID (WINAPI *DeleteProcThreadAttributeListFunction)( + LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList); +static DeleteProcThreadAttributeListFunction delete_proc_thread_attribute_list; + +} // namespace + +namespace base { +namespace win { + +StartupInformation::StartupInformation() { + memset(&startup_info_, 0, sizeof(startup_info_)); + + // Pre Windows Vista doesn't support STARTUPINFOEX. + if (base::win::GetVersion() < base::win::VERSION_VISTA) { + startup_info_.StartupInfo.cb = sizeof(STARTUPINFO); + return; + } + + startup_info_.StartupInfo.cb = sizeof(startup_info_); + + // Load the attribute API functions. + if (!initialize_proc_thread_attribute_list || + !update_proc_thread_attribute_list || + !delete_proc_thread_attribute_list) { + HMODULE module = ::GetModuleHandleW(L"kernel32.dll"); + initialize_proc_thread_attribute_list = + reinterpret_cast<InitializeProcThreadAttributeListFunction>( + ::GetProcAddress(module, "InitializeProcThreadAttributeList")); + update_proc_thread_attribute_list = + reinterpret_cast<UpdateProcThreadAttributeFunction>( + ::GetProcAddress(module, "UpdateProcThreadAttribute")); + delete_proc_thread_attribute_list = + reinterpret_cast<DeleteProcThreadAttributeListFunction>( + ::GetProcAddress(module, "DeleteProcThreadAttributeList")); + } +} + +StartupInformation::~StartupInformation() { + if (startup_info_.lpAttributeList) { + delete_proc_thread_attribute_list(startup_info_.lpAttributeList); + delete [] reinterpret_cast<BYTE*>(startup_info_.lpAttributeList); + } +} + +bool StartupInformation::InitializeProcThreadAttributeList( + DWORD attribute_count) { + if (startup_info_.StartupInfo.cb != sizeof(startup_info_) || + startup_info_.lpAttributeList) + return false; + + SIZE_T size = 0; + initialize_proc_thread_attribute_list(NULL, attribute_count, 0, &size); + if (size == 0) + return false; + + startup_info_.lpAttributeList = + reinterpret_cast<LPPROC_THREAD_ATTRIBUTE_LIST>(new BYTE[size]); + if (!initialize_proc_thread_attribute_list(startup_info_.lpAttributeList, + attribute_count, 0, &size)) { + delete [] reinterpret_cast<BYTE*>(startup_info_.lpAttributeList); + startup_info_.lpAttributeList = NULL; + return false; + } + + return true; +} + +bool StartupInformation::UpdateProcThreadAttribute( + DWORD_PTR attribute, + void* value, + size_t size) { + if (!startup_info_.lpAttributeList) + return false; + return !!update_proc_thread_attribute_list(startup_info_.lpAttributeList, 0, + attribute, value, size, NULL, NULL); +} + +} // namespace win +} // namespace base + diff --git a/security/sandbox/chromium/base/win/startup_information.h b/security/sandbox/chromium/base/win/startup_information.h new file mode 100644 index 000000000..5b777baef --- /dev/null +++ b/security/sandbox/chromium/base/win/startup_information.h @@ -0,0 +1,51 @@ +// 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. + +#ifndef BASE_WIN_STARTUP_INFORMATION_H_ +#define BASE_WIN_STARTUP_INFORMATION_H_ + +#include <windows.h> +#include <stddef.h> + +#include "base/base_export.h" +#include "base/macros.h" + +namespace base { +namespace win { + +// Manages the lifetime of additional attributes in STARTUPINFOEX. +class BASE_EXPORT StartupInformation { + public: + StartupInformation(); + + ~StartupInformation(); + + // Initialize the attribute list for the specified number of entries. + bool InitializeProcThreadAttributeList(DWORD attribute_count); + + // Sets one entry in the initialized attribute list. + // |value| needs to live at least as long as the StartupInformation object + // this is called on. + bool UpdateProcThreadAttribute(DWORD_PTR attribute, + void* value, + size_t size); + + LPSTARTUPINFOW startup_info() { return &startup_info_.StartupInfo; } + LPSTARTUPINFOW startup_info() const { + return const_cast<const LPSTARTUPINFOW>(&startup_info_.StartupInfo); + } + + bool has_extended_startup_info() const { + return !!startup_info_.lpAttributeList; + } + + private: + STARTUPINFOEXW startup_info_; + DISALLOW_COPY_AND_ASSIGN(StartupInformation); +}; + +} // namespace win +} // namespace base + +#endif // BASE_WIN_STARTUP_INFORMATION_H_ diff --git a/security/sandbox/chromium/base/win/windows_version.cc b/security/sandbox/chromium/base/win/windows_version.cc new file mode 100644 index 000000000..eb3f4993d --- /dev/null +++ b/security/sandbox/chromium/base/win/windows_version.cc @@ -0,0 +1,225 @@ +// 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 "base/win/windows_version.h" + +#include <windows.h> + +#include "base/file_version_info_win.h" +#include "base/files/file_path.h" +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "base/strings/utf_string_conversions.h" +#include "base/win/registry.h" + +namespace { +typedef BOOL (WINAPI *GetProductInfoPtr)(DWORD, DWORD, DWORD, DWORD, PDWORD); +} // namespace + +namespace base { +namespace win { + +namespace { + +// Helper to map a major.minor.x.build version (e.g. 6.1) to a Windows release. +Version MajorMinorBuildToVersion(int major, int minor, int build) { + if ((major == 5) && (minor > 0)) { + // Treat XP Pro x64, Home Server, and Server 2003 R2 as Server 2003. + return (minor == 1) ? VERSION_XP : VERSION_SERVER_2003; + } else if (major == 6) { + switch (minor) { + case 0: + // Treat Windows Server 2008 the same as Windows Vista. + return VERSION_VISTA; + case 1: + // Treat Windows Server 2008 R2 the same as Windows 7. + return VERSION_WIN7; + case 2: + // Treat Windows Server 2012 the same as Windows 8. + return VERSION_WIN8; + default: + DCHECK_EQ(minor, 3); + return VERSION_WIN8_1; + } + } else if (major == 10) { + if (build < 10586) { + return VERSION_WIN10; + } else { + return VERSION_WIN10_TH2; + } + } else if (major > 6) { + NOTREACHED(); + return VERSION_WIN_LAST; + } + + return VERSION_PRE_XP; +} + +// Retrieve a version from kernel32. This is useful because when running in +// compatibility mode for a down-level version of the OS, the file version of +// kernel32 will still be the "real" version. +Version GetVersionFromKernel32() { + scoped_ptr<FileVersionInfoWin> file_version_info( + static_cast<FileVersionInfoWin*>( + FileVersionInfoWin::CreateFileVersionInfo( + base::FilePath(FILE_PATH_LITERAL("kernel32.dll"))))); + if (file_version_info) { + const int major = + HIWORD(file_version_info->fixed_file_info()->dwFileVersionMS); + const int minor = + LOWORD(file_version_info->fixed_file_info()->dwFileVersionMS); + const int build = + HIWORD(file_version_info->fixed_file_info()->dwFileVersionLS); + return MajorMinorBuildToVersion(major, minor, build); + } + + NOTREACHED(); + return VERSION_WIN_LAST; +} + +} // namespace + +// static +OSInfo* OSInfo::GetInstance() { + // Note: we don't use the Singleton class because it depends on AtExitManager, + // and it's convenient for other modules to use this classs without it. This + // pattern is copied from gurl.cc. + static OSInfo* info; + if (!info) { + OSInfo* new_info = new OSInfo(); + if (InterlockedCompareExchangePointer( + reinterpret_cast<PVOID*>(&info), new_info, NULL)) { + delete new_info; + } + } + return info; +} + +OSInfo::OSInfo() + : version_(VERSION_PRE_XP), + kernel32_version_(VERSION_PRE_XP), + got_kernel32_version_(false), + architecture_(OTHER_ARCHITECTURE), + wow64_status_(GetWOW64StatusForProcess(GetCurrentProcess())) { + OSVERSIONINFOEX version_info = { sizeof version_info }; + ::GetVersionEx(reinterpret_cast<OSVERSIONINFO*>(&version_info)); + version_number_.major = version_info.dwMajorVersion; + version_number_.minor = version_info.dwMinorVersion; + version_number_.build = version_info.dwBuildNumber; + version_ = MajorMinorBuildToVersion( + version_number_.major, version_number_.minor, version_number_.build); + service_pack_.major = version_info.wServicePackMajor; + service_pack_.minor = version_info.wServicePackMinor; + + SYSTEM_INFO system_info = {}; + ::GetNativeSystemInfo(&system_info); + switch (system_info.wProcessorArchitecture) { + case PROCESSOR_ARCHITECTURE_INTEL: architecture_ = X86_ARCHITECTURE; break; + case PROCESSOR_ARCHITECTURE_AMD64: architecture_ = X64_ARCHITECTURE; break; + case PROCESSOR_ARCHITECTURE_IA64: architecture_ = IA64_ARCHITECTURE; break; + } + processors_ = system_info.dwNumberOfProcessors; + allocation_granularity_ = system_info.dwAllocationGranularity; + + GetProductInfoPtr get_product_info; + DWORD os_type; + + if (version_info.dwMajorVersion == 6 || version_info.dwMajorVersion == 10) { + // Only present on Vista+. + get_product_info = reinterpret_cast<GetProductInfoPtr>( + ::GetProcAddress(::GetModuleHandle(L"kernel32.dll"), "GetProductInfo")); + + get_product_info(version_info.dwMajorVersion, version_info.dwMinorVersion, + 0, 0, &os_type); + switch (os_type) { + case PRODUCT_CLUSTER_SERVER: + case PRODUCT_DATACENTER_SERVER: + case PRODUCT_DATACENTER_SERVER_CORE: + case PRODUCT_ENTERPRISE_SERVER: + case PRODUCT_ENTERPRISE_SERVER_CORE: + case PRODUCT_ENTERPRISE_SERVER_IA64: + case PRODUCT_SMALLBUSINESS_SERVER: + case PRODUCT_SMALLBUSINESS_SERVER_PREMIUM: + case PRODUCT_STANDARD_SERVER: + case PRODUCT_STANDARD_SERVER_CORE: + case PRODUCT_WEB_SERVER: + version_type_ = SUITE_SERVER; + break; + case PRODUCT_PROFESSIONAL: + case PRODUCT_ULTIMATE: + case PRODUCT_ENTERPRISE: + case PRODUCT_BUSINESS: + version_type_ = SUITE_PROFESSIONAL; + break; + case PRODUCT_HOME_BASIC: + case PRODUCT_HOME_PREMIUM: + case PRODUCT_STARTER: + default: + version_type_ = SUITE_HOME; + break; + } + } else if (version_info.dwMajorVersion == 5 && + version_info.dwMinorVersion == 2) { + if (version_info.wProductType == VER_NT_WORKSTATION && + system_info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) { + version_type_ = SUITE_PROFESSIONAL; + } else if (version_info.wSuiteMask & VER_SUITE_WH_SERVER ) { + version_type_ = SUITE_HOME; + } else { + version_type_ = SUITE_SERVER; + } + } else if (version_info.dwMajorVersion == 5 && + version_info.dwMinorVersion == 1) { + if(version_info.wSuiteMask & VER_SUITE_PERSONAL) + version_type_ = SUITE_HOME; + else + version_type_ = SUITE_PROFESSIONAL; + } else { + // Windows is pre XP so we don't care but pick a safe default. + version_type_ = SUITE_HOME; + } +} + +OSInfo::~OSInfo() { +} + +Version OSInfo::Kernel32Version() const { + if (!got_kernel32_version_) { + kernel32_version_ = GetVersionFromKernel32(); + got_kernel32_version_ = true; + } + return kernel32_version_; +} + +std::string OSInfo::processor_model_name() { + if (processor_model_name_.empty()) { + const wchar_t kProcessorNameString[] = + L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"; + base::win::RegKey key(HKEY_LOCAL_MACHINE, kProcessorNameString, KEY_READ); + string16 value; + key.ReadValue(L"ProcessorNameString", &value); + processor_model_name_ = UTF16ToUTF8(value); + } + return processor_model_name_; +} + +// static +OSInfo::WOW64Status OSInfo::GetWOW64StatusForProcess(HANDLE process_handle) { + typedef BOOL (WINAPI* IsWow64ProcessFunc)(HANDLE, PBOOL); + IsWow64ProcessFunc is_wow64_process = reinterpret_cast<IsWow64ProcessFunc>( + GetProcAddress(GetModuleHandle(L"kernel32.dll"), "IsWow64Process")); + if (!is_wow64_process) + return WOW64_DISABLED; + BOOL is_wow64 = FALSE; + if (!(*is_wow64_process)(process_handle, &is_wow64)) + return WOW64_UNKNOWN; + return is_wow64 ? WOW64_ENABLED : WOW64_DISABLED; +} + +Version GetVersion() { + return OSInfo::GetInstance()->version(); +} + +} // namespace win +} // namespace base diff --git a/security/sandbox/chromium/base/win/windows_version.h b/security/sandbox/chromium/base/win/windows_version.h new file mode 100644 index 000000000..7bc8b6fe5 --- /dev/null +++ b/security/sandbox/chromium/base/win/windows_version.h @@ -0,0 +1,133 @@ +// 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. + +#ifndef BASE_WIN_WINDOWS_VERSION_H_ +#define BASE_WIN_WINDOWS_VERSION_H_ + +#include <stddef.h> + +#include <string> + +#include "base/base_export.h" +#include "base/macros.h" + +typedef void* HANDLE; + +namespace base { +namespace win { + +// The running version of Windows. This is declared outside OSInfo for +// syntactic sugar reasons; see the declaration of GetVersion() below. +// NOTE: Keep these in order so callers can do things like +// "if (base::win::GetVersion() >= base::win::VERSION_VISTA) ...". +// +// This enum is used in metrics histograms, so they shouldn't be reordered or +// removed. New values can be added before VERSION_WIN_LAST. +enum Version { + VERSION_PRE_XP = 0, // Not supported. + VERSION_XP = 1, + VERSION_SERVER_2003 = 2, // Also includes XP Pro x64 and Server 2003 R2. + VERSION_VISTA = 3, // Also includes Windows Server 2008. + VERSION_WIN7 = 4, // Also includes Windows Server 2008 R2. + VERSION_WIN8 = 5, // Also includes Windows Server 2012. + VERSION_WIN8_1 = 6, // Also includes Windows Server 2012 R2. + VERSION_WIN10 = 7, // Also includes Windows 10 Server. + VERSION_WIN10_TH2 = 8, // Threshold 2: Version 1511, Build 10586. + VERSION_WIN_LAST, // Indicates error condition. +}; + +// A rough bucketing of the available types of versions of Windows. This is used +// to distinguish enterprise enabled versions from home versions and potentially +// server versions. +enum VersionType { + SUITE_HOME, + SUITE_PROFESSIONAL, + SUITE_SERVER, + SUITE_LAST, +}; + +// A singleton that can be used to query various pieces of information about the +// OS and process state. Note that this doesn't use the base Singleton class, so +// it can be used without an AtExitManager. +class BASE_EXPORT OSInfo { + public: + struct VersionNumber { + int major; + int minor; + int build; + }; + + struct ServicePack { + int major; + int minor; + }; + + // The processor architecture this copy of Windows natively uses. For + // example, given an x64-capable processor, we have three possibilities: + // 32-bit Chrome running on 32-bit Windows: X86_ARCHITECTURE + // 32-bit Chrome running on 64-bit Windows via WOW64: X64_ARCHITECTURE + // 64-bit Chrome running on 64-bit Windows: X64_ARCHITECTURE + enum WindowsArchitecture { + X86_ARCHITECTURE, + X64_ARCHITECTURE, + IA64_ARCHITECTURE, + OTHER_ARCHITECTURE, + }; + + // Whether a process is running under WOW64 (the wrapper that allows 32-bit + // processes to run on 64-bit versions of Windows). This will return + // WOW64_DISABLED for both "32-bit Chrome on 32-bit Windows" and "64-bit + // Chrome on 64-bit Windows". WOW64_UNKNOWN means "an error occurred", e.g. + // the process does not have sufficient access rights to determine this. + enum WOW64Status { + WOW64_DISABLED, + WOW64_ENABLED, + WOW64_UNKNOWN, + }; + + static OSInfo* GetInstance(); + + Version version() const { return version_; } + Version Kernel32Version() const; + // The next two functions return arrays of values, [major, minor(, build)]. + VersionNumber version_number() const { return version_number_; } + VersionType version_type() const { return version_type_; } + ServicePack service_pack() const { return service_pack_; } + WindowsArchitecture architecture() const { return architecture_; } + int processors() const { return processors_; } + size_t allocation_granularity() const { return allocation_granularity_; } + WOW64Status wow64_status() const { return wow64_status_; } + std::string processor_model_name(); + + // Like wow64_status(), but for the supplied handle instead of the current + // process. This doesn't touch member state, so you can bypass the singleton. + static WOW64Status GetWOW64StatusForProcess(HANDLE process_handle); + + private: + OSInfo(); + ~OSInfo(); + + Version version_; + mutable Version kernel32_version_; + mutable bool got_kernel32_version_; + VersionNumber version_number_; + VersionType version_type_; + ServicePack service_pack_; + WindowsArchitecture architecture_; + int processors_; + size_t allocation_granularity_; + WOW64Status wow64_status_; + std::string processor_model_name_; + + DISALLOW_COPY_AND_ASSIGN(OSInfo); +}; + +// Because this is by far the most commonly-requested value from the above +// singleton, we add a global-scope accessor here as syntactic sugar. +BASE_EXPORT Version GetVersion(); + +} // namespace win +} // namespace base + +#endif // BASE_WIN_WINDOWS_VERSION_H_ |