summaryrefslogtreecommitdiffstats
path: root/sandbox
diff options
context:
space:
mode:
authorrvargas@google.com <rvargas@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2010-01-27 19:20:42 +0000
committerrvargas@google.com <rvargas@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2010-01-27 19:20:42 +0000
commit4f1f3d0f03c79ddaace56f067cf28a27f9466b7d (patch)
treebc0bcae7b48b6e4e218d4fca358af50467893940 /sandbox
parent2377f7f26715ae20f671c5fd7e7edee778c1f64f (diff)
downloadchromium_src-4f1f3d0f03c79ddaace56f067cf28a27f9466b7d.zip
chromium_src-4f1f3d0f03c79ddaace56f067cf28a27f9466b7d.tar.gz
chromium_src-4f1f3d0f03c79ddaace56f067cf28a27f9466b7d.tar.bz2
Improve handling and testing of reparse points.
BUG=28804 TEST=unit tests. Review URL: http://codereview.chromium.org/553080 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@37286 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'sandbox')
-rw-r--r--sandbox/sandbox.gyp5
-rw-r--r--sandbox/src/file_policy_test.cc89
-rw-r--r--sandbox/src/filesystem_policy.cc12
-rw-r--r--sandbox/src/win_utils.cc80
-rw-r--r--sandbox/src/win_utils.h7
-rw-r--r--sandbox/src/win_utils_unittest.cc51
-rw-r--r--sandbox/tests/common/controller.cc51
-rw-r--r--sandbox/tests/common/controller.h10
-rw-r--r--sandbox/tests/common/test_utils.cc72
-rw-r--r--sandbox/tests/common/test_utils.h19
10 files changed, 295 insertions, 101 deletions
diff --git a/sandbox/sandbox.gyp b/sandbox/sandbox.gyp
index 1574e5d..58f0059 100644
--- a/sandbox/sandbox.gyp
+++ b/sandbox/sandbox.gyp
@@ -286,6 +286,8 @@
'sources': [
'tests/common/controller.cc',
'tests/common/controller.h',
+ 'tests/common/test_utils.cc',
+ 'tests/common/test_utils.h',
'tests/integration_tests/integration_tests.cc',
'src/dep_test.cc',
'src/file_policy_test.cc',
@@ -324,6 +326,8 @@
'../testing/gtest.gyp:gtest',
],
'sources': [
+ 'tests/common/test_utils.cc',
+ 'tests/common/test_utils.h',
'tests/unit_tests/unit_tests.cc',
'src/interception_unittest.cc',
'src/service_resolver_unittest.cc',
@@ -335,6 +339,7 @@
'src/policy_opcodes_unittest.cc',
'src/ipc_unittest.cc',
'src/threadpool_unittest.cc',
+ 'src/win_utils_unittest.cc',
],
},
{
diff --git a/sandbox/src/file_policy_test.cc b/sandbox/src/file_policy_test.cc
index e62f08a..f4a2e19 100644
--- a/sandbox/src/file_policy_test.cc
+++ b/sandbox/src/file_policy_test.cc
@@ -1,92 +1,23 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2006-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.
-#include "sandbox/src/sandbox_policy.h"
-
#include <windows.h>
#include <winioctl.h>
#include "base/scoped_handle_win.h"
-#include "testing/gtest/include/gtest/gtest.h"
+#include "sandbox/src/nt_internals.h"
#include "sandbox/src/sandbox.h"
#include "sandbox/src/sandbox_factory.h"
-#include "sandbox/src/nt_internals.h"
+#include "sandbox/src/sandbox_policy.h"
#include "sandbox/tests/common/controller.h"
+#include "sandbox/tests/common/test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
#define BINDNTDLL(name) \
name ## Function name = reinterpret_cast<name ## Function>( \
::GetProcAddress(::GetModuleHandle(L"ntdll.dll"), #name))
-namespace {
-
-typedef struct _REPARSE_DATA_BUFFER {
- ULONG ReparseTag;
- USHORT ReparseDataLength;
- USHORT Reserved;
- union {
- struct {
- USHORT SubstituteNameOffset;
- USHORT SubstituteNameLength;
- USHORT PrintNameOffset;
- USHORT PrintNameLength;
- ULONG Flags;
- WCHAR PathBuffer[1];
- } SymbolicLinkReparseBuffer;
- struct {
- USHORT SubstituteNameOffset;
- USHORT SubstituteNameLength;
- USHORT PrintNameOffset;
- USHORT PrintNameLength;
- WCHAR PathBuffer[1];
- } MountPointReparseBuffer;
- struct {
- UCHAR DataBuffer[1];
- } GenericReparseBuffer;
- };
-} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
-
-// Sets a reparse point. |source| will now point to |target|. Returns true if
-// the call succeeds, false otherwise.
-bool SetReparsePoint(HANDLE source, const wchar_t* target) {
- USHORT size_target = static_cast<USHORT>(wcslen(target)) * sizeof(target[0]);
-
- char buffer[2000] = {0};
- DWORD returned;
-
- REPARSE_DATA_BUFFER* data = reinterpret_cast<REPARSE_DATA_BUFFER*>(buffer);
-
- data->ReparseTag = 0xa0000003;
- memcpy(data->MountPointReparseBuffer.PathBuffer, target, size_target + 2);
- data->MountPointReparseBuffer.SubstituteNameLength = size_target;
- data->MountPointReparseBuffer.PrintNameOffset = size_target + 2;
- data->ReparseDataLength = size_target + 4 + 8;
-
- int data_size = data->ReparseDataLength + 8;
-
- if (!DeviceIoControl(source, FSCTL_SET_REPARSE_POINT, &buffer, data_size,
- NULL, 0, &returned, NULL)) {
- return false;
- }
- return true;
-}
-
-// Delete the reparse point referenced by |source|. Returns true if the call
-// succeeds, false otherwise.
-bool DeleteReparsePoint(HANDLE source) {
- DWORD returned;
- REPARSE_DATA_BUFFER data = {0};
- data.ReparseTag = 0xa0000003;
- if (!DeviceIoControl(source, FSCTL_DELETE_REPARSE_POINT, &data, 8, NULL, 0,
- &returned, NULL)) {
- return false;
- }
-
- return true;
-}
-
-} // unamed namespace
-
namespace sandbox {
const ULONG kSharing = FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE;
@@ -126,7 +57,7 @@ SBOX_TESTS_COMMAND int File_Win32Create(int argc, wchar_t **argv) {
SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
}
- std::wstring full_path = MakePathToSys32(argv[0], false);
+ std::wstring full_path = MakePathToSys(argv[0], false);
if (full_path.empty()) {
return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
}
@@ -158,7 +89,7 @@ SBOX_TESTS_COMMAND int File_CreateSys32(int argc, wchar_t **argv) {
if (argc != 1)
return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
- std::wstring file = MakePathToSys32(argv[0], true);
+ std::wstring file = MakePathToSys(argv[0], true);
UNICODE_STRING object_name;
RtlInitUnicodeString(&object_name, file.c_str());
@@ -193,7 +124,7 @@ SBOX_TESTS_COMMAND int File_OpenSys32(int argc, wchar_t **argv) {
if (argc != 1)
return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
- std::wstring file = MakePathToSys32(argv[0], true);
+ std::wstring file = MakePathToSys(argv[0], true);
UNICODE_STRING object_name;
RtlInitUnicodeString(&object_name, file.c_str());
@@ -217,7 +148,7 @@ SBOX_TESTS_COMMAND int File_OpenSys32(int argc, wchar_t **argv) {
}
SBOX_TESTS_COMMAND int File_GetDiskSpace(int argc, wchar_t **argv) {
- std::wstring sys_path = MakePathToSys32(L"", false);
+ std::wstring sys_path = MakePathToSys(L"", false);
if (sys_path.empty()) {
return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
}
@@ -273,7 +204,7 @@ SBOX_TESTS_COMMAND int File_QueryAttributes(int argc, wchar_t **argv) {
bool expect_directory = (L'd' == argv[1][0]);
UNICODE_STRING object_name;
- std::wstring file = MakePathToSys32(argv[0], true);
+ std::wstring file = MakePathToSys(argv[0], true);
RtlInitUnicodeString(&object_name, file.c_str());
OBJECT_ATTRIBUTES obj_attributes = {0};
diff --git a/sandbox/src/filesystem_policy.cc b/sandbox/src/filesystem_policy.cc
index c11c031..a703188 100644
--- a/sandbox/src/filesystem_policy.cc
+++ b/sandbox/src/filesystem_policy.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2006-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.
@@ -40,6 +40,12 @@ NTSTATUS NtCreateFileInTarget(HANDLE* target_file_handle,
return status;
}
+ if (!sandbox::SameObject(local_handle, obj_attributes->ObjectName->Buffer)) {
+ // The handle points somewhere else. Fail the operation.
+ ::CloseHandle(local_handle);
+ return STATUS_ACCESS_DENIED;
+ }
+
if (!::DuplicateHandle(::GetCurrentProcess(), local_handle,
target_process, target_file_handle, 0, FALSE,
DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
@@ -49,7 +55,7 @@ NTSTATUS NtCreateFileInTarget(HANDLE* target_file_handle,
return STATUS_SUCCESS;
}
-}
+} // namespace.
namespace sandbox {
@@ -61,7 +67,7 @@ bool FileSystemPolicy::GenerateRules(const wchar_t* name,
return false;
}
- // TODO(cpu): This prefix add is a hack because we don't have the
+ // TODO(cpu) bug 32224: This prefix add is a hack because we don't have the
// infrastructure to normalize names. In any case we need to escape the
// question marks.
if (!PreProcessName(mod_name, &mod_name)) {
diff --git a/sandbox/src/win_utils.cc b/sandbox/src/win_utils.cc
index f5d39f2..bf4936b 100644
--- a/sandbox/src/win_utils.cc
+++ b/sandbox/src/win_utils.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2006-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.
@@ -32,6 +32,16 @@ const KnownReservedKey kKnownKey[] = {
{ 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 {
@@ -77,8 +87,7 @@ DWORD IsReparsePoint(const std::wstring& full_path, bool* result) {
path = path.substr(kNTPrefixLen);
// Check if it's a pipe. We can't query the attributes of a pipe.
- const wchar_t kPipe[] = L"pipe\\";
- if (0 == path.compare(0, arraysize(kPipe) - 1, kPipe)) {
+ if (IsPipe(path)) {
*result = FALSE;
return ERROR_SUCCESS;
}
@@ -111,6 +120,66 @@ DWORD IsReparsePoint(const std::wstring& full_path, bool* result) {
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);
+
+ if (0 == actual_path.compare(full_path))
+ 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 -= 2;
+
+ // 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 != actual_path.compare(0, vol_length, vol_name))
+ return false;
+
+ // Check the path after the drive letter.
+ if (0 != actual_path.compare(vol_length, std::wstring::npos,
+ &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.
@@ -171,8 +240,9 @@ bool GetPathFromHandle(HANDLE handle, std::wstring* path) {
NtQueryObjectFunction NtQueryObject = NULL;
ResolveNTFunctionPtr("NtQueryObject", &NtQueryObject);
- OBJECT_NAME_INFORMATION* name = NULL;
- ULONG size = 0;
+ 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);
diff --git a/sandbox/src/win_utils.h b/sandbox/src/win_utils.h
index b3aad3f..c52f3e3 100644
--- a/sandbox/src/win_utils.h
+++ b/sandbox/src/win_utils.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2006-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.
@@ -30,8 +30,8 @@ class AutoLock {
};
private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(AutoLock);
CRITICAL_SECTION *lock_;
+ DISALLOW_IMPLICIT_CONSTRUCTORS(AutoLock);
};
// Basic implementation of a singleton which calls the destructor
@@ -71,6 +71,9 @@ bool ConvertToLongPath(const std::wstring& short_path, std::wstring* long_path);
// returns true if any of them is a reparse point.
DWORD IsReparsePoint(const std::wstring& full_path, bool* result);
+// Returns true if the handle corresponds to the object pointed by this path.
+bool SameObject(HANDLE handle, const wchar_t* full_path);
+
// Resolves a handle to a path. Returns true if the handle can be resolved.
bool GetPathFromHandle(HANDLE handle, std::wstring* path);
diff --git a/sandbox/src/win_utils_unittest.cc b/sandbox/src/win_utils_unittest.cc
new file mode 100644
index 0000000..a7dc998
--- /dev/null
+++ b/sandbox/src/win_utils_unittest.cc
@@ -0,0 +1,51 @@
+// 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.
+
+#include <windows.h>
+
+#include "sandbox/src/win_utils.h"
+#include "sandbox/tests/common/test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(WinUtils, IsReparsePoint) {
+ using sandbox::IsReparsePoint;
+
+ // Create a temp file because we need write access to it.
+ wchar_t temp_directory[MAX_PATH];
+ wchar_t my_folder[MAX_PATH];
+ ASSERT_NE(::GetTempPath(MAX_PATH, temp_directory), 0);
+ ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, my_folder), 0);
+
+ // Delete the file and create a directory instead.
+ ASSERT_TRUE(::DeleteFile(my_folder));
+ ASSERT_TRUE(::CreateDirectory(my_folder, NULL));
+
+ bool result = true;
+ EXPECT_EQ(ERROR_SUCCESS, IsReparsePoint(my_folder, &result));
+ EXPECT_FALSE(result);
+
+ // We have to fix Bug 32224 to pass this test.
+ std::wstring not_found = std::wstring(my_folder) + L"\\foo\\bar";
+ // EXPECT_EQ(ERROR_PATH_NOT_FOUND, IsReparsePoint(not_found, &result));
+
+ std::wstring new_file = std::wstring(my_folder) + L"\\foo";
+ EXPECT_EQ(ERROR_SUCCESS, IsReparsePoint(new_file, &result));
+ EXPECT_FALSE(result);
+
+ // Replace the directory with a reparse point to %temp%.
+ HANDLE dir = ::CreateFile(my_folder, FILE_ALL_ACCESS,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
+ OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ EXPECT_TRUE(INVALID_HANDLE_VALUE != dir);
+
+ std::wstring temp_dir_nt = std::wstring(L"\\??\\") + temp_directory;
+ EXPECT_TRUE(SetReparsePoint(dir, temp_dir_nt.c_str()));
+
+ EXPECT_EQ(ERROR_SUCCESS, IsReparsePoint(new_file, &result));
+ EXPECT_TRUE(result);
+
+ EXPECT_TRUE(DeleteReparsePoint(dir));
+ EXPECT_TRUE(::CloseHandle(dir));
+ EXPECT_TRUE(::RemoveDirectory(my_folder));
+}
diff --git a/sandbox/tests/common/controller.cc b/sandbox/tests/common/controller.cc
index 802b1b6..6e0f080 100644
--- a/sandbox/tests/common/controller.cc
+++ b/sandbox/tests/common/controller.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2006-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.
@@ -8,17 +8,13 @@
#include "sandbox/src/sandbox_factory.h"
#include "sandbox/src/sandbox_utils.h"
+#include "sandbox/src/wow64.h"
namespace {
static const int kDefaultTimeout = 3000;
-} // namespace
-
-namespace sandbox {
-
-// Utility function that constructs a full path to a file inside the system32
-// folder.
+// Constructs a full path to a file inside the system32 folder.
std::wstring MakePathToSys32(const wchar_t* name, bool is_obj_man_path) {
wchar_t windows_path[MAX_PATH] = {0};
if (0 == ::GetSystemWindowsDirectoryW(windows_path, MAX_PATH))
@@ -36,6 +32,36 @@ std::wstring MakePathToSys32(const wchar_t* name, bool is_obj_man_path) {
return full_path;
}
+// Constructs a full path to a file inside the syswow64 folder.
+std::wstring MakePathToSysWow64(const wchar_t* name, bool is_obj_man_path) {
+ wchar_t windows_path[MAX_PATH] = {0};
+ if (0 == ::GetSystemWindowsDirectoryW(windows_path, MAX_PATH))
+ return std::wstring();
+
+ std::wstring full_path(windows_path);
+ if (full_path.empty())
+ return full_path;
+
+ if (is_obj_man_path)
+ full_path.insert(0, L"\\??\\");
+
+ full_path += L"\\SysWOW64\\";
+ full_path += name;
+ return full_path;
+}
+
+} // namespace
+
+namespace sandbox {
+
+std::wstring MakePathToSys(const wchar_t* name, bool is_obj_man_path) {
+ Wow64 current_proc(NULL, NULL);
+ if (current_proc.IsWow64())
+ return MakePathToSysWow64(name, is_obj_man_path);
+ else
+ return MakePathToSys32(name, is_obj_man_path);
+}
+
BrokerServices* GetBroker() {
static BrokerServices* broker = SandboxFactory::GetBrokerServices();
static bool is_initialized = false;
@@ -111,6 +137,17 @@ bool TestRunner::AddRuleSys32(TargetPolicy::Semantics semantics,
if (win32_path.empty())
return false;
+ if (!AddRule(TargetPolicy::SUBSYS_FILES, semantics, win32_path.c_str()))
+ return false;
+
+ Wow64 current_proc(NULL, NULL);
+ if (!current_proc.IsWow64())
+ return true;
+
+ win32_path = MakePathToSysWow64(pattern, false);
+ if (win32_path.empty())
+ return false;
+
return AddRule(TargetPolicy::SUBSYS_FILES, semantics, win32_path.c_str());
}
diff --git a/sandbox/tests/common/controller.h b/sandbox/tests/common/controller.h
index 8300846..3f1d0c2 100644
--- a/sandbox/tests/common/controller.h
+++ b/sandbox/tests/common/controller.h
@@ -1,8 +1,8 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2006-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.
-#ifndef SANDBOX_TESTS_COMMON_CONTROLLER_H__
+#ifndef SANDBOX_TESTS_COMMON_CONTROLLER_H_
#define SANDBOX_TESTS_COMMON_CONTROLLER_H__
#include <windows.h>
@@ -117,12 +117,12 @@ class TestRunner {
// Returns the broker services.
BrokerServices* GetBroker();
-// Constructs a full path to a file inside the system32 folder.
-std::wstring MakePathToSys32(const wchar_t* name, bool is_obj_man_path);
+// Constructs a full path to a file inside the system32 (or syswow64) folder.
+std::wstring MakePathToSys(const wchar_t* name, bool is_obj_man_path);
// Runs the given test on the target process.
int DispatchCall(int argc, wchar_t **argv);
} // namespace sandbox
-#endif // SANDBOX_TESTS_COMMON_CONTROLLER_H__
+#endif // SANDBOX_TESTS_COMMON_CONTROLLER_H_
diff --git a/sandbox/tests/common/test_utils.cc b/sandbox/tests/common/test_utils.cc
new file mode 100644
index 0000000..929c322
--- /dev/null
+++ b/sandbox/tests/common/test_utils.cc
@@ -0,0 +1,72 @@
+// Copyright (c) 2006-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.
+
+#include "sandbox/tests/common/test_utils.h"
+
+#include <winioctl.h>
+
+typedef struct _REPARSE_DATA_BUFFER {
+ ULONG ReparseTag;
+ USHORT ReparseDataLength;
+ USHORT Reserved;
+ union {
+ struct {
+ USHORT SubstituteNameOffset;
+ USHORT SubstituteNameLength;
+ USHORT PrintNameOffset;
+ USHORT PrintNameLength;
+ ULONG Flags;
+ WCHAR PathBuffer[1];
+ } SymbolicLinkReparseBuffer;
+ struct {
+ USHORT SubstituteNameOffset;
+ USHORT SubstituteNameLength;
+ USHORT PrintNameOffset;
+ USHORT PrintNameLength;
+ WCHAR PathBuffer[1];
+ } MountPointReparseBuffer;
+ struct {
+ UCHAR DataBuffer[1];
+ } GenericReparseBuffer;
+ };
+} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
+
+// Sets a reparse point. |source| will now point to |target|. Returns true if
+// the call succeeds, false otherwise.
+bool SetReparsePoint(HANDLE source, const wchar_t* target) {
+ USHORT size_target = static_cast<USHORT>(wcslen(target)) * sizeof(target[0]);
+
+ char buffer[2000] = {0};
+ DWORD returned;
+
+ REPARSE_DATA_BUFFER* data = reinterpret_cast<REPARSE_DATA_BUFFER*>(buffer);
+
+ data->ReparseTag = 0xa0000003;
+ memcpy(data->MountPointReparseBuffer.PathBuffer, target, size_target + 2);
+ data->MountPointReparseBuffer.SubstituteNameLength = size_target;
+ data->MountPointReparseBuffer.PrintNameOffset = size_target + 2;
+ data->ReparseDataLength = size_target + 4 + 8;
+
+ int data_size = data->ReparseDataLength + 8;
+
+ if (!DeviceIoControl(source, FSCTL_SET_REPARSE_POINT, &buffer, data_size,
+ NULL, 0, &returned, NULL)) {
+ return false;
+ }
+ return true;
+}
+
+// Delete the reparse point referenced by |source|. Returns true if the call
+// succeeds, false otherwise.
+bool DeleteReparsePoint(HANDLE source) {
+ DWORD returned;
+ REPARSE_DATA_BUFFER data = {0};
+ data.ReparseTag = 0xa0000003;
+ if (!DeviceIoControl(source, FSCTL_DELETE_REPARSE_POINT, &data, 8, NULL, 0,
+ &returned, NULL)) {
+ return false;
+ }
+
+ return true;
+}
diff --git a/sandbox/tests/common/test_utils.h b/sandbox/tests/common/test_utils.h
new file mode 100644
index 0000000..9e17660
--- /dev/null
+++ b/sandbox/tests/common/test_utils.h
@@ -0,0 +1,19 @@
+// Copyright (c) 2006-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.
+
+#ifndef SANDBOX_TESTS_COMMON_TEST_UTILS_H_
+#define SANDBOX_TESTS_COMMON_TEST_UTILS_H_
+
+#include <windows.h>
+
+// Sets a reparse point. |source| will now point to |target|. Returns true if
+// the call succeeds, false otherwise.
+bool SetReparsePoint(HANDLE source, const wchar_t* target);
+
+// Delete the reparse point referenced by |source|. Returns true if the call
+// succeeds, false otherwise.
+bool DeleteReparsePoint(HANDLE source);
+
+#endif // SANDBOX_TESTS_COMMON_TEST_UTILS_H_
+