diff options
Diffstat (limited to 'sandbox/src/win_utils.cc')
-rw-r--r-- | sandbox/src/win_utils.cc | 323 |
1 files changed, 0 insertions, 323 deletions
diff --git a/sandbox/src/win_utils.cc b/sandbox/src/win_utils.cc deleted file mode 100644 index 8a43d97..0000000 --- a/sandbox/src/win_utils.cc +++ /dev/null @@ -1,323 +0,0 @@ -// Copyright (c) 2011 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/src/win_utils.h" - -#include <map> - -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "sandbox/src/internal_types.h" -#include "sandbox/src/nt_internals.h" - -namespace { - -// Holds the information about a known registry key. -struct KnownReservedKey { - const wchar_t* name; - HKEY key; -}; - -// Contains all the known registry key by name and by handle. -const KnownReservedKey kKnownKey[] = { - { L"HKEY_CLASSES_ROOT", HKEY_CLASSES_ROOT }, - { L"HKEY_CURRENT_USER", HKEY_CURRENT_USER }, - { L"HKEY_LOCAL_MACHINE", HKEY_LOCAL_MACHINE}, - { L"HKEY_USERS", HKEY_USERS}, - { L"HKEY_PERFORMANCE_DATA", HKEY_PERFORMANCE_DATA}, - { L"HKEY_PERFORMANCE_TEXT", HKEY_PERFORMANCE_TEXT}, - { L"HKEY_PERFORMANCE_NLSTEXT", HKEY_PERFORMANCE_NLSTEXT}, - { L"HKEY_CURRENT_CONFIG", HKEY_CURRENT_CONFIG}, - { L"HKEY_DYN_DATA", HKEY_DYN_DATA} -}; - -// Returns true if the provided path points to a pipe. -bool IsPipe(const std::wstring& path) { - size_t start = 0; - if (0 == path.compare(0, sandbox::kNTPrefixLen, sandbox::kNTPrefix)) - start = sandbox::kNTPrefixLen; - - const wchar_t kPipe[] = L"pipe\\"; - return (0 == path.compare(start, arraysize(kPipe) - 1, kPipe)); -} - -} // namespace - -namespace sandbox { - -HKEY GetReservedKeyFromName(const std::wstring& name) { - for (size_t i = 0; i < arraysize(kKnownKey); ++i) { - if (name == kKnownKey[i].name) - return kKnownKey[i].key; - } - - return NULL; -} - -bool ResolveRegistryName(std::wstring name, std::wstring* resolved_name) { - for (size_t i = 0; i < arraysize(kKnownKey); ++i) { - if (name.find(kKnownKey[i].name) == 0) { - HKEY key; - DWORD disposition; - if (ERROR_SUCCESS != ::RegCreateKeyEx(kKnownKey[i].key, L"", 0, NULL, 0, - MAXIMUM_ALLOWED, NULL, &key, - &disposition)) - return false; - - bool result = GetPathFromHandle(key, resolved_name); - ::RegCloseKey(key); - - if (!result) - return false; - - *resolved_name += name.substr(wcslen(kKnownKey[i].name)); - return true; - } - } - - return false; -} - -DWORD IsReparsePoint(const std::wstring& full_path, bool* result) { - std::wstring path = full_path; - - // Remove the nt prefix. - if (0 == path.compare(0, kNTPrefixLen, kNTPrefix)) - path = path.substr(kNTPrefixLen); - - // Check if it's a pipe. We can't query the attributes of a pipe. - if (IsPipe(path)) { - *result = FALSE; - return ERROR_SUCCESS; - } - - std::wstring::size_type last_pos = std::wstring::npos; - - do { - path = path.substr(0, last_pos); - - DWORD attributes = ::GetFileAttributes(path.c_str()); - if (INVALID_FILE_ATTRIBUTES == attributes) { - DWORD error = ::GetLastError(); - if (error != ERROR_FILE_NOT_FOUND && - error != ERROR_PATH_NOT_FOUND && - error != ERROR_INVALID_NAME) { - // Unexpected error. - NOTREACHED(); - return error; - } - } else if (FILE_ATTRIBUTE_REPARSE_POINT & attributes) { - // This is a reparse point. - *result = true; - return ERROR_SUCCESS; - } - - last_pos = path.rfind(L'\\'); - } while (last_pos != std::wstring::npos); - - *result = false; - return ERROR_SUCCESS; -} - -// We get a |full_path| of the form \??\c:\some\foo\bar, and the name that -// we'll get from |handle| will be \device\harddiskvolume1\some\foo\bar. -bool SameObject(HANDLE handle, const wchar_t* full_path) { - std::wstring path(full_path); - DCHECK(!path.empty()); - - // Check if it's a pipe. - if (IsPipe(path)) - return true; - - std::wstring actual_path; - if (!GetPathFromHandle(handle, &actual_path)) - return false; - - // This may end with a backslash. - const wchar_t kBackslash = '\\'; - if (path[path.length() - 1] == kBackslash) - path = path.substr(0, path.length() - 1); - - // Perfect match (case-insesitive check). - if (0 == _wcsicmp(actual_path.c_str(), path.c_str())) - return true; - - // Look for the drive letter. - size_t colon_pos = path.find(L':'); - if (colon_pos == 0 || colon_pos == std::wstring::npos) - return false; - - // Only one character for the drive. - if (colon_pos > 1 && path[colon_pos - 2] != kBackslash) - return false; - - // We only need 3 chars, but let's alloc a buffer for four. - wchar_t drive[4] = {0}; - wchar_t vol_name[MAX_PATH]; - memcpy(drive, &path[colon_pos - 1], 2 * sizeof(*drive)); - - // We'll get a double null terminated string. - DWORD vol_length = ::QueryDosDeviceW(drive, vol_name, MAX_PATH); - if (vol_length < 2 || vol_length == MAX_PATH) - return false; - - // Ignore the nulls at the end. - vol_length = static_cast<DWORD>(wcslen(vol_name)); - - // The two paths should be the same length. - if (vol_length + path.size() - (colon_pos + 1) != actual_path.size()) - return false; - - // Check up to the drive letter. - if (0 != _wcsnicmp(actual_path.c_str(), vol_name, vol_length)) - return false; - - // Check the path after the drive letter. - if (0 != _wcsicmp(&actual_path[vol_length], &path[colon_pos + 1])) - return false; - - return true; -} - -bool ConvertToLongPath(const std::wstring& short_path, - std::wstring* long_path) { - // Check if the path is a NT path. - bool is_nt_path = false; - std::wstring path = short_path; - if (0 == path.compare(0, kNTPrefixLen, kNTPrefix)) { - path = path.substr(kNTPrefixLen); - is_nt_path = true; - } - - DWORD size = MAX_PATH; - scoped_array<wchar_t> long_path_buf(new wchar_t[size]); - - DWORD return_value = ::GetLongPathName(path.c_str(), long_path_buf.get(), - size); - while (return_value >= size) { - size *= 2; - long_path_buf.reset(new wchar_t[size]); - return_value = ::GetLongPathName(path.c_str(), long_path_buf.get(), size); - } - - DWORD last_error = ::GetLastError(); - if (0 == return_value && (ERROR_FILE_NOT_FOUND == last_error || - ERROR_PATH_NOT_FOUND == last_error || - ERROR_INVALID_NAME == last_error)) { - // The file does not exist, but maybe a sub path needs to be expanded. - std::wstring::size_type last_slash = path.rfind(L'\\'); - if (std::wstring::npos == last_slash) - return false; - - std::wstring begin = path.substr(0, last_slash); - std::wstring end = path.substr(last_slash); - if (!ConvertToLongPath(begin, &begin)) - return false; - - // Ok, it worked. Let's reset the return value. - path = begin + end; - return_value = 1; - } else if (0 != return_value) { - path = long_path_buf.get(); - } - - if (return_value != 0) { - if (is_nt_path) { - *long_path = kNTPrefix; - *long_path += path; - } else { - *long_path = path; - } - - return true; - } - - return false; -} - -bool GetPathFromHandle(HANDLE handle, std::wstring* path) { - NtQueryObjectFunction NtQueryObject = NULL; - ResolveNTFunctionPtr("NtQueryObject", &NtQueryObject); - - OBJECT_NAME_INFORMATION initial_buffer; - OBJECT_NAME_INFORMATION* name = &initial_buffer; - ULONG size = sizeof(initial_buffer); - // Query the name information a first time to get the size of the name. - NTSTATUS status = NtQueryObject(handle, ObjectNameInformation, name, size, - &size); - - scoped_ptr<OBJECT_NAME_INFORMATION> name_ptr; - if (size) { - name = reinterpret_cast<OBJECT_NAME_INFORMATION*>(new BYTE[size]); - name_ptr.reset(name); - - // Query the name information a second time to get the name of the - // object referenced by the handle. - status = NtQueryObject(handle, ObjectNameInformation, name, size, &size); - } - - if (STATUS_SUCCESS != status) - return false; - - path->assign(name->ObjectName.Buffer, name->ObjectName.Length / - sizeof(name->ObjectName.Buffer[0])); - return true; -} - -bool GetNtPathFromWin32Path(const std::wstring& path, std::wstring* nt_path) { - HANDLE file = ::CreateFileW(path.c_str(), 0, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, - OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); - if (file == INVALID_HANDLE_VALUE) - return false; - bool rv = GetPathFromHandle(file, nt_path); - ::CloseHandle(file); - return rv; -} - -bool WriteProtectedChildMemory(HANDLE child_process, void* address, - const void* buffer, size_t length) { - // First, remove the protections. - DWORD old_protection; - if (!::VirtualProtectEx(child_process, address, length, - PAGE_WRITECOPY, &old_protection)) - return false; - - SIZE_T written; - bool ok = ::WriteProcessMemory(child_process, address, buffer, length, - &written) && (length == written); - - // Always attempt to restore the original protection. - if (!::VirtualProtectEx(child_process, address, length, - old_protection, &old_protection)) - return false; - - return ok; -} - -}; // namespace sandbox - -// TODO(jschuh): http://crbug.com/11789 -// I'm guessing we have a race where some "security" software is messing -// with ntdll/imports underneath us. So, we retry a few times, and in the -// worst case we sleep briefly before a few more attempts. (Normally sleeping -// would be very bad, but it's better than crashing in this case.) -void ResolveNTFunctionPtr(const char* name, void* ptr) { - const int max_tries = 5; - const int sleep_threshold = 2; - - static HMODULE ntdll = ::GetModuleHandle(sandbox::kNtdllName); - - FARPROC* function_ptr = reinterpret_cast<FARPROC*>(ptr); - *function_ptr = ::GetProcAddress(ntdll, name); - - for (int tries = 1; !(*function_ptr) && tries < max_tries; ++tries) { - if (tries >= sleep_threshold) - ::Sleep(1); - ntdll = ::GetModuleHandle(sandbox::kNtdllName); - *function_ptr = ::GetProcAddress(ntdll, name); - } - - CHECK(*function_ptr); -} |