Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1736)

Unified Diff: base/memory/shared_memory_win_unittest.cc

Issue 1677163003: base: Create file mappings with reduced access control permissions. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Comments from mark. Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « base/memory/shared_memory_win.cc ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: base/memory/shared_memory_win_unittest.cc
diff --git a/base/memory/shared_memory_win_unittest.cc b/base/memory/shared_memory_win_unittest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..6e19083f73586cebed0fa9f42093ae023b776f38
--- /dev/null
+++ b/base/memory/shared_memory_win_unittest.cc
@@ -0,0 +1,220 @@
+// Copyright 2016 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 <sddl.h>
+
+#include "base/command_line.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/shared_memory.h"
+#include "base/process/process.h"
+#include "base/rand_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/sys_string_conversions.h"
+#include "base/test/multiprocess_test.h"
+#include "base/test/test_timeouts.h"
+#include "base/win/scoped_handle.h"
+#include "testing/multiprocess_func_list.h"
+
+namespace base {
+namespace {
+const char* kHandleSwitchName = "shared_memory_win_test_switch";
+
+// Creates a process token with a low integrity SID.
+win::ScopedHandle CreateLowIntegritySID() {
+ HANDLE process_token_raw = nullptr;
+ BOOL success = ::OpenProcessToken(GetCurrentProcess(),
+ TOKEN_DUPLICATE | TOKEN_ADJUST_DEFAULT |
+ TOKEN_QUERY | TOKEN_ASSIGN_PRIMARY,
+ &process_token_raw);
+ if (!success)
+ return base::win::ScopedHandle();
+ win::ScopedHandle process_token(process_token_raw);
+
+ HANDLE lowered_process_token_raw = nullptr;
+ success =
+ ::DuplicateTokenEx(process_token.Get(), 0, NULL, SecurityImpersonation,
+ TokenPrimary, &lowered_process_token_raw);
+ if (!success)
+ return base::win::ScopedHandle();
+ win::ScopedHandle lowered_process_token(lowered_process_token_raw);
+
+ // Low integrity SID
+ WCHAR integrity_sid_string[20] = L"S-1-16-4096";
+ PSID integrity_sid = nullptr;
+ success = ::ConvertStringSidToSid(integrity_sid_string, &integrity_sid);
+ if (!success)
+ return base::win::ScopedHandle();
+
+ TOKEN_MANDATORY_LABEL TIL = {0};
Nico 2016/02/19 03:33:01 FAILED: ninja -t msvc -e environment.x86 -- C:\b\b
+ TIL.Label.Attributes = SE_GROUP_INTEGRITY;
+ TIL.Label.Sid = integrity_sid;
+ success = ::SetTokenInformation(
+ lowered_process_token.Get(), TokenIntegrityLevel, &TIL,
+ sizeof(TOKEN_MANDATORY_LABEL) + GetLengthSid(integrity_sid));
+ if (!success)
+ return base::win::ScopedHandle();
+ return lowered_process_token;
+}
+
+// Reads a HANDLE from the pipe as a raw int, least significant digit first.
+win::ScopedHandle ReadHandleFromPipe(HANDLE pipe) {
+ // Read from parent pipe.
+ const size_t buf_size = 1000;
+ char buffer[buf_size];
+ memset(buffer, 0, buf_size);
+ DWORD bytes_read;
+ BOOL success = ReadFile(pipe, buffer, buf_size, &bytes_read, NULL);
+
+ if (!success || bytes_read == 0) {
+ LOG(ERROR) << "Failed to read handle from pipe.";
+ return win::ScopedHandle();
+ }
+
+ int handle_as_int = 0;
+ int power_of_ten = 1;
+ for (unsigned int i = 0; i < bytes_read; ++i) {
+ handle_as_int += buffer[i] * power_of_ten;
+ power_of_ten *= 10;
+ }
+
+ return win::ScopedHandle(reinterpret_cast<HANDLE>(handle_as_int));
+}
+
+// Writes a HANDLE to a pipe as a raw int, least significant digit first.
+void WriteHandleToPipe(HANDLE pipe, HANDLE handle) {
+ uint32_t handle_as_int = reinterpret_cast<uint32_t>(handle);
brucedawson 2016/02/20 00:49:52 VC++ 2015 prefers double casts for the truncation-
+
+ scoped_ptr<char, base::FreeDeleter> buffer(static_cast<char*>(malloc(1000)));
+ size_t index = 0;
+ while (handle_as_int > 0) {
+ buffer.get()[index] = handle_as_int % 10;
+ handle_as_int /= 10;
+ ++index;
+ }
+
+ ::ConnectNamedPipe(pipe, nullptr);
+ DWORD written;
+ ASSERT_TRUE(::WriteFile(pipe, buffer.get(), index, &written, NULL));
+}
+
+// Creates a communication pipe with the given name.
+win::ScopedHandle CreateCommunicationPipe(const std::wstring& name) {
+ return win::ScopedHandle(CreateNamedPipe(name.c_str(), // pipe name
+ PIPE_ACCESS_DUPLEX, PIPE_WAIT, 255,
+ 1000, 1000, 0, NULL));
+}
+
+// Generates a random name for a communication pipe.
+std::wstring CreateCommunicationPipeName() {
+ uint64_t rand_values[4];
+ RandBytes(&rand_values, sizeof(rand_values));
+ std::wstring child_pipe_name = StringPrintf(
+ L"\\\\.\\pipe\\SharedMemoryWinTest_%016llx%016llx%016llx%016llx",
+ rand_values[0], rand_values[1], rand_values[2], rand_values[3]);
+ return child_pipe_name;
+}
+
+class SharedMemoryWinTest : public base::MultiProcessTest {
+ protected:
+ CommandLine MakeCmdLine(const std::string& procname) override {
+ CommandLine line = base::MultiProcessTest::MakeCmdLine(procname);
+ line.AppendSwitchASCII(kHandleSwitchName, communication_pipe_name_);
+ return line;
+ }
+
+ std::string communication_pipe_name_;
+};
+
+MULTIPROCESS_TEST_MAIN(LowerPermissions) {
+ std::string handle_name =
+ CommandLine::ForCurrentProcess()->GetSwitchValueASCII(kHandleSwitchName);
+ std::wstring handle_name16 = SysUTF8ToWide(handle_name);
+ win::ScopedHandle parent_pipe(
+ ::CreateFile(handle_name16.c_str(), // pipe name
+ GENERIC_READ,
+ 0, // no sharing
+ NULL, // default security attributes
+ OPEN_EXISTING, // opens existing pipe
+ 0, // default attributes
+ NULL)); // no template file
+ if (parent_pipe.Get() == INVALID_HANDLE_VALUE) {
+ LOG(ERROR) << "Failed to open communication pipe.";
+ return 1;
+ }
+
+ win::ScopedHandle received_handle = ReadHandleFromPipe(parent_pipe.Get());
+ if (!received_handle.Get()) {
+ LOG(ERROR) << "Failed to read handle from pipe.";
+ return 1;
+ }
+
+ // Attempting to add the WRITE_DAC permission should fail.
+ HANDLE duped_handle;
+ BOOL success = ::DuplicateHandle(GetCurrentProcess(), received_handle.Get(),
+ GetCurrentProcess(), &duped_handle,
+ FILE_MAP_READ | WRITE_DAC, FALSE, 0);
+ if (success) {
+ LOG(ERROR) << "Should not have been able to add WRITE_DAC permission.";
+ return 1;
+ }
+
+ // Attempting to add the FILE_MAP_WRITE permission should fail.
+ success = ::DuplicateHandle(GetCurrentProcess(), received_handle.Get(),
+ GetCurrentProcess(), &duped_handle,
+ FILE_MAP_READ | FILE_MAP_WRITE, FALSE, 0);
+ if (success) {
+ LOG(ERROR) << "Should not have been able to add FILE_MAP_WRITE permission.";
+ return 1;
+ }
+
+ // Attempting to duplicate the HANDLE with the same permissions should
+ // succeed.
+ success = ::DuplicateHandle(GetCurrentProcess(), received_handle.Get(),
+ GetCurrentProcess(), &duped_handle, FILE_MAP_READ,
+ FALSE, 0);
+ if (!success) {
+ LOG(ERROR) << "Failed to duplicate handle.";
+ return 4;
+ }
+ ::CloseHandle(duped_handle);
+ return 0;
+}
+
+TEST_F(SharedMemoryWinTest, LowerPermissions) {
+ std::wstring communication_pipe_name = CreateCommunicationPipeName();
+ communication_pipe_name_ = SysWideToUTF8(communication_pipe_name);
+
+ win::ScopedHandle communication_pipe =
+ CreateCommunicationPipe(communication_pipe_name);
+ ASSERT_TRUE(communication_pipe.Get());
+
+ win::ScopedHandle lowered_process_token = CreateLowIntegritySID();
+ ASSERT_TRUE(lowered_process_token.Get());
+
+ base::LaunchOptions options;
+ options.as_user = lowered_process_token.Get();
+ base::Process process = SpawnChildWithOptions("LowerPermissions", options);
+ ASSERT_TRUE(process.IsValid());
+
+ SharedMemory memory;
+ memory.CreateAndMapAnonymous(1001);
+
+ // Duplicate into child process, giving only FILE_MAP_READ permissions.
+ HANDLE raw_handle = nullptr;
+ ::DuplicateHandle(::GetCurrentProcess(), memory.handle().GetHandle(),
+ process.Handle(), &raw_handle,
+ FILE_MAP_READ | SECTION_QUERY, FALSE, 0);
+ ASSERT_TRUE(raw_handle);
+
+ WriteHandleToPipe(communication_pipe.Get(), raw_handle);
+
+ int exit_code;
+ EXPECT_TRUE(process.WaitForExitWithTimeout(TestTimeouts::action_max_timeout(),
+ &exit_code));
+ EXPECT_EQ(0, exit_code);
+}
+
+} // namespace
+} // namespace base
« no previous file with comments | « base/memory/shared_memory_win.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698