summaryrefslogtreecommitdiffstats
path: root/sandbox/win
diff options
context:
space:
mode:
authorjschuh@chromium.org <jschuh@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-02-26 19:21:18 +0000
committerjschuh@chromium.org <jschuh@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-02-26 19:21:18 +0000
commitaad3a0ee8771945a83e45646415c154bb837e1a4 (patch)
tree6534ca4ff4273de48781fd2e218f7a14fbfb15e4 /sandbox/win
parent7c849b3d759fa9fedd7d4aea73577d643465918d (diff)
downloadchromium_src-aad3a0ee8771945a83e45646415c154bb837e1a4.zip
chromium_src-aad3a0ee8771945a83e45646415c154bb837e1a4.tar.gz
chromium_src-aad3a0ee8771945a83e45646415c154bb837e1a4.tar.bz2
Reduce sandbox permissions granted to alternate desktop
This pass adds the first round of deny ACEs for the Winstation and Desktop objects. Assuming these stick, I'll get more aggressive in a follow-up. BUG=346586 NOTRY=true Review URL: https://codereview.chromium.org/178423005 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@253546 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'sandbox/win')
-rw-r--r--sandbox/win/sandbox_poc/main_ui_window.cc7
-rw-r--r--sandbox/win/src/acl.cc18
-rw-r--r--sandbox/win/src/acl.h20
-rw-r--r--sandbox/win/src/window.cc28
-rw-r--r--sandbox/win/tests/validation_tests/commands.cc58
-rw-r--r--sandbox/win/tests/validation_tests/commands.h7
-rw-r--r--sandbox/win/tests/validation_tests/suite.cc22
7 files changed, 134 insertions, 26 deletions
diff --git a/sandbox/win/sandbox_poc/main_ui_window.cc b/sandbox/win/sandbox_poc/main_ui_window.cc
index 243075c..1671424 100644
--- a/sandbox/win/sandbox_poc/main_ui_window.cc
+++ b/sandbox/win/sandbox_poc/main_ui_window.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 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.
@@ -553,8 +553,9 @@ bool MainUIWindow::SpawnTarget() {
if (INVALID_HANDLE_VALUE == pipe_handle_)
AddDebugMessage(L"Failed to create pipe. Error %d", ::GetLastError());
- if (!sandbox::AddKnownSidToKernelObject(pipe_handle_, WinWorldSid,
- FILE_ALL_ACCESS))
+ if (!sandbox::AddKnownSidToObject(pipe_handle_, SE_KERNEL_OBJECT,
+ WinWorldSid, GRANT_ACCESS,
+ FILE_ALL_ACCESS))
AddDebugMessage(L"Failed to set security on pipe. Error %d",
::GetLastError());
diff --git a/sandbox/win/src/acl.cc b/sandbox/win/src/acl.cc
index 70d2a8d..0f2936ab 100644
--- a/sandbox/win/src/acl.cc
+++ b/sandbox/win/src/acl.cc
@@ -36,10 +36,10 @@ bool GetDefaultDacl(HANDLE token,
return true;
}
-bool AddSidToDacl(const Sid& sid, ACL* old_dacl, ACCESS_MASK access,
- ACL** new_dacl) {
+bool AddSidToDacl(const Sid& sid, ACL* old_dacl, ACCESS_MODE access_mode,
+ ACCESS_MASK access, ACL** new_dacl) {
EXPLICIT_ACCESS new_access = {0};
- new_access.grfAccessMode = GRANT_ACCESS;
+ new_access.grfAccessMode = access_mode;
new_access.grfAccessPermissions = access;
new_access.grfInheritance = NO_INHERITANCE;
@@ -64,7 +64,8 @@ bool AddSidToDefaultDacl(HANDLE token, const Sid& sid, ACCESS_MASK access) {
return false;
ACL* new_dacl = NULL;
- if (!AddSidToDacl(sid, default_dacl->DefaultDacl, access, &new_dacl))
+ if (!AddSidToDacl(sid, default_dacl->DefaultDacl, GRANT_ACCESS, access,
+ &new_dacl))
return false;
TOKEN_DEFAULT_DACL new_token_dacl = {0};
@@ -90,8 +91,9 @@ bool AddUserSidToDefaultDacl(HANDLE token, ACCESS_MASK access) {
access);
}
-bool AddKnownSidToKernelObject(HANDLE object, const Sid& sid,
- ACCESS_MASK access) {
+bool AddKnownSidToObject(HANDLE object, SE_OBJECT_TYPE object_type,
+ const Sid& sid, ACCESS_MODE access_mode,
+ ACCESS_MASK access) {
PSECURITY_DESCRIPTOR descriptor = NULL;
PACL old_dacl = NULL;
PACL new_dacl = NULL;
@@ -101,12 +103,12 @@ bool AddKnownSidToKernelObject(HANDLE object, const Sid& sid,
&old_dacl, NULL, &descriptor))
return false;
- if (!AddSidToDacl(sid.GetPSID(), old_dacl, access, &new_dacl)) {
+ if (!AddSidToDacl(sid.GetPSID(), old_dacl, access_mode, access, &new_dacl)) {
::LocalFree(descriptor);
return false;
}
- DWORD result = ::SetSecurityInfo(object, SE_KERNEL_OBJECT,
+ DWORD result = ::SetSecurityInfo(object, object_type,
DACL_SECURITY_INFORMATION, NULL, NULL,
new_dacl, NULL);
diff --git a/sandbox/win/src/acl.h b/sandbox/win/src/acl.h
index 25d5cdb..531259f 100644
--- a/sandbox/win/src/acl.h
+++ b/sandbox/win/src/acl.h
@@ -5,6 +5,7 @@
#ifndef SANDBOX_SRC_ACL_H_
#define SANDBOX_SRC_ACL_H_
+#include <AccCtrl.h>
#include <windows.h>
#include "base/memory/scoped_ptr.h"
@@ -16,11 +17,11 @@ namespace sandbox {
bool GetDefaultDacl(HANDLE token,
scoped_ptr_malloc<TOKEN_DEFAULT_DACL>* default_dacl);
-// Appends an ACE represented by |sid| and |access| to |old_dacl|. If the
-// function succeeds, new_dacl contains the new dacl and must be freed using
-// LocalFree.
-bool AddSidToDacl(const Sid& sid, ACL* old_dacl, ACCESS_MASK access,
- ACL** new_dacl);
+// Appends an ACE represented by |sid|, |access_mode|, and |access| to
+// |old_dacl|. If the function succeeds, new_dacl contains the new dacl and
+// must be freed using LocalFree.
+bool AddSidToDacl(const Sid& sid, ACL* old_dacl, ACCESS_MODE access_mode,
+ ACCESS_MASK access, ACL** new_dacl);
// Adds and ACE represented by |sid| and |access| to the default dacl present
// in the token.
@@ -30,10 +31,11 @@ bool AddSidToDefaultDacl(HANDLE token, const Sid& sid, ACCESS_MASK access);
// present in the token.
bool AddUserSidToDefaultDacl(HANDLE token, ACCESS_MASK access);
-// Adds an ACE represented by |known_sid| and |access| to the dacl of the kernel
-// object referenced by |object|.
-bool AddKnownSidToKernelObject(HANDLE object, const Sid& sid,
- ACCESS_MASK access);
+// Adds an ACE represented by |known_sid|, |access_mode|, and |access| to
+// the dacl of the kernel object referenced by |object| and of |object_type|.
+bool AddKnownSidToObject(HANDLE object, SE_OBJECT_TYPE object_type,
+ const Sid& sid, ACCESS_MODE access_mode,
+ ACCESS_MASK access);
} // namespace sandbox
diff --git a/sandbox/win/src/window.cc b/sandbox/win/src/window.cc
index d21858a..32c02b2 100644
--- a/sandbox/win/src/window.cc
+++ b/sandbox/win/src/window.cc
@@ -8,6 +8,8 @@
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
+#include "sandbox/win/src/acl.h"
+#include "sandbox/win/src/sid.h"
namespace {
@@ -46,8 +48,20 @@ ResultCode CreateAltWindowStation(HWINSTA* winsta) {
*winsta = ::CreateWindowStationW(NULL, 0, WINSTA_ALL_ACCESS, &attributes);
LocalFree(attributes.lpSecurityDescriptor);
- if (*winsta)
+ if (*winsta) {
+ // Replace the DACL on the new Winstation with a reduced privilege version.
+ // We can soft fail on this for now, as it's just an extra mitigation.
+ static const ACCESS_MASK kWinstaDenyMask = DELETE | WRITE_DAC |
+ WRITE_OWNER |
+ WINSTA_ACCESSCLIPBOARD |
+ WINSTA_CREATEDESKTOP |
+ WINSTA_ENUMDESKTOPS |
+ WINSTA_ENUMERATE |
+ WINSTA_EXITWINDOWS;
+ AddKnownSidToObject(*winsta, SE_WINDOW_OBJECT, Sid(WinRestrictedCodeSid),
+ DENY_ACCESS, kWinstaDenyMask);
return SBOX_ALL_OK;
+ }
return SBOX_ERROR_CANNOT_CREATE_WINSTATION;
}
@@ -94,8 +108,18 @@ ResultCode CreateAltDesktop(HWINSTA winsta, HDESK* desktop) {
}
}
- if (*desktop)
+ if (*desktop) {
+ // Replace the DACL on the new Desktop with a reduced privilege version.
+ // We can soft fail on this for now, as it's just an extra mitigation.
+ static const ACCESS_MASK kDesktopDenyMask = WRITE_DAC | WRITE_OWNER |
+ DESKTOP_HOOKCONTROL |
+ DESKTOP_JOURNALPLAYBACK |
+ DESKTOP_JOURNALRECORD |
+ DESKTOP_SWITCHDESKTOP;
+ AddKnownSidToObject(*desktop, SE_WINDOW_OBJECT, Sid(WinRestrictedCodeSid),
+ DENY_ACCESS, kDesktopDenyMask);
return SBOX_ALL_OK;
+ }
return SBOX_ERROR_CANNOT_CREATE_DESKTOP;
}
diff --git a/sandbox/win/tests/validation_tests/commands.cc b/sandbox/win/tests/validation_tests/commands.cc
index eefc498..e7620c3 100644
--- a/sandbox/win/tests/validation_tests/commands.cc
+++ b/sandbox/win/tests/validation_tests/commands.cc
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <Aclapi.h>
#include <windows.h>
#include <string>
@@ -240,11 +241,62 @@ SBOX_TESTS_COMMAND int SwitchToSboxDesktop(int, wchar_t **) {
}
int TestSwitchDesktop() {
- HDESK sbox_desk = ::GetThreadDesktop(::GetCurrentThreadId());
- if (NULL == sbox_desk) {
+ HDESK desktop = ::GetThreadDesktop(::GetCurrentThreadId());
+ if (NULL == desktop) {
return SBOX_TEST_FAILED;
}
- if (::SwitchDesktop(sbox_desk)) {
+ if (::SwitchDesktop(desktop)) {
+ return SBOX_TEST_SUCCEEDED;
+ }
+ return SBOX_TEST_DENIED;
+}
+
+SBOX_TESTS_COMMAND int OpenAlternateDesktop(int, wchar_t **argv) {
+ return TestOpenAlternateDesktop(argv[0]);
+}
+
+int TestOpenAlternateDesktop(wchar_t *desktop_name) {
+ // Test for WRITE_DAC permission on the handle.
+ HDESK desktop = ::GetThreadDesktop(::GetCurrentThreadId());
+ if (desktop) {
+ HANDLE test_handle;
+ if (::DuplicateHandle(::GetCurrentProcess(), desktop,
+ ::GetCurrentProcess(), &test_handle,
+ WRITE_DAC, FALSE, 0)) {
+ DWORD result = ::SetSecurityInfo(test_handle, SE_WINDOW_OBJECT,
+ DACL_SECURITY_INFORMATION, NULL, NULL,
+ NULL, NULL);
+ ::CloseHandle(test_handle);
+ if (result != ERROR_ACCESS_DENIED) {
+ return SBOX_TEST_SUCCEEDED;
+ }
+ } else if (::GetLastError() != ERROR_ACCESS_DENIED) {
+ return SBOX_TEST_FAILED;
+ }
+ }
+
+ // Open by name with WRITE_DAC.
+ if ((desktop = ::OpenDesktop(desktop_name, 0, FALSE, WRITE_DAC)) ||
+ ::GetLastError() != ERROR_ACCESS_DENIED) {
+ ::CloseDesktop(desktop);
+ return SBOX_TEST_SUCCEEDED;
+ }
+
+ return SBOX_TEST_DENIED;
+}
+
+BOOL CALLBACK DesktopTestEnumProc(LPTSTR desktop_name, LPARAM result) {
+ return TRUE;
+}
+
+SBOX_TESTS_COMMAND int EnumAlternateWinsta(int, wchar_t **) {
+ return TestEnumAlternateWinsta();
+}
+
+int TestEnumAlternateWinsta() {
+ int result = SBOX_TEST_DENIED;
+ // Try to enumerate the destops on the alternate windowstation.
+ if (::EnumDesktopsW(NULL, DesktopTestEnumProc, 0)) {
return SBOX_TEST_SUCCEEDED;
}
return SBOX_TEST_DENIED;
diff --git a/sandbox/win/tests/validation_tests/commands.h b/sandbox/win/tests/validation_tests/commands.h
index 3a6a0f5..f9b6199 100644
--- a/sandbox/win/tests/validation_tests/commands.h
+++ b/sandbox/win/tests/validation_tests/commands.h
@@ -36,6 +36,13 @@ int TestOpenInputDesktop();
// Tries to switch the interactive desktop. Returns a SboxTestResult.
int TestSwitchDesktop();
+// Tries to open the alternate desktop. Returns a SboxTestResult.
+int TestOpenAlternateDesktop(wchar_t *desktop_name);
+
+// Tries to enumerate desktops on the alternate windowstation.
+// Returns a SboxTestResult.
+int TestEnumAlternateWinsta();
+
} // namespace sandbox
#endif // SANDBOX_TESTS_VALIDATION_TESTS_COMMANDS_H__
diff --git a/sandbox/win/tests/validation_tests/suite.cc b/sandbox/win/tests/validation_tests/suite.cc
index 95209b7..f85b8da 100644
--- a/sandbox/win/tests/validation_tests/suite.cc
+++ b/sandbox/win/tests/validation_tests/suite.cc
@@ -111,11 +111,31 @@ TEST(ValidationSuite, TestRegistry) {
// to get to the interactive desktop or to make the sbox desktop interactive.
TEST(ValidationSuite, TestDesktop) {
TestRunner runner;
- runner.GetPolicy()->SetAlternateDesktop(false);
+ runner.GetPolicy()->SetAlternateDesktop(true);
EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"OpenInteractiveDesktop NULL"));
EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"SwitchToSboxDesktop NULL"));
}
+// Tests that the permissions on the Windowstation does not allow the sandbox
+// to get to the interactive desktop or to make the sbox desktop interactive.
+TEST(ValidationSuite, TestAlternateDesktop) {
+ base::win::Version version = base::win::GetVersion();
+ if (version < base::win::VERSION_WIN7)
+ return;
+
+ TestRunner runner;
+ EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"EnumAlternateWinsta NULL"));
+
+ wchar_t command[1024] = {0};
+ runner.SetTimeout(3600000);
+ runner.GetPolicy()->SetAlternateDesktop(true);
+ runner.GetPolicy()->SetDelayedIntegrityLevel(INTEGRITY_LEVEL_UNTRUSTED);
+ base::string16 desktop_name = runner.GetPolicy()->GetAlternateDesktop();
+ desktop_name = desktop_name.substr(desktop_name.find('\\') + 1);
+ wsprintf(command, L"OpenAlternateDesktop %lS", desktop_name.c_str());
+ EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(command));
+}
+
// Tests if the windows are correctly protected by the sandbox.
TEST(ValidationSuite, TestWindows) {
TestRunner runner;