diff options
author | jschuh@chromium.org <jschuh@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-04-11 16:15:40 +0000 |
---|---|---|
committer | jschuh@chromium.org <jschuh@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-04-11 16:15:40 +0000 |
commit | 2efdbfd1a2f7c3eda02d44c66dafd3266fe407f7 (patch) | |
tree | fc4bcdbcda95c201915a2026dabfc462a05671ce /sandbox/src | |
parent | 0e3ff73611ad3230acfe02cdbeeee99afcfac600 (diff) | |
download | chromium_src-2efdbfd1a2f7c3eda02d44c66dafd3266fe407f7.zip chromium_src-2efdbfd1a2f7c3eda02d44c66dafd3266fe407f7.tar.gz chromium_src-2efdbfd1a2f7c3eda02d44c66dafd3266fe407f7.tar.bz2 |
Add sandbox support for associating peer processes
TEST=HandlePolicyTest.DuplicatePeerHandle
Review URL: https://chromiumcodereview.appspot.com/9960045
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@131778 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'sandbox/src')
-rw-r--r-- | sandbox/src/broker_services.cc | 81 | ||||
-rw-r--r-- | sandbox/src/broker_services.h | 29 | ||||
-rw-r--r-- | sandbox/src/handle_policy_test.cc | 22 | ||||
-rw-r--r-- | sandbox/src/sandbox.h | 8 |
4 files changed, 128 insertions, 12 deletions
diff --git a/sandbox/src/broker_services.cc b/sandbox/src/broker_services.cc index d361c2e..d30cdb6 100644 --- a/sandbox/src/broker_services.cc +++ b/sandbox/src/broker_services.cc @@ -45,7 +45,25 @@ enum { THREAD_CTRL_LAST }; -} +// Helper structure that allows the Broker to associate a job notification +// with a job object and with a policy. +struct JobTracker { + HANDLE job; + sandbox::PolicyBase* policy; + JobTracker(HANDLE cjob, sandbox::PolicyBase* cpolicy) + : job(cjob), policy(cpolicy) { + } +}; + +// Helper structure that allows the broker to track peer processes +struct PeerTracker { + HANDLE wait_object_; + base::win::ScopedHandle process_; + PeerTracker() : wait_object_(NULL) { + } +}; + +} // namespace namespace sandbox { @@ -92,6 +110,16 @@ BrokerServicesBase::~BrokerServicesBase() { ::PostQueuedCompletionStatus(job_port_, 0, THREAD_CTRL_QUIT, FALSE); ::CloseHandle(job_port_); + { // Cancel the wait events for all the peers. + AutoLock lock(&lock_); + for (PeerTrackerMap::iterator it = peer_map_.begin(); + it != peer_map_.end(); ++it) { + // This call terminates any running handlers. + ::UnregisterWaitEx(it->second->wait_object_, NULL); + delete it->second; + } + } + if (WAIT_TIMEOUT == ::WaitForSingleObject(job_thread_, 1000)) { // Cannot clean broker services. NOTREACHED(); @@ -312,7 +340,56 @@ ResultCode BrokerServicesBase::WaitForAllTargets() { bool BrokerServicesBase::IsActiveTarget(DWORD process_id) { AutoLock lock(&lock_); - return child_process_ids_.find(process_id) != child_process_ids_.end(); + return child_process_ids_.find(process_id) != child_process_ids_.end() || + peer_map_.find(process_id) != peer_map_.end(); +} + +VOID CALLBACK BrokerServicesBase::RemovePeerData(PVOID parameter, BOOLEAN) { + DWORD process_id = reinterpret_cast<DWORD>(parameter); + BrokerServicesBase* broker = BrokerServicesBase::GetInstance(); + PeerTracker* peer_data; + + { // Hold the lock only during removal (since UregisterWaitEx can block). + AutoLock lock(&broker->lock_); + PeerTrackerMap::iterator it = broker->peer_map_.find(process_id); + peer_data = it->second; + broker->peer_map_.erase(it); + } + + HANDLE wait_object = peer_data->wait_object_; + delete peer_data; + // This prevents us from terminating our own running handler. + ::UnregisterWaitEx(wait_object, INVALID_HANDLE_VALUE); +} + +ResultCode BrokerServicesBase::AddTargetPeer(HANDLE peer_process) { + DWORD process_id = ::GetProcessId(peer_process); + if (!process_id) + return SBOX_ERROR_GENERIC; + + scoped_ptr<PeerTracker> peer(new PeerTracker); + if (!::DuplicateHandle(::GetCurrentProcess(), peer_process, + ::GetCurrentProcess(), peer->process_.Receive(), + SYNCHRONIZE, FALSE, 0)) { + return SBOX_ERROR_GENERIC; + } + + AutoLock lock(&lock_); + if (!peer_map_.insert(std::make_pair(process_id, peer.get())).second) + return SBOX_ERROR_BAD_PARAMS; + + if (!::RegisterWaitForSingleObject(&peer->wait_object_, + peer->process_, RemovePeerData, + reinterpret_cast<void*>(process_id), + INFINITE, WT_EXECUTEINWAITTHREAD | + WT_EXECUTEONLYONCE)) { + peer_map_.erase(process_id); + return SBOX_ERROR_GENERIC; + } + + // Leak the pointer since it will be cleaned up by the callback. + peer.release(); + return SBOX_ALL_OK; } } // namespace sandbox diff --git a/sandbox/src/broker_services.h b/sandbox/src/broker_services.h index 8e4cb54..8c4cdbc 100644 --- a/sandbox/src/broker_services.h +++ b/sandbox/src/broker_services.h @@ -6,8 +6,10 @@ #define SANDBOX_SRC_BROKER_SERVICES_H__ #include <list> +#include <map> #include <set> #include "base/basictypes.h" +#include "base/win/scoped_handle.h" #include "sandbox/src/crosscall_server.h" #include "sandbox/src/job.h" #include "sandbox/src/sandbox.h" @@ -15,6 +17,13 @@ #include "sandbox/src/win2k_threadpool.h" #include "sandbox/src/win_utils.h" +namespace { + +struct JobTracker; +struct PeerTracker; + +} // namespace + namespace sandbox { class PolicyBase; @@ -45,6 +54,8 @@ class BrokerServicesBase : public BrokerServices, virtual ResultCode WaitForAllTargets(); + virtual ResultCode AddTargetPeer(HANDLE peer_process); + // Checks if the supplied process ID matches one of the broker's active // target processes // Returns: @@ -52,16 +63,6 @@ class BrokerServicesBase : public BrokerServices, bool IsActiveTarget(DWORD process_id); private: - // Helper structure that allows the Broker to associate a job notification - // with a job object and with a policy. - struct JobTracker { - HANDLE job; - PolicyBase* policy; - JobTracker(HANDLE cjob, PolicyBase* cpolicy) - : job(cjob), policy(cpolicy) { - } - }; - // Releases the Job and notifies the associated Policy object to its // resources as well. static void FreeResources(JobTracker* tracker); @@ -70,6 +71,9 @@ class BrokerServicesBase : public BrokerServices, // notifications and cleanup-related tasks. static DWORD WINAPI TargetEventsThread(PVOID param); + // Removes a target peer from the process list if it expires. + static VOID CALLBACK RemovePeerData(PVOID parameter, BOOLEAN); + // The completion port used by the job objects to communicate events to // the worker thread. HANDLE job_port_; @@ -92,6 +96,11 @@ class BrokerServicesBase : public BrokerServices, typedef std::list<JobTracker*> JobTrackerList; JobTrackerList tracker_list_; + // Maps peer process IDs to the saved handle and wait event. + // Prevents peer callbacks from accessing the broker after destruction. + typedef std::map<DWORD, PeerTracker*> PeerTrackerMap; + PeerTrackerMap peer_map_; + // Provides a fast lookup to identify sandboxed processes. std::set<DWORD> child_process_ids_; diff --git a/sandbox/src/handle_policy_test.cc b/sandbox/src/handle_policy_test.cc index bccca67..bb08b86 100644 --- a/sandbox/src/handle_policy_test.cc +++ b/sandbox/src/handle_policy_test.cc @@ -65,5 +65,27 @@ TEST(HandlePolicyTest, DuplicateHandle) { EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(cmd_line.c_str())); } +// Tests that duplicating an object works only when the policy allows it. +TEST(HandlePolicyTest, DuplicatePeerHandle) { + TestRunner target; + TestRunner runner; + + // Kick off an asynchronous target process for testing. + target.SetAsynchronous(true); + target.SetUnsandboxed(true); + EXPECT_EQ(SBOX_TEST_SUCCEEDED, target.RunTest(L"Handle_WaitProcess 30000")); + + // First test that we fail to open the event. + std::wstring cmd_line = base::StringPrintf(L"Handle_DuplicateEvent %d", + target.process_id()); + EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(cmd_line.c_str())); + + // Now successfully open the event after adding a duplicate handle rule. + EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_HANDLES, + TargetPolicy::HANDLES_DUP_ANY, + L"Event")); + EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(cmd_line.c_str())); +} + } // namespace sandbox diff --git a/sandbox/src/sandbox.h b/sandbox/src/sandbox.h index 683bda7..18c05ce 100644 --- a/sandbox/src/sandbox.h +++ b/sandbox/src/sandbox.h @@ -84,6 +84,14 @@ class BrokerServices { // If the return is ERROR_GENERIC, you can call ::GetLastError() to get // more information. virtual ResultCode WaitForAllTargets() = 0; + + // Adds an unsandboxed process as a peer for policy decisions (e.g. + // HANDLES_DUP_ANY policy). + // Returns: + // ALL_OK if successful. All other return values imply failure. + // If the return is ERROR_GENERIC, you can call ::GetLastError() to get + // more information. + virtual ResultCode AddTargetPeer(HANDLE peer_process) = 0; }; // TargetServices models the current process from the perspective |