diff options
author | nsylvain@chromium.org <nsylvain@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-20 16:05:56 +0000 |
---|---|---|
committer | nsylvain@chromium.org <nsylvain@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-20 16:05:56 +0000 |
commit | ff608eb386a2662bbe076a2a59b21eb90bc34532 (patch) | |
tree | 63c82289115c4b64d6d444816aab4f895f43917c /sandbox/src | |
parent | 1e3af029048d55a3b7c39100683121d71c8ea673 (diff) | |
download | chromium_src-ff608eb386a2662bbe076a2a59b21eb90bc34532.zip chromium_src-ff608eb386a2662bbe076a2a59b21eb90bc34532.tar.gz chromium_src-ff608eb386a2662bbe076a2a59b21eb90bc34532.tar.bz2 |
Add support for alternate window station.
TEST: Start chrome, make sure it loads pages, then user process explorer to make sure the WindowStation handle name is not the same as the browser process.
BUG:10996
Review URL: http://codereview.chromium.org/113190
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@16483 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'sandbox/src')
-rw-r--r-- | sandbox/src/broker_services.cc | 5 | ||||
-rw-r--r-- | sandbox/src/policy_target_test.cc | 88 | ||||
-rw-r--r-- | sandbox/src/sandbox.vcproj | 8 | ||||
-rw-r--r-- | sandbox/src/sandbox_policy.h | 20 | ||||
-rw-r--r-- | sandbox/src/sandbox_policy_base.cc | 86 | ||||
-rw-r--r-- | sandbox/src/sandbox_policy_base.h | 37 | ||||
-rw-r--r-- | sandbox/src/sandbox_types.h | 8 | ||||
-rw-r--r-- | sandbox/src/target_process.cc | 10 | ||||
-rw-r--r-- | sandbox/src/target_process.h | 4 | ||||
-rw-r--r-- | sandbox/src/window.cc | 142 | ||||
-rw-r--r-- | sandbox/src/window.h | 39 |
11 files changed, 412 insertions, 35 deletions
diff --git a/sandbox/src/broker_services.cc b/sandbox/src/broker_services.cc index 24fa63d..557c82d 100644 --- a/sandbox/src/broker_services.cc +++ b/sandbox/src/broker_services.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Copyright (c) 2006-2009 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. @@ -256,7 +256,8 @@ ResultCode BrokerServicesBase::SpawnTarget(const wchar_t* exe_path, TargetProcess* target = new TargetProcess(initial_token, lockdown_token, job, thread_pool_); - std::wstring desktop = policy_base->GetDesktop(); + std::wstring desktop = policy_base->GetAlternateDesktop(); + win_result = target->Create(exe_path, command_line, desktop.empty() ? NULL : desktop.c_str(), &process_info); diff --git a/sandbox/src/policy_target_test.cc b/sandbox/src/policy_target_test.cc index 63948685..e4ff837 100644 --- a/sandbox/src/policy_target_test.cc +++ b/sandbox/src/policy_target_test.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Copyright (c) 2006-2009 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. @@ -165,6 +165,12 @@ TEST(PolicyTargetTest, OpenProcess) { // current desktop. TEST(PolicyTargetTest, DesktopPolicy) { BrokerServices* broker = GetBroker(); + + // Precreate the desktop. + TargetPolicy* temp_policy = broker->CreatePolicy(); + temp_policy->CreateAlternateDesktop(false); + temp_policy->Release(); + ASSERT_TRUE(broker != NULL); // Get the path to the sandboxed app. @@ -180,7 +186,7 @@ TEST(PolicyTargetTest, DesktopPolicy) { PROCESS_INFORMATION target = {0}; TargetPolicy* policy = broker->CreatePolicy(); - policy->SetDesktop(L"desktop_for_sbox"); + policy->SetAlternateDesktop(false); policy->SetTokenLevel(USER_INTERACTIVE, USER_LOCKDOWN); result = broker->SpawnTarget(prog_name, arguments.c_str(), policy, &target); policy->Release(); @@ -194,7 +200,8 @@ TEST(PolicyTargetTest, DesktopPolicy) { EXPECT_NE(::GetThreadDesktop(target.dwThreadId), ::GetThreadDesktop(::GetCurrentThreadId())); - HDESK desk = ::OpenDesktop(L"desktop_for_sbox", 0, FALSE, DESKTOP_ENUMERATE); + std::wstring desktop_name = policy->GetAlternateDesktop(); + HDESK desk = ::OpenDesktop(desktop_name.c_str(), 0, FALSE, DESKTOP_ENUMERATE); EXPECT_TRUE(NULL != desk); EXPECT_TRUE(::CloseDesktop(desk)); EXPECT_TRUE(::TerminateProcess(target.hProcess, 0)); @@ -204,11 +211,80 @@ TEST(PolicyTargetTest, DesktopPolicy) { EXPECT_TRUE(::CloseHandle(target.hProcess)); EXPECT_TRUE(::CloseHandle(target.hThread)); - // Wait for the desktop to be deleted by the destructor of TargetProcess - Sleep(2000); + // Close the desktop handle. + temp_policy = broker->CreatePolicy(); + temp_policy->DestroyAlternateDesktop(); + temp_policy->Release(); - desk = ::OpenDesktop(L"desktop_for_sbox", 0, FALSE, DESKTOP_ENUMERATE); + // Make sure the desktop does not exist anymore. + desk = ::OpenDesktop(desktop_name.c_str(), 0, FALSE, DESKTOP_ENUMERATE); EXPECT_TRUE(NULL == desk); } +// Launches the app in the sandbox and ask it to wait in an +// infinite loop. Waits for 2 seconds and then check if the +// winstation associated with the app thread is not the same as the +// current desktop. +TEST(PolicyTargetTest, WinstaPolicy) { + BrokerServices* broker = GetBroker(); + + // Precreate the desktop. + TargetPolicy* temp_policy = broker->CreatePolicy(); + temp_policy->CreateAlternateDesktop(true); + temp_policy->Release(); + + ASSERT_TRUE(broker != NULL); + + // Get the path to the sandboxed app. + wchar_t prog_name[MAX_PATH]; + GetModuleFileNameW(NULL, prog_name, MAX_PATH); + + std::wstring arguments(L"\""); + arguments += prog_name; + arguments += L"\" -child 0 wait"; // Don't care about the "state" argument. + + // Launch the app. + ResultCode result = SBOX_ALL_OK; + PROCESS_INFORMATION target = {0}; + + TargetPolicy* policy = broker->CreatePolicy(); + policy->SetAlternateDesktop(true); + policy->SetTokenLevel(USER_INTERACTIVE, USER_LOCKDOWN); + result = broker->SpawnTarget(prog_name, arguments.c_str(), policy, &target); + policy->Release(); + + EXPECT_EQ(SBOX_ALL_OK, result); + + EXPECT_EQ(1, ::ResumeThread(target.hThread)); + + EXPECT_EQ(WAIT_TIMEOUT, ::WaitForSingleObject(target.hProcess, 2000)); + + EXPECT_NE(::GetThreadDesktop(target.dwThreadId), + ::GetThreadDesktop(::GetCurrentThreadId())); + + std::wstring desktop_name = policy->GetAlternateDesktop(); + ASSERT_FALSE(desktop_name.empty()); + + // Make sure there is a backslash, for the window station name. + EXPECT_NE(desktop_name.find_first_of(L'\\'), std::wstring::npos); + + // Isolate the desktop name. + desktop_name = desktop_name.substr(desktop_name.find_first_of(L'\\') + 1); + + HDESK desk = ::OpenDesktop(desktop_name.c_str(), 0, FALSE, DESKTOP_ENUMERATE); + // This should fail if the desktop is really on another window station. + EXPECT_FALSE(NULL != desk); + EXPECT_TRUE(::TerminateProcess(target.hProcess, 0)); + + ::WaitForSingleObject(target.hProcess, INFINITE); + + EXPECT_TRUE(::CloseHandle(target.hProcess)); + EXPECT_TRUE(::CloseHandle(target.hThread)); + + // Close the desktop handle. + temp_policy = broker->CreatePolicy(); + temp_policy->DestroyAlternateDesktop(); + temp_policy->Release(); +} + } // namespace sandbox diff --git a/sandbox/src/sandbox.vcproj b/sandbox/src/sandbox.vcproj index c3f6231..f206e01 100644 --- a/sandbox/src/sandbox.vcproj +++ b/sandbox/src/sandbox.vcproj @@ -183,6 +183,14 @@ RelativePath=".\sid.h" > </File> + <File + RelativePath=".\window.cc" + > + </File> + <File + RelativePath=".\window.h" + > + </File> </Filter> <Filter Name="Interception" diff --git a/sandbox/src/sandbox_policy.h b/sandbox/src/sandbox_policy.h index c454a56..716cefa 100644 --- a/sandbox/src/sandbox_policy.h +++ b/sandbox/src/sandbox_policy.h @@ -1,10 +1,12 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Copyright (c) 2006-2009 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_SRC_SANDBOX_POLICY_H_ #define SANDBOX_SRC_SANDBOX_POLICY_H_ +#include <string> + #include "base/basictypes.h" #include "sandbox/src/sandbox_types.h" #include "sandbox/src/security_level.h" @@ -80,8 +82,20 @@ class TargetPolicy { virtual ResultCode SetJobLevel(JobLevel job_level, uint32 ui_exceptions) = 0; // Specifies the desktop on which the application is going to run. If the - // desktop does not exist, it will be created. - virtual ResultCode SetDesktop(const wchar_t* desktop) = 0; + // desktop does not exist, it will be created. If alternate_winstation is + // set to true, the desktop will be created on an alternate window station. + virtual ResultCode SetAlternateDesktop(bool alternate_winstation) = 0; + + // Returns the name of the alternate desktop used. If an alternate window + // station is specified, the name is prepended by the window station name, + // followed by a backslash. + virtual std::wstring GetAlternateDesktop() const = 0; + + // Precreates the desktop and window station, if any. + virtual ResultCode CreateAlternateDesktop(bool alternate_winstation) = 0; + + // Destroys the desktop and windows station. + virtual void DestroyAlternateDesktop() = 0; // Sets the integrity level of the process in the sandbox. The integrity level // will not take effect before you call LowerToken. User Interface Privilege diff --git a/sandbox/src/sandbox_policy_base.cc b/sandbox/src/sandbox_policy_base.cc index 95afe43..ca41591a5 100644 --- a/sandbox/src/sandbox_policy_base.cc +++ b/sandbox/src/sandbox_policy_base.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Copyright (c) 2006-2009 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. @@ -24,6 +24,7 @@ #include "sandbox/src/sync_dispatcher.h" #include "sandbox/src/sync_policy.h" #include "sandbox/src/target_process.h" +#include "sandbox/src/window.h" namespace { // The standard windows size for one memory page. @@ -48,6 +49,10 @@ namespace sandbox { SANDBOX_INTERCEPT IntegrityLevel g_shared_delayed_integrity_level; +// Initializes static members. +HWINSTA PolicyBase::alternate_winstation_handle_ = NULL; +HDESK PolicyBase::alternate_desktop_handle_ = NULL; + PolicyBase::PolicyBase() : ref_count(1), lockdown_level_(USER_LOCKDOWN), @@ -58,7 +63,9 @@ PolicyBase::PolicyBase() policy_(NULL), policy_maker_(NULL), file_system_init_(false), - relaxed_interceptions_(true) { + relaxed_interceptions_(true), + use_alternate_desktop_(false), + use_alternate_winstation_(false) { ::InitializeCriticalSection(&lock_); // Initialize the IPC dispatcher array. memset(&ipc_targets_, NULL, sizeof(ipc_targets_)); @@ -132,6 +139,81 @@ DWORD PolicyBase::MakeTokens(HANDLE* initial, HANDLE* lockdown) { return SBOX_ALL_OK; } +std::wstring PolicyBase::GetAlternateDesktop() const { + // No alternate desktop or winstation. Return an empty string. + if (!use_alternate_desktop_ && !use_alternate_winstation_) { + return std::wstring(); + } + + // The desktop and winstation should have been created by now. + // If we hit this scenario, it means that the user ignored the failure + // during SetAlternateDesktop, so we ignore it here too. + if (use_alternate_desktop_ && !alternate_desktop_handle_) { + return std::wstring(); + } + if (use_alternate_winstation_ && (!alternate_desktop_handle_ || + !alternate_winstation_handle_)) { + return std::wstring(); + } + + return GetFullDesktopName(alternate_winstation_handle_, + alternate_desktop_handle_); +} + +ResultCode PolicyBase::CreateAlternateDesktop(bool alternate_winstation) { + if (alternate_winstation) { + // Previously called with alternate_winstation = false? + if (!alternate_winstation_handle_ && alternate_desktop_handle_) + return SBOX_ERROR_UNSUPPORTED; + + // Check if it's already created. + if (alternate_winstation_handle_ && alternate_desktop_handle_) + return SBOX_ALL_OK; + + DCHECK(!alternate_winstation_handle_); + // Create the window station. + ResultCode result = CreateAltWindowStation(&alternate_winstation_handle_); + if (SBOX_ALL_OK != result) + return result; + + // Verify that everything is fine. + if (!alternate_winstation_handle_ || + GetWindowObjectName(alternate_winstation_handle_).empty()) + return SBOX_ERROR_CANNOT_CREATE_DESKTOP; + + // Create the destkop. + result = CreateAltDesktop(alternate_winstation_handle_, + &alternate_desktop_handle_); + if (SBOX_ALL_OK != result) + return result; + + // Verify that everything is fine. + if (!alternate_desktop_handle_ || + GetWindowObjectName(alternate_desktop_handle_).empty()) + return SBOX_ERROR_CANNOT_CREATE_DESKTOP; + } else { + // Previously called with alternate_winstation = true? + if (alternate_winstation_handle_) + return SBOX_ERROR_UNSUPPORTED; + + // Check if it already exists. + if (alternate_desktop_handle_) + return SBOX_ALL_OK; + + // Create the destkop. + ResultCode result = CreateAltDesktop(NULL, &alternate_desktop_handle_); + if (SBOX_ALL_OK != result) + return result; + + // Verify that everything is fine. + if (!alternate_desktop_handle_ || + GetWindowObjectName(alternate_desktop_handle_).empty()) + return SBOX_ERROR_CANNOT_CREATE_DESKTOP; + } + + return SBOX_ALL_OK; +} + bool PolicyBase::AddTarget(TargetProcess* target) { if (NULL != policy_) policy_maker_->Done(); diff --git a/sandbox/src/sandbox_policy_base.h b/sandbox/src/sandbox_policy_base.h index 5b34272..b6f2693 100644 --- a/sandbox/src/sandbox_policy_base.h +++ b/sandbox/src/sandbox_policy_base.h @@ -1,11 +1,11 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Copyright (c) 2006-2009 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_SRC_SANDBOX_POLICY_BASE_H_ #define SANDBOX_SRC_SANDBOX_POLICY_BASE_H_ -#include <Windows.h> +#include <windows.h> #include <list> #include "base/basictypes.h" @@ -57,9 +57,26 @@ class PolicyBase : public Dispatcher, public TargetPolicy { return SBOX_ALL_OK; } - virtual ResultCode SetDesktop(const wchar_t* desktop) { - desktop_ = desktop; - return SBOX_ALL_OK; + virtual ResultCode SetAlternateDesktop(bool alternate_winstation) { + use_alternate_desktop_ = true; + use_alternate_winstation_ = alternate_winstation; + return CreateAlternateDesktop(alternate_winstation); + } + + virtual std::wstring GetAlternateDesktop() const; + + virtual ResultCode CreateAlternateDesktop(bool alternate_winstation); + + virtual void DestroyAlternateDesktop() { + if (alternate_desktop_handle_) { + ::CloseDesktop(alternate_desktop_handle_); + alternate_desktop_handle_ = NULL; + } + + if (alternate_winstation_handle_) { + ::CloseWindowStation(alternate_winstation_handle_); + alternate_winstation_handle_ = NULL; + } } virtual ResultCode SetIntegrityLevel(IntegrityLevel integrity_level) { @@ -84,10 +101,6 @@ class PolicyBase : public Dispatcher, public TargetPolicy { return SBOX_ALL_OK; } - std::wstring GetDesktop() const { - return desktop_; - } - // Creates a Job object with the level specified in a previous call to // SetJobLevel(). Returns the standard windows of ::GetLastError(). DWORD MakeJobObject(HANDLE* job); @@ -133,7 +146,8 @@ class PolicyBase : public Dispatcher, public TargetPolicy { TokenLevel initial_level_; JobLevel job_level_; uint32 ui_exceptions_; - std::wstring desktop_; + bool use_alternate_desktop_; + bool use_alternate_winstation_; IntegrityLevel integrity_level_; IntegrityLevel delayed_integrity_level_; // The array of objects that will answer IPC calls. @@ -149,6 +163,9 @@ class PolicyBase : public Dispatcher, public TargetPolicy { // The list of dlls to unload in the target process. std::vector<std::wstring> blacklisted_dlls_; + static HDESK alternate_desktop_handle_; + static HWINSTA alternate_winstation_handle_; + DISALLOW_COPY_AND_ASSIGN(PolicyBase); }; diff --git a/sandbox/src/sandbox_types.h b/sandbox/src/sandbox_types.h index 641b228..3346085 100644 --- a/sandbox/src/sandbox_types.h +++ b/sandbox/src/sandbox_types.h @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Copyright (c) 2006-2009 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. @@ -31,6 +31,12 @@ enum ResultCode { SBOX_ERROR_WAIT_ALREADY_CALLED = 9, // A channel error prevented DoCall from executing. SBOX_ERROR_CHANNEL_ERROR = 10, + // Failed to create the alternate desktop. + SBOX_ERROR_CANNOT_CREATE_DESKTOP = 11, + // Failed to create the alternate window station. + SBOX_ERROR_CANNOT_CREATE_WINSTATION = 12, + // Failed to switch back to the interactive window station. + SBOX_ERROR_FAILED_TO_SWITCH_BACK_WINSTATION = 13, // Placeholder for last item of the enum. SBOX_ERROR_LAST }; diff --git a/sandbox/src/target_process.cc b/sandbox/src/target_process.cc index 2d039d9..5bd0a8c 100644 --- a/sandbox/src/target_process.cc +++ b/sandbox/src/target_process.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Copyright (c) 2006-2009 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. @@ -83,7 +83,6 @@ TargetProcess::TargetProcess(HANDLE initial_token, HANDLE lockdown_token, exe_name_(NULL), sandbox_process_(NULL), sandbox_thread_(NULL), - desktop_handle_(NULL), sandbox_process_id_(0) { } @@ -113,8 +112,6 @@ TargetProcess::~TargetProcess() { ::CloseHandle(sandbox_process_); if (shared_section_) ::CloseHandle(shared_section_); - if (desktop_handle_) - ::CloseDesktop(desktop_handle_); free(exe_name_); } @@ -130,15 +127,12 @@ DWORD TargetProcess::Create(const wchar_t* exe_path, scoped_ptr_malloc<wchar_t> cmd_line(_wcsdup(command_line)); scoped_ptr_malloc<wchar_t> desktop_name(desktop ? _wcsdup(desktop) : NULL); + // Start the target process suspended. const DWORD flags = CREATE_SUSPENDED | CREATE_BREAKAWAY_FROM_JOB | CREATE_UNICODE_ENVIRONMENT | DETACHED_PROCESS; - // Start the target process suspended STARTUPINFO startup_info = {sizeof(STARTUPINFO)}; if (desktop) { - // Ensure that the desktop exists - desktop_handle_ = ::CreateDesktop(desktop_name.get(), NULL, NULL, 0, - DESKTOP_CREATEWINDOW, NULL); startup_info.lpDesktop = desktop_name.get(); } diff --git a/sandbox/src/target_process.h b/sandbox/src/target_process.h index 19cdc62..aeb14d6 100644 --- a/sandbox/src/target_process.h +++ b/sandbox/src/target_process.h @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Copyright (c) 2006-2009 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. @@ -105,8 +105,6 @@ class TargetProcess { void* base_address_; // Full name of the target executable. wchar_t* exe_name_; - // Desktop where the target process is running. - HDESK desktop_handle_; // Function used for testing. friend TargetProcess* MakeTestTargetProcess(HANDLE process, diff --git a/sandbox/src/window.cc b/sandbox/src/window.cc new file mode 100644 index 0000000..cd6022c --- /dev/null +++ b/sandbox/src/window.cc @@ -0,0 +1,142 @@ +// Copyright (c) 2009 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/window.h" + +#include <aclapi.h> + +#include "base/logging.h" +#include "base/scoped_ptr.h" + +namespace { + +// Gets the security attributes of a window object referenced by |handle|. The +// lpSecurityDescriptor member of the SECURITY_ATTRIBUTES parameter returned +// must be freed using LocalFree by the caller. +bool GetSecurityAttributes(HANDLE handle, SECURITY_ATTRIBUTES* attributes) { + attributes->bInheritHandle = FALSE; + attributes->nLength = sizeof(SECURITY_ATTRIBUTES); + + PACL dacl = NULL; + DWORD result = ::GetSecurityInfo(handle, SE_WINDOW_OBJECT, + DACL_SECURITY_INFORMATION, NULL, NULL, &dacl, + NULL, &attributes->lpSecurityDescriptor); + if (ERROR_SUCCESS == result) + return true; + + return false; +} + +} + +namespace sandbox { + +ResultCode CreateAltWindowStation(HWINSTA* winsta) { + // Get the security attributes from the current window station; we will + // use this as the base security attributes for the new window station. + SECURITY_ATTRIBUTES attributes = {0}; + if (!GetSecurityAttributes(::GetProcessWindowStation(), &attributes)) { + return SBOX_ERROR_CANNOT_CREATE_WINSTATION; + } + + // Create the window station using NULL for the name to ask the os to + // generate it. + // TODO(nsylvain): don't ask for WINSTA_ALL_ACCESS if we don't need to. + *winsta = ::CreateWindowStationW(NULL, 0, WINSTA_ALL_ACCESS, &attributes); + LocalFree(attributes.lpSecurityDescriptor); + + if (*winsta) + return SBOX_ALL_OK; + + return SBOX_ERROR_CANNOT_CREATE_WINSTATION; +} + +ResultCode CreateAltDesktop(HWINSTA winsta, HDESK* desktop) { + std::wstring desktop_name = L"sbox_alternate_desktop_"; + + // Append the current PID to the desktop name. + wchar_t buffer[16]; + _snwprintf_s(buffer, sizeof(buffer) / sizeof(wchar_t), L"0x%X", + ::GetCurrentProcessId()); + desktop_name += buffer; + + // Get the security attributes from the current desktop, we will use this as + // the base security attributes for the new desktop. + SECURITY_ATTRIBUTES attributes = {0}; + if (!GetSecurityAttributes(GetThreadDesktop(GetCurrentThreadId()), + &attributes)) { + return SBOX_ERROR_CANNOT_CREATE_DESKTOP; + } + + // Back up the current window station, in case we need to switch it. + HWINSTA current_winsta = ::GetProcessWindowStation(); + + if (winsta) { + // We need to switch to the alternate window station before creating the + // desktop. + if (!::SetProcessWindowStation(winsta)) { + ::LocalFree(attributes.lpSecurityDescriptor); + return SBOX_ERROR_CANNOT_CREATE_DESKTOP; + } + } + + // Create the destkop. + // TODO(nsylvain): don't ask for GENERIC_ALL if we don't need to. + *desktop = ::CreateDesktop(desktop_name.c_str(), NULL, NULL, 0, GENERIC_ALL, + &attributes); + ::LocalFree(attributes.lpSecurityDescriptor); + + if (winsta) { + // Revert to the right window station. + if (!::SetProcessWindowStation(current_winsta)) { + return SBOX_ERROR_FAILED_TO_SWITCH_BACK_WINSTATION; + } + } + + if (*desktop) + return SBOX_ALL_OK; + + return SBOX_ERROR_CANNOT_CREATE_DESKTOP; +} + +std::wstring GetWindowObjectName(HANDLE handle) { + // Get the size of the name. + DWORD size = 0; + ::GetUserObjectInformation(handle, UOI_NAME, NULL, 0, &size); + + if (!size) { + NOTREACHED(); + return std::wstring(); + } + + // Create the buffer that will hold the name. + scoped_ptr<wchar_t> name_buffer(new wchar_t[size]); + + // Query the name of the object. + if (!::GetUserObjectInformation(handle, UOI_NAME, name_buffer.get(), size, + &size)) { + NOTREACHED(); + return std::wstring(); + } + + return std::wstring(name_buffer.get()); +} + +std::wstring GetFullDesktopName(HWINSTA winsta, HDESK desktop) { + if (!desktop) { + NOTREACHED(); + return std::wstring(); + } + + std::wstring name; + if (winsta) { + name = GetWindowObjectName(winsta); + name += L'\\'; + } + + name += GetWindowObjectName(desktop); + return name; +} + +} // namespace sandbox diff --git a/sandbox/src/window.h b/sandbox/src/window.h new file mode 100644 index 0000000..f65b463 --- /dev/null +++ b/sandbox/src/window.h @@ -0,0 +1,39 @@ +// Copyright (c) 2009 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_SRC_WINDOW_H_ +#define SANDBOX_SRC_WINDOW_H_ + +#include <windows.h> +#include <string> + +#include "sandbox/src/sandbox_types.h" + +namespace sandbox { + + // Creates a window station. The name is generated by the OS. The security + // descriptor is based on the security descriptor of the current window + // station. + ResultCode CreateAltWindowStation(HWINSTA* winsta); + + // Creates a desktop. The name is a static string followed by the pid of the + // current process. The security descriptor on the new desktop is based on the + // security descriptor of the desktop associated with the current thread. + // If a winsta is specified, the function will switch to it before creating + // the desktop. If the functions fails the switch back to the current winsta, + // the function will return SBOX_ERROR_FAILED_TO_SWITCH_BACK_WINSTATION. + ResultCode CreateAltDesktop(HWINSTA winsta, HDESK* desktop); + + // Returns the name of a desktop or a window station. + std::wstring GetWindowObjectName(HANDLE handle); + + // Returns the name of the desktop referenced by |desktop|. If a window + // station is specified, the name is prepended with the window station name, + // followed by a backslash. This name can be used as the lpDesktop parameter + // to CreateProcess. + std::wstring GetFullDesktopName(HWINSTA winsta, HDESK desktop); + +} // namespace sandbox + +#endif // SANDBOX_SRC_WINDOW_H_ |