summaryrefslogtreecommitdiffstats
path: root/sandbox/src
diff options
context:
space:
mode:
authornsylvain@chromium.org <nsylvain@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-05-20 16:05:56 +0000
committernsylvain@chromium.org <nsylvain@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-05-20 16:05:56 +0000
commitff608eb386a2662bbe076a2a59b21eb90bc34532 (patch)
tree63c82289115c4b64d6d444816aab4f895f43917c /sandbox/src
parent1e3af029048d55a3b7c39100683121d71c8ea673 (diff)
downloadchromium_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.cc5
-rw-r--r--sandbox/src/policy_target_test.cc88
-rw-r--r--sandbox/src/sandbox.vcproj8
-rw-r--r--sandbox/src/sandbox_policy.h20
-rw-r--r--sandbox/src/sandbox_policy_base.cc86
-rw-r--r--sandbox/src/sandbox_policy_base.h37
-rw-r--r--sandbox/src/sandbox_types.h8
-rw-r--r--sandbox/src/target_process.cc10
-rw-r--r--sandbox/src/target_process.h4
-rw-r--r--sandbox/src/window.cc142
-rw-r--r--sandbox/src/window.h39
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_