diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c index e6ae638be5e..034cf23ad4e 100644 --- a/dlls/advapi32/tests/security.c +++ b/dlls/advapi32/tests/security.c @@ -46,6 +46,14 @@ #define SEMAPHORE_QUERY_STATE 0x0001 #endif +#ifndef THREAD_SET_LIMITED_INFORMATION +#define THREAD_SET_LIMITED_INFORMATION 0x0400 +#define THREAD_QUERY_LIMITED_INFORMATION 0x0800 +#endif + +#define THREAD_ALL_ACCESS_NT4 (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3ff) +#define THREAD_ALL_ACCESS_VISTA (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xffff) + /* copied from Wine winternl.h - not included in the Windows SDK */ typedef enum _OBJECT_INFORMATION_CLASS { ObjectBasicInformation, @@ -4950,6 +4958,70 @@ todo_wine CloseHandle(mapping); } +static void test_thread_security(void) +{ + DWORD ret, i, access; + HANDLE thread, dup; + static const struct + { + int generic, mapped; + } map[] = + { + { 0, 0 }, + { GENERIC_READ, STANDARD_RIGHTS_READ | THREAD_QUERY_INFORMATION | THREAD_GET_CONTEXT }, + { GENERIC_WRITE, STANDARD_RIGHTS_WRITE | THREAD_SET_INFORMATION | THREAD_SET_CONTEXT | THREAD_TERMINATE | THREAD_SUSPEND_RESUME | 0x4 }, + { GENERIC_EXECUTE, STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE }, + { GENERIC_ALL, THREAD_ALL_ACCESS_NT4 } + }; + + SetLastError(0xdeadbeef); + thread = CreateThread(NULL, 0, (void *)0xdeadbeef, NULL, CREATE_SUSPENDED, &ret); + ok(thread != 0, "CreateThread error %d\n", GetLastError()); + + access = get_obj_access(thread); + ok(access == THREAD_ALL_ACCESS_NT4 || access == THREAD_ALL_ACCESS_VISTA, "expected THREAD_ALL_ACCESS, got %#x\n", access); + + for (i = 0; i < sizeof(map)/sizeof(map[0]); i++) + { + SetLastError( 0xdeadbeef ); + ret = DuplicateHandle(GetCurrentProcess(), thread, GetCurrentProcess(), &dup, + map[i].generic, FALSE, 0); + ok(ret, "DuplicateHandle error %d\n", GetLastError()); + + access = get_obj_access(dup); + switch (map[i].generic) + { + case GENERIC_READ: +todo_wine + ok(access == map[i].mapped || access == (map[i].mapped | THREAD_QUERY_LIMITED_INFORMATION) /* Vista+ */, + "%d: expected %#x, got %#x\n", i, map[i].mapped, access); + break; + case GENERIC_WRITE: +todo_wine + ok(access == map[i].mapped || access == (map[i].mapped | THREAD_SET_LIMITED_INFORMATION) /* Vista+ */, + "%d: expected %#x, got %#x\n", i, map[i].mapped, access); + break; + case GENERIC_EXECUTE: +todo_wine + ok(access == map[i].mapped || access == (map[i].mapped | THREAD_QUERY_LIMITED_INFORMATION) /* Vista+ */, + "%d: expected %#x, got %#x\n", i, map[i].mapped, access); + break; + case GENERIC_ALL: + ok(access == map[i].mapped || access == THREAD_ALL_ACCESS_VISTA, + "%d: expected %#x, got %#x\n", i, map[i].mapped, access); + break; + default: + ok(access == map[i].mapped, "%d: expected %#x, got %#x\n", i, map[i].mapped, access); + break; + } + + CloseHandle(dup); + } + + TerminateThread(thread, 0); + CloseHandle(thread); +} + static BOOL validate_impersonation_token(HANDLE token, DWORD *token_type) { DWORD ret, needed; @@ -5026,6 +5098,7 @@ static void test_kernel_objects_security(void) test_semaphore_security(token); test_file_security(token); test_filemap_security(); + test_thread_security(); /* FIXME: test other kernel object types */ CloseHandle(process_token);