This series' main purpose is to fix the handles' attributes of standard I/O handles in CreateProcess. Needed behavior in CreateProcess is implemented by supporting the DUPLICATE_SAME_ATTRIBUTES option in NtDuplicateObject() and DuplicateHandle(). This option is not documented in SDK, but is in DDK. Manifest constant has been added to DDK header (maybe now Wine's DUPLICATE_MAKE_GLOBAL could be moved here to).
-- v2: server: Preserve handle flags when inheriting a std handle. server: Implement support for DUPLICATE_SAME_ATTRIBUTES in DuplicateHandle(). kernel32/tests: Test DUPLICATE_SAME_ATTRIBUTES flag in DuplicateHandle(). kernel32: Added tests about std handle flags inheritance.
From: Eric Pouech epouech@codeweavers.com
Adding support for protect-from-close handle flag to CreateProcess test infrastructure.
Signed-off-by: Eric Pouech epouech@codeweavers.com --- dlls/kernel32/tests/process.c | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-)
diff --git a/dlls/kernel32/tests/process.c b/dlls/kernel32/tests/process.c index 0e5bf82530b..5eaf6586a72 100644 --- a/dlls/kernel32/tests/process.c +++ b/dlls/kernel32/tests/process.c @@ -323,8 +323,9 @@ static void WINAPIV __WINE_PRINTF_ATTR(2,3) childPrintf(HANDLE h, const char* fm #define HATTR_NULL 0x08 /* NULL handle value */ #define HATTR_INVALID 0x04 /* INVALID_HANDLE_VALUE */ #define HATTR_TYPE 0x0c /* valid handle, with type set */ -#define HATTR_INHERIT 0x10 /* inheritance flag set */ -#define HATTR_UNTOUCHED 0x20 /* Identify fields untouched by GetStartupInfoW */ +#define HATTR_UNTOUCHED 0x10 /* Identify fields untouched by GetStartupInfoW */ +#define HATTR_INHERIT 0x20 /* inheritance flag set */ +#define HATTR_PROTECT 0x40 /* protect from close flag set */
#define HANDLE_UNTOUCHEDW (HANDLE)(DWORD_PTR)(0x5050505050505050ull)
@@ -346,8 +347,13 @@ static unsigned encode_handle_attributes(HANDLE h) if (dw == FILE_TYPE_CHAR || dw == FILE_TYPE_DISK || dw == FILE_TYPE_PIPE) { DWORD info; - if (GetHandleInformation(h, &info) && (info & HANDLE_FLAG_INHERIT)) - result |= HATTR_INHERIT; + if (GetHandleInformation(h, &info)) + { + if (info & HANDLE_FLAG_INHERIT) + result |= HATTR_INHERIT; + if (info & HANDLE_FLAG_PROTECT_FROM_CLOSE) + result |= HATTR_PROTECT; + } } else dw = FILE_TYPE_UNKNOWN; @@ -3146,6 +3152,7 @@ static void copy_change_subsystem(const char* in, const char* out, DWORD subsyst #define ARG_STARTUPINFO 0x00000000 #define ARG_CP_INHERIT 0x40000000 #define ARG_HANDLE_INHERIT 0x20000000 +#define ARG_HANDLE_PROTECT 0x10000000 #define ARG_HANDLE_MASK (~0xff000000)
static BOOL check_run_child(const char *exec, DWORD flags, BOOL cp_inherit, @@ -3217,6 +3224,13 @@ static BOOL build_startupinfo( STARTUPINFOA *startup, unsigned args, HANDLE hstd ok(0, "Unsupported handle type %x\n", args & ARG_HANDLE_MASK); return FALSE; } + if ((args & ARG_HANDLE_PROTECT) && needs_close) + { + ret = SetHandleInformation(hstd[0], HANDLE_FLAG_PROTECT_FROM_CLOSE, HANDLE_FLAG_PROTECT_FROM_CLOSE); + ok(ret, "Couldn't set inherit flag to hstd[0]\n"); + ret = SetHandleInformation(hstd[1], HANDLE_FLAG_PROTECT_FROM_CLOSE, HANDLE_FLAG_PROTECT_FROM_CLOSE); + ok(ret, "Couldn't set inherit flag to hstd[1]\n"); + }
if (args & ARG_STD) { @@ -3261,6 +3275,14 @@ static void test_StdHandleInheritance(void) /* all others handles type behave as H_DISK */ {ARG_STARTUPINFO | ARG_HANDLE_INHERIT | H_DISK, HATTR_NULL, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN}, {ARG_STD | ARG_HANDLE_INHERIT | H_DISK, HATTR_TYPE | HATTR_INHERIT | FILE_TYPE_DISK}, + + /* all others handles type behave as H_DISK */ + {ARG_STARTUPINFO | H_DISK, HATTR_NULL, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN}, +/* 5*/ {ARG_STD | H_DISK, HATTR_TYPE | FILE_TYPE_DISK, .is_todo = 1}, + + /* all others handles type behave as H_DISK */ + {ARG_STARTUPINFO | ARG_HANDLE_PROTECT | H_DISK, HATTR_NULL, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN}, + {ARG_STD | ARG_HANDLE_PROTECT | H_DISK, HATTR_TYPE | HATTR_PROTECT | FILE_TYPE_DISK, .is_todo = 1}, }, nothing_gui[] = { @@ -3372,7 +3394,9 @@ static void test_StdHandleInheritance(void) DeleteFileA(resfile); if (needs_close) { + SetHandleInformation(hstd[0], HANDLE_FLAG_PROTECT_FROM_CLOSE, 0); CloseHandle(hstd[0]); + SetHandleInformation(hstd[1], HANDLE_FLAG_PROTECT_FROM_CLOSE, 0); CloseHandle(hstd[1]); } winetest_pop_context();
From: Eric Pouech epouech@codeweavers.com
Signed-off-by: Eric Pouech epouech@codeweavers.com --- dlls/kernel32/tests/process.c | 44 +++++++++++++++++++++++++++++++++++ include/winnt.h | 1 + 2 files changed, 45 insertions(+)
diff --git a/dlls/kernel32/tests/process.c b/dlls/kernel32/tests/process.c index 5eaf6586a72..a7fef049c8e 100644 --- a/dlls/kernel32/tests/process.c +++ b/dlls/kernel32/tests/process.c @@ -2549,6 +2549,50 @@ static void test_DuplicateHandle(void) ok(r, "DuplicateHandle error %lu\n", GetLastError()); ok(f == out || broken(/* Win7 */ (((ULONG_PTR)f & 3) == 3) && (f != out)), "f != out\n"); CloseHandle(out); + + /* Test DUPLICATE_SAME_ATTRIBUTES */ + f = CreateFileA("NUL", GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0); + ok(f != INVALID_HANDLE_VALUE, "Failed to open NUL %lu\n", GetLastError()); + r = GetHandleInformation(f, &info); + ok(r && info == 0, "Unexpected info %lx\n", info); + + r = DuplicateHandle(GetCurrentProcess(), f, GetCurrentProcess(), &out, + 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES); + ok(r, "DuplicateHandle error %lu\n", GetLastError()); + r = GetHandleInformation(out, &info); + todo_wine + ok(r && info == 0, "Unexpected info %lx\n", info); + CloseHandle(out); + + r = SetHandleInformation(f, HANDLE_FLAG_INHERIT | HANDLE_FLAG_PROTECT_FROM_CLOSE, + HANDLE_FLAG_INHERIT | HANDLE_FLAG_PROTECT_FROM_CLOSE); + ok(r, "SetHandleInformation error %lu\n", GetLastError()); + info = 0xdeabeef; + r = GetHandleInformation(f, &info); + ok(r && info == (HANDLE_FLAG_INHERIT | HANDLE_FLAG_PROTECT_FROM_CLOSE), "Unexpected info %lx\n", info); + ok(r, "SetHandleInformation error %lu\n", GetLastError()); + r = DuplicateHandle(GetCurrentProcess(), f, GetCurrentProcess(), &out, + 0, FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES); + ok(r, "DuplicateHandle error %lu\n", GetLastError()); + info = 0xdeabeef; + r = GetHandleInformation(out, &info); + todo_wine + ok(r && info == (HANDLE_FLAG_INHERIT | HANDLE_FLAG_PROTECT_FROM_CLOSE), "Unexpected info %lx\n", info); + r = SetHandleInformation(out, HANDLE_FLAG_PROTECT_FROM_CLOSE, 0); + ok(r, "SetHandleInformation error %lu\n", GetLastError()); + CloseHandle(out); + r = SetHandleInformation(f, HANDLE_FLAG_INHERIT | HANDLE_FLAG_PROTECT_FROM_CLOSE, 0); + ok(r, "SetHandleInformation error %lu\n", GetLastError()); + CloseHandle(f); + + r = DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(), GetCurrentProcess(), &out, + 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES); + ok(r, "DuplicateHandle error %lu\n", GetLastError()); + info = 0xdeabeef; + r = GetHandleInformation(out, &info); + todo_wine + ok(r && info == 0, "Unexpected info %lx\n", info); + CloseHandle(out); }
#define test_completion(a, b, c, d, e) _test_completion(__LINE__, a, b, c, d, e) diff --git a/include/winnt.h b/include/winnt.h index 8c91ebc79b5..b2a3cacf066 100644 --- a/include/winnt.h +++ b/include/winnt.h @@ -5367,6 +5367,7 @@ typedef struct _QUOTA_LIMITS_EX {
#define DUPLICATE_CLOSE_SOURCE 0x00000001 #define DUPLICATE_SAME_ACCESS 0x00000002 +#define DUPLICATE_SAME_ATTRIBUTES 0x00000004 /* Defined in DDK */ #ifdef __WINESRC__ #define DUPLICATE_MAKE_GLOBAL 0x80000000 /* Not a Windows flag */ #endif
From: Eric Pouech epouech@codeweavers.com
This flag is documented on MSDN in ZwDuplicateObject() but not in DuplicateHandle(). Yet functional on both.
Signed-off-by: Eric Pouech epouech@codeweavers.com --- dlls/kernel32/tests/process.c | 3 --- server/handle.c | 6 +++++- 2 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/dlls/kernel32/tests/process.c b/dlls/kernel32/tests/process.c index a7fef049c8e..ed291d071cc 100644 --- a/dlls/kernel32/tests/process.c +++ b/dlls/kernel32/tests/process.c @@ -2560,7 +2560,6 @@ static void test_DuplicateHandle(void) 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES); ok(r, "DuplicateHandle error %lu\n", GetLastError()); r = GetHandleInformation(out, &info); - todo_wine ok(r && info == 0, "Unexpected info %lx\n", info); CloseHandle(out);
@@ -2576,7 +2575,6 @@ static void test_DuplicateHandle(void) ok(r, "DuplicateHandle error %lu\n", GetLastError()); info = 0xdeabeef; r = GetHandleInformation(out, &info); - todo_wine ok(r && info == (HANDLE_FLAG_INHERIT | HANDLE_FLAG_PROTECT_FROM_CLOSE), "Unexpected info %lx\n", info); r = SetHandleInformation(out, HANDLE_FLAG_PROTECT_FROM_CLOSE, 0); ok(r, "SetHandleInformation error %lu\n", GetLastError()); @@ -2590,7 +2588,6 @@ static void test_DuplicateHandle(void) ok(r, "DuplicateHandle error %lu\n", GetLastError()); info = 0xdeabeef; r = GetHandleInformation(out, &info); - todo_wine ok(r && info == 0, "Unexpected info %lx\n", info); CloseHandle(out); } diff --git a/server/handle.c b/server/handle.c index 0595fdb403b..967b6ce75f1 100644 --- a/server/handle.c +++ b/server/handle.c @@ -566,7 +566,7 @@ obj_handle_t duplicate_handle( struct process *src, obj_handle_t src_handle, str { obj_handle_t res; struct handle_entry *entry; - unsigned int src_access; + unsigned int src_access, src_flags; struct object *obj = get_handle_obj( src, src_handle, 0, NULL );
if (!obj) return 0; @@ -574,6 +574,7 @@ obj_handle_t duplicate_handle( struct process *src, obj_handle_t src_handle, str src_access = entry->access; else /* pseudo-handle, give it full access */ src_access = obj->ops->map_access( obj, GENERIC_ALL ); + src_flags = src_access >> RESERVED_SHIFT; src_access &= ~RESERVED_ALL;
if (options & DUPLICATE_SAME_ACCESS) @@ -611,6 +612,9 @@ obj_handle_t duplicate_handle( struct process *src, obj_handle_t src_handle, str res = alloc_handle_entry( dst, obj, access, attr ); }
+ if (res && (options & DUPLICATE_SAME_ATTRIBUTES)) + set_handle_flags( dst, res, ~0u, src_flags ); + release_object( obj ); return res; }
From: Eric Pouech epouech@codeweavers.com
Signed-off-by: Eric Pouech epouech@codeweavers.com --- dlls/kernel32/tests/process.c | 4 ++-- server/process.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/dlls/kernel32/tests/process.c b/dlls/kernel32/tests/process.c index ed291d071cc..1ecf8a35f21 100644 --- a/dlls/kernel32/tests/process.c +++ b/dlls/kernel32/tests/process.c @@ -3319,11 +3319,11 @@ static void test_StdHandleInheritance(void)
/* all others handles type behave as H_DISK */ {ARG_STARTUPINFO | H_DISK, HATTR_NULL, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN}, -/* 5*/ {ARG_STD | H_DISK, HATTR_TYPE | FILE_TYPE_DISK, .is_todo = 1}, +/* 5*/ {ARG_STD | H_DISK, HATTR_TYPE | FILE_TYPE_DISK},
/* all others handles type behave as H_DISK */ {ARG_STARTUPINFO | ARG_HANDLE_PROTECT | H_DISK, HATTR_NULL, .is_broken = HATTR_TYPE | FILE_TYPE_UNKNOWN}, - {ARG_STD | ARG_HANDLE_PROTECT | H_DISK, HATTR_TYPE | HATTR_PROTECT | FILE_TYPE_DISK, .is_todo = 1}, + {ARG_STD | ARG_HANDLE_PROTECT | H_DISK, HATTR_TYPE | HATTR_PROTECT | FILE_TYPE_DISK}, }, nothing_gui[] = { diff --git a/server/process.c b/server/process.c index a0d5ea64d97..e166aeae64e 100644 --- a/server/process.c +++ b/server/process.c @@ -1336,11 +1336,11 @@ DECL_HANDLER(new_process) if (!(req->flags & PROCESS_CREATE_FLAGS_INHERIT_HANDLES) && info->data->console != 1) { info->data->hstdin = duplicate_handle( parent, info->data->hstdin, process, - 0, OBJ_INHERIT, DUPLICATE_SAME_ACCESS ); + 0, 0, DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES ); info->data->hstdout = duplicate_handle( parent, info->data->hstdout, process, - 0, OBJ_INHERIT, DUPLICATE_SAME_ACCESS ); + 0, 0, DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES ); info->data->hstderr = duplicate_handle( parent, info->data->hstderr, process, - 0, OBJ_INHERIT, DUPLICATE_SAME_ACCESS ); + 0, 0, DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES ); /* some handles above may have been invalid; this is not an error */ if (get_error() == STATUS_INVALID_HANDLE || get_error() == STATUS_OBJECT_TYPE_MISMATCH) clear_error();