summaryrefslogtreecommitdiffstats
path: root/sandbox/src
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/src
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/src')
-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
5 files changed, 150 insertions, 89 deletions
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));
+}