| Index: sandbox/win/src/handle_closer_test.cc
|
| diff --git a/sandbox/win/src/handle_closer_test.cc b/sandbox/win/src/handle_closer_test.cc
|
| index 5b7be474f58d27b5794305c329f6b20b1afb3f9c..f1f80e8888fe6b69f8c679a50aa21e755c46803c 100644
|
| --- a/sandbox/win/src/handle_closer_test.cc
|
| +++ b/sandbox/win/src/handle_closer_test.cc
|
| @@ -5,6 +5,7 @@
|
| #include "base/strings/stringprintf.h"
|
| #include "base/win/scoped_handle.h"
|
| #include "sandbox/win/src/handle_closer_agent.h"
|
| +#include "sandbox/win/src/nt_internals.h"
|
| #include "sandbox/win/src/sandbox.h"
|
| #include "sandbox/win/src/sandbox_factory.h"
|
| #include "sandbox/win/src/target_services.h"
|
| @@ -42,6 +43,26 @@ HANDLE GetMarkerFile(const wchar_t *extension) {
|
| NULL, OPEN_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, NULL);
|
| }
|
|
|
| +// Returns type infomation for an NT object. This routine is expected to be
|
| +// called for invalid handles so it catches STATUS_INVALID_HANDLE exceptions
|
| +// that can be generated when handle tracing is enabled.
|
| +NTSTATUS QueryObjectTypeInformation(HANDLE handle, void* buffer, ULONG* size) {
|
| + static NtQueryObject QueryObject = NULL;
|
| + if (!QueryObject)
|
| + ResolveNTFunctionPtr("NtQueryObject", &QueryObject);
|
| +
|
| + NTSTATUS status = STATUS_UNSUCCESSFUL;
|
| + __try {
|
| + status = QueryObject(handle, ObjectTypeInformation, buffer, *size, size);
|
| + }
|
| + __except(GetExceptionCode() == STATUS_INVALID_HANDLE
|
| + ? EXCEPTION_EXECUTE_HANDLER
|
| + : EXCEPTION_CONTINUE_SEARCH) {
|
| + status = STATUS_INVALID_HANDLE;
|
| + }
|
| + return status;
|
| +}
|
| +
|
| // Used by the thread pool tests.
|
| HANDLE finish_event;
|
| const int kWaitCount = 20;
|
| @@ -66,7 +87,7 @@ SBOX_TESTS_COMMAND int CheckForFileHandles(int argc, wchar_t **argv) {
|
| // Create a unique marker file that is open while the test is running.
|
| // The handles leak, but it will be closed by the test or on exit.
|
| for (int i = 0; i < arraysize(kFileExtensions); ++i)
|
| - EXPECT_NE(GetMarkerFile(kFileExtensions[i]), INVALID_HANDLE_VALUE);
|
| + CHECK_NE(GetMarkerFile(kFileExtensions[i]), INVALID_HANDLE_VALUE);
|
| return SBOX_TEST_SUCCEEDED;
|
|
|
| case AFTER_REVERT: {
|
| @@ -104,6 +125,70 @@ SBOX_TESTS_COMMAND int CheckForFileHandles(int argc, wchar_t **argv) {
|
| return SBOX_TEST_SUCCEEDED;
|
| }
|
|
|
| +// Checks that supplied handle is an Event and it's not waitable.
|
| +// Format: CheckForEventHandles
|
| +SBOX_TESTS_COMMAND int CheckForEventHandles(int argc, wchar_t** argv) {
|
| + static int state = BEFORE_INIT;
|
| + static std::vector<HANDLE> to_check;
|
| +
|
| + switch (state++) {
|
| + case BEFORE_INIT:
|
| + // Create a unique marker file that is open while the test is running.
|
| + for (int i = 0; i < arraysize(kFileExtensions); ++i) {
|
| + HANDLE handle = GetMarkerFile(kFileExtensions[i]);
|
| + CHECK_NE(handle, INVALID_HANDLE_VALUE);
|
| + to_check.push_back(handle);
|
| + }
|
| + return SBOX_TEST_SUCCEEDED;
|
| +
|
| + case AFTER_REVERT:
|
| + for (auto handle : to_check) {
|
| + // Set up buffers for the type info and the name.
|
| + std::vector<BYTE> type_info_buffer(sizeof(OBJECT_TYPE_INFORMATION) +
|
| + 32 * sizeof(wchar_t));
|
| + OBJECT_TYPE_INFORMATION* type_info =
|
| + reinterpret_cast<OBJECT_TYPE_INFORMATION*>(&(type_info_buffer[0]));
|
| + NTSTATUS rc;
|
| +
|
| + // Get the type name, reusing the buffer.
|
| + ULONG size = static_cast<ULONG>(type_info_buffer.size());
|
| + rc = QueryObjectTypeInformation(handle, type_info, &size);
|
| + while (rc == STATUS_INFO_LENGTH_MISMATCH ||
|
| + rc == STATUS_BUFFER_OVERFLOW) {
|
| + type_info_buffer.resize(size + sizeof(wchar_t));
|
| + type_info = reinterpret_cast<OBJECT_TYPE_INFORMATION*>(
|
| + &(type_info_buffer[0]));
|
| + rc = QueryObjectTypeInformation(handle, type_info, &size);
|
| + // Leave padding for the nul terminator.
|
| + if (NT_SUCCESS(rc) && size == type_info_buffer.size())
|
| + rc = STATUS_INFO_LENGTH_MISMATCH;
|
| + }
|
| +
|
| + CHECK(NT_SUCCESS(rc));
|
| + CHECK(type_info->Name.Buffer);
|
| +
|
| + type_info->Name.Buffer[type_info->Name.Length / sizeof(wchar_t)] =
|
| + L'\0';
|
| +
|
| + // Should be an Event now.
|
| + CHECK_EQ(wcslen(type_info->Name.Buffer), 5U);
|
| + CHECK_EQ(wcscmp(L"Event", type_info->Name.Buffer), 0);
|
| +
|
| + // Should not be able to wait.
|
| + CHECK_EQ(WaitForSingleObject(handle, INFINITE), WAIT_FAILED);
|
| +
|
| + // Should be able to close.
|
| + CHECK_EQ(TRUE, CloseHandle(handle));
|
| + }
|
| + return SBOX_TEST_SUCCEEDED;
|
| +
|
| + default: // Do nothing.
|
| + break;
|
| + }
|
| +
|
| + return SBOX_TEST_SUCCEEDED;
|
| +}
|
| +
|
| TEST(HandleCloserTest, CheckForMarkerFiles) {
|
| TestRunner runner;
|
| runner.SetTimeout(2000);
|
| @@ -145,6 +230,24 @@ TEST(HandleCloserTest, CloseMarkerFiles) {
|
| "Failed: " << command;
|
| }
|
|
|
| +TEST(HandleCloserTest, CheckStuffedHandle) {
|
| + TestRunner runner;
|
| + runner.SetTimeout(2000);
|
| + runner.SetTestState(EVERY_STATE);
|
| + sandbox::TargetPolicy* policy = runner.GetPolicy();
|
| +
|
| + for (int i = 0; i < arraysize(kFileExtensions); ++i) {
|
| + base::string16 handle_name;
|
| + base::win::ScopedHandle marker(GetMarkerFile(kFileExtensions[i]));
|
| + CHECK(marker.IsValid());
|
| + CHECK(sandbox::GetHandleName(marker.Get(), &handle_name));
|
| + CHECK_EQ(policy->AddKernelObjectToClose(L"File", handle_name.c_str()),
|
| + SBOX_ALL_OK);
|
| + }
|
| +
|
| + EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckForEventHandles"));
|
| +}
|
| +
|
| void WINAPI ThreadPoolTask(void* event, BOOLEAN timeout) {
|
| static volatile LONG waiters_remaining = kWaitCount;
|
| CHECK(!timeout);
|
|
|