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); |