summaryrefslogtreecommitdiffstats
path: root/security/sandbox/chromium/sandbox/win/src/app_container_test.cc
diff options
context:
space:
mode:
Diffstat (limited to 'security/sandbox/chromium/sandbox/win/src/app_container_test.cc')
-rw-r--r--security/sandbox/chromium/sandbox/win/src/app_container_test.cc342
1 files changed, 342 insertions, 0 deletions
diff --git a/security/sandbox/chromium/sandbox/win/src/app_container_test.cc b/security/sandbox/chromium/sandbox/win/src/app_container_test.cc
new file mode 100644
index 0000000000..a6c0948a94
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/app_container_test.cc
@@ -0,0 +1,342 @@
+// Copyright (c) 2012 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 <memory>
+#include <string>
+#include <vector>
+
+#include "base/rand_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/win/scoped_handle.h"
+#include "base/win/scoped_process_information.h"
+#include "base/win/windows_version.h"
+#include "sandbox/win/src/app_container_profile_base.h"
+#include "sandbox/win/src/sync_policy_test.h"
+#include "sandbox/win/src/win_utils.h"
+#include "sandbox/win/tests/common/controller.h"
+#include "sandbox/win/tests/common/test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+
+namespace {
+
+const wchar_t kAppContainerSid[] =
+ L"S-1-15-2-3251537155-1984446955-2931258699-841473695-1938553385-"
+ L"924012148-2839372144";
+
+std::wstring GenerateRandomPackageName() {
+ return base::StringPrintf(L"%016lX%016lX", base::RandUint64(),
+ base::RandUint64());
+}
+
+const char* TokenTypeToName(TOKEN_TYPE token_type) {
+ return token_type == ::TokenPrimary ? "Primary Token" : "Impersonation Token";
+}
+
+void CheckToken(HANDLE token,
+ TOKEN_TYPE token_type,
+ PSECURITY_CAPABILITIES security_capabilities,
+ BOOL restricted) {
+ ASSERT_EQ(restricted, ::IsTokenRestricted(token))
+ << TokenTypeToName(token_type);
+
+ DWORD appcontainer;
+ DWORD return_length;
+ ASSERT_TRUE(::GetTokenInformation(token, ::TokenIsAppContainer, &appcontainer,
+ sizeof(appcontainer), &return_length))
+ << TokenTypeToName(token_type);
+ ASSERT_TRUE(appcontainer) << TokenTypeToName(token_type);
+ TOKEN_TYPE token_type_real;
+ ASSERT_TRUE(::GetTokenInformation(token, ::TokenType, &token_type_real,
+ sizeof(token_type_real), &return_length))
+ << TokenTypeToName(token_type);
+ ASSERT_EQ(token_type_real, token_type) << TokenTypeToName(token_type);
+ if (token_type == ::TokenImpersonation) {
+ SECURITY_IMPERSONATION_LEVEL imp_level;
+ ASSERT_TRUE(::GetTokenInformation(token, ::TokenImpersonationLevel,
+ &imp_level, sizeof(imp_level),
+ &return_length))
+ << TokenTypeToName(token_type);
+ ASSERT_EQ(imp_level, ::SecurityImpersonation)
+ << TokenTypeToName(token_type);
+ }
+
+ std::unique_ptr<Sid> package_sid;
+ ASSERT_TRUE(GetTokenAppContainerSid(token, &package_sid))
+ << TokenTypeToName(token_type);
+ EXPECT_TRUE(::EqualSid(security_capabilities->AppContainerSid,
+ package_sid->GetPSID()))
+ << TokenTypeToName(token_type);
+
+ std::vector<SidAndAttributes> capabilities;
+ ASSERT_TRUE(GetTokenGroups(token, ::TokenCapabilities, &capabilities))
+ << TokenTypeToName(token_type);
+
+ ASSERT_EQ(capabilities.size(), security_capabilities->CapabilityCount)
+ << TokenTypeToName(token_type);
+ for (size_t index = 0; index < capabilities.size(); ++index) {
+ EXPECT_EQ(capabilities[index].GetAttributes(),
+ security_capabilities->Capabilities[index].Attributes)
+ << TokenTypeToName(token_type);
+ EXPECT_TRUE(::EqualSid(capabilities[index].GetPSID(),
+ security_capabilities->Capabilities[index].Sid))
+ << TokenTypeToName(token_type);
+ }
+}
+
+void CheckProcessToken(HANDLE process,
+ PSECURITY_CAPABILITIES security_capabilities,
+ bool restricted) {
+ HANDLE token_handle;
+ ASSERT_TRUE(::OpenProcessToken(process, TOKEN_ALL_ACCESS, &token_handle));
+ base::win::ScopedHandle token(token_handle);
+ CheckToken(token_handle, ::TokenPrimary, security_capabilities, restricted);
+}
+
+void CheckThreadToken(HANDLE thread,
+ PSECURITY_CAPABILITIES security_capabilities,
+ bool restricted) {
+ HANDLE token_handle;
+ ASSERT_TRUE(::OpenThreadToken(thread, TOKEN_ALL_ACCESS, TRUE, &token_handle));
+ base::win::ScopedHandle token(token_handle);
+ CheckToken(token_handle, ::TokenImpersonation, security_capabilities,
+ restricted);
+}
+
+// Check for LPAC using an access check. We could query for a security attribute
+// but that's undocumented and has the potential to change.
+void CheckLpacToken(HANDLE process) {
+ HANDLE token_handle;
+ ASSERT_TRUE(::OpenProcessToken(process, TOKEN_ALL_ACCESS, &token_handle));
+ base::win::ScopedHandle token(token_handle);
+ ASSERT_TRUE(
+ ::DuplicateToken(token.Get(), ::SecurityImpersonation, &token_handle));
+ token.Set(token_handle);
+ PSECURITY_DESCRIPTOR security_desc_ptr;
+ // AC is AllPackages, S-1-15-2-2 is AllRestrictedPackages. An LPAC token
+ // will get granted access of 2, where as a normal AC token will get 3.
+ ASSERT_TRUE(::ConvertStringSecurityDescriptorToSecurityDescriptor(
+ L"O:SYG:SYD:(A;;0x3;;;WD)(A;;0x1;;;AC)(A;;0x2;;;S-1-15-2-2)",
+ SDDL_REVISION_1, &security_desc_ptr, nullptr));
+ std::unique_ptr<void, LocalFreeDeleter> security_desc(security_desc_ptr);
+ GENERIC_MAPPING generic_mapping = {};
+ PRIVILEGE_SET priv_set = {};
+ DWORD priv_set_length = sizeof(PRIVILEGE_SET);
+ DWORD granted_access;
+ BOOL access_status;
+ ASSERT_TRUE(::AccessCheck(security_desc_ptr, token.Get(), MAXIMUM_ALLOWED,
+ &generic_mapping, &priv_set, &priv_set_length,
+ &granted_access, &access_status));
+ ASSERT_TRUE(access_status);
+ ASSERT_EQ(DWORD{2}, granted_access);
+}
+
+class AppContainerProfileTest : public ::testing::Test {
+ public:
+ void SetUp() override {
+ if (base::win::GetVersion() < base::win::Version::WIN8)
+ return;
+ package_name_ = GenerateRandomPackageName();
+ broker_services_ = GetBroker();
+ policy_ = broker_services_->CreatePolicy();
+ ASSERT_EQ(SBOX_ALL_OK,
+ policy_->SetProcessMitigations(MITIGATION_HEAP_TERMINATE));
+ ASSERT_EQ(SBOX_ALL_OK,
+ policy_->AddAppContainerProfile(package_name_.c_str(), true));
+ // For testing purposes we known the base class so cast directly.
+ profile_ = static_cast<AppContainerProfileBase*>(
+ policy_->GetAppContainerProfile().get());
+ }
+
+ void TearDown() override {
+ if (scoped_process_info_.IsValid())
+ ::TerminateProcess(scoped_process_info_.process_handle(), 0);
+ if (profile_)
+ AppContainerProfileBase::Delete(package_name_.c_str());
+ }
+
+ protected:
+ void CreateProcess() {
+ // Get the path to the sandboxed app.
+ wchar_t prog_name[MAX_PATH] = {};
+ ASSERT_NE(DWORD{0}, ::GetModuleFileNameW(nullptr, prog_name, MAX_PATH));
+
+ PROCESS_INFORMATION process_info = {};
+ ResultCode last_warning = SBOX_ALL_OK;
+ DWORD last_error = 0;
+ ResultCode result = broker_services_->SpawnTarget(
+ prog_name, prog_name, policy_, &last_warning, &last_error,
+ &process_info);
+ ASSERT_EQ(SBOX_ALL_OK, result) << "Last Error: " << last_error;
+ scoped_process_info_.Set(process_info);
+ }
+
+ std::wstring package_name_;
+ BrokerServices* broker_services_;
+ scoped_refptr<AppContainerProfileBase> profile_;
+ scoped_refptr<TargetPolicy> policy_;
+ base::win::ScopedProcessInformation scoped_process_info_;
+};
+
+} // namespace
+
+
+TEST(AppContainerTest, DenyOpenEventForLowBox) {
+ if (base::win::GetVersion() < base::win::Version::WIN8)
+ return;
+
+ TestRunner runner(JOB_UNPROTECTED, USER_UNPROTECTED, USER_UNPROTECTED);
+
+ EXPECT_EQ(SBOX_ALL_OK, runner.GetPolicy()->SetLowBox(kAppContainerSid));
+ // Run test once, this ensures the app container directory exists, we
+ // ignore the result.
+ runner.RunTest(L"Event_Open f test");
+ std::wstring event_name = L"AppContainerNamedObjects\\";
+ event_name += kAppContainerSid;
+ event_name += L"\\test";
+
+ base::win::ScopedHandle event(
+ ::CreateEvent(nullptr, false, false, event_name.c_str()));
+ ASSERT_TRUE(event.IsValid());
+
+ EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Event_Open f test"));
+}
+
+TEST_F(AppContainerProfileTest, CheckIncompatibleOptions) {
+ if (!profile_)
+ return;
+ EXPECT_EQ(SBOX_ERROR_BAD_PARAMS,
+ policy_->SetIntegrityLevel(INTEGRITY_LEVEL_UNTRUSTED));
+ EXPECT_EQ(SBOX_ERROR_BAD_PARAMS, policy_->SetLowBox(kAppContainerSid));
+
+ MitigationFlags expected_mitigations = 0;
+ MitigationFlags expected_delayed = MITIGATION_HEAP_TERMINATE;
+ sandbox::ResultCode expected_result = SBOX_ERROR_BAD_PARAMS;
+
+ if (base::win::GetVersion() >= base::win::Version::WIN10_RS5) {
+ expected_mitigations = MITIGATION_HEAP_TERMINATE;
+ expected_delayed = 0;
+ expected_result = SBOX_ALL_OK;
+ }
+
+ EXPECT_EQ(expected_mitigations, policy_->GetProcessMitigations());
+ EXPECT_EQ(expected_delayed, policy_->GetDelayedProcessMitigations());
+ EXPECT_EQ(expected_result,
+ policy_->SetProcessMitigations(MITIGATION_HEAP_TERMINATE));
+}
+
+TEST_F(AppContainerProfileTest, NoCapabilities) {
+ if (!profile_)
+ return;
+
+ policy_->SetTokenLevel(USER_UNPROTECTED, USER_UNPROTECTED);
+ policy_->SetJobLevel(JOB_NONE, 0);
+
+ CreateProcess();
+ auto security_capabilities = profile_->GetSecurityCapabilities();
+
+ CheckProcessToken(scoped_process_info_.process_handle(),
+ security_capabilities.get(), FALSE);
+ CheckThreadToken(scoped_process_info_.thread_handle(),
+ security_capabilities.get(), FALSE);
+}
+
+TEST_F(AppContainerProfileTest, NoCapabilitiesRestricted) {
+ if (!profile_)
+ return;
+
+ policy_->SetTokenLevel(USER_LOCKDOWN, USER_RESTRICTED_SAME_ACCESS);
+ policy_->SetJobLevel(JOB_NONE, 0);
+
+ CreateProcess();
+ auto security_capabilities = profile_->GetSecurityCapabilities();
+
+ CheckProcessToken(scoped_process_info_.process_handle(),
+ security_capabilities.get(), TRUE);
+ CheckThreadToken(scoped_process_info_.thread_handle(),
+ security_capabilities.get(), TRUE);
+}
+
+TEST_F(AppContainerProfileTest, WithCapabilities) {
+ if (!profile_)
+ return;
+
+ profile_->AddCapability(kInternetClient);
+ profile_->AddCapability(kInternetClientServer);
+ policy_->SetTokenLevel(USER_UNPROTECTED, USER_UNPROTECTED);
+ policy_->SetJobLevel(JOB_NONE, 0);
+
+ CreateProcess();
+ auto security_capabilities = profile_->GetSecurityCapabilities();
+
+ CheckProcessToken(scoped_process_info_.process_handle(),
+ security_capabilities.get(), FALSE);
+ CheckThreadToken(scoped_process_info_.thread_handle(),
+ security_capabilities.get(), FALSE);
+}
+
+TEST_F(AppContainerProfileTest, WithCapabilitiesRestricted) {
+ if (!profile_)
+ return;
+
+ profile_->AddCapability(kInternetClient);
+ profile_->AddCapability(kInternetClientServer);
+ policy_->SetTokenLevel(USER_LOCKDOWN, USER_RESTRICTED_SAME_ACCESS);
+ policy_->SetJobLevel(JOB_NONE, 0);
+
+ CreateProcess();
+ auto security_capabilities = profile_->GetSecurityCapabilities();
+
+ CheckProcessToken(scoped_process_info_.process_handle(),
+ security_capabilities.get(), TRUE);
+ CheckThreadToken(scoped_process_info_.thread_handle(),
+ security_capabilities.get(), TRUE);
+}
+
+TEST_F(AppContainerProfileTest, WithImpersonationCapabilities) {
+ if (!profile_)
+ return;
+
+ profile_->AddCapability(kInternetClient);
+ profile_->AddCapability(kInternetClientServer);
+ profile_->AddImpersonationCapability(kPrivateNetworkClientServer);
+ profile_->AddImpersonationCapability(kPicturesLibrary);
+ policy_->SetTokenLevel(USER_UNPROTECTED, USER_UNPROTECTED);
+ policy_->SetJobLevel(JOB_NONE, 0);
+
+ CreateProcess();
+ auto security_capabilities = profile_->GetSecurityCapabilities();
+
+ CheckProcessToken(scoped_process_info_.process_handle(),
+ security_capabilities.get(), FALSE);
+ SecurityCapabilities impersonation_security_capabilities(
+ profile_->GetPackageSid(), profile_->GetImpersonationCapabilities());
+ CheckThreadToken(scoped_process_info_.thread_handle(),
+ &impersonation_security_capabilities, FALSE);
+}
+
+TEST_F(AppContainerProfileTest, NoCapabilitiesLPAC) {
+ if (base::win::GetVersion() < base::win::Version::WIN10_RS1)
+ return;
+
+ profile_->SetEnableLowPrivilegeAppContainer(true);
+ policy_->SetTokenLevel(USER_UNPROTECTED, USER_UNPROTECTED);
+ policy_->SetJobLevel(JOB_NONE, 0);
+
+ CreateProcess();
+ auto security_capabilities = profile_->GetSecurityCapabilities();
+
+ CheckProcessToken(scoped_process_info_.process_handle(),
+ security_capabilities.get(), FALSE);
+ CheckThreadToken(scoped_process_info_.thread_handle(),
+ security_capabilities.get(), FALSE);
+ CheckLpacToken(scoped_process_info_.process_handle());
+}
+
+} // namespace sandbox