Commit 31fc1d25 authored by caitkp@chromium.org's avatar caitkp@chromium.org

Use an alternate mechanism for CreateFile calls in Chrome

BUG=334379

Review URL: https://codereview.chromium.org/138593004

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@245464 0039d316-1c4b-4281-b951-d872f2087c98
parent 675f2f2d
...@@ -2478,6 +2478,13 @@ ...@@ -2478,6 +2478,13 @@
['enable_ipc_fuzzer==1', { ['enable_ipc_fuzzer==1', {
'defines': ['ENABLE_IPC_FUZZER=1'], 'defines': ['ENABLE_IPC_FUZZER=1'],
}], }],
['OS=="win" and component=="shared_library"', {
'dependencies': [
# All targets in a component build must depend on chrome_redirects,
# to ensure that certain calls go through it.
'<(DEPTH)/chrome_elf/chrome_elf.gyp:chrome_redirects',
],
}],
], # conditions for 'target_defaults' ], # conditions for 'target_defaults'
'target_conditions': [ 'target_conditions': [
['enable_wexit_time_destructors==1', { ['enable_wexit_time_destructors==1', {
......
...@@ -84,6 +84,11 @@ ...@@ -84,6 +84,11 @@
'../content/content.gyp:content_app_browser', '../content/content.gyp:content_app_browser',
], ],
'conditions': [ 'conditions': [
['OS=="win"', {
'dependencies': [
'<(DEPTH)/chrome_elf/chrome_elf.gyp:chrome_elf',
],
}],
['use_aura==1', { ['use_aura==1', {
'dependencies': [ 'dependencies': [
'../ui/compositor/compositor.gyp:compositor', '../ui/compositor/compositor.gyp:compositor',
...@@ -363,6 +368,13 @@ ...@@ -363,6 +368,13 @@
'app/chrome_main_delegate.cc', 'app/chrome_main_delegate.cc',
'app/chrome_main_delegate.h', 'app/chrome_main_delegate.h',
], ],
'conditions': [
['OS=="win"', {
'dependencies': [
'<(DEPTH)/chrome_elf/chrome_elf.gyp:chrome_elf',
],
}],
],
}, # target chrome_child_dll }, # target chrome_child_dll
], ],
}], }],
......
...@@ -512,6 +512,7 @@ ...@@ -512,6 +512,7 @@
'../base/base.gyp:base', '../base/base.gyp:base',
'../breakpad/breakpad.gyp:breakpad_handler', '../breakpad/breakpad.gyp:breakpad_handler',
'../breakpad/breakpad.gyp:breakpad_sender', '../breakpad/breakpad.gyp:breakpad_sender',
'../chrome_elf/chrome_elf.gyp:chrome_elf',
'../components/components.gyp:breakpad_component', '../components/components.gyp:breakpad_component',
'../components/components.gyp:policy', '../components/components.gyp:policy',
'../chrome_elf/chrome_elf.gyp:chrome_elf', '../chrome_elf/chrome_elf.gyp:chrome_elf',
......
...@@ -5,4 +5,5 @@ ...@@ -5,4 +5,5 @@
LIBRARY "chrome_elf.dll" LIBRARY "chrome_elf.dll"
EXPORTS EXPORTS
CreateFileW=chrome_redirects.CreateFileW
SignalChromeElf SignalChromeElf
...@@ -11,6 +11,35 @@ ...@@ -11,6 +11,35 @@
'blacklist.gypi', 'blacklist.gypi',
], ],
'targets': [ 'targets': [
{
'target_name': 'chrome_redirects',
'type': 'shared_library',
'include_dirs': [
'..',
],
'sources': [
'chrome_redirects.def',
],
'dependencies': [
'chrome_elf_lib',
],
'msvs_settings': {
'VCLinkerTool': {
'BaseAddress': '0x01c10000',
# Set /SUBSYSTEM:WINDOWS.
'SubSystem': '2',
},
},
'conditions': [
['component=="shared_library"', {
# In component builds, all targets depend on chrome_redirects by
# default. Remove it here to avoid a circular dependency.
'dependencies!': [
'../chrome_elf/chrome_elf.gyp:chrome_redirects',
],
}],
],
},
{ {
'target_name': 'chrome_elf', 'target_name': 'chrome_elf',
'type': 'shared_library', 'type': 'shared_library',
...@@ -25,11 +54,12 @@ ...@@ -25,11 +54,12 @@
'dependencies': [ 'dependencies': [
'blacklist', 'blacklist',
'chrome_elf_lib', 'chrome_elf_lib',
'chrome_redirects',
], ],
'msvs_settings': { 'msvs_settings': {
'VCLinkerTool': { 'VCLinkerTool': {
'BaseAddress': '0x01c20000', 'BaseAddress': '0x01c20000',
# Set /SUBSYSTEM:WINDOWS for chrome_elf.dll (for consistency). # Set /SUBSYSTEM:WINDOWS.
'SubSystem': '2', 'SubSystem': '2',
'AdditionalDependencies!': [ 'AdditionalDependencies!': [
'user32.lib', 'user32.lib',
...@@ -45,6 +75,7 @@ ...@@ -45,6 +75,7 @@
'type': 'executable', 'type': 'executable',
'sources': [ 'sources': [
'blacklist/test/blacklist_test.cc', 'blacklist/test/blacklist_test.cc',
'create_file/chrome_create_file_unittest.cc',
'elf_imports_unittest.cc', 'elf_imports_unittest.cc',
'ntdll_cache_unittest.cc', 'ntdll_cache_unittest.cc',
], ],
...@@ -73,10 +104,23 @@ ...@@ -73,10 +104,23 @@
'..', '..',
], ],
'sources': [ 'sources': [
'chrome_elf_constants.cc',
'chrome_elf_constants.h',
'chrome_elf_types.h', 'chrome_elf_types.h',
'create_file/chrome_create_file.cc',
'create_file/chrome_create_file.h',
'ntdll_cache.cc', 'ntdll_cache.cc',
'ntdll_cache.h', 'ntdll_cache.h',
], ],
'conditions': [
['component=="shared_library"', {
# In component builds, all targets depend on chrome_redirects by
# default. Remove it here to avoid a circular dependency.
'dependencies!': [
'../chrome_elf/chrome_elf.gyp:chrome_redirects',
],
}],
],
}, },
], ],
} }
// Copyright 2014 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 "chrome_elf/chrome_elf_constants.h"
const wchar_t kUserDataDirName[] = L"User Data";
#if defined(GOOGLE_CHROME_BUILD)
const wchar_t kAppDataDirName[] = L"Google\\Chrome";
#else
const wchar_t kAppDataDirName[] = L"Chromium";
#endif
// Copyright 2014 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.
// A handful of resource-like constants related to the ChromeELF.
#ifndef CHROME_ELF_CHROME_ELF_CONSTANTS_H_
#define CHROME_ELF_CHROME_ELF_CONSTANTS_H_
// directory names
extern const wchar_t kAppDataDirName[];
extern const wchar_t kUserDataDirName[];
#endif // CHROME_ELF_CHROME_ELF_CONSTANTS_H_
; Copyright 2014 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.
LIBRARY "chrome_redirects.dll"
EXPORTS
CreateFileW=CreateFileWRedirect
// Copyright 2014 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 "chrome_elf/create_file/chrome_create_file.h"
#include <string>
#include "base/strings/string16.h"
#include "chrome_elf/chrome_elf_constants.h"
#include "chrome_elf/ntdll_cache.h"
#include "sandbox/win/src/nt_internals.h"
namespace {
// From ShlObj.h in the Windows SDK.
#define CSIDL_LOCAL_APPDATA 0x001c
typedef BOOL (WINAPI *PathIsUNCFunction)(
IN LPCWSTR path);
typedef BOOL (WINAPI *PathAppendFunction)(
IN LPWSTR path,
IN LPCWSTR more);
typedef BOOL (WINAPI *PathIsPrefixFunction)(
IN LPCWSTR prefix,
IN LPCWSTR path);
typedef HRESULT (WINAPI *SHGetFolderPathFunction)(
IN HWND hwnd_owner,
IN int folder,
IN HANDLE token,
IN DWORD flags,
OUT LPWSTR path);
PathIsUNCFunction g_path_is_unc_func;
PathAppendFunction g_path_append_func;
PathIsPrefixFunction g_path_is_prefix_func;
SHGetFolderPathFunction g_get_folder_func;
// Populates the g_*_func pointers to functions which will be used in
// ShouldBypass(). Chrome_elf cannot have a load-time dependency on shell32 or
// shlwapi as this would induce a load-time dependency on user32.dll. Instead,
// the addresses of the functions we need are retrieved the first time this
// method is called, and cached to avoid subsequent calls to GetProcAddress().
// It is assumed that the host process will never unload these functions.
// Returns true if all the functions needed are present.
bool PopulateShellFunctions() {
// Early exit if functions have already been populated.
if (g_path_is_unc_func && g_path_append_func &&
g_path_is_prefix_func && g_get_folder_func) {
return true;
}
// Get the addresses of the functions we need and store them for future use.
// These handles are intentionally leaked to ensure that these modules do not
// get unloaded.
HMODULE shell32 = ::LoadLibrary(L"shell32.dll");
HMODULE shlwapi = ::LoadLibrary(L"shlwapi.dll");
if (!shlwapi || !shell32)
return false;
g_path_is_unc_func = reinterpret_cast<PathIsUNCFunction>(
::GetProcAddress(shlwapi, "PathIsUNCW"));
g_path_append_func = reinterpret_cast<PathAppendFunction>(
::GetProcAddress(shlwapi, "PathAppendW"));
g_path_is_prefix_func = reinterpret_cast<PathIsPrefixFunction>(
::GetProcAddress(shlwapi, "PathIsPrefixW"));
g_get_folder_func = reinterpret_cast<SHGetFolderPathFunction>(
::GetProcAddress(shell32, "SHGetFolderPathW"));
return g_path_is_unc_func && g_path_append_func &&
g_path_is_prefix_func && g_get_folder_func;
}
} // namespace
HANDLE WINAPI CreateFileWRedirect(
LPCWSTR file_name,
DWORD desired_access,
DWORD share_mode,
LPSECURITY_ATTRIBUTES security_attributes,
DWORD creation_disposition,
DWORD flags_and_attributes,
HANDLE template_file) {
if (ShouldBypass(file_name)) {
return CreateFileNTDLL(file_name,
desired_access,
share_mode,
security_attributes,
creation_disposition,
flags_and_attributes,
template_file);
}
return CreateFile(file_name,
desired_access,
share_mode,
security_attributes,
creation_disposition,
flags_and_attributes,
template_file);
}
HANDLE CreateFileNTDLL(
LPCWSTR file_name,
DWORD desired_access,
DWORD share_mode,
LPSECURITY_ATTRIBUTES security_attributes,
DWORD creation_disposition,
DWORD flags_and_attributes,
HANDLE template_file) {
HANDLE file_handle = INVALID_HANDLE_VALUE;
NTSTATUS result = STATUS_UNSUCCESSFUL;
IO_STATUS_BLOCK io_status_block = {};
// Convert from Win32 domain to to NT creation disposition values.
switch (creation_disposition) {
case CREATE_NEW:
creation_disposition = FILE_CREATE;
break;
case CREATE_ALWAYS:
creation_disposition = FILE_OVERWRITE_IF;
break;
case OPEN_EXISTING:
creation_disposition = FILE_OPEN;
break;
case OPEN_ALWAYS:
creation_disposition = FILE_OPEN_IF;
break;
case TRUNCATE_EXISTING:
creation_disposition = FILE_OVERWRITE;
break;
default:
SetLastError(ERROR_INVALID_PARAMETER);
return INVALID_HANDLE_VALUE;
}
if (!g_ntdll_lookup["NtCreateFile"] ||
!g_ntdll_lookup["RtlInitUnicodeString"]) {
return INVALID_HANDLE_VALUE;
}
NtCreateFileFunction create_file =
reinterpret_cast<NtCreateFileFunction>(g_ntdll_lookup["NtCreateFile"]);
RtlInitUnicodeStringFunction init_unicode_string =
reinterpret_cast<RtlInitUnicodeStringFunction>(
g_ntdll_lookup["RtlInitUnicodeString"]);
UNICODE_STRING path_unicode_string;
// Format the path into an NT path. Arguably this should be done with
// RtlDosPathNameToNtPathName_U, but afaict this is equivalent for
// local paths. Using this with a UNC path name will almost certainly
// break in interesting ways.
base::string16 filename_string(L"\\??\\");
filename_string += file_name;
init_unicode_string(&path_unicode_string, filename_string.c_str());
OBJECT_ATTRIBUTES path_attributes = {};
InitializeObjectAttributes(&path_attributes,
&path_unicode_string,
OBJ_CASE_INSENSITIVE,
NULL, // No Root Directory
NULL); // No Security Descriptor
// Set create_options, desired_access, and flags_and_attributes to match those
// set by kernel32!CreateFile.
ULONG create_options = FILE_ATTRIBUTE_DEVICE | FILE_ATTRIBUTE_ARCHIVE;
desired_access |= 0x100080;
flags_and_attributes &= 0x2FFA7;
result = create_file(&file_handle,
desired_access,
&path_attributes,
&io_status_block,
0, // Allocation size
flags_and_attributes,
share_mode,
creation_disposition,
create_options,
NULL,
0);
if (result != STATUS_SUCCESS) {
if (result == STATUS_OBJECT_NAME_COLLISION &&
creation_disposition == FILE_CREATE) {
SetLastError(ERROR_FILE_EXISTS);
}
return INVALID_HANDLE_VALUE;
}
if (creation_disposition == FILE_OPEN_IF) {
SetLastError(io_status_block.Information == FILE_OPENED ?
ERROR_ALREADY_EXISTS : ERROR_SUCCESS);
} else if (creation_disposition == FILE_OVERWRITE_IF) {
SetLastError(io_status_block.Information == FILE_OVERWRITTEN ?
ERROR_ALREADY_EXISTS : ERROR_SUCCESS);
} else {
SetLastError(ERROR_SUCCESS);
}
return file_handle;
}
bool ShouldBypass(LPCWSTR file_name) {
// If the shell functions are not present, forward the call to kernel32.
if (!PopulateShellFunctions())
return false;
// Forward all UNC filepaths to kernel32.
if (g_path_is_unc_func(file_name))
return false;
wchar_t local_appdata_path[MAX_PATH];
// Get the %LOCALAPPDATA% Path and append the location of our UserData
// directory to it.
HRESULT appdata_result = g_get_folder_func(
NULL, CSIDL_LOCAL_APPDATA, NULL, 0, local_appdata_path);
// If getting the %LOCALAPPDATA% path or appending to it failed, then forward
// the call to kernel32.
if (!SUCCEEDED(appdata_result) ||
!g_path_append_func(local_appdata_path, kAppDataDirName) ||
!g_path_append_func(local_appdata_path, kUserDataDirName)) {
return false;
}
// Check if we are trying to access something in the UserData dir. If so,
// then redirect the call to bypass kernel32.
return !!g_path_is_prefix_func(local_appdata_path, file_name);
}
// Copyright 2014 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 CHROME_ELF_CREATE_FILE_CHROME_CREATE_FILE_H_
#define CHROME_ELF_CREATE_FILE_CHROME_CREATE_FILE_H_
#include <windows.h>
#include "chrome_elf/chrome_elf_types.h"
// A CreateFileW replacement that will call NTCreateFile directly when the
// criteria defined in ShouldBypass() are satisfied for |lp_file_name|.
extern "C" HANDLE WINAPI CreateFileWRedirect(
LPCWSTR file_name,
DWORD desired_access,
DWORD share_mode,
LPSECURITY_ATTRIBUTES security_attributes,
DWORD creation_disposition,
DWORD flags_and_attributes,
HANDLE template_file);
// Partial reimplementation of kernel32!CreateFile (very partial: only handles
// reading and writing to files in the User Data directory).
HANDLE CreateFileNTDLL(
LPCWSTR file_name,
DWORD desired_access,
DWORD share_mode,
LPSECURITY_ATTRIBUTES security_attributes,
DWORD creation_disposition,
DWORD flags_and_attributes,
HANDLE template_file);
// Determines whether or not we should use our version of CreateFile, or the
// system version (only uses ours if we're writing to the user data directory).
bool ShouldBypass(LPCWSTR file_name);
#endif // CHROME_ELF_CREATE_FILE_CHROME_CREATE_FILE_H_
// Copyright 2014 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 "chrome_elf/create_file/chrome_create_file.h"
#include <windows.h>
#include <bitset>
#include <string>
#include "base/base_paths_win.h"
#include "base/file_util.h"
#include "base/files/file_path.h"
#include "base/files/scoped_temp_dir.h"
#include "base/path_service.h"
#include "base/threading/platform_thread.h"
#include "base/win/iat_patch_function.h"
#include "base/win/scoped_handle.h"
#include "base/win/windows_version.h"
#include "chrome_elf/chrome_elf_constants.h"
#include "chrome_elf/ntdll_cache.h"
#include "sandbox/win/src/nt_internals.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
namespace {
// Test fixtures -------------------------------------------------------------
class ChromeCreateFileTest : public PlatformTest {
protected:
struct NtCreateFileParams {
ACCESS_MASK desired_access;
OBJECT_ATTRIBUTES object_attributes;
PLARGE_INTEGER allocation_size;
ULONG file_attributes;
ULONG share_access;
ULONG create_disposition;
ULONG create_options;
PVOID ea_buffer;
ULONG ea_length;
};
enum CallPath {
ELF,
KERNEL
};
template<CallPath path>
static NTSTATUS WINAPI FakeNtCreateFile(
PHANDLE file_handle,
ACCESS_MASK desired_access,
POBJECT_ATTRIBUTES object_attributes,
PIO_STATUS_BLOCK io_status_block,
PLARGE_INTEGER allocation_size,
ULONG file_attributes,
ULONG share_access,
ULONG create_disposition,
ULONG create_options,
PVOID ea_buffer,
ULONG ea_length) {
return self_->HandleCreateFileCall(file_handle,
desired_access,
object_attributes,
io_status_block,
allocation_size,
file_attributes,
share_access,
create_disposition,
create_options,
ea_buffer,
ea_length,
path);
}
virtual void SetUp() OVERRIDE {
original_thread_ = base::PlatformThread::CurrentId();
InitCache();
PlatformTest::SetUp();
base::FilePath user_data_dir;
PathService::Get(base::DIR_LOCAL_APP_DATA, &user_data_dir);
ASSERT_TRUE(temp_dir_.CreateUniqueTempDirUnderPath(user_data_dir));
ASSERT_TRUE(temp_dir2_.CreateUniqueTempDir());
self_ = this;
}
void RedirectNtCreateFileCalls() {
old_func_ptr_ =
reinterpret_cast<NtCreateFileFunction>(g_ntdll_lookup["NtCreateFile"]);
// KernelBase.dll only exists for Win7 and later, prior to that, kernel32
// imports from ntdll directly.
if (base::win::GetVersion() < base::win::VERSION_WIN7) {
patcher_.Patch(L"kernel32.dll", "ntdll.dll", "NtCreateFile",
reinterpret_cast<void(*)()>(&FakeNtCreateFile<KERNEL>));
} else {
patcher_.Patch(L"kernelbase.dll", "ntdll.dll", "NtCreateFile",
reinterpret_cast<void(*)()>(&FakeNtCreateFile<KERNEL>));
}
g_ntdll_lookup["NtCreateFile"] = reinterpret_cast<void(*)()>(
&ChromeCreateFileTest::FakeNtCreateFile<ELF>);
}
void ResetNtCreateFileCalls() {
g_ntdll_lookup["NtCreateFile"] = reinterpret_cast<void*>(old_func_ptr_);
patcher_.Unpatch();
}
NTSTATUS HandleCreateFileCall(PHANDLE file_handle,
ACCESS_MASK desired_access,
POBJECT_ATTRIBUTES object_attributes,
PIO_STATUS_BLOCK io_status_block,
PLARGE_INTEGER allocation_size,
ULONG file_attributes,
ULONG share_access,
ULONG create_disposition,
ULONG create_options,
PVOID ea_buffer,
ULONG ea_length,
CallPath call_path) {
if (original_thread_ == base::PlatformThread::CurrentId()) {
SetParams(desired_access,
object_attributes,
allocation_size,
file_attributes,
share_access,
create_disposition,
create_options,
ea_buffer,
ea_length,
call_path == ELF ? &elf_params_ : &kernel_params_);
}
// Forward the call to the real NTCreateFile.
return old_func_ptr_(file_handle,
desired_access,
object_attributes,
io_status_block,
allocation_size,
file_attributes,
share_access,
create_disposition,
create_options,
ea_buffer,
ea_length);
}
void SetParams(ACCESS_MASK desired_access,
POBJECT_ATTRIBUTES object_attributes,
PLARGE_INTEGER allocation_size,
ULONG file_attributes,
ULONG share_access,
ULONG create_disposition,
ULONG create_options,
PVOID ea_buffer,
ULONG ea_length,
NtCreateFileParams* params) {
params->desired_access = desired_access;
params->object_attributes.Length = object_attributes->Length;
params->object_attributes.ObjectName = object_attributes->ObjectName;
params->object_attributes.RootDirectory = object_attributes->RootDirectory;
params->object_attributes.Attributes = object_attributes->Attributes;
params->object_attributes.SecurityDescriptor =
object_attributes->SecurityDescriptor;
params->object_attributes.SecurityQualityOfService =
object_attributes->SecurityQualityOfService;
params->allocation_size = allocation_size;
params->file_attributes = file_attributes;
params->share_access = share_access;
params->create_disposition = create_disposition;
params->create_options = create_options;
params->ea_buffer = ea_buffer;
params->ea_length = ea_length;
}
void CheckParams() {
std::bitset<32> elf((int) elf_params_.desired_access);
std::bitset<32> ker((int) kernel_params_.desired_access);
EXPECT_EQ(kernel_params_.desired_access, elf_params_.desired_access)
<< elf << "\n" << ker;
EXPECT_EQ(kernel_params_.object_attributes.Length,
elf_params_.object_attributes.Length);
EXPECT_EQ(kernel_params_.object_attributes.RootDirectory,
elf_params_.object_attributes.RootDirectory);
EXPECT_EQ(kernel_params_.object_attributes.Attributes,
elf_params_.object_attributes.Attributes);
EXPECT_EQ(kernel_params_.object_attributes.SecurityDescriptor,
elf_params_.object_attributes.SecurityDescriptor);
EXPECT_EQ(kernel_params_.allocation_size, elf_params_.allocation_size);
EXPECT_EQ(kernel_params_.file_attributes, elf_params_.file_attributes);
EXPECT_EQ(kernel_params_.share_access, elf_params_.share_access);
EXPECT_EQ(kernel_params_.create_disposition,
elf_params_.create_disposition);
EXPECT_EQ(kernel_params_.create_options, elf_params_.create_options);
EXPECT_EQ(kernel_params_.ea_buffer, elf_params_.ea_buffer);
EXPECT_EQ(kernel_params_.ea_length, elf_params_.ea_length);
}
void DoWriteCheck(const base::FilePath& path, bool is_system) {
base::win::ScopedHandle file_handle;
const char kTestData[] = "0123456789";
int buffer_size = sizeof(kTestData) - 1;
DWORD bytes_written;
if (is_system) {
file_handle.Set(::CreateFileW(path.value().c_str(),
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL));
} else {
file_handle.Set(CreateFileNTDLL(path.value().c_str(),
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL));
}
EXPECT_FALSE(file_handle == INVALID_HANDLE_VALUE);
::WriteFile(file_handle, kTestData, buffer_size, &bytes_written, NULL);
EXPECT_EQ(buffer_size, bytes_written);
}
void DoReadCheck(const base::FilePath& path, bool is_system) {
base::win::ScopedHandle file_handle;
const char kTestData[] = "0123456789";
int buffer_size = sizeof(kTestData) - 1;
DWORD bytes_read;
char read_buffer[10];
if (is_system) {
file_handle.Set(::CreateFileW(path.value().c_str(),
GENERIC_READ,
0,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL));
} else {
file_handle.Set(CreateFileNTDLL(path.value().c_str(),
GENERIC_READ,
0,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL));
}
EXPECT_FALSE(file_handle == INVALID_HANDLE_VALUE);
::ReadFile(file_handle, read_buffer, buffer_size, &bytes_read, NULL);
EXPECT_EQ(buffer_size, bytes_read);
EXPECT_EQ(0, memcmp(kTestData, read_buffer, bytes_read));
}
static ChromeCreateFileTest* self_;
NtCreateFileFunction old_func_ptr_;
base::ScopedTempDir temp_dir_;
base::ScopedTempDir temp_dir2_;
base::win::IATPatchFunction patcher_;
NtCreateFileParams kernel_params_;
NtCreateFileParams elf_params_;
base::PlatformThreadId original_thread_;
};
ChromeCreateFileTest* ChromeCreateFileTest::self_ = NULL;
// Tests ---------------------------------------------------------------------
TEST_F(ChromeCreateFileTest, CheckWriteAndReadParams) {
RedirectNtCreateFileCalls();
// Make sure we can write to this file handle when called via the system.
base::FilePath junk_path_1 = temp_dir_.path().Append(L"junk_1.txt");
base::FilePath junk_path_2 = temp_dir_.path().Append(L"junk_2.txt");
DoWriteCheck(junk_path_1, true);
DoWriteCheck(junk_path_2, false);
CheckParams();
// Make sure we can read from this file handle when called via the system.
DoReadCheck(junk_path_1, true);
DoReadCheck(junk_path_2, false);
CheckParams();
ResetNtCreateFileCalls();
}
TEST_F(ChromeCreateFileTest, BypassTest) {
std::wstring UNC_filepath_file(L"\\\\.\\some_file.txt");
base::FilePath local_path;
PathService::Get(base::DIR_LOCAL_APP_DATA, &local_path);
local_path = local_path.Append(kAppDataDirName).Append(
kUserDataDirName).Append(L"default\\Preferences");
base::FilePath desktop_path;
PathService::Get(base::DIR_USER_DESKTOP, &desktop_path);
desktop_path = desktop_path.Append(L"Downloads\\junk.txt");
EXPECT_FALSE(ShouldBypass(UNC_filepath_file.c_str()));
EXPECT_FALSE(ShouldBypass(desktop_path.value().c_str()));
EXPECT_TRUE(ShouldBypass(local_path.value().c_str()));
}
TEST_F(ChromeCreateFileTest, NtCreateFileAddressCheck) {
HMODULE ntdll_handle = ::GetModuleHandle(L"ntdll.dll");
EXPECT_EQ(::GetProcAddress(ntdll_handle, "NtCreateFile"),
g_ntdll_lookup["NtCreateFile"]);
}
TEST_F(ChromeCreateFileTest, ReadWriteFromNtDll) {
base::FilePath file_name = temp_dir_.path().Append(L"some_file.txt");
DoWriteCheck(file_name, false);
DoReadCheck(file_name, false);
}
} // namespace
...@@ -25,6 +25,7 @@ typedef LONG NTSTATUS; ...@@ -25,6 +25,7 @@ typedef LONG NTSTATUS;
#define STATUS_ACCESS_DENIED ((NTSTATUS)0xC0000022L) #define STATUS_ACCESS_DENIED ((NTSTATUS)0xC0000022L)
#define STATUS_BUFFER_TOO_SMALL ((NTSTATUS)0xC0000023L) #define STATUS_BUFFER_TOO_SMALL ((NTSTATUS)0xC0000023L)
#define STATUS_OBJECT_NAME_NOT_FOUND ((NTSTATUS)0xC0000034L) #define STATUS_OBJECT_NAME_NOT_FOUND ((NTSTATUS)0xC0000034L)
#define STATUS_OBJECT_NAME_COLLISION ((NTSTATUS)0xC0000035L)
#define STATUS_PROCEDURE_NOT_FOUND ((NTSTATUS)0xC000007AL) #define STATUS_PROCEDURE_NOT_FOUND ((NTSTATUS)0xC000007AL)
#define STATUS_INVALID_IMAGE_FORMAT ((NTSTATUS)0xC000007BL) #define STATUS_INVALID_IMAGE_FORMAT ((NTSTATUS)0xC000007BL)
#define STATUS_NO_TOKEN ((NTSTATUS)0xC000007CL) #define STATUS_NO_TOKEN ((NTSTATUS)0xC000007CL)
...@@ -125,6 +126,15 @@ typedef struct _IO_STATUS_BLOCK { ...@@ -125,6 +126,15 @@ typedef struct _IO_STATUS_BLOCK {
#define FILE_OPEN_NO_RECALL 0x00400000 #define FILE_OPEN_NO_RECALL 0x00400000
#define FILE_OPEN_FOR_FREE_SPACE_QUERY 0x00800000 #define FILE_OPEN_FOR_FREE_SPACE_QUERY 0x00800000
// Create/open result values. These are the disposition values returned on the
// io status information.
#define FILE_SUPERSEDED 0x00000000
#define FILE_OPENED 0x00000001
#define FILE_CREATED 0x00000002
#define FILE_OVERWRITTEN 0x00000003
#define FILE_EXISTS 0x00000004
#define FILE_DOES_NOT_EXIST 0x00000005
typedef NTSTATUS (WINAPI *NtCreateFileFunction)( typedef NTSTATUS (WINAPI *NtCreateFileFunction)(
OUT PHANDLE FileHandle, OUT PHANDLE FileHandle,
IN ACCESS_MASK DesiredAccess, IN ACCESS_MASK DesiredAccess,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment