Bug#959707: wine-development: please consider wine-staging patches, needed for e.g. Blizzard games
Package: wine-development
Version: 5.5-3.1
Severity: normal
Tags: patch upstream
Dear Maintainer,
Please consider the patches from wine-staging:
https://github.com/wine-staging/wine-staging
Different patches are needed for different applications. For example, the
32-bit version of StarCraft 2 constantly runs out of its 4GB memory space, but
the 64-bit version of StarCraft 2 doesn't work due to:
https://bugs.winehq.org/show_bug.cgi?id=46586
I have tested the relevant wine-staging patches mentioned in the bug report
(ntdll-User_Shared_Data, winebuild-Fake_Dlls and ntdll-Builtin_Prot) including
their dependency patches, and they work to fix the issue and now I can run the
64-bit version of StarCraft 2.
See attached for an example debdiff against wine 5.5. For subsequent versions
the patches are smaller.
X
-- Package-specific info:
/usr/bin/wine points to /usr/bin/wine-development.
-- System Information:
Debian Release: bullseye/sid
APT prefers testing
APT policy: (990, 'testing'), (500, 'unstable-debug'), (500, 'testing-debug'), (500, 'stable'), (300, 'unstable'), (100, 'experimental'), (1, 'experimental-debug')
Architecture: amd64 (x86_64)
Foreign Architectures: i386
Kernel: Linux 5.5.0-1-amd64 (SMP w/4 CPU cores)
Locale: LANG=en_GB.utf8, LC_CTYPE=en_GB.utf8 (charmap=UTF-8), LANGUAGE=en_GB:en (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash
Init: systemd (via /run/systemd/system)
LSM: AppArmor: enabled
Versions of packages wine-development depends on:
ii wine32-development 5.5-3.1
ii wine64-development 5.5-3.1
wine-development recommends no packages.
Versions of packages wine-development suggests:
ii dosbox 0.74-3-1
pn exe-thumbnailer | kio-extras <none>
pn playonlinux <none>
pn q4wine <none>
pn winbind <none>
pn wine-binfmt <none>
ii winetricks 0.0+20200412-1
Versions of packages libwine-development depends on:
ii libasound2 1.2.2-2.1
ii libc6 2.30-4
ii libfaudio0 20.04-2
ii libfontconfig1 2.13.1-4
ii libfreetype6 2.10.1-2
ii libgcc-s1 10-20200418-1
ii libglib2.0-0 2.64.2-1
ii libgphoto2-6 2.5.24-1
ii libgphoto2-port12 2.5.24-1
ii libgstreamer-plugins-base1.0-0 1.16.2-4
ii libgstreamer1.0-0 1.16.2-2
ii liblcms2-2 2.9-4+b1
ii libldap-2.4-2 2.4.49+dfsg-4
ii libmpg123-0 1.25.13-1
ii libncurses6 6.2-1
ii libopenal1 1:1.19.1-1+b1
ii libpcap0.8 1.9.1-4
ii libpulse0 13.0-5
ii libtinfo6 6.2-1
ii libudev1 245.5-2
ii libunwind8 1.2.1-9
ii libvkd3d1 1.1-4
ii libx11-6 2:1.6.9-2
ii libxext6 2:1.3.3-1+b2
ii libxml2 2.9.10+dfsg-5
ii ocl-icd-libopencl1 [libopencl1] 2.2.12-4
ii zlib1g 1:1.2.11.dfsg-2
Versions of packages libwine-development recommends:
ii fonts-liberation 1:1.07.4-11
ii fonts-wine 5.0-4
ii gstreamer1.0-plugins-good 1.16.2-3
ii libasound2-plugins 1.2.2-1
ii libgl1-mesa-dri 19.3.3-1
Versions of packages libwine-development suggests:
pn cups-bsd <none>
ii gstreamer1.0-libav 1.16.2-2
pn gstreamer1.0-plugins-bad <none>
ii gstreamer1.0-plugins-ugly 1.16.2-2+b1
ii ttf-mscorefonts-installer 3.8
Versions of packages wine32-development depends on:
ii libc6 2.30-4
ii libwine-development 5.5-3.1
wine32-development recommends no packages.
Versions of packages wine32-development suggests:
pn wine32-development-preloader <none>
Versions of packages wine64-development depends on:
ii libc6 2.30-4
ii libwine-development 5.5-3.1
Versions of packages wine64-development recommends:
ii wine32-development 5.5-3.1
Versions of packages wine64-development suggests:
pn wine64-development-preloader <none>
Versions of packages wine-development is related to:
pn dxvk <none>
pn dxvk-wine32-development <none>
pn dxvk-wine64-development <none>
ii fonts-wine 5.0-4
-- no debconf information
diff -Nru wine-development-5.5/debian/changelog wine-development-5.5/debian/changelog
--- wine-development-5.5/debian/changelog 2020-04-02 23:32:21.000000000 +0100
+++ wine-development-5.5/debian/changelog 2020-05-04 01:33:29.000000000 +0100
@@ -1,3 +1,10 @@
+wine-development (5.5-3.1) UNRELEASED; urgency=medium
+
+ * Non-maintainer upload.
+ * Add patches from upstream #46586
+
+ -- Ximin Luo <infinity0@debian.org> Mon, 04 May 2020 01:33:29 +0100
+
wine-development (5.5-3) unstable; urgency=medium
* Drop libsane from the build dependencies.
diff -Nru wine-development-5.5/debian/patches/advapi32-CreateRestrictedToken/0001-ntdll-Implement-NtFilterToken.patch wine-development-5.5/debian/patches/advapi32-CreateRestrictedToken/0001-ntdll-Implement-NtFilterToken.patch
--- wine-development-5.5/debian/patches/advapi32-CreateRestrictedToken/0001-ntdll-Implement-NtFilterToken.patch 1970-01-01 01:00:00.000000000 +0100
+++ wine-development-5.5/debian/patches/advapi32-CreateRestrictedToken/0001-ntdll-Implement-NtFilterToken.patch 2020-05-04 01:33:29.000000000 +0100
@@ -0,0 +1,295 @@
+From 1eb8acd819f9eee8fdf154d0ef43881008265916 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
+Date: Fri, 4 Aug 2017 02:33:14 +0200
+Subject: ntdll: Implement NtFilterToken.
+
+---
+ dlls/ntdll/nt.c | 59 ++++++++++++++++++++++++++++++++++++
+ dlls/ntdll/ntdll.spec | 2 +-
+ include/winnt.h | 5 +++
+ include/winternl.h | 1 +
+ server/process.c | 2 +-
+ server/protocol.def | 10 ++++++
+ server/security.h | 4 ++-
+ server/token.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++++--
+ 8 files changed, 162 insertions(+), 5 deletions(-)
+
+--- a/dlls/ntdll/nt.c
++++ b/dlls/ntdll/nt.c
+@@ -211,6 +211,65 @@
+ }
+
+ /******************************************************************************
++ * NtFilterToken [NTDLL.@]
++ * ZwFilterToken [NTDLL.@]
++ */
++NTSTATUS WINAPI NtFilterToken( HANDLE token, ULONG flags, TOKEN_GROUPS *disable_sids,
++ TOKEN_PRIVILEGES *privileges, TOKEN_GROUPS *restrict_sids,
++ HANDLE *new_token )
++{
++ data_size_t privileges_len = 0;
++ data_size_t sids_len = 0;
++ SID *sids = NULL;
++ NTSTATUS status;
++
++ TRACE( "(%p, 0x%08x, %p, %p, %p, %p)\n", token, flags, disable_sids, privileges,
++ restrict_sids, new_token );
++
++ if (flags)
++ FIXME( "flags %x unsupported\n", flags );
++
++ if (restrict_sids)
++ FIXME( "support for restricting sids not yet implemented\n" );
++
++ if (privileges)
++ privileges_len = privileges->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES);
++
++ if (disable_sids)
++ {
++ DWORD len, i;
++ BYTE *tmp;
++
++ for (i = 0; i < disable_sids->GroupCount; i++)
++ sids_len += RtlLengthSid( disable_sids->Groups[i].Sid );
++
++ sids = RtlAllocateHeap( GetProcessHeap(), 0, sids_len );
++ if (!sids) return STATUS_NO_MEMORY;
++
++ for (i = 0, tmp = (BYTE *)sids; i < disable_sids->GroupCount; i++, tmp += len)
++ {
++ len = RtlLengthSid( disable_sids->Groups[i].Sid );
++ memcpy( tmp, disable_sids->Groups[i].Sid, len );
++ }
++ }
++
++ SERVER_START_REQ( filter_token )
++ {
++ req->handle = wine_server_obj_handle( token );
++ req->flags = flags;
++ req->privileges_size = privileges_len;
++ wine_server_add_data( req, privileges->Privileges, privileges_len );
++ wine_server_add_data( req, sids, sids_len );
++ status = wine_server_call( req );
++ if (!status) *new_token = wine_server_ptr_handle( reply->new_handle );
++ }
++ SERVER_END_REQ;
++
++ RtlFreeHeap( GetProcessHeap(), 0, sids );
++ return status;
++}
++
++/******************************************************************************
+ * NtOpenProcessToken [NTDLL.@]
+ * ZwOpenProcessToken [NTDLL.@]
+ */
+--- a/dlls/ntdll/ntdll.spec
++++ b/dlls/ntdll/ntdll.spec
+@@ -207,7 +207,7 @@
+ # @ stub NtEnumerateSystemEnvironmentValuesEx
+ @ stdcall NtEnumerateValueKey(long long long ptr long ptr)
+ @ stub NtExtendSection
+-# @ stub NtFilterToken
++@ stdcall NtFilterToken(long long ptr ptr ptr ptr)
+ @ stdcall NtFindAtom(ptr long ptr)
+ @ stdcall NtFlushBuffersFile(long ptr)
+ @ stdcall NtFlushInstructionCache(long ptr long)
+--- a/include/winnt.h
++++ b/include/winnt.h
+@@ -4225,6 +4225,11 @@
+ TOKEN_ADJUST_SESSIONID | \
+ TOKEN_ADJUST_DEFAULT )
+
++#define DISABLE_MAX_PRIVILEGE 0x1
++#define SANDBOX_INERT 0x2
++#define LUA_TOKEN 0x4
++#define WRITE_RESTRICTED 0x8
++
+ #ifndef _SECURITY_DEFINED
+ #define _SECURITY_DEFINED
+
+--- a/include/winternl.h
++++ b/include/winternl.h
+@@ -2443,6 +2443,7 @@
+ NTSYSAPI NTSTATUS WINAPI NtEnumerateKey(HANDLE,ULONG,KEY_INFORMATION_CLASS,void *,DWORD,DWORD *);
+ NTSYSAPI NTSTATUS WINAPI NtEnumerateValueKey(HANDLE,ULONG,KEY_VALUE_INFORMATION_CLASS,PVOID,ULONG,PULONG);
+ NTSYSAPI NTSTATUS WINAPI NtExtendSection(HANDLE,PLARGE_INTEGER);
++NTSYSAPI NTSTATUS WINAPI NtFilterToken(HANDLE,ULONG,TOKEN_GROUPS*,TOKEN_PRIVILEGES*,TOKEN_GROUPS*,HANDLE*);
+ NTSYSAPI NTSTATUS WINAPI NtFindAtom(const WCHAR*,ULONG,RTL_ATOM*);
+ NTSYSAPI NTSTATUS WINAPI NtFlushBuffersFile(HANDLE,IO_STATUS_BLOCK*);
+ NTSYSAPI NTSTATUS WINAPI NtFlushInstructionCache(HANDLE,LPCVOID,SIZE_T);
+--- a/server/process.c
++++ b/server/process.c
+@@ -568,7 +568,7 @@
+ : alloc_handle_table( process, 0 );
+ /* Note: for security reasons, starting a new process does not attempt
+ * to use the current impersonation token for the new process */
+- process->token = token_duplicate( parent->token, TRUE, 0, NULL );
++ process->token = token_duplicate( parent->token, TRUE, 0, NULL, NULL, 0, NULL, 0 );
+ process->affinity = parent->affinity;
+ }
+ if (!process->handles || !process->token) goto error;
+--- a/server/protocol.def
++++ b/server/protocol.def
+@@ -3423,6 +3423,16 @@
+ obj_handle_t new_handle; /* duplicated handle */
+ @END
+
++@REQ(filter_token)
++ obj_handle_t handle; /* handle to the token to duplicate */
++ unsigned int flags; /* flags */
++ data_size_t privileges_size; /* size of privileges */
++ VARARG(privileges,LUID_AND_ATTRIBUTES,privileges_size); /* privileges to remove from new token */
++ VARARG(disable_sids,SID); /* array of groups to remove from new token */
++@REPLY
++ obj_handle_t new_handle; /* filtered handle */
++@END
++
+ @REQ(access_check)
+ obj_handle_t handle; /* handle to the token */
+ unsigned int desired_access; /* desired access to the object */
+--- a/server/security.h
++++ b/server/security.h
+@@ -56,7 +56,9 @@
+ extern struct token *token_create_admin(void);
+ extern int token_assign_label( struct token *token, PSID label );
+ extern struct token *token_duplicate( struct token *src_token, unsigned primary,
+- int impersonation_level, const struct security_descriptor *sd );
++ int impersonation_level, const struct security_descriptor *sd,
++ const LUID_AND_ATTRIBUTES *filter_privileges, unsigned int priv_count,
++ const SID *filter_groups, unsigned int group_count );
+ extern int token_check_privileges( struct token *token, int all_required,
+ const LUID_AND_ATTRIBUTES *reqprivs,
+ unsigned int count, LUID_AND_ATTRIBUTES *usedprivs);
+--- a/server/token.c
++++ b/server/token.c
+@@ -285,6 +285,19 @@
+ return TRUE;
+ }
+
++static unsigned int get_sid_count( const SID *sid, data_size_t size )
++{
++ unsigned int count;
++
++ for (count = 0; size >= sizeof(SID) && security_sid_len( sid ) <= size; count++)
++ {
++ size -= security_sid_len( sid );
++ sid = (const SID *)((char *)sid + security_sid_len( sid ));
++ }
++
++ return count;
++}
++
+ /* checks whether all members of a security descriptor fit inside the size
+ * of memory specified */
+ int sd_is_valid( const struct security_descriptor *sd, data_size_t size )
+@@ -626,8 +639,36 @@
+ return token;
+ }
+
++static int filter_group( struct group *group, const SID *filter, unsigned int count )
++{
++ unsigned int i;
++
++ for (i = 0; i < count; i++)
++ {
++ if (security_equal_sid( &group->sid, filter )) return 1;
++ filter = (const SID *)((char *)filter + security_sid_len( filter ));
++ }
++
++ return 0;
++}
++
++static int filter_privilege( struct privilege *privilege, const LUID_AND_ATTRIBUTES *filter, unsigned int count )
++{
++ unsigned int i;
++
++ for (i = 0; i < count; i++)
++ {
++ if (!memcmp( &privilege->luid, &filter[i].Luid, sizeof(LUID) ))
++ return 1;
++ }
++
++ return 0;
++}
++
+ struct token *token_duplicate( struct token *src_token, unsigned primary,
+- int impersonation_level, const struct security_descriptor *sd )
++ int impersonation_level, const struct security_descriptor *sd,
++ const LUID_AND_ATTRIBUTES *filter_privileges, unsigned int priv_count,
++ const SID *filter_groups, unsigned int group_count)
+ {
+ const luid_t *modified_id =
+ primary || (impersonation_level == src_token->impersonation_level) ?
+@@ -663,6 +704,12 @@
+ return NULL;
+ }
+ memcpy( newgroup, group, size );
++ if (filter_group( group, filter_groups, group_count ))
++ {
++ newgroup->enabled = 0;
++ newgroup->def = 0;
++ newgroup->deny_only = 1;
++ }
+ list_add_tail( &token->groups, &newgroup->entry );
+ if (src_token->primary_group == &group->sid)
+ {
+@@ -674,11 +721,14 @@
+
+ /* copy privileges */
+ LIST_FOR_EACH_ENTRY( privilege, &src_token->privileges, struct privilege, entry )
++ {
++ if (filter_privilege( privilege, filter_privileges, priv_count )) continue;
+ if (!privilege_add( token, &privilege->luid, privilege->enabled ))
+ {
+ release_object( token );
+ return NULL;
+ }
++ }
+
+ if (sd) default_set_sd( &token->obj, sd, OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
+ DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION );
+@@ -1311,13 +1361,43 @@
+ TOKEN_DUPLICATE,
+ &token_ops )))
+ {
+- struct token *token = token_duplicate( src_token, req->primary, req->impersonation_level, sd );
++ struct token *token = token_duplicate( src_token, req->primary, req->impersonation_level, sd, NULL, 0, NULL, 0 );
+ if (token)
+ {
+ reply->new_handle = alloc_handle_no_access_check( current->process, token, req->access, objattr->attributes );
+ release_object( token );
+ }
+ release_object( src_token );
++ }
++}
++
++/* creates a restricted version of a token */
++DECL_HANDLER(filter_token)
++{
++ struct token *src_token;
++
++ if ((src_token = (struct token *)get_handle_obj( current->process, req->handle,
++ TOKEN_DUPLICATE,
++ &token_ops )))
++ {
++ const LUID_AND_ATTRIBUTES *filter_privileges = get_req_data();
++ unsigned int priv_count, group_count;
++ const SID *filter_groups;
++ struct token *token;
++
++ priv_count = min( req->privileges_size, get_req_data_size() ) / sizeof(LUID_AND_ATTRIBUTES);
++ filter_groups = (const SID *)((char *)filter_privileges + priv_count * sizeof(LUID_AND_ATTRIBUTES));
++ group_count = get_sid_count( filter_groups, get_req_data_size() - priv_count * sizeof(LUID_AND_ATTRIBUTES) );
++
++ token = token_duplicate( src_token, src_token->primary, src_token->impersonation_level, NULL,
++ filter_privileges, priv_count, filter_groups, group_count );
++ if (token)
++ {
++ unsigned int access = get_handle_access( current->process, req->handle );
++ reply->new_handle = alloc_handle_no_access_check( current->process, token, access, 0 );
++ release_object( token );
++ }
++ release_object( src_token );
+ }
+ }
+
diff -Nru wine-development-5.5/debian/patches/advapi32-CreateRestrictedToken/0002-advapi32-Implement-CreateRestrictedToken.patch wine-development-5.5/debian/patches/advapi32-CreateRestrictedToken/0002-advapi32-Implement-CreateRestrictedToken.patch
--- wine-development-5.5/debian/patches/advapi32-CreateRestrictedToken/0002-advapi32-Implement-CreateRestrictedToken.patch 1970-01-01 01:00:00.000000000 +0100
+++ wine-development-5.5/debian/patches/advapi32-CreateRestrictedToken/0002-advapi32-Implement-CreateRestrictedToken.patch 2020-05-04 01:33:29.000000000 +0100
@@ -0,0 +1,129 @@
+From 3c1f5962482e7acf531f57f49d923d9c4e5278b1 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
+Date: Fri, 4 Aug 2017 02:51:57 +0200
+Subject: [PATCH] advapi32: Implement CreateRestrictedToken.
+
+---
+ dlls/kernelbase/security.c | 103 ++++++++++++++++++++++++++++++-------
+ 1 file changed, 84 insertions(+), 19 deletions(-)
+
+--- a/dlls/kernelbase/security.c
++++ b/dlls/kernelbase/security.c
+@@ -642,31 +642,96 @@
+ return ret;
+ }
+
++static BOOL allocate_groups(TOKEN_GROUPS **groups_ret, SID_AND_ATTRIBUTES *sids, DWORD count)
++{
++ TOKEN_GROUPS *groups;
++ DWORD i;
++
++ if (!count)
++ {
++ *groups_ret = NULL;
++ return TRUE;
++ }
++
++ groups = (TOKEN_GROUPS *)heap_alloc(FIELD_OFFSET(TOKEN_GROUPS, Groups) +
++ count * sizeof(SID_AND_ATTRIBUTES));
++ if (!groups)
++ {
++ SetLastError(ERROR_OUTOFMEMORY);
++ return FALSE;
++ }
++
++ groups->GroupCount = count;
++ for (i = 0; i < count; i++)
++ groups->Groups[i] = sids[i];
++
++ *groups_ret = groups;
++ return TRUE;
++}
++
++static BOOL allocate_privileges(TOKEN_PRIVILEGES **privileges_ret, LUID_AND_ATTRIBUTES *privs, DWORD count)
++{
++ TOKEN_PRIVILEGES *privileges;
++ DWORD i;
++
++ if (!count)
++ {
++ *privileges_ret = NULL;
++ return TRUE;
++ }
++
++ privileges = (TOKEN_PRIVILEGES *)heap_alloc(FIELD_OFFSET(TOKEN_PRIVILEGES, Privileges) +
++ count * sizeof(LUID_AND_ATTRIBUTES));
++ if (!privileges)
++ {
++ SetLastError(ERROR_OUTOFMEMORY);
++ return FALSE;
++ }
++
++ privileges->PrivilegeCount = count;
++ for (i = 0; i < count; i++)
++ privileges->Privileges[i] = privs[i];
++
++ *privileges_ret = privileges;
++ return TRUE;
++}
++
+ /*************************************************************************
+ * CreateRestrictedToken (kernelbase.@)
+ */
+-BOOL WINAPI CreateRestrictedToken( HANDLE token, DWORD flags,
+- DWORD disable_count, PSID_AND_ATTRIBUTES disable_sids,
+- DWORD delete_count, PLUID_AND_ATTRIBUTES delete_privs,
+- DWORD restrict_count, PSID_AND_ATTRIBUTES restrict_sids, PHANDLE ret )
++BOOL WINAPI CreateRestrictedToken( HANDLE baseToken, DWORD flags,
++ DWORD nDisableSids, PSID_AND_ATTRIBUTES disableSids,
++ DWORD nDeletePrivs, PLUID_AND_ATTRIBUTES deletePrivs,
++ DWORD nRestrictSids, PSID_AND_ATTRIBUTES restrictSids, PHANDLE newToken )
+ {
+- TOKEN_TYPE type;
+- SECURITY_IMPERSONATION_LEVEL level = SecurityAnonymous;
+- DWORD size;
+-
+- FIXME("(%p, 0x%x, %u, %p, %u, %p, %u, %p, %p): stub\n",
+- token, flags, disable_count, disable_sids, delete_count, delete_privs,
+- restrict_count, restrict_sids, ret );
+-
+- size = sizeof(type);
+- if (!GetTokenInformation( token, TokenType, &type, size, &size )) return FALSE;
+- if (type == TokenImpersonation)
+- {
+- size = sizeof(level);
+- if (!GetTokenInformation( token, TokenImpersonationLevel, &level, size, &size ))
+- return FALSE;
+- }
+- return DuplicateTokenEx( token, MAXIMUM_ALLOWED, NULL, level, type, ret );
++ TOKEN_PRIVILEGES *delete_privs = NULL;
++ TOKEN_GROUPS *disable_groups = NULL;
++ TOKEN_GROUPS *restrict_sids = NULL;
++ BOOL ret = FALSE;
++
++ TRACE("(%p, 0x%x, %u, %p, %u, %p, %u, %p, %p)\n",
++ baseToken, flags, nDisableSids, disableSids,
++ nDeletePrivs, deletePrivs,
++ nRestrictSids, restrictSids,
++ newToken);
++
++ if (!allocate_groups(&disable_groups, disableSids, nDisableSids))
++ goto done;
++
++ if (!allocate_privileges(&delete_privs, deletePrivs, nDeletePrivs))
++ goto done;
++
++ if (!allocate_groups(&restrict_sids, restrictSids, nRestrictSids))
++ goto done;
++
++ ret = set_ntstatus(NtFilterToken(baseToken, flags, disable_groups, delete_privs, restrict_sids, newToken));
++
++done:
++ heap_free(disable_groups);
++ heap_free(delete_privs);
++ heap_free(restrict_sids);
++ return ret;
++
+ }
+
+ /******************************************************************************
diff -Nru wine-development-5.5/debian/patches/advapi32-CreateRestrictedToken/definition wine-development-5.5/debian/patches/advapi32-CreateRestrictedToken/definition
--- wine-development-5.5/debian/patches/advapi32-CreateRestrictedToken/definition 1970-01-01 01:00:00.000000000 +0100
+++ wine-development-5.5/debian/patches/advapi32-CreateRestrictedToken/definition 2020-05-04 01:33:29.000000000 +0100
@@ -0,0 +1 @@
+Fixes: [25834] Implement advapi32.CreateRestrictedToken
diff -Nru wine-development-5.5/debian/patches/advapi32-Token_Integrity_Level/0001-advapi32-tests-Extend-security-label-token-integrity.patch wine-development-5.5/debian/patches/advapi32-Token_Integrity_Level/0001-advapi32-tests-Extend-security-label-token-integrity.patch
--- wine-development-5.5/debian/patches/advapi32-Token_Integrity_Level/0001-advapi32-tests-Extend-security-label-token-integrity.patch 1970-01-01 01:00:00.000000000 +0100
+++ wine-development-5.5/debian/patches/advapi32-Token_Integrity_Level/0001-advapi32-tests-Extend-security-label-token-integrity.patch 2020-05-04 01:33:29.000000000 +0100
@@ -0,0 +1,450 @@
+From 8044f571b7e674ce9e562488864d48646a9c7b88 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
+Date: Mon, 7 Aug 2017 01:25:02 +0200
+Subject: [PATCH] advapi32/tests: Extend security label / token integrity
+ tests.
+
+---
+ dlls/advapi32/tests/Makefile.in | 2 +-
+ dlls/advapi32/tests/security.c | 389 +++++++++++++++++++++++++++++++-
+ 2 files changed, 387 insertions(+), 4 deletions(-)
+
+--- a/dlls/advapi32/tests/Makefile.in
++++ b/dlls/advapi32/tests/Makefile.in
+@@ -1,5 +1,5 @@
+ TESTDLL = advapi32.dll
+-IMPORTS = ole32 advapi32
++IMPORTS = ole32 user32 advapi32
+
+ C_SRCS = \
+ cred.c \
+--- a/dlls/advapi32/tests/security.c
++++ b/dlls/advapi32/tests/security.c
+@@ -7005,13 +7005,19 @@
+ {
+ static SID low_level = {SID_REVISION, 1, {SECURITY_MANDATORY_LABEL_AUTHORITY},
+ {SECURITY_MANDATORY_LOW_RID}};
++ static SID medium_level = {SID_REVISION, 1, {SECURITY_MANDATORY_LABEL_AUTHORITY},
++ {SECURITY_MANDATORY_MEDIUM_RID}};
++ static SID high_level = {SID_REVISION, 1, {SECURITY_MANDATORY_LABEL_AUTHORITY},
++ {SECURITY_MANDATORY_HIGH_RID}};
+ char buffer_sd[SECURITY_DESCRIPTOR_MIN_LENGTH];
+- SECURITY_DESCRIPTOR *sd = (SECURITY_DESCRIPTOR *)&buffer_sd, *sd2;
++ SECURITY_DESCRIPTOR *sd = (SECURITY_DESCRIPTOR *)&buffer_sd, *sd2, *sd3;
+ char buffer_acl[256], buffer[MAX_PATH];
+- ACL *acl = (ACL *)&buffer_acl, *acl2, *acl_child;
++ ACL *acl = (ACL *)&buffer_acl, *acl2, *acl_child, *sacl;
+ BOOL defaulted, present, ret, found;
+- HANDLE token, token2, token3;
++ HANDLE token, token2, token3, token4, token5, token6;
+ EXPLICIT_ACCESSW exp_access;
++ TOKEN_MANDATORY_LABEL *tml;
++ BYTE buffer_integrity[64];
+ PROCESS_INFORMATION info;
+ DWORD size, index, retd;
+ ACCESS_ALLOWED_ACE *ace;
+@@ -7161,6 +7167,185 @@
+ /* The security label is also not inherited */
+ if (pAddMandatoryAce)
+ {
++ memset(buffer_integrity, 0, sizeof(buffer_integrity));
++ ret = GetTokenInformation(token, TokenIntegrityLevel, buffer_integrity, sizeof(buffer_integrity), &size);
++ ok(ret, "GetTokenInformation failed with error %u\n", GetLastError());
++ tml = (TOKEN_MANDATORY_LABEL *)buffer_integrity;
++ ok(EqualSid(tml->Label.Sid, &medium_level) || EqualSid(tml->Label.Sid, &high_level),
++ "Expected medium or high integrity level\n");
++
++ if (EqualSid(tml->Label.Sid, &high_level))
++ {
++ DWORD process_id;
++ HANDLE process;
++ HWND shell;
++
++ /* This test tries to get a medium token and then impersonates this token. The
++ * idea is to check whether the sd label of a newly created token depends on the
++ * current active token or the integrity level of the newly created token. */
++
++ /* Steal process token of the explorer.exe process */
++ shell = GetShellWindow();
++ todo_wine ok(shell != NULL, "Failed to get shell window\n");
++ if (!shell) shell = GetDesktopWindow(); /* FIXME: Workaround for Wine */
++ ok(GetWindowThreadProcessId(shell, &process_id),
++ "Failed to get process id of shell window: %u\n", GetLastError());
++ process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, process_id);
++ ok(process != NULL, "Failed to open process: %u\n", GetLastError());
++ ok(OpenProcessToken(process, TOKEN_ALL_ACCESS, &token4),
++ "Failed to open process token: %u\n", GetLastError());
++ CloseHandle(process);
++
++ /* Check TokenIntegrityLevel and LABEL_SECURITY_INFORMATION of explorer.exe token */
++ memset(buffer_integrity, 0, sizeof(buffer_integrity));
++ ret = GetTokenInformation(token4, TokenIntegrityLevel, buffer_integrity, sizeof(buffer_integrity), &size);
++ ok(ret, "GetTokenInformation failed with error %u\n", GetLastError());
++ tml = (TOKEN_MANDATORY_LABEL *)buffer_integrity;
++ todo_wine ok(EqualSid(tml->Label.Sid, &medium_level), "Expected medium integrity level\n");
++
++ size = 0;
++ ret = GetKernelObjectSecurity(token4, LABEL_SECURITY_INFORMATION, NULL, 0, &size);
++ ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
++ "Unexpected GetKernelObjectSecurity return value %u, error %u\n", ret, GetLastError());
++
++ sd3 = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
++ ret = GetKernelObjectSecurity(token4, LABEL_SECURITY_INFORMATION, sd3, size, &size);
++ ok(ret, "GetKernelObjectSecurity failed with error %u\n", GetLastError());
++
++ sacl = NULL;
++ ret = GetSecurityDescriptorSacl(sd3, &present, &sacl, &defaulted);
++ ok(ret, "GetSecurityDescriptorSacl failed with error %u\n", GetLastError());
++ ok(present, "No SACL in the security descriptor\n");
++ ok(sacl != NULL, "NULL SACL in the security descriptor\n");
++
++ if (sacl)
++ {
++ ret = GetAce(sacl, 0, (void **)&ace);
++ ok(ret, "GetAce failed with error %u\n", GetLastError());
++ ok(ace->Header.AceType == SYSTEM_MANDATORY_LABEL_ACE_TYPE,
++ "Unexpected ACE type %#x\n", ace->Header.AceType);
++ todo_wine ok(EqualSid(&ace->SidStart, &medium_level),
++ "Expected medium integrity level\n");
++ }
++
++ HeapFree(GetProcessHeap(), 0, sd3);
++
++ /* Start child process with the explorer.exe token */
++ memset(&startup, 0, sizeof(startup));
++ startup.cb = sizeof(startup);
++ startup.dwFlags = STARTF_USESHOWWINDOW;
++ startup.wShowWindow = SW_SHOWNORMAL;
++
++ sprintf(buffer, "%s tests/security.c test_token_sd_medium", myARGV[0]);
++ ret = CreateProcessAsUserA(token4, NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info);
++ ok(ret || GetLastError() == ERROR_PRIVILEGE_NOT_HELD,
++ "CreateProcess failed with error %u\n", GetLastError());
++ if (ret)
++ {
++ winetest_wait_child_process(info.hProcess);
++ CloseHandle(info.hProcess);
++ CloseHandle(info.hThread);
++ }
++ else
++ win_skip("Skipping test for creating process with medium level token\n");
++
++ ret = DuplicateTokenEx(token4, 0, NULL, SecurityImpersonation, TokenImpersonation, &token5);
++ ok(ret, "DuplicateTokenEx failed with error %u\n", GetLastError());
++ ret = SetThreadToken(NULL, token5);
++ todo_wine ok(ret, "SetThreadToken failed with error %u\n", GetLastError());
++ CloseHandle(token4);
++
++ /* Restrict current process token while impersonating a medium integrity token */
++ ret = CreateRestrictedToken(token, 0, 0, NULL, 0, NULL, 0, NULL, &token6);
++ ok(ret, "CreateRestrictedToken failed with error %u\n", GetLastError());
++
++ memset(buffer_integrity, 0, sizeof(buffer_integrity));
++ ret = GetTokenInformation(token6, TokenIntegrityLevel, buffer_integrity, sizeof(buffer_integrity), &size);
++ ok(ret, "GetTokenInformation failed with error %u\n", GetLastError());
++ tml = (TOKEN_MANDATORY_LABEL *)buffer_integrity;
++ ok(EqualSid(tml->Label.Sid, &high_level), "Expected high integrity level\n");
++
++ size = 0;
++ ret = GetKernelObjectSecurity(token6, LABEL_SECURITY_INFORMATION, NULL, 0, &size);
++ ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
++ "Unexpected GetKernelObjectSecurity return value %u, error %u\n", ret, GetLastError());
++
++ sd3 = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
++ ret = GetKernelObjectSecurity(token6, LABEL_SECURITY_INFORMATION, sd3, size, &size);
++ ok(ret, "GetKernelObjectSecurity failed with error %u\n", GetLastError());
++
++ sacl = NULL;
++ ret = GetSecurityDescriptorSacl(sd3, &present, &sacl, &defaulted);
++ ok(ret, "GetSecurityDescriptorSacl failed with error %u\n", GetLastError());
++ todo_wine ok(present, "No SACL in the security descriptor\n");
++ todo_wine ok(sacl != NULL, "NULL SACL in the security descriptor\n");
++
++ if (sacl)
++ {
++ ret = GetAce(sacl, 0, (void **)&ace);
++ ok(ret, "GetAce failed with error %u\n", GetLastError());
++ ok(ace->Header.AceType == SYSTEM_MANDATORY_LABEL_ACE_TYPE,
++ "Unexpected ACE type %#x\n", ace->Header.AceType);
++ ok(EqualSid(&ace->SidStart, &medium_level),
++ "Expected medium integrity level\n");
++ }
++
++ HeapFree(GetProcessHeap(), 0, sd3);
++ RevertToSelf();
++ CloseHandle(token5);
++
++ /* Start child process with the restricted token */
++ sprintf(buffer, "%s tests/security.c test_token_sd_restricted", myARGV[0]);
++ ret = CreateProcessAsUserA(token6, NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info);
++ ok(ret, "CreateProcess failed with error %u\n", GetLastError());
++ winetest_wait_child_process(info.hProcess);
++ CloseHandle(info.hProcess);
++ CloseHandle(info.hThread);
++ CloseHandle(token6);
++
++ /* DuplicateTokenEx should assign security label even when SA points to empty SD */
++ memset(sd, 0, sizeof(buffer_sd));
++ ret = InitializeSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION);
++ ok(ret, "InitializeSecurityDescriptor failed with error %u\n", GetLastError());
++
++ sa.nLength = sizeof(SECURITY_ATTRIBUTES);
++ sa.lpSecurityDescriptor = sd;
++ sa.bInheritHandle = FALSE;
++
++ ret = DuplicateTokenEx(token, 0, &sa, 0, TokenPrimary, &token6);
++ ok(ret, "DuplicateTokenEx failed with error %u\n", GetLastError());
++
++ size = 0;
++ ret = GetKernelObjectSecurity(token6, LABEL_SECURITY_INFORMATION, NULL, 0, &size);
++ todo_wine ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
++ "Unexpected GetKernelObjectSecurity return value %u, error %u\n", ret, GetLastError());
++
++ sd3 = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
++ ret = GetKernelObjectSecurity(token6, LABEL_SECURITY_INFORMATION, sd3, size, &size);
++ todo_wine ok(ret, "GetKernelObjectSecurity failed with error %u\n", GetLastError());
++
++ sacl = NULL;
++ ret = GetSecurityDescriptorSacl(sd3, &present, &sacl, &defaulted);
++ todo_wine ok(ret, "GetSecurityDescriptorSacl failed with error %u\n", GetLastError());
++ todo_wine ok(present, "No SACL in the security descriptor\n");
++ todo_wine ok(sacl != NULL, "NULL SACL in the security descriptor\n");
++
++ if (sacl)
++ {
++ ret = GetAce(sacl, 0, (void **)&ace);
++ ok(ret, "GetAce failed with error %u\n", GetLastError());
++ ok(ace->Header.AceType == SYSTEM_MANDATORY_LABEL_ACE_TYPE,
++ "Unexpected ACE type %#x\n", ace->Header.AceType);
++ ok(EqualSid(&ace->SidStart, &high_level),
++ "Expected high integrity level\n");
++ }
++
++ HeapFree(GetProcessHeap(), 0, sd3);
++ CloseHandle(token6);
++ }
++ else
++ skip("Skipping test, running without admin rights\n");
++
+ ret = InitializeAcl(acl, 256, ACL_REVISION);
+ ok(ret, "InitializeAcl failed with error %u\n", GetLastError());
+
+@@ -7176,6 +7361,90 @@
+
+ ret = SetKernelObjectSecurity(token, LABEL_SECURITY_INFORMATION, sd);
+ ok(ret, "SetKernelObjectSecurity failed with error %u\n", GetLastError());
++
++ /* changing the label of the security descriptor does not change the integrity level of the token itself */
++ memset(buffer_integrity, 0, sizeof(buffer_integrity));
++ ret = GetTokenInformation(token, TokenIntegrityLevel, buffer_integrity, sizeof(buffer_integrity), &size);
++ ok(ret, "GetTokenInformation failed with error %u\n", GetLastError());
++ tml = (TOKEN_MANDATORY_LABEL *)buffer_integrity;
++ ok(EqualSid(tml->Label.Sid, &medium_level) || EqualSid(tml->Label.Sid, &high_level),
++ "Expected medium or high integrity level\n");
++
++ /* restricting / duplicating a token resets the mandatory sd label */
++ ret = CreateRestrictedToken(token, 0, 0, NULL, 0, NULL, 0, NULL, &token4);
++ ok(ret, "CreateRestrictedToken failed with error %u\n", GetLastError());
++
++ memset(buffer_integrity, 0, sizeof(buffer_integrity));
++ ret = GetTokenInformation(token4, TokenIntegrityLevel, buffer_integrity, sizeof(buffer_integrity), &size);
++ ok(ret, "GetTokenInformation failed with error %u\n", GetLastError());
++ tml = (TOKEN_MANDATORY_LABEL *)buffer_integrity;
++ ok(EqualSid(tml->Label.Sid, &medium_level) || EqualSid(tml->Label.Sid, &high_level),
++ "Expected medium or high integrity level\n");
++
++ size = 0;
++ ret = GetKernelObjectSecurity(token4, LABEL_SECURITY_INFORMATION, NULL, 0, &size);
++ ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
++ "Unexpected GetKernelObjectSecurity return value %u, error %u\n", ret, GetLastError());
++
++ sd3 = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
++ ret = GetKernelObjectSecurity(token4, LABEL_SECURITY_INFORMATION, sd3, size, &size);
++ ok(ret, "GetKernelObjectSecurity failed with error %u\n", GetLastError());
++
++ ret = GetSecurityDescriptorSacl(sd3, &present, &sacl, &defaulted);
++ ok(ret, "GetSecurityDescriptorSacl failed with error %u\n", GetLastError());
++ todo_wine ok(present, "No SACL in the security descriptor\n");
++ todo_wine ok(sacl != NULL, "NULL SACL in the security descriptor\n");
++
++ if (sacl)
++ {
++ ret = GetAce(sacl, 0, (void **)&ace);
++ ok(ret, "GetAce failed with error %u\n", GetLastError());
++ ok(ace->Header.AceType == SYSTEM_MANDATORY_LABEL_ACE_TYPE,
++ "Unexpected ACE type %#x\n", ace->Header.AceType);
++ ok(EqualSid(&ace->SidStart, &medium_level) || EqualSid(&ace->SidStart, &high_level),
++ "Low integrity level should not have been inherited\n");
++ }
++
++ HeapFree(GetProcessHeap(), 0, sd3);
++ CloseHandle(token4);
++
++ ret = DuplicateTokenEx(token, 0, NULL, 0, TokenPrimary, &token4);
++ ok(ret, "DuplicateTokenEx failed with error %u\n", GetLastError());
++
++ memset(buffer_integrity, 0, sizeof(buffer_integrity));
++ ret = GetTokenInformation(token4, TokenIntegrityLevel, buffer_integrity, sizeof(buffer_integrity), &size);
++ ok(ret, "GetTokenInformation failed with error %u\n", GetLastError());
++ tml = (TOKEN_MANDATORY_LABEL*) buffer_integrity;
++ ok(EqualSid(tml->Label.Sid, &medium_level) || EqualSid(tml->Label.Sid, &high_level),
++ "Expected medium or high integrity level\n");
++
++ size = 0;
++ ret = GetKernelObjectSecurity(token4, LABEL_SECURITY_INFORMATION, NULL, 0, &size);
++ todo_wine ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
++ "Unexpected GetKernelObjectSecurity return value %u, error %u\n", ret, GetLastError());
++
++ sd3 = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
++ ret = GetKernelObjectSecurity(token4, LABEL_SECURITY_INFORMATION, sd3, size, &size);
++ todo_wine ok(ret, "GetKernelObjectSecurity failed with error %u\n", GetLastError());
++
++ sacl = NULL;
++ ret = GetSecurityDescriptorSacl(sd3, &present, &sacl, &defaulted);
++ todo_wine ok(ret, "GetSecurityDescriptorSacl failed with error %u\n", GetLastError());
++ todo_wine ok(present, "No SACL in the security descriptor\n");
++ todo_wine ok(sacl != NULL, "NULL SACL in the security descriptor\n");
++
++ if (sacl)
++ {
++ ret = GetAce(sacl, 0, (void **)&ace);
++ ok(ret, "GetAce failed with error %u\n", GetLastError());
++ ok(ace->Header.AceType == SYSTEM_MANDATORY_LABEL_ACE_TYPE,
++ "Unexpected ACE type %#x\n", ace->Header.AceType);
++ ok(EqualSid(&ace->SidStart, &medium_level) || EqualSid(&ace->SidStart, &high_level),
++ "Low integrity level should not have been inherited\n");
++ }
++
++ HeapFree(GetProcessHeap(), 0, sd3);
++ CloseHandle(token4);
+ }
+ else
+ win_skip("SYSTEM_MANDATORY_LABEL not supported\n");
+@@ -7283,6 +7552,116 @@
+ HeapFree(GetProcessHeap(), 0, sd);
+ }
+
++static void test_child_token_sd_restricted(void)
++{
++ static SID high_level = {SID_REVISION, 1, {SECURITY_MANDATORY_LABEL_AUTHORITY},
++ {SECURITY_MANDATORY_HIGH_RID}};
++ SYSTEM_MANDATORY_LABEL_ACE *ace_label;
++ BOOL ret, present, defaulted;
++ TOKEN_MANDATORY_LABEL *tml;
++ BYTE buffer_integrity[64];
++ SECURITY_DESCRIPTOR *sd;
++ HANDLE token;
++ DWORD size;
++ ACL *acl;
++
++ if (!pAddMandatoryAce)
++ {
++ win_skip("SYSTEM_MANDATORY_LABEL not supported\n");
++ return;
++ }
++
++ ret = OpenProcessToken(GetCurrentProcess(), MAXIMUM_ALLOWED, &token);
++ ok(ret, "OpenProcessToken failed with error %u\n", GetLastError());
++
++ ret = GetKernelObjectSecurity(token, LABEL_SECURITY_INFORMATION, NULL, 0, &size);
++ ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
++ "Unexpected GetKernelObjectSecurity return value %d, error %u\n", ret, GetLastError());
++
++ sd = HeapAlloc(GetProcessHeap(), 0, size);
++ ret = GetKernelObjectSecurity(token, LABEL_SECURITY_INFORMATION, sd, size, &size);
++ ok(ret, "GetKernelObjectSecurity failed with error %u\n", GetLastError());
++
++ acl = NULL;
++ present = FALSE;
++ defaulted = TRUE;
++ ret = GetSecurityDescriptorSacl(sd, &present, &acl, &defaulted);
++ ok(ret, "GetSecurityDescriptorSacl failed with error %u\n", GetLastError());
++ ok(present, "SACL not present\n");
++ ok(acl && acl != (void *)0xdeadbeef, "Got invalid SACL\n");
++ ok(!defaulted, "SACL defaulted\n");
++ ok(acl->AceCount == 1, "Expected exactly one ACE\n");
++ ret = GetAce(acl, 0, (void **)&ace_label);
++ ok(ret, "GetAce failed with error %u\n", GetLastError());
++ ok(ace_label->Header.AceType == SYSTEM_MANDATORY_LABEL_ACE_TYPE,
++ "Unexpected ACE type %#x\n", ace_label->Header.AceType);
++ ok(EqualSid(&ace_label->SidStart, &high_level),
++ "Expected high integrity level\n");
++
++ memset(buffer_integrity, 0, sizeof(buffer_integrity));
++ ret = GetTokenInformation(token, TokenIntegrityLevel, buffer_integrity, sizeof(buffer_integrity), &size);
++ ok(ret, "GetTokenInformation failed with error %u\n", GetLastError());
++ tml = (TOKEN_MANDATORY_LABEL *)buffer_integrity;
++ ok(EqualSid(tml->Label.Sid, &high_level), "Expected high integrity level\n");
++
++ HeapFree(GetProcessHeap(), 0, sd);
++}
++
++static void test_child_token_sd_medium(void)
++{
++ static SID medium_level = {SID_REVISION, 1, {SECURITY_MANDATORY_LABEL_AUTHORITY},
++ {SECURITY_MANDATORY_MEDIUM_RID}};
++ SYSTEM_MANDATORY_LABEL_ACE *ace_label;
++ BOOL ret, present, defaulted;
++ TOKEN_MANDATORY_LABEL *tml;
++ BYTE buffer_integrity[64];
++ SECURITY_DESCRIPTOR *sd;
++ HANDLE token;
++ DWORD size;
++ ACL *acl;
++
++ if (!pAddMandatoryAce)
++ {
++ win_skip("SYSTEM_MANDATORY_LABEL not supported\n");
++ return;
++ }
++
++ ret = OpenProcessToken(GetCurrentProcess(), MAXIMUM_ALLOWED, &token);
++ ok(ret, "OpenProcessToken failed with error %u\n", GetLastError());
++
++ ret = GetKernelObjectSecurity(token, LABEL_SECURITY_INFORMATION, NULL, 0, &size);
++ ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
++ "Unexpected GetKernelObjectSecurity return value %d, error %u\n", ret, GetLastError());
++
++ sd = HeapAlloc(GetProcessHeap(), 0, size);
++ ret = GetKernelObjectSecurity(token, LABEL_SECURITY_INFORMATION, sd, size, &size);
++ ok(ret, "GetKernelObjectSecurity failed with error %u\n", GetLastError());
++
++ acl = NULL;
++ present = FALSE;
++ defaulted = TRUE;
++ ret = GetSecurityDescriptorSacl(sd, &present, &acl, &defaulted);
++ ok(ret, "GetSecurityDescriptorSacl failed with error %u\n", GetLastError());
++ ok(present, "SACL not present\n");
++ ok(acl && acl != (void *)0xdeadbeef, "Got invalid SACL\n");
++ ok(!defaulted, "SACL defaulted\n");
++ ok(acl->AceCount == 1, "Expected exactly one ACE\n");
++ ret = GetAce(acl, 0, (void **)&ace_label);
++ ok(ret, "GetAce failed with error %u\n", GetLastError());
++ ok(ace_label->Header.AceType == SYSTEM_MANDATORY_LABEL_ACE_TYPE,
++ "Unexpected ACE type %#x\n", ace_label->Header.AceType);
++ todo_wine ok(EqualSid(&ace_label->SidStart, &medium_level),
++ "Expected medium integrity level\n");
++
++ memset(buffer_integrity, 0, sizeof(buffer_integrity));
++ ret = GetTokenInformation(token, TokenIntegrityLevel, buffer_integrity, sizeof(buffer_integrity), &size);
++ ok(ret, "GetTokenInformation failed with error %u\n", GetLastError());
++ tml = (TOKEN_MANDATORY_LABEL *)buffer_integrity;
++ todo_wine ok(EqualSid(tml->Label.Sid, &medium_level), "Expected medium integrity level\n");
++
++ HeapFree(GetProcessHeap(), 0, sd);
++}
++
+ static void test_GetExplicitEntriesFromAclW(void)
+ {
+ static const WCHAR wszCurrentUser[] = { 'C','U','R','R','E','N','T','_','U','S','E','R','\0'};
+@@ -7536,6 +7915,10 @@
+ {
+ if (!strcmp(myARGV[2], "test_token_sd"))
+ test_child_token_sd();
++ else if (!strcmp(myARGV[2], "test_token_sd_restricted"))
++ test_child_token_sd_restricted();
++ else if (!strcmp(myARGV[2], "test_token_sd_medium"))
++ test_child_token_sd_medium();
+ else
+ test_process_security_child();
+ return;
diff -Nru wine-development-5.5/debian/patches/advapi32-Token_Integrity_Level/0002-server-Implement-token-elevation-information.patch wine-development-5.5/debian/patches/advapi32-Token_Integrity_Level/0002-server-Implement-token-elevation-information.patch
--- wine-development-5.5/debian/patches/advapi32-Token_Integrity_Level/0002-server-Implement-token-elevation-information.patch 1970-01-01 01:00:00.000000000 +0100
+++ wine-development-5.5/debian/patches/advapi32-Token_Integrity_Level/0002-server-Implement-token-elevation-information.patch 2020-05-04 01:33:29.000000000 +0100
@@ -0,0 +1,127 @@
+From c8dc0ec6406e8449b59c219ede2e9bd88d8a56fa Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
+Date: Sat, 5 Aug 2017 00:26:03 +0200
+Subject: [PATCH] server: Implement token elevation information.
+
+---
+ dlls/ntdll/nt.c | 16 ++++++++++++----
+ server/protocol.def | 8 ++++++++
+ server/token.c | 22 +++++++++++++++++++---
+ 3 files changed, 39 insertions(+), 7 deletions(-)
+
+--- a/dlls/ntdll/nt.c
++++ b/dlls/ntdll/nt.c
+@@ -657,18 +657,26 @@
+ SERVER_END_REQ;
+ break;
+ case TokenElevationType:
++ SERVER_START_REQ( get_token_elevation_type )
+ {
+ TOKEN_ELEVATION_TYPE *elevation_type = tokeninfo;
+- FIXME("QueryInformationToken( ..., TokenElevationType, ...) semi-stub\n");
+- *elevation_type = TokenElevationTypeFull;
++ req->handle = wine_server_obj_handle( token );
++ status = wine_server_call( req );
++ if (status == STATUS_SUCCESS)
++ *elevation_type = reply->elevation;
+ }
++ SERVER_END_REQ;
+ break;
+ case TokenElevation:
++ SERVER_START_REQ( get_token_elevation_type )
+ {
+ TOKEN_ELEVATION *elevation = tokeninfo;
+- FIXME("QueryInformationToken( ..., TokenElevation, ...) semi-stub\n");
+- elevation->TokenIsElevated = TRUE;
++ req->handle = wine_server_obj_handle( token );
++ status = wine_server_call( req );
++ if (status == STATUS_SUCCESS)
++ elevation->TokenIsElevated = (reply->elevation == TokenElevationTypeFull);
+ }
++ SERVER_END_REQ;
+ break;
+ case TokenSessionId:
+ {
+--- a/server/protocol.def
++++ b/server/protocol.def
+@@ -3732,6 +3732,14 @@
+ @END
+
+
++/* Get elevation level of token */
++@REQ(get_token_elevation_type)
++ obj_handle_t handle; /* handle to the object */
++@REPLY
++ unsigned int elevation; /* elevation level */
++@END
++
++
+ /* Create I/O completion port */
+ @REQ(create_completion)
+ unsigned int access; /* desired access to a port */
+--- a/server/token.c
++++ b/server/token.c
+@@ -110,6 +110,7 @@
+ ACL *default_dacl; /* the default DACL to assign to objects created by this user */
+ TOKEN_SOURCE source; /* source of the token */
+ int impersonation_level; /* impersonation level this token is capable of if non-primary token */
++ TOKEN_ELEVATION_TYPE elevation; /* elevation level */
+ };
+
+ struct privilege
+@@ -552,7 +553,7 @@
+ const LUID_AND_ATTRIBUTES *privs, unsigned int priv_count,
+ const ACL *default_dacl, TOKEN_SOURCE source,
+ const luid_t *modified_id,
+- int impersonation_level )
++ int impersonation_level, TOKEN_ELEVATION_TYPE elevation )
+ {
+ struct token *token = alloc_object( &token_ops );
+ if (token)
+@@ -574,6 +575,7 @@
+ token->impersonation_level = impersonation_level;
+ token->default_dacl = NULL;
+ token->primary_group = NULL;
++ token->elevation = elevation;
+
+ /* copy user */
+ token->user = memdup( user, security_sid_len( user ));
+@@ -689,7 +691,8 @@
+ token = create_token( primary, src_token->user, NULL, 0,
+ NULL, 0, src_token->default_dacl,
+ src_token->source, modified_id,
+- impersonation_level );
++ impersonation_level,
++ src_token->elevation );
+ if (!token) return token;
+
+ /* copy groups */
+@@ -895,7 +898,7 @@
+ static const TOKEN_SOURCE admin_source = {"SeMgr", {0, 0}};
+ token = create_token( TRUE, user_sid, admin_groups, ARRAY_SIZE( admin_groups ),
+ admin_privs, ARRAY_SIZE( admin_privs ), default_dacl,
+- admin_source, NULL, -1 );
++ admin_source, NULL, -1, TokenElevationTypeFull );
+ /* we really need a primary group */
+ assert( token->primary_group );
+ }
+@@ -1633,6 +1636,19 @@
+ release_object( token );
+ }
+ }
++
++DECL_HANDLER(get_token_elevation_type)
++{
++ struct token *token;
++
++ if ((token = (struct token *)get_handle_obj( current->process, req->handle,
++ TOKEN_QUERY,
++ &token_ops )))
++ {
++ reply->elevation = token->elevation;
++ release_object( token );
++ }
++}
+
+ DECL_HANDLER(get_token_default_dacl)
+ {
diff -Nru wine-development-5.5/debian/patches/advapi32-Token_Integrity_Level/0003-server-Correctly-treat-zero-access-mask-in-duplicate.patch wine-development-5.5/debian/patches/advapi32-Token_Integrity_Level/0003-server-Correctly-treat-zero-access-mask-in-duplicate.patch
--- wine-development-5.5/debian/patches/advapi32-Token_Integrity_Level/0003-server-Correctly-treat-zero-access-mask-in-duplicate.patch 1970-01-01 01:00:00.000000000 +0100
+++ wine-development-5.5/debian/patches/advapi32-Token_Integrity_Level/0003-server-Correctly-treat-zero-access-mask-in-duplicate.patch 2020-05-04 01:33:29.000000000 +0100
@@ -0,0 +1,74 @@
+From 7e73f449d158f0d6a6b6b421d073dbaf1741e1c7 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
+Date: Mon, 7 Aug 2017 02:22:11 +0200
+Subject: server: Correctly treat zero access mask in duplicate_token
+ wineserver call.
+
+---
+ dlls/advapi32/tests/security.c | 14 +++++++-------
+ server/token.c | 3 ++-
+ 2 files changed, 9 insertions(+), 8 deletions(-)
+
+--- a/dlls/advapi32/tests/security.c
++++ b/dlls/advapi32/tests/security.c
+@@ -7252,7 +7252,7 @@
+ ret = DuplicateTokenEx(token4, 0, NULL, SecurityImpersonation, TokenImpersonation, &token5);
+ ok(ret, "DuplicateTokenEx failed with error %u\n", GetLastError());
+ ret = SetThreadToken(NULL, token5);
+- todo_wine ok(ret, "SetThreadToken failed with error %u\n", GetLastError());
++ ok(ret, "SetThreadToken failed with error %u\n", GetLastError());
+ CloseHandle(token4);
+
+ /* Restrict current process token while impersonating a medium integrity token */
+@@ -7317,16 +7317,16 @@
+
+ size = 0;
+ ret = GetKernelObjectSecurity(token6, LABEL_SECURITY_INFORMATION, NULL, 0, &size);
+- todo_wine ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
++ ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
+ "Unexpected GetKernelObjectSecurity return value %u, error %u\n", ret, GetLastError());
+
+ sd3 = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
+ ret = GetKernelObjectSecurity(token6, LABEL_SECURITY_INFORMATION, sd3, size, &size);
+- todo_wine ok(ret, "GetKernelObjectSecurity failed with error %u\n", GetLastError());
++ ok(ret, "GetKernelObjectSecurity failed with error %u\n", GetLastError());
+
+ sacl = NULL;
+ ret = GetSecurityDescriptorSacl(sd3, &present, &sacl, &defaulted);
+- todo_wine ok(ret, "GetSecurityDescriptorSacl failed with error %u\n", GetLastError());
++ ok(ret, "GetSecurityDescriptorSacl failed with error %u\n", GetLastError());
+ todo_wine ok(present, "No SACL in the security descriptor\n");
+ todo_wine ok(sacl != NULL, "NULL SACL in the security descriptor\n");
+
+@@ -7420,16 +7420,16 @@
+
+ size = 0;
+ ret = GetKernelObjectSecurity(token4, LABEL_SECURITY_INFORMATION, NULL, 0, &size);
+- todo_wine ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
++ ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
+ "Unexpected GetKernelObjectSecurity return value %u, error %u\n", ret, GetLastError());
+
+ sd3 = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
+ ret = GetKernelObjectSecurity(token4, LABEL_SECURITY_INFORMATION, sd3, size, &size);
+- todo_wine ok(ret, "GetKernelObjectSecurity failed with error %u\n", GetLastError());
++ ok(ret, "GetKernelObjectSecurity failed with error %u\n", GetLastError());
+
+ sacl = NULL;
+ ret = GetSecurityDescriptorSacl(sd3, &present, &sacl, &defaulted);
+- todo_wine ok(ret, "GetSecurityDescriptorSacl failed with error %u\n", GetLastError());
++ ok(ret, "GetSecurityDescriptorSacl failed with error %u\n", GetLastError());
+ todo_wine ok(present, "No SACL in the security descriptor\n");
+ todo_wine ok(sacl != NULL, "NULL SACL in the security descriptor\n");
+
+--- a/server/token.c
++++ b/server/token.c
+@@ -1367,7 +1367,8 @@
+ struct token *token = token_duplicate( src_token, req->primary, req->impersonation_level, sd, NULL, 0, NULL, 0 );
+ if (token)
+ {
+- reply->new_handle = alloc_handle_no_access_check( current->process, token, req->access, objattr->attributes );
++ unsigned int access = req->access ? req->access : get_handle_access( current->process, req->handle );
++ reply->new_handle = alloc_handle_no_access_check( current->process, token, access, objattr->attributes );
+ release_object( token );
+ }
+ release_object( src_token );
diff -Nru wine-development-5.5/debian/patches/advapi32-Token_Integrity_Level/0004-server-Implement-token-integrity-level.patch wine-development-5.5/debian/patches/advapi32-Token_Integrity_Level/0004-server-Implement-token-integrity-level.patch
--- wine-development-5.5/debian/patches/advapi32-Token_Integrity_Level/0004-server-Implement-token-integrity-level.patch 1970-01-01 01:00:00.000000000 +0100
+++ wine-development-5.5/debian/patches/advapi32-Token_Integrity_Level/0004-server-Implement-token-integrity-level.patch 2020-05-04 01:33:29.000000000 +0100
@@ -0,0 +1,144 @@
+From ae503e8e7eb8f4fcb9bf3e642458c2a1bba6ccaa Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
+Date: Mon, 7 Aug 2017 02:28:35 +0200
+Subject: [PATCH] server: Implement token integrity level.
+
+---
+ dlls/ntdll/nt.c | 23 ++++++++++++++---------
+ server/protocol.def | 7 +++++++
+ server/token.c | 30 +++++++++++++++++++++++++++---
+ 3 files changed, 48 insertions(+), 12 deletions(-)
+
+--- a/dlls/ntdll/nt.c
++++ b/dlls/ntdll/nt.c
+@@ -432,7 +432,7 @@
+ 0, /* TokenAccessInformation */
+ 0, /* TokenVirtualizationAllowed */
+ sizeof(DWORD), /* TokenVirtualizationEnabled */
+- sizeof(TOKEN_MANDATORY_LABEL) + sizeof(SID), /* TokenIntegrityLevel [sizeof(SID) includes one SubAuthority] */
++ 0, /* TokenIntegrityLevel */
+ 0, /* TokenUIAccess */
+ 0, /* TokenMandatoryPolicy */
+ 0, /* TokenLogonSid */
+@@ -691,18 +691,23 @@
+ }
+ break;
+ case TokenIntegrityLevel:
++ SERVER_START_REQ( get_token_integrity )
+ {
+- /* report always "S-1-16-12288" (high mandatory level) for now */
+- static const SID high_level = {SID_REVISION, 1, {SECURITY_MANDATORY_LABEL_AUTHORITY},
+- {SECURITY_MANDATORY_HIGH_RID}};
+-
+ TOKEN_MANDATORY_LABEL *tml = tokeninfo;
+- PSID psid = tml + 1;
++ PSID sid = tml + 1;
++ DWORD sid_len = tokeninfolength < sizeof(*tml) ? 0 : tokeninfolength - sizeof(*tml);
+
+- tml->Label.Sid = psid;
+- tml->Label.Attributes = SE_GROUP_INTEGRITY | SE_GROUP_INTEGRITY_ENABLED;
+- memcpy(psid, &high_level, sizeof(SID));
++ req->handle = wine_server_obj_handle( token );
++ wine_server_set_reply( req, sid, sid_len );
++ status = wine_server_call( req );
++ if (retlen) *retlen = reply->sid_len + sizeof(*tml);
++ if (status == STATUS_SUCCESS)
++ {
++ tml->Label.Sid = sid;
++ tml->Label.Attributes = SE_GROUP_INTEGRITY | SE_GROUP_INTEGRITY_ENABLED;
++ }
+ }
++ SERVER_END_REQ;
+ break;
+ case TokenAppContainerSid:
+ {
+--- a/server/protocol.def
++++ b/server/protocol.def
+@@ -3456,6 +3456,13 @@
+ VARARG(sid,SID); /* the sid specified by which_sid from the token */
+ @END
+
++@REQ(get_token_integrity)
++ obj_handle_t handle; /* handle to the token */
++@REPLY
++ data_size_t sid_len; /* length needed to store sid */
++ VARARG(sid,SID); /* the integrity sid */
++@END
++
+ @REQ(get_token_groups)
+ obj_handle_t handle; /* handle to the token */
+ @REPLY
+--- a/server/token.c
++++ b/server/token.c
+@@ -111,6 +111,7 @@
+ TOKEN_SOURCE source; /* source of the token */
+ int impersonation_level; /* impersonation level this token is capable of if non-primary token */
+ TOKEN_ELEVATION_TYPE elevation; /* elevation level */
++ const SID *integrity; /* token integrity */
+ };
+
+ struct privilege
+@@ -553,7 +554,8 @@
+ const LUID_AND_ATTRIBUTES *privs, unsigned int priv_count,
+ const ACL *default_dacl, TOKEN_SOURCE source,
+ const luid_t *modified_id,
+- int impersonation_level, TOKEN_ELEVATION_TYPE elevation )
++ int impersonation_level, TOKEN_ELEVATION_TYPE elevation,
++ const SID *integrity )
+ {
+ struct token *token = alloc_object( &token_ops );
+ if (token)
+@@ -637,6 +639,7 @@
+ }
+
+ token->source = source;
++ token->integrity = integrity;
+ }
+ return token;
+ }
+@@ -692,7 +695,8 @@
+ NULL, 0, src_token->default_dacl,
+ src_token->source, modified_id,
+ impersonation_level,
+- src_token->elevation );
++ src_token->elevation,
++ src_token->integrity );
+ if (!token) return token;
+
+ /* copy groups */
+@@ -898,7 +902,7 @@
+ static const TOKEN_SOURCE admin_source = {"SeMgr", {0, 0}};
+ token = create_token( TRUE, user_sid, admin_groups, ARRAY_SIZE( admin_groups ),
+ admin_privs, ARRAY_SIZE( admin_privs ), default_dacl,
+- admin_source, NULL, -1, TokenElevationTypeFull );
++ admin_source, NULL, -1, TokenElevationTypeFull, &high_label_sid );
+ /* we really need a primary group */
+ assert( token->primary_group );
+ }
+@@ -1531,6 +1535,26 @@
+ release_object( token );
+ }
+ }
++
++/* retrieves the integrity sid */
++DECL_HANDLER(get_token_integrity)
++{
++ struct token *token;
++
++ reply->sid_len = 0;
++
++ if ((token = (struct token *)get_handle_obj( current->process, req->handle,
++ TOKEN_QUERY,
++ &token_ops )))
++ {
++ reply->sid_len = security_sid_len( token->integrity );
++ if (reply->sid_len <= get_reply_max_size())
++ set_reply_data( token->integrity, reply->sid_len );
++ else
++ set_error( STATUS_BUFFER_TOO_SMALL );
++ release_object( token );
++ }
++}
+
+ /* retrieves the groups that the user represented by the token belongs to */
+ DECL_HANDLER(get_token_groups)
diff -Nru wine-development-5.5/debian/patches/advapi32-Token_Integrity_Level/0005-server-Use-all-group-attributes-in-create_token.patch wine-development-5.5/debian/patches/advapi32-Token_Integrity_Level/0005-server-Use-all-group-attributes-in-create_token.patch
--- wine-development-5.5/debian/patches/advapi32-Token_Integrity_Level/0005-server-Use-all-group-attributes-in-create_token.patch 1970-01-01 01:00:00.000000000 +0100
+++ wine-development-5.5/debian/patches/advapi32-Token_Integrity_Level/0005-server-Use-all-group-attributes-in-create_token.patch 2020-05-04 01:33:29.000000000 +0100
@@ -0,0 +1,41 @@
+From 48f4c131f9e8ffc091dde12437ad0772ed1c5ca6 Mon Sep 17 00:00:00 2001
+From: Sebastian Lackner <sebastian@fds-team.de>
+Date: Sun, 6 Aug 2017 15:16:33 +0200
+Subject: server: Use all group attributes in create_token.
+
+---
+ server/token.c | 14 +++++++-------
+ 1 file changed, 7 insertions(+), 7 deletions(-)
+
+--- a/server/token.c
++++ b/server/token.c
+@@ -599,13 +599,13 @@
+ return NULL;
+ }
+ memcpy( &group->sid, groups[i].Sid, security_sid_len( groups[i].Sid ));
+- group->enabled = TRUE;
+- group->def = TRUE;
+- group->logon = (groups[i].Attributes & SE_GROUP_LOGON_ID) != 0;
+ group->mandatory = (groups[i].Attributes & SE_GROUP_MANDATORY) != 0;
+- group->owner = (groups[i].Attributes & SE_GROUP_OWNER) != 0;
+- group->resource = FALSE;
+- group->deny_only = FALSE;
++ group->def = (groups[i].Attributes & SE_GROUP_ENABLED_BY_DEFAULT) != 0;
++ group->enabled = (groups[i].Attributes & SE_GROUP_ENABLED) != 0;
++ group->owner = (groups[i].Attributes & SE_GROUP_OWNER) != 0;
++ group->deny_only = (groups[i].Attributes & SE_GROUP_USE_FOR_DENY_ONLY) != 0;
++ group->logon = (groups[i].Attributes & SE_GROUP_LOGON_ID) != 0;
++ group->resource = (groups[i].Attributes & SE_GROUP_RESOURCE) != 0;
+ list_add_tail( &token->groups, &group->entry );
+ /* Use first owner capable group as owner and primary group */
+ if (!token->primary_group && group->owner)
+@@ -1610,8 +1610,8 @@
+ if (group->enabled) *attr_ptr |= SE_GROUP_ENABLED;
+ if (group->owner) *attr_ptr |= SE_GROUP_OWNER;
+ if (group->deny_only) *attr_ptr |= SE_GROUP_USE_FOR_DENY_ONLY;
+- if (group->resource) *attr_ptr |= SE_GROUP_RESOURCE;
+ if (group->logon) *attr_ptr |= SE_GROUP_LOGON_ID;
++ if (group->resource) *attr_ptr |= SE_GROUP_RESOURCE;
+
+ memcpy(sid_ptr, &group->sid, security_sid_len( &group->sid ));
+
diff -Nru wine-development-5.5/debian/patches/advapi32-Token_Integrity_Level/0006-ntdll-Add-function-to-create-new-tokens-for-elevatio.patch wine-development-5.5/debian/patches/advapi32-Token_Integrity_Level/0006-ntdll-Add-function-to-create-new-tokens-for-elevatio.patch
--- wine-development-5.5/debian/patches/advapi32-Token_Integrity_Level/0006-ntdll-Add-function-to-create-new-tokens-for-elevatio.patch 1970-01-01 01:00:00.000000000 +0100
+++ wine-development-5.5/debian/patches/advapi32-Token_Integrity_Level/0006-ntdll-Add-function-to-create-new-tokens-for-elevatio.patch 2020-05-04 01:33:29.000000000 +0100
@@ -0,0 +1,204 @@
+From 8959c13f2be7e2a31f27c8483ee2202692f00710 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
+Date: Sat, 5 Aug 2017 01:45:29 +0200
+Subject: [PATCH] ntdll: Add function to create new tokens for elevation
+ purposes.
+
+---
+ dlls/ntdll/ntdll.spec | 3 ++
+ dlls/ntdll/ntdll_misc.h | 3 ++
+ dlls/ntdll/process.c | 18 +++++++++
+ server/protocol.def | 8 ++++
+ server/security.h | 1 +
+ server/token.c | 84 +++++++++++++++++++++++++++++++++++++++++
+ 6 files changed, 117 insertions(+)
+
+--- a/dlls/ntdll/ntdll.spec
++++ b/dlls/ntdll/ntdll.spec
+@@ -1568,6 +1568,9 @@
+ # Virtual memory
+ @ cdecl __wine_locked_recvmsg(long ptr long)
+
++# Token
++@ cdecl __wine_create_default_token(long)
++
+ # Version
+ @ cdecl wine_get_version() NTDLL_wine_get_version
+ @ cdecl wine_get_build_id() NTDLL_wine_get_build_id
+--- a/dlls/ntdll/ntdll_misc.h
++++ b/dlls/ntdll/ntdll_misc.h
+@@ -91,6 +91,9 @@
+ extern char **build_envp( const WCHAR *envW ) DECLSPEC_HIDDEN;
+ extern NTSTATUS restart_process( RTL_USER_PROCESS_PARAMETERS *params, NTSTATUS status ) DECLSPEC_HIDDEN;
+
++/* token */
++extern HANDLE CDECL __wine_create_default_token(BOOL admin);
++
+ /* server support */
+ extern timeout_t server_start_time DECLSPEC_HIDDEN;
+ extern unsigned int server_cpus DECLSPEC_HIDDEN;
+--- a/dlls/ntdll/process.c
++++ b/dlls/ntdll/process.c
+@@ -125,6 +125,24 @@
+ return ret;
+ }
+
++/***********************************************************************
++ * __wine_create_default_token (NTDLL.@)
++ *
++ * Creates a default limited or admin token.
++ */
++HANDLE CDECL __wine_create_default_token( BOOL admin )
++{
++ HANDLE ret = NULL;
++ SERVER_START_REQ( create_token )
++ {
++ req->admin = admin;
++ if (!wine_server_call( req ))
++ ret = wine_server_ptr_handle( reply->token );
++ }
++ SERVER_END_REQ;
++ return ret;
++}
++
+ static UINT process_error_mode;
+
+ #define UNIMPLEMENTED_INFO_CLASS(c) \
+--- a/server/protocol.def
++++ b/server/protocol.def
+@@ -3747,6 +3747,14 @@
+ @END
+
+
++/* Create a new token */
++@REQ(create_token)
++ unsigned int admin; /* admin or limited token */
++@REPLY
++ obj_handle_t token; /* handle for new token */
++@END
++
++
+ /* Create I/O completion port */
+ @REQ(create_completion)
+ unsigned int access; /* desired access to a port */
+--- a/server/security.h
++++ b/server/security.h
+@@ -49,6 +49,7 @@
+ extern const PSID security_builtin_admins_sid;
+ extern const PSID security_domain_users_sid;
+ extern const PSID security_high_label_sid;
++extern const PSID security_medium_label_sid;
+
+
+ /* token functions */
+--- a/server/token.c
++++ b/server/token.c
+@@ -77,6 +77,7 @@
+ static const SID authenticated_user_sid = { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_AUTHENTICATED_USER_RID } };
+ static const SID local_system_sid = { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_LOCAL_SYSTEM_RID } };
+ static const SID high_label_sid = { SID_REVISION, 1, { SECURITY_MANDATORY_LABEL_AUTHORITY }, { SECURITY_MANDATORY_HIGH_RID } };
++static const SID medium_label_sid = { SID_REVISION, 1, { SECURITY_MANDATORY_LABEL_AUTHORITY }, { SECURITY_MANDATORY_MEDIUM_RID } };
+ static const SID_N(5) local_user_sid = { SID_REVISION, 5, { SECURITY_NT_AUTHORITY }, { SECURITY_NT_NON_UNIQUE, 0, 0, 0, 1000 } };
+ static const SID_N(2) builtin_admins_sid = { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS } };
+ static const SID_N(2) builtin_users_sid = { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_USERS } };
+@@ -93,6 +94,7 @@
+ const PSID security_builtin_users_sid = (PSID)&builtin_users_sid;
+ const PSID security_domain_users_sid = (PSID)&domain_users_sid;
+ const PSID security_high_label_sid = (PSID)&high_label_sid;
++const PSID security_medium_label_sid = (PSID)&medium_label_sid;
+
+ static luid_t prev_luid_value = { 1000, 0 };
+
+@@ -915,6 +917,64 @@
+ return token;
+ }
+
++static struct token *token_create_limited( void )
++{
++ struct token *token = NULL;
++ static const SID_IDENTIFIER_AUTHORITY nt_authority = { SECURITY_NT_AUTHORITY };
++ static const unsigned int alias_admins_subauth[] = { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS };
++ static const unsigned int alias_users_subauth[] = { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_USERS };
++ /* on Windows, this value changes every time the user logs on */
++ static const unsigned int logon_subauth[] = { SECURITY_LOGON_IDS_RID, 0, 1 /* FIXME: should be randomly generated when tokens are inherited by new processes */ };
++ PSID alias_admins_sid;
++ PSID alias_users_sid;
++ PSID logon_sid;
++ const SID *user_sid = security_unix_uid_to_sid( getuid() );
++ ACL *default_dacl = create_default_dacl( user_sid );
++
++ alias_admins_sid = security_sid_alloc( &nt_authority, sizeof(alias_admins_subauth)/sizeof(alias_admins_subauth[0]),
++ alias_admins_subauth );
++ alias_users_sid = security_sid_alloc( &nt_authority, sizeof(alias_users_subauth)/sizeof(alias_users_subauth[0]),
++ alias_users_subauth );
++ logon_sid = security_sid_alloc( &nt_authority, sizeof(logon_subauth)/sizeof(logon_subauth[0]),
++ logon_subauth );
++
++ if (alias_admins_sid && alias_users_sid && logon_sid && default_dacl)
++ {
++ const LUID_AND_ATTRIBUTES user_privs[] =
++ {
++ { SeChangeNotifyPrivilege , SE_PRIVILEGE_ENABLED },
++ { SeShutdownPrivilege , 0 },
++ { SeUndockPrivilege , 0 },
++ };
++ /* note: we don't include non-builtin groups here for the user -
++ * telling us these is the job of a client-side program */
++ const SID_AND_ATTRIBUTES user_groups[] =
++ {
++ { security_world_sid, SE_GROUP_ENABLED|SE_GROUP_ENABLED_BY_DEFAULT|SE_GROUP_MANDATORY },
++ { security_local_sid, SE_GROUP_ENABLED|SE_GROUP_ENABLED_BY_DEFAULT|SE_GROUP_MANDATORY },
++ { security_interactive_sid, SE_GROUP_ENABLED|SE_GROUP_ENABLED_BY_DEFAULT|SE_GROUP_MANDATORY },
++ { security_authenticated_user_sid, SE_GROUP_ENABLED|SE_GROUP_ENABLED_BY_DEFAULT|SE_GROUP_MANDATORY },
++ { security_domain_users_sid, SE_GROUP_ENABLED|SE_GROUP_ENABLED_BY_DEFAULT|SE_GROUP_MANDATORY|SE_GROUP_OWNER },
++ { alias_admins_sid, SE_GROUP_USE_FOR_DENY_ONLY },
++ { alias_users_sid, SE_GROUP_ENABLED|SE_GROUP_ENABLED_BY_DEFAULT|SE_GROUP_MANDATORY },
++ { logon_sid, SE_GROUP_ENABLED|SE_GROUP_ENABLED_BY_DEFAULT|SE_GROUP_MANDATORY|SE_GROUP_LOGON_ID },
++ };
++ static const TOKEN_SOURCE admin_source = {"SeMgr", {0, 0}};
++ token = create_token( TRUE, user_sid, user_groups, sizeof(user_groups)/sizeof(user_groups[0]),
++ user_privs, sizeof(user_privs)/sizeof(user_privs[0]), default_dacl,
++ admin_source, NULL, -1, TokenElevationTypeLimited, &medium_label_sid );
++ /* we really need a primary group */
++ assert( token->primary_group );
++ }
++
++ free( logon_sid );
++ free( alias_admins_sid );
++ free( alias_users_sid );
++ free( default_dacl );
++
++ return token;
++}
++
+ static struct privilege *token_find_privilege( struct token *token, const LUID *luid, int enabled_only )
+ {
+ struct privilege *privilege;
+@@ -1720,3 +1780,27 @@
+ release_object( token );
+ }
+ }
++
++DECL_HANDLER(create_token)
++{
++ struct token *token;
++ PSID label;
++
++ if (req->admin)
++ {
++ token = token_create_admin();
++ label = security_high_label_sid;
++ }
++ else
++ {
++ token = token_create_limited();
++ label = security_medium_label_sid;
++ }
++
++ if (token)
++ {
++ if (token_assign_label( token, label ))
++ reply->token = alloc_handle( current->process, token, TOKEN_ALL_ACCESS, 0 );
++ release_object( token );
++ }
++}
diff -Nru wine-development-5.5/debian/patches/advapi32-Token_Integrity_Level/0007-shell32-Implement-process-elevation-using-runas-verb.patch wine-development-5.5/debian/patches/advapi32-Token_Integrity_Level/0007-shell32-Implement-process-elevation-using-runas-verb.patch
--- wine-development-5.5/debian/patches/advapi32-Token_Integrity_Level/0007-shell32-Implement-process-elevation-using-runas-verb.patch 1970-01-01 01:00:00.000000000 +0100
+++ wine-development-5.5/debian/patches/advapi32-Token_Integrity_Level/0007-shell32-Implement-process-elevation-using-runas-verb.patch 2020-05-04 01:33:29.000000000 +0100
@@ -0,0 +1,61 @@
+From cf24ca0854a5b0dca2055f0991fd9a932125c65e Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
+Date: Sat, 5 Aug 2017 02:03:20 +0200
+Subject: shell32: Implement process elevation using runas verb.
+
+---
+ dlls/shell32/shlexec.c | 22 ++++++++++++++++++++--
+ 1 file changed, 20 insertions(+), 2 deletions(-)
+
+--- a/dlls/shell32/shlexec.c
++++ b/dlls/shell32/shlexec.c
+@@ -50,6 +50,8 @@
+
+ WINE_DEFAULT_DEBUG_CHANNEL(exec);
+
++extern HANDLE CDECL __wine_create_default_token(BOOL admin);
++
+ static const WCHAR wszOpen[] = {'o','p','e','n',0};
+ static const WCHAR wszExe[] = {'.','e','x','e',0};
+ static const WCHAR wszILPtr[] = {':','%','p',0};
+@@ -312,6 +314,8 @@
+ static UINT_PTR SHELL_ExecuteW(const WCHAR *lpCmd, WCHAR *env, BOOL shWait,
+ const SHELLEXECUTEINFOW *psei, LPSHELLEXECUTEINFOW psei_out)
+ {
++ static WCHAR runasW[] = {'r','u','n','a','s',0};
++ HANDLE token = NULL;
+ STARTUPINFOW startup;
+ PROCESS_INFORMATION info;
+ UINT_PTR retval = SE_ERR_NOASSOC;
+@@ -344,8 +348,20 @@
+ dwCreationFlags = CREATE_UNICODE_ENVIRONMENT;
+ if (!(psei->fMask & SEE_MASK_NO_CONSOLE))
+ dwCreationFlags |= CREATE_NEW_CONSOLE;
+- if (CreateProcessW(NULL, (LPWSTR)lpCmd, NULL, NULL, FALSE, dwCreationFlags, env,
+- lpDirectory, &startup, &info))
++
++ /* Spawning a process with runas verb means that the process should be
++ * executed with admin rights. This function ignores the manifest data,
++ * and allows programs to elevate rights on-demand. On Windows a complex
++ * RPC menchanism is used, using CreateProcessAsUser would fail because
++ * it can only be used to drop rights. */
++ if (psei->lpVerb && !strcmpiW(psei->lpVerb, runasW))
++ {
++ if (!(token = __wine_create_default_token(TRUE)))
++ ERR("Failed to create admin token\n");
++ }
++
++ if (CreateProcessAsUserW(token, NULL, (LPWSTR)lpCmd, NULL, NULL, FALSE,
++ dwCreationFlags, env, lpDirectory, &startup, &info))
+ {
+ /* Give 30 seconds to the app to come up, if desired. Probably only needed
+ when starting app immediately before making a DDE connection. */
+@@ -365,6 +381,8 @@
+ retval = ERROR_BAD_FORMAT;
+ }
+
++ if (token) CloseHandle(token);
++
+ TRACE("returning %lu\n", retval);
+
+ psei_out->hInstApp = (HINSTANCE)retval;
diff -Nru wine-development-5.5/debian/patches/advapi32-Token_Integrity_Level/0008-ntdll-Implement-process-token-elevation-through-mani.patch wine-development-5.5/debian/patches/advapi32-Token_Integrity_Level/0008-ntdll-Implement-process-token-elevation-through-mani.patch
--- wine-development-5.5/debian/patches/advapi32-Token_Integrity_Level/0008-ntdll-Implement-process-token-elevation-through-mani.patch 1970-01-01 01:00:00.000000000 +0100
+++ wine-development-5.5/debian/patches/advapi32-Token_Integrity_Level/0008-ntdll-Implement-process-token-elevation-through-mani.patch 2020-05-04 01:33:29.000000000 +0100
@@ -0,0 +1,136 @@
+From 6a09d34647aa517e45bc0bb20a92d0d94a1da888 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
+Date: Sat, 5 Aug 2017 03:39:55 +0200
+Subject: [PATCH] ntdll: Implement process token elevation through manifests.
+
+---
+ dlls/ntdll/loader.c | 37 +++++++++++++++++++++++++++++++++++++
+ server/process.c | 8 ++++++++
+ server/process.h | 1 +
+ server/protocol.def | 7 +++++++
+ server/token.c | 14 ++++++++++++++
+ 5 files changed, 67 insertions(+)
+
+--- a/dlls/ntdll/loader.c
++++ b/dlls/ntdll/loader.c
+@@ -3808,6 +3808,32 @@
+
+
+ /***********************************************************************
++ * elevate_process
++ */
++static void elevate_process( void )
++{
++ NTSTATUS status;
++ HANDLE token;
++
++ if (!(token = __wine_create_default_token( TRUE )))
++ {
++ ERR( "Failed to create admin token\n" );
++ return;
++ }
++
++ SERVER_START_REQ( replace_process_token )
++ {
++ req->token = wine_server_obj_handle( token );
++ if ((status = wine_server_call( req )))
++ ERR( "Failed to replace process token: %08x\n", status );
++ }
++ SERVER_END_REQ;
++
++ NtClose( token );
++}
++
++
++/***********************************************************************
+ * load_global_options
+ */
+ static void load_global_options(void)
+@@ -4236,6 +4262,7 @@
+ 's','y','s','t','e','m','3','2','\\',
+ 'k','e','r','n','e','l','3','2','.','d','l','l',0};
+ RTL_USER_PROCESS_PARAMETERS *params;
++ ACTIVATION_CONTEXT_RUN_LEVEL_INFORMATION runlevel;
+ WINE_MODREF *wm;
+ NTSTATUS status;
+ ANSI_STRING func_name;
+@@ -4327,6 +4354,16 @@
+
+ virtual_set_large_address_space();
+
++ /* elevate process if necessary */
++ status = RtlQueryInformationActivationContext( 0, NULL, 0, RunlevelInformationInActivationContext,
++ &runlevel, sizeof(runlevel), NULL );
++ if (!status && (runlevel.RunLevel == ACTCTX_RUN_LEVEL_HIGHEST_AVAILABLE ||
++ runlevel.RunLevel == ACTCTX_RUN_LEVEL_REQUIRE_ADMIN))
++ {
++ TRACE( "Application requested admin rights (run level %d)\n", runlevel.RunLevel );
++ elevate_process(); /* FIXME: the process exists with a wrong token for a short time */
++ }
++
+ /* the main exe needs to be the first in the load order list */
+ RemoveEntryList( &wm->ldr.InLoadOrderModuleList );
+ InsertHeadList( &peb->LdrData->InLoadOrderModuleList, &wm->ldr.InLoadOrderModuleList );
+--- a/server/process.c
++++ b/server/process.c
+@@ -1107,6 +1107,14 @@
+ return snapshot;
+ }
+
++/* replace the token of a process */
++void replace_process_token( struct process *process, struct token *new_token )
++{
++ release_object(current->process->token);
++ current->process->token = new_token;
++ grab_object(new_token);
++}
++
+ /* create a new process */
+ DECL_HANDLER(new_process)
+ {
+--- a/server/process.h
++++ b/server/process.h
+@@ -139,6 +139,7 @@
+ extern void detach_debugged_processes( struct thread *debugger );
+ extern struct process_snapshot *process_snap( int *count );
+ extern void enum_processes( int (*cb)(struct process*, void*), void *user);
++extern void replace_process_token( struct process *process, struct token *token );
+
+ /* console functions */
+ extern void inherit_console( struct thread *parent_thread, struct process *parent,
+--- a/server/protocol.def
++++ b/server/protocol.def
+@@ -3755,6 +3755,13 @@
+ @END
+
+
++/* Create a new token */
++@REQ(replace_process_token)
++ obj_handle_t token; /* new process token */
++@REPLY
++@END
++
++
+ /* Create I/O completion port */
+ @REQ(create_completion)
+ unsigned int access; /* desired access to a port */
+--- a/server/token.c
++++ b/server/token.c
+@@ -1804,3 +1804,17 @@
+ release_object( token );
+ }
+ }
++
++/* Replaces the token of the current process */
++DECL_HANDLER(replace_process_token)
++{
++ struct token *token;
++
++ if ((token = (struct token *)get_handle_obj( current->process, req->token,
++ TOKEN_ASSIGN_PRIMARY,
++ &token_ops )))
++ {
++ replace_process_token( current->process, token );
++ release_object( token );
++ }
++}
diff -Nru wine-development-5.5/debian/patches/advapi32-Token_Integrity_Level/0010-server-Implement-support-for-creating-processes-usin.patch wine-development-5.5/debian/patches/advapi32-Token_Integrity_Level/0010-server-Implement-support-for-creating-processes-usin.patch
--- wine-development-5.5/debian/patches/advapi32-Token_Integrity_Level/0010-server-Implement-support-for-creating-processes-usin.patch 1970-01-01 01:00:00.000000000 +0100
+++ wine-development-5.5/debian/patches/advapi32-Token_Integrity_Level/0010-server-Implement-support-for-creating-processes-usin.patch 2020-05-04 01:33:29.000000000 +0100
@@ -0,0 +1,300 @@
+From 51830c6683b199e79cb9e782ee51555054a4da7c Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
+Date: Sun, 6 Aug 2017 02:08:05 +0200
+Subject: [PATCH] server: Implement support for creating processes using a
+ token.
+
+---
+ dlls/kernelbase/process.c | 24 +++++++++++++-----------
+ dlls/ntdll/process.c | 3 ++-
+ server/process.c | 39 +++++++++++++++++++++++++++++++++++----
+ server/process.h | 2 +-
+ server/protocol.def | 1 +
+ server/request.c | 2 +-
+ server/security.h | 2 ++
+ server/token.c | 11 +++++++++++
+ 8 files changed, 66 insertions(+), 18 deletions(-)
+
+--- a/dlls/kernelbase/process.c
++++ b/dlls/kernelbase/process.c
+@@ -242,7 +242,7 @@
+ /***********************************************************************
+ * create_nt_process
+ */
+-static NTSTATUS create_nt_process( SECURITY_ATTRIBUTES *psa, SECURITY_ATTRIBUTES *tsa,
++static NTSTATUS create_nt_process( HANDLE token, SECURITY_ATTRIBUTES *psa, SECURITY_ATTRIBUTES *tsa,
+ BOOL inherit, DWORD flags, RTL_USER_PROCESS_PARAMETERS *params,
+ RTL_USER_PROCESS_INFORMATION *info, HANDLE parent )
+ {
+@@ -257,7 +257,7 @@
+ status = RtlCreateUserProcess( &nameW, OBJ_CASE_INSENSITIVE, params,
+ psa ? psa->lpSecurityDescriptor : NULL,
+ tsa ? tsa->lpSecurityDescriptor : NULL,
+- parent, inherit, 0, 0, info );
++ parent, inherit, 0, token, info );
+ RtlFreeUnicodeString( &nameW );
+ }
+ return status;
+@@ -267,7 +267,7 @@
+ /***********************************************************************
+ * create_vdm_process
+ */
+-static NTSTATUS create_vdm_process( SECURITY_ATTRIBUTES *psa, SECURITY_ATTRIBUTES *tsa,
++static NTSTATUS create_vdm_process( HANDLE token, SECURITY_ATTRIBUTES *psa, SECURITY_ATTRIBUTES *tsa,
+ BOOL inherit, DWORD flags, RTL_USER_PROCESS_PARAMETERS *params,
+ RTL_USER_PROCESS_INFORMATION *info )
+ {
+@@ -288,7 +288,7 @@
+ winevdm, params->ImagePathName.Buffer, params->CommandLine.Buffer );
+ RtlInitUnicodeString( ¶ms->ImagePathName, winevdm );
+ RtlInitUnicodeString( ¶ms->CommandLine, newcmdline );
+- status = create_nt_process( psa, tsa, inherit, flags, params, info, NULL );
++ status = create_nt_process( token, psa, tsa, inherit, flags, params, info, NULL );
+ HeapFree( GetProcessHeap(), 0, newcmdline );
+ return status;
+ }
+@@ -297,7 +297,7 @@
+ /***********************************************************************
+ * create_cmd_process
+ */
+-static NTSTATUS create_cmd_process( SECURITY_ATTRIBUTES *psa, SECURITY_ATTRIBUTES *tsa,
++static NTSTATUS create_cmd_process( HANDLE token, SECURITY_ATTRIBUTES *psa, SECURITY_ATTRIBUTES *tsa,
+ BOOL inherit, DWORD flags, RTL_USER_PROCESS_PARAMETERS *params,
+ RTL_USER_PROCESS_INFORMATION *info )
+ {
+@@ -316,7 +316,7 @@
+ swprintf( newcmdline, len, L"%s /s/c \"%s\"", comspec, params->CommandLine.Buffer );
+ RtlInitUnicodeString( ¶ms->ImagePathName, comspec );
+ RtlInitUnicodeString( ¶ms->CommandLine, newcmdline );
+- status = create_nt_process( psa, tsa, inherit, flags, params, info, NULL );
++ status = create_nt_process( token, psa, tsa, inherit, flags, params, info, NULL );
+ RtlFreeHeap( GetProcessHeap(), 0, newcmdline );
+ return status;
+ }
+@@ -448,7 +448,9 @@
+
+ TRACE( "app %s cmdline %s\n", debugstr_w(app_name), debugstr_w(cmd_line) );
+
+- if (token) FIXME( "Creating a process with a token is not yet implemented\n" );
++ /* FIXME: Starting a process which requires admin rights should fail
++ * with ERROR_ELEVATION_REQUIRED when no token is passed. */
++
+ if (new_token) FIXME( "No support for returning created process token\n" );
+
+ if (app_name)
+@@ -521,7 +523,7 @@
+ }
+ }
+
+- status = create_nt_process( process_attr, thread_attr, inherit, flags, params, &rtl_info, parent );
++ status = create_nt_process( token, process_attr, thread_attr, inherit, flags, params, &rtl_info, parent );
+ switch (status)
+ {
+ case STATUS_SUCCESS:
+@@ -530,7 +532,7 @@
+ case STATUS_INVALID_IMAGE_NE_FORMAT:
+ case STATUS_INVALID_IMAGE_PROTECT:
+ TRACE( "starting %s as Win16/DOS binary\n", debugstr_w(app_name) );
+- status = create_vdm_process( process_attr, thread_attr, inherit, flags, params, &rtl_info );
++ status = create_vdm_process( token, process_attr, thread_attr, inherit, flags, params, &rtl_info );
+ break;
+ case STATUS_INVALID_IMAGE_NOT_MZ:
+ /* check for .com or .bat extension */
+@@ -538,12 +540,12 @@
+ if (!wcsicmp( p, L".com" ) || !wcsicmp( p, L".pif" ))
+ {
+ TRACE( "starting %s as DOS binary\n", debugstr_w(app_name) );
+- status = create_vdm_process( process_attr, thread_attr, inherit, flags, params, &rtl_info );
++ status = create_vdm_process( token, process_attr, thread_attr, inherit, flags, params, &rtl_info );
+ }
+ else if (!wcsicmp( p, L".bat" ) || !wcsicmp( p, L".cmd" ))
+ {
+ TRACE( "starting %s as batch binary\n", debugstr_w(app_name) );
+- status = create_cmd_process( process_attr, thread_attr, inherit, flags, params, &rtl_info );
++ status = create_cmd_process( token, process_attr, thread_attr, inherit, flags, params, &rtl_info );
+ }
+ break;
+ }
+--- a/dlls/ntdll/process.c
++++ b/dlls/ntdll/process.c
+@@ -1667,7 +1667,7 @@
+ RTL_USER_PROCESS_PARAMETERS *params,
+ SECURITY_DESCRIPTOR *process_descr,
+ SECURITY_DESCRIPTOR *thread_descr,
+- HANDLE parent, BOOLEAN inherit, HANDLE debug, HANDLE exception,
++ HANDLE parent, BOOLEAN inherit, HANDLE debug, HANDLE token,
+ RTL_USER_PROCESS_INFORMATION *info )
+ {
+ NTSTATUS status;
+@@ -1735,6 +1735,7 @@
+ req->access = PROCESS_ALL_ACCESS;
+ req->cpu = pe_info.cpu;
+ req->info_size = startup_info_size;
++ req->token = wine_server_obj_handle( token );
+ wine_server_add_data( req, objattr, attr_len );
+ wine_server_add_data( req, startup_info, startup_info_size );
+ wine_server_add_data( req, params->Environment, env_size );
+--- a/server/process.c
++++ b/server/process.c
+@@ -491,7 +491,7 @@
+ /* create a new process */
+ /* if the function fails the fd is closed */
+ struct process *create_process( int fd, struct process *parent, int inherit_all,
+- const struct security_descriptor *sd )
++ const struct security_descriptor *sd, struct token *token )
+ {
+ struct process *process;
+
+@@ -568,7 +568,7 @@
+ : alloc_handle_table( process, 0 );
+ /* Note: for security reasons, starting a new process does not attempt
+ * to use the current impersonation token for the new process */
+- process->token = token_duplicate( parent->token, TRUE, 0, NULL, NULL, 0, NULL, 0 );
++ process->token = token_duplicate( token ? token : parent->token, TRUE, 0, NULL, NULL, 0, NULL, 0 );
+ process->affinity = parent->affinity;
+ }
+ if (!process->handles || !process->token) goto error;
+@@ -1124,6 +1124,7 @@
+ const struct security_descriptor *sd;
+ const struct object_attributes *objattr = get_req_object_attributes( &sd, &name, NULL );
+ struct process *process = NULL;
++ struct token *token = NULL;
+ struct process *parent;
+ struct thread *parent_thread = current;
+ int socket_fd = thread_get_inflight_fd( current, req->socket_fd );
+@@ -1177,10 +1178,39 @@
+ return;
+ }
+
++ if (req->token)
++ {
++ token = get_token_from_handle( req->token, TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY );
++ if (!token)
++ {
++ close( socket_fd );
++ return;
++ }
++ if (!token_is_primary( token ))
++ {
++ set_error( STATUS_BAD_TOKEN_TYPE );
++ release_object( token );
++ close( socket_fd );
++ return;
++ }
++ }
++
++ if (!req->info_size) /* create an orphaned process */
++ {
++ if ((process = create_process( socket_fd, NULL, 0, sd, token )))
++ {
++ create_thread( -1, process, NULL );
++ release_object( process );
++ }
++ if (token) release_object( token );
++ return;
++ }
++
+ /* build the startup info for a new process */
+ if (!(info = alloc_object( &startup_info_ops )))
+ {
+ close( socket_fd );
++ if (token) release_object( token );
+ release_object( parent );
+ return;
+ }
+@@ -1228,7 +1258,7 @@
+ #undef FIXUP_LEN
+ }
+
+- if (!(process = create_process( socket_fd, parent, req->inherit_all, sd ))) goto done;
++ if (!(process = create_process( socket_fd, parent, req->inherit_all, sd, token ))) goto done;
+
+ process->startup_info = (struct startup_info *)grab_object( info );
+
+@@ -1289,6 +1319,7 @@
+ reply->handle = alloc_handle_no_access_check( current->process, process, req->access, objattr->attributes );
+
+ done:
++ if (token) release_object( token );
+ if (process) release_object( process );
+ release_object( parent );
+ release_object( info );
+@@ -1322,7 +1353,7 @@
+ close( socket_fd );
+ return;
+ }
+- if (!(process = create_process( socket_fd, NULL, 0, NULL ))) return;
++ if (!(process = create_process( socket_fd, NULL, 0, NULL, NULL ))) return;
+ create_thread( -1, process, NULL );
+ release_object( process );
+ }
+--- a/server/process.h
++++ b/server/process.h
+@@ -118,7 +118,7 @@
+ extern void free_ptid( unsigned int id );
+ extern void *get_ptid_entry( unsigned int id );
+ extern struct process *create_process( int fd, struct process *parent, int inherit_all,
+- const struct security_descriptor *sd );
++ const struct security_descriptor *sd, struct token *token );
+ extern data_size_t init_process( struct thread *thread );
+ extern struct thread *get_process_first_thread( struct process *process );
+ extern struct process *get_process_from_id( process_id_t id );
+--- a/server/protocol.def
++++ b/server/protocol.def
+@@ -791,6 +791,7 @@
+ unsigned int access; /* access rights for process object */
+ client_cpu_t cpu; /* CPU that the new process will use */
+ data_size_t info_size; /* size of startup info */
++ obj_handle_t token; /* token for the new process */
+ VARARG(objattr,object_attributes); /* object attributes */
+ VARARG(info,startup_info,info_size); /* startup information */
+ VARARG(env,unicode_str); /* environment for new process */
+--- a/server/request.c
++++ b/server/request.c
+@@ -582,7 +582,7 @@
+ int client = accept( get_unix_fd( master_socket->fd ), (struct sockaddr *) &dummy, &len );
+ if (client == -1) return;
+ fcntl( client, F_SETFL, O_NONBLOCK );
+- if ((process = create_process( client, NULL, 0, NULL )))
++ if ((process = create_process( client, NULL, 0, NULL, NULL )))
+ {
+ create_thread( -1, process, NULL );
+ release_object( process );
+--- a/server/security.h
++++ b/server/security.h
+@@ -67,6 +67,8 @@
+ extern const SID *token_get_user( struct token *token );
+ extern const SID *token_get_primary_group( struct token *token );
+ extern int token_sid_present( struct token *token, const SID *sid, int deny);
++extern struct token *get_token_from_handle( obj_handle_t handle, unsigned int access );
++extern int token_is_primary( struct token *token );
+
+ static inline const ACE_HEADER *ace_next( const ACE_HEADER *ace )
+ {
+--- a/server/token.c
++++ b/server/token.c
+@@ -843,6 +843,12 @@
+ return ret;
+ }
+
++struct token *get_token_from_handle( obj_handle_t handle, unsigned int access )
++{
++ return (struct token *)get_handle_obj( current->process, handle,
++ access, &token_ops );
++}
++
+ struct token *token_create_admin( void )
+ {
+ struct token *token = NULL;
+@@ -1269,6 +1275,11 @@
+ return token->primary_group;
+ }
+
++int token_is_primary( struct token *token )
++{
++ return token->primary;
++}
++
+ int check_object_access(struct object *obj, unsigned int *access)
+ {
+ GENERIC_MAPPING mapping;
diff -Nru wine-development-5.5/debian/patches/advapi32-Token_Integrity_Level/0012-user32-Start-explorer.exe-using-limited-rights.patch wine-development-5.5/debian/patches/advapi32-Token_Integrity_Level/0012-user32-Start-explorer.exe-using-limited-rights.patch
--- wine-development-5.5/debian/patches/advapi32-Token_Integrity_Level/0012-user32-Start-explorer.exe-using-limited-rights.patch 1970-01-01 01:00:00.000000000 +0100
+++ wine-development-5.5/debian/patches/advapi32-Token_Integrity_Level/0012-user32-Start-explorer.exe-using-limited-rights.patch 2020-05-04 01:33:29.000000000 +0100
@@ -0,0 +1,73 @@
+From baff5c160cf7f1ac0011bf8f55d506bf0346e1fd Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
+Date: Mon, 7 Aug 2017 02:53:06 +0200
+Subject: [PATCH] user32: Start explorer.exe using limited rights.
+
+---
+ dlls/advapi32/tests/security.c | 4 ++--
+ dlls/user32/win.c | 12 ++++++++++--
+ 2 files changed, 12 insertions(+), 4 deletions(-)
+
+--- a/dlls/advapi32/tests/security.c
++++ b/dlls/advapi32/tests/security.c
+@@ -7201,7 +7201,7 @@
+ ret = GetTokenInformation(token4, TokenIntegrityLevel, buffer_integrity, sizeof(buffer_integrity), &size);
+ ok(ret, "GetTokenInformation failed with error %u\n", GetLastError());
+ tml = (TOKEN_MANDATORY_LABEL *)buffer_integrity;
+- todo_wine ok(EqualSid(tml->Label.Sid, &medium_level), "Expected medium integrity level\n");
++ ok(EqualSid(tml->Label.Sid, &medium_level), "Expected medium integrity level\n");
+
+ size = 0;
+ ret = GetKernelObjectSecurity(token4, LABEL_SECURITY_INFORMATION, NULL, 0, &size);
+@@ -7657,7 +7657,7 @@
+ ret = GetTokenInformation(token, TokenIntegrityLevel, buffer_integrity, sizeof(buffer_integrity), &size);
+ ok(ret, "GetTokenInformation failed with error %u\n", GetLastError());
+ tml = (TOKEN_MANDATORY_LABEL *)buffer_integrity;
+- todo_wine ok(EqualSid(tml->Label.Sid, &medium_level), "Expected medium integrity level\n");
++ ok(EqualSid(tml->Label.Sid, &medium_level), "Expected medium integrity level\n");
+
+ HeapFree(GetProcessHeap(), 0, sd);
+ }
+--- a/dlls/user32/win.c
++++ b/dlls/user32/win.c
+@@ -44,6 +44,8 @@
+ #define NB_USER_HANDLES ((LAST_USER_HANDLE - FIRST_USER_HANDLE + 1) >> 1)
+ #define USER_HANDLE_TO_INDEX(hwnd) ((LOWORD(hwnd) - FIRST_USER_HANDLE) >> 1)
+
++extern HANDLE CDECL __wine_create_default_token(BOOL admin);
++
+ static DWORD process_layout = ~0u;
+
+ static struct list window_surfaces = LIST_INIT( window_surfaces );
+@@ -2089,6 +2091,7 @@
+ WCHAR app[MAX_PATH + ARRAY_SIZE( explorer )];
+ WCHAR cmdline[MAX_PATH + ARRAY_SIZE( explorer ) + ARRAY_SIZE( args )];
+ WCHAR desktop[MAX_PATH];
++ HANDLE token;
+ void *redir;
+
+ SERVER_START_REQ( set_user_object_info )
+@@ -2121,9 +2124,12 @@
+ strcpyW( cmdline, app );
+ strcatW( cmdline, args );
+
++ if (!(token = __wine_create_default_token( FALSE )))
++ ERR( "Failed to create limited token\n" );
++
+ Wow64DisableWow64FsRedirection( &redir );
+- if (CreateProcessW( app, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS,
+- NULL, windir, &si, &pi ))
++ if (CreateProcessAsUserW( token, app, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS,
++ NULL, windir, &si, &pi ))
+ {
+ TRACE( "started explorer pid %04x tid %04x\n", pi.dwProcessId, pi.dwThreadId );
+ WaitForInputIdle( pi.hProcess, 10000 );
+@@ -2133,6 +2139,8 @@
+ else WARN( "failed to start explorer, err %d\n", GetLastError() );
+ Wow64RevertWow64FsRedirection( redir );
+
++ if (token) CloseHandle( token );
++
+ SERVER_START_REQ( get_desktop_window )
+ {
+ req->force = 1;
diff -Nru wine-development-5.5/debian/patches/advapi32-Token_Integrity_Level/0013-server-Correctly-assign-security-labels-for-tokens.patch wine-development-5.5/debian/patches/advapi32-Token_Integrity_Level/0013-server-Correctly-assign-security-labels-for-tokens.patch
--- wine-development-5.5/debian/patches/advapi32-Token_Integrity_Level/0013-server-Correctly-assign-security-labels-for-tokens.patch 1970-01-01 01:00:00.000000000 +0100
+++ wine-development-5.5/debian/patches/advapi32-Token_Integrity_Level/0013-server-Correctly-assign-security-labels-for-tokens.patch 2020-05-04 01:33:29.000000000 +0100
@@ -0,0 +1,211 @@
+From 6d8fd34cabbcbc64062675be610fb8704fcdc3ec Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
+Date: Mon, 7 Aug 2017 03:33:26 +0200
+Subject: [PATCH] server: Correctly assign security labels for tokens.
+
+---
+ dlls/advapi32/tests/security.c | 21 ++++++++++-----------
+ server/process.c | 8 +-------
+ server/security.h | 2 +-
+ server/token.c | 41 ++++++++++++++++++++++++-----------------
+ 4 files changed, 36 insertions(+), 36 deletions(-)
+
+--- a/dlls/advapi32/tests/security.c
++++ b/dlls/advapi32/tests/security.c
+@@ -7103,7 +7103,6 @@
+ defaulted = TRUE;
+ ret = GetSecurityDescriptorDacl(sd2, &present, &acl2, &defaulted);
+ ok(ret, "GetSecurityDescriptorDacl failed with error %u\n", GetLastError());
+- todo_wine
+ ok(present, "DACL not present\n");
+
+ if (present)
+@@ -7224,7 +7223,7 @@
+ ok(ret, "GetAce failed with error %u\n", GetLastError());
+ ok(ace->Header.AceType == SYSTEM_MANDATORY_LABEL_ACE_TYPE,
+ "Unexpected ACE type %#x\n", ace->Header.AceType);
+- todo_wine ok(EqualSid(&ace->SidStart, &medium_level),
++ ok(EqualSid(&ace->SidStart, &medium_level),
+ "Expected medium integrity level\n");
+ }
+
+@@ -7277,8 +7276,8 @@
+ sacl = NULL;
+ ret = GetSecurityDescriptorSacl(sd3, &present, &sacl, &defaulted);
+ ok(ret, "GetSecurityDescriptorSacl failed with error %u\n", GetLastError());
+- todo_wine ok(present, "No SACL in the security descriptor\n");
+- todo_wine ok(sacl != NULL, "NULL SACL in the security descriptor\n");
++ ok(present, "No SACL in the security descriptor\n");
++ ok(sacl != NULL, "NULL SACL in the security descriptor\n");
+
+ if (sacl)
+ {
+@@ -7327,8 +7326,8 @@
+ sacl = NULL;
+ ret = GetSecurityDescriptorSacl(sd3, &present, &sacl, &defaulted);
+ ok(ret, "GetSecurityDescriptorSacl failed with error %u\n", GetLastError());
+- todo_wine ok(present, "No SACL in the security descriptor\n");
+- todo_wine ok(sacl != NULL, "NULL SACL in the security descriptor\n");
++ ok(present, "No SACL in the security descriptor\n");
++ ok(sacl != NULL, "NULL SACL in the security descriptor\n");
+
+ if (sacl)
+ {
+@@ -7392,8 +7391,8 @@
+
+ ret = GetSecurityDescriptorSacl(sd3, &present, &sacl, &defaulted);
+ ok(ret, "GetSecurityDescriptorSacl failed with error %u\n", GetLastError());
+- todo_wine ok(present, "No SACL in the security descriptor\n");
+- todo_wine ok(sacl != NULL, "NULL SACL in the security descriptor\n");
++ ok(present, "No SACL in the security descriptor\n");
++ ok(sacl != NULL, "NULL SACL in the security descriptor\n");
+
+ if (sacl)
+ {
+@@ -7430,8 +7429,8 @@
+ sacl = NULL;
+ ret = GetSecurityDescriptorSacl(sd3, &present, &sacl, &defaulted);
+ ok(ret, "GetSecurityDescriptorSacl failed with error %u\n", GetLastError());
+- todo_wine ok(present, "No SACL in the security descriptor\n");
+- todo_wine ok(sacl != NULL, "NULL SACL in the security descriptor\n");
++ ok(present, "No SACL in the security descriptor\n");
++ ok(sacl != NULL, "NULL SACL in the security descriptor\n");
+
+ if (sacl)
+ {
+@@ -7650,7 +7649,7 @@
+ ok(ret, "GetAce failed with error %u\n", GetLastError());
+ ok(ace_label->Header.AceType == SYSTEM_MANDATORY_LABEL_ACE_TYPE,
+ "Unexpected ACE type %#x\n", ace_label->Header.AceType);
+- todo_wine ok(EqualSid(&ace_label->SidStart, &medium_level),
++ ok(EqualSid(&ace_label->SidStart, &medium_level),
+ "Expected medium integrity level\n");
+
+ memset(buffer_integrity, 0, sizeof(buffer_integrity));
+--- a/server/process.c
++++ b/server/process.c
+@@ -568,17 +568,11 @@
+ : alloc_handle_table( process, 0 );
+ /* Note: for security reasons, starting a new process does not attempt
+ * to use the current impersonation token for the new process */
+- process->token = token_duplicate( token ? token : parent->token, TRUE, 0, NULL, NULL, 0, NULL, 0 );
++ process->token = token_duplicate( token ? token : parent->token, TRUE, 0, NULL, NULL, 0, NULL, 0, NULL );
+ process->affinity = parent->affinity;
+ }
+ if (!process->handles || !process->token) goto error;
+
+- /* Assign a high security label to the token. The default would be medium
+- * but Wine provides admin access to all applications right now so high
+- * makes more sense for the time being. */
+- if (!token_assign_label( process->token, security_high_label_sid ))
+- goto error;
+-
+ set_fd_events( process->msg_fd, POLLIN ); /* start listening to events */
+ return process;
+
+--- a/server/security.h
++++ b/server/security.h
+@@ -59,7 +59,7 @@
+ extern struct token *token_duplicate( struct token *src_token, unsigned primary,
+ int impersonation_level, const struct security_descriptor *sd,
+ const LUID_AND_ATTRIBUTES *filter_privileges, unsigned int priv_count,
+- const SID *filter_groups, unsigned int group_count );
++ const SID *filter_groups, unsigned int group_count, struct token *impersonation );
+ extern int token_check_privileges( struct token *token, int all_required,
+ const LUID_AND_ATTRIBUTES *reqprivs,
+ unsigned int count, LUID_AND_ATTRIBUTES *usedprivs);
+--- a/server/token.c
++++ b/server/token.c
+@@ -675,7 +675,7 @@
+ struct token *token_duplicate( struct token *src_token, unsigned primary,
+ int impersonation_level, const struct security_descriptor *sd,
+ const LUID_AND_ATTRIBUTES *filter_privileges, unsigned int priv_count,
+- const SID *filter_groups, unsigned int group_count)
++ const SID *filter_groups, unsigned int group_count, struct token *impersonation)
+ {
+ const luid_t *modified_id =
+ primary || (impersonation_level == src_token->impersonation_level) ?
+@@ -742,6 +742,12 @@
+ if (sd) default_set_sd( &token->obj, sd, OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
+ DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION );
+
++ if (!token_assign_label( token, impersonation ? (PSID)impersonation->integrity : (PSID)token->integrity ))
++ {
++ release_object( token );
++ return NULL;
++ }
++
+ return token;
+ }
+
+@@ -913,6 +919,12 @@
+ admin_source, NULL, -1, TokenElevationTypeFull, &high_label_sid );
+ /* we really need a primary group */
+ assert( token->primary_group );
++
++ if (!token_assign_label( token, (PSID)token->integrity ))
++ {
++ release_object( token );
++ token = NULL;
++ }
+ }
+
+ free( logon_sid );
+@@ -971,6 +983,12 @@
+ admin_source, NULL, -1, TokenElevationTypeLimited, &medium_label_sid );
+ /* we really need a primary group */
+ assert( token->primary_group );
++
++ if (!token_assign_label( token, (PSID)token->integrity ))
++ {
++ release_object( token );
++ token = NULL;
++ }
+ }
+
+ free( logon_sid );
+@@ -1439,7 +1457,8 @@
+ TOKEN_DUPLICATE,
+ &token_ops )))
+ {
+- struct token *token = token_duplicate( src_token, req->primary, req->impersonation_level, sd, NULL, 0, NULL, 0 );
++ struct token *token = token_duplicate( src_token, req->primary, req->impersonation_level, sd, NULL, 0,
++ NULL, 0, thread_get_impersonation_token( current ) );
+ if (token)
+ {
+ unsigned int access = req->access ? req->access : get_handle_access( current->process, req->handle );
+@@ -1469,7 +1488,7 @@
+ group_count = get_sid_count( filter_groups, get_req_data_size() - priv_count * sizeof(LUID_AND_ATTRIBUTES) );
+
+ token = token_duplicate( src_token, src_token->primary, src_token->impersonation_level, NULL,
+- filter_privileges, priv_count, filter_groups, group_count );
++ filter_privileges, priv_count, filter_groups, group_count, thread_get_impersonation_token( current ) );
+ if (token)
+ {
+ unsigned int access = get_handle_access( current->process, req->handle );
+@@ -1795,23 +1814,11 @@
+ DECL_HANDLER(create_token)
+ {
+ struct token *token;
+- PSID label;
+-
+- if (req->admin)
+- {
+- token = token_create_admin();
+- label = security_high_label_sid;
+- }
+- else
+- {
+- token = token_create_limited();
+- label = security_medium_label_sid;
+- }
+
++ token = req->admin ? token_create_admin() : token_create_limited();
+ if (token)
+ {
+- if (token_assign_label( token, label ))
+- reply->token = alloc_handle( current->process, token, TOKEN_ALL_ACCESS, 0 );
++ reply->token = alloc_handle( current->process, token, TOKEN_ALL_ACCESS, 0 );
+ release_object( token );
+ }
+ }
diff -Nru wine-development-5.5/debian/patches/advapi32-Token_Integrity_Level/0014-programs-runas-Basic-implementation-for-starting-pro.patch wine-development-5.5/debian/patches/advapi32-Token_Integrity_Level/0014-programs-runas-Basic-implementation-for-starting-pro.patch
--- wine-development-5.5/debian/patches/advapi32-Token_Integrity_Level/0014-programs-runas-Basic-implementation-for-starting-pro.patch 1970-01-01 01:00:00.000000000 +0100
+++ wine-development-5.5/debian/patches/advapi32-Token_Integrity_Level/0014-programs-runas-Basic-implementation-for-starting-pro.patch 2020-05-04 01:33:29.000000000 +0100
@@ -0,0 +1,327 @@
+From 5bf0baa79c46ec44dfd5e1340e96ff9289bc37f8 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
+Date: Sun, 6 Aug 2017 03:15:34 +0200
+Subject: [PATCH] programs/runas: Basic implementation for starting processes
+ with a different trustlevel.
+
+---
+ configure.ac | 1 +
+ programs/runas/Makefile.in | 8 ++
+ programs/runas/runas.c | 214 +++++++++++++++++++++++++++++++++++++
+ programs/runas/runas.h | 26 +++++
+ programs/runas/runas.rc | 39 +++++++
+ 5 files changed, 288 insertions(+)
+ create mode 100644 programs/runas/Makefile.in
+ create mode 100644 programs/runas/runas.c
+ create mode 100644 programs/runas/runas.h
+ create mode 100644 programs/runas/runas.rc
+
+--- a/configure.ac
++++ b/configure.ac
+@@ -3945,6 +3945,7 @@
+ WINE_CONFIG_MAKEFILE(programs/regsvcs)
+ WINE_CONFIG_MAKEFILE(programs/regsvr32)
+ WINE_CONFIG_MAKEFILE(programs/rpcss)
++WINE_CONFIG_MAKEFILE(programs/runas)
+ WINE_CONFIG_MAKEFILE(programs/rundll.exe16,enable_win16)
+ WINE_CONFIG_MAKEFILE(programs/rundll32)
+ WINE_CONFIG_MAKEFILE(programs/sc)
+--- /dev/null
++++ b/programs/runas/Makefile.in
+@@ -0,0 +1,8 @@
++MODULE = runas.exe
++APPMODE = -mconsole -municode -mno-cygwin
++IMPORTS = advapi32 user32
++
++C_SRCS = \
++ runas.c
++
++RC_SRCS = runas.rc
+--- /dev/null
++++ b/programs/runas/runas.c
+@@ -0,0 +1,214 @@
++/*
++ * runas.exe implementation
++ *
++ * Copyright 2017 Michael Müller
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
++ */
++
++#include <windows.h>
++#include <wchar.h>
++#include <wine/debug.h>
++
++#include "runas.h"
++
++WINE_DEFAULT_DEBUG_CHANNEL(runas);
++
++extern HANDLE CDECL __wine_create_default_token(BOOL admin);
++
++struct cmdinfo
++{
++ WCHAR *program;
++ DWORD trustlevel;
++};
++
++static void output_writeconsole(const WCHAR *str, DWORD wlen)
++{
++ DWORD count, ret;
++
++ ret = WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), str, wlen, &count, NULL);
++ if (!ret)
++ {
++ DWORD len;
++ char *msgA;
++
++ /* On Windows WriteConsoleW() fails if the output is redirected. So fall
++ * back to WriteFile(), assuming the console encoding is still the right
++ * one in that case.
++ */
++ len = WideCharToMultiByte(GetConsoleOutputCP(), 0, str, wlen, NULL, 0, NULL, NULL);
++ msgA = HeapAlloc(GetProcessHeap(), 0, len * sizeof(char));
++ if (!msgA) return;
++
++ WideCharToMultiByte(GetConsoleOutputCP(), 0, str, wlen, msgA, len, NULL, NULL);
++ WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), msgA, len, &count, FALSE);
++ HeapFree(GetProcessHeap(), 0, msgA);
++ }
++}
++
++static void output_formatstring(const WCHAR *fmt, __ms_va_list va_args)
++{
++ WCHAR *str;
++ DWORD len;
++
++ SetLastError(NO_ERROR);
++ len = FormatMessageW(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,
++ fmt, 0, 0, (WCHAR *)&str, 0, &va_args);
++ if (len == 0 && GetLastError() != NO_ERROR)
++ {
++ WINE_FIXME("Could not format string: le=%u, fmt=%s\n", GetLastError(), wine_dbgstr_w(fmt));
++ return;
++ }
++ output_writeconsole(str, len);
++ LocalFree(str);
++}
++
++static void WINAPIV output_message(unsigned int id, ...)
++{
++ WCHAR fmt[1024];
++ __ms_va_list va_args;
++
++ if (!LoadStringW(GetModuleHandleW(NULL), id, fmt, sizeof(fmt)/sizeof(WCHAR)))
++ {
++ WINE_FIXME("LoadString failed with %d\n", GetLastError());
++ return;
++ }
++ __ms_va_start(va_args, id);
++ output_formatstring(fmt, va_args);
++ __ms_va_end(va_args);
++}
++
++static void show_usage(void)
++{
++ output_message(STRING_USAGE);
++}
++
++static void show_trustlevels(void)
++{
++ output_message(STRING_TRUSTLEVELS);
++ ExitProcess(0);
++}
++
++static WCHAR *starts_with(WCHAR *str, const WCHAR *start)
++{
++ DWORD start_len = lstrlenW(start);
++ if (lstrlenW(str) < start_len)
++ return NULL;
++ if (wcsncmp(str, start, start_len))
++ return NULL;
++ return str + start_len;
++}
++
++static BOOL parse_command_line(int argc, WCHAR *argv[], struct cmdinfo *cmd)
++{
++ static const WCHAR showtrustlevelsW[] = {'/','s','h','o','w','t','r','u','s','t','l','e','v','e','l','s',0};
++ static const WCHAR trustlevelW[] = {'/','t','r','u','s','t','l','e','v','e','l',':',0};
++ int i;
++
++ memset(cmd, 0, sizeof(*cmd));
++
++ for (i = 1; i < argc; i++)
++ {
++ if (argv[i][0] == '/')
++ {
++ WCHAR *arg;
++
++ if ((arg = starts_with(argv[i], trustlevelW)))
++ cmd->trustlevel = wcstoul(arg, NULL, 0);
++ else if (!lstrcmpW(argv[i], showtrustlevelsW))
++ show_trustlevels();
++ else
++ WINE_FIXME("Ignoring parameter %s\n", wine_dbgstr_w(argv[i]));
++ }
++ else if (argv[i][0])
++ {
++ if (cmd->program) return FALSE;
++ cmd->program = argv[i];
++ }
++ }
++
++ return TRUE;
++}
++
++static BOOL start_process(struct cmdinfo *cmd)
++{
++ PROCESS_INFORMATION info;
++ STARTUPINFOW startup;
++ HANDLE token = NULL;
++ BOOL ret;
++
++ if (cmd->trustlevel == 0x20000)
++ {
++ if (!(token = __wine_create_default_token(FALSE)))
++ ERR("Failed to create limited token\n");
++ }
++
++ memset(&startup, 0, sizeof(startup));
++ startup.cb = sizeof(startup);
++ ret = CreateProcessAsUserW(token, NULL, cmd->program, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info);
++ if (ret)
++ {
++ CloseHandle(info.hProcess);
++ CloseHandle(info.hThread);
++ }
++ else
++ {
++ DWORD error = GetLastError();
++ WCHAR *str;
++
++ if (FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER |
++ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, error, 0, (WCHAR *)&str, 0, NULL))
++ {
++ output_message(STRING_START_ERROR, cmd->program, error, str);
++ LocalFree(str);
++ }
++ else
++ WINE_FIXME("Failed to format error: %u\n", error);
++ }
++
++ if (token) CloseHandle(token);
++ return ret;
++}
++
++int wmain(int argc, WCHAR *argv[])
++{
++ struct cmdinfo cmd;
++
++ if (argc <= 1)
++ {
++ show_usage();
++ return 0;
++ }
++
++ if (!parse_command_line(argc, argv, &cmd))
++ {
++ show_usage();
++ return 1;
++ }
++
++ if (!cmd.program)
++ {
++ show_usage();
++ return 1;
++ }
++
++ if (cmd.trustlevel && cmd.trustlevel != 0x20000)
++ {
++ output_message(STRING_UNHANDLED_TRUSTLEVEL, cmd.trustlevel);
++ return 1;
++ }
++
++ return start_process(&cmd);
++}
+--- /dev/null
++++ b/programs/runas/runas.h
+@@ -0,0 +1,26 @@
++/*
++ * runas.exe implementation
++ *
++ * Copyright 2017 Michael Müller
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
++ */
++
++#include <windef.h>
++
++#define STRING_USAGE 101
++#define STRING_UNHANDLED_TRUSTLEVEL 102
++#define STRING_TRUSTLEVELS 103
++#define STRING_START_ERROR 104
+--- /dev/null
++++ b/programs/runas/runas.rc
+@@ -0,0 +1,39 @@
++/*
++ * runas.exe implementation
++ *
++ * Copyright 2017 Michael Müller
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
++ */
++
++#include "runas.h"
++
++#pragma makedep po
++
++LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT
++
++STRINGTABLE
++{
++ STRING_USAGE, "Usage of RUNAS:\n\n\
++\RUNAS /trustlevel:<trustlevel> program\n\n\
++\ /showtrustlevels Show possible trustlevels\n\
++\ /trustlevel <trustlevel> should be listed in /showtrustlevels\n\
++\ program Program to start\n\n"
++ STRING_UNHANDLED_TRUSTLEVEL, "runas: Unhandled trustlevel 0x%1!x!\n"
++ STRING_TRUSTLEVELS, "The following trustlevels are supported:\n\
++0x20000 (standard user)\n"
++ STRING_START_ERROR, "RUNAS-Error: %1 could not be started\n\
++ %2!u!: %3\n"
++}
diff -Nru wine-development-5.5/debian/patches/advapi32-Token_Integrity_Level/0015-ntdll-Add-semi-stub-for-TokenLinkedToken-info-class.patch wine-development-5.5/debian/patches/advapi32-Token_Integrity_Level/0015-ntdll-Add-semi-stub-for-TokenLinkedToken-info-class.patch
--- wine-development-5.5/debian/patches/advapi32-Token_Integrity_Level/0015-ntdll-Add-semi-stub-for-TokenLinkedToken-info-class.patch 1970-01-01 01:00:00.000000000 +0100
+++ wine-development-5.5/debian/patches/advapi32-Token_Integrity_Level/0015-ntdll-Add-semi-stub-for-TokenLinkedToken-info-class.patch 2020-05-04 01:33:29.000000000 +0100
@@ -0,0 +1,53 @@
+From 6d4621ddba8139747345c05f6251bae9b3c68e39 Mon Sep 17 00:00:00 2001
+From: Sebastian Lackner <sebastian@fds-team.de>
+Date: Mon, 7 Aug 2017 15:28:33 +0200
+Subject: ntdll: Add semi-stub for TokenLinkedToken info class.
+
+---
+ dlls/ntdll/nt.c | 28 +++++++++++++++++++++++++++-
+ 1 file changed, 27 insertions(+), 1 deletion(-)
+
+--- a/dlls/ntdll/nt.c
++++ b/dlls/ntdll/nt.c
+@@ -426,7 +426,7 @@
+ 0, /* TokenAuditPolicy */
+ 0, /* TokenOrigin */
+ sizeof(TOKEN_ELEVATION_TYPE), /* TokenElevationType */
+- 0, /* TokenLinkedToken */
++ sizeof(TOKEN_LINKED_TOKEN), /* TokenLinkedToken */
+ sizeof(TOKEN_ELEVATION), /* TokenElevation */
+ 0, /* TokenHasRestrictions */
+ 0, /* TokenAccessInformation */
+@@ -667,6 +667,32 @@
+ }
+ SERVER_END_REQ;
+ break;
++ case TokenLinkedToken:
++ SERVER_START_REQ( get_token_elevation_type )
++ {
++ TOKEN_LINKED_TOKEN *linked_token = tokeninfo;
++ req->handle = wine_server_obj_handle( token );
++ status = wine_server_call( req );
++ if (status == STATUS_SUCCESS)
++ {
++ HANDLE token;
++ /* FIXME: On Wine we do not have real linked tokens yet. Typically, a
++ * program running with admin privileges is linked to a limited token,
++ * and vice versa. We just create a new token instead of storing links
++ * on the wineserver side. Using TokenLinkedToken twice should return
++ * back the original token. */
++ if ((reply->elevation == TokenElevationTypeFull || reply->elevation == TokenElevationTypeLimited) &&
++ (token = __wine_create_default_token( reply->elevation != TokenElevationTypeFull )))
++ {
++ status = NtDuplicateToken( token, 0, NULL, SecurityIdentification, TokenImpersonation, &linked_token->LinkedToken );
++ NtClose( token );
++ }
++ else
++ status = STATUS_NO_TOKEN;
++ }
++ }
++ SERVER_END_REQ;
++ break;
+ case TokenElevation:
+ SERVER_START_REQ( get_token_elevation_type )
+ {
diff -Nru wine-development-5.5/debian/patches/advapi32-Token_Integrity_Level/definition wine-development-5.5/debian/patches/advapi32-Token_Integrity_Level/definition
--- wine-development-5.5/debian/patches/advapi32-Token_Integrity_Level/definition 1970-01-01 01:00:00.000000000 +0100
+++ wine-development-5.5/debian/patches/advapi32-Token_Integrity_Level/definition 2020-05-04 01:33:29.000000000 +0100
@@ -0,0 +1,4 @@
+Fixes: [40613] Basic implementation for token integrity levels and UAC handling
+Fixes: [39262] Run explorer.exe as unevaluated process
+Depends: advapi32-CreateRestrictedToken
+Depends: Staging
diff -Nru wine-development-5.5/debian/patches/debianization/addons.patch wine-development-5.5/debian/patches/debianization/addons.patch
--- wine-development-5.5/debian/patches/debianization/addons.patch 2020-03-30 03:48:44.000000000 +0100
+++ wine-development-5.5/debian/patches/debianization/addons.patch 2020-05-04 01:33:29.000000000 +0100
@@ -4,7 +4,7 @@
--- a/dlls/appwiz.cpl/addons.c
+++ b/dlls/appwiz.cpl/addons.c
-@@ -210,7 +210,7 @@ static enum install_res install_from_dos
+@@ -210,7 +210,7 @@
lstrcpyW( path, dir );
if (!wcsncmp( path, L"\\??\\", 4 )) path[1] = '\\'; /* change \??\ into \\?\ */
@@ -13,7 +13,7 @@
lstrcpyW( path + len, subdir );
lstrcatW( path, L"\\" );
-@@ -314,10 +314,14 @@ static enum install_res install_from_def
+@@ -314,10 +314,14 @@
}
if (ret == INSTALL_NEXT)
diff -Nru wine-development-5.5/debian/patches/debianization/makefile.patch wine-development-5.5/debian/patches/debianization/makefile.patch
--- wine-development-5.5/debian/patches/debianization/makefile.patch 2020-03-30 03:48:44.000000000 +0100
+++ wine-development-5.5/debian/patches/debianization/makefile.patch 2020-05-04 01:33:29.000000000 +0100
@@ -3,7 +3,7 @@
--- a/Makefile.in
+++ b/Makefile.in
-@@ -27,9 +27,9 @@ datarootdir = @datarootdir@
+@@ -27,9 +27,9 @@
datadir = @datadir@
mandir = @mandir@
includedir = @includedir@
diff -Nru wine-development-5.5/debian/patches/debianization/mingw.patch wine-development-5.5/debian/patches/debianization/mingw.patch
--- wine-development-5.5/debian/patches/debianization/mingw.patch 2020-04-01 05:07:21.000000000 +0100
+++ wine-development-5.5/debian/patches/debianization/mingw.patch 2020-05-04 01:33:29.000000000 +0100
@@ -3,7 +3,7 @@
--- a/configure.ac
+++ b/configure.ac
-@@ -1026,12 +1026,11 @@ then
+@@ -1026,12 +1026,11 @@
then
ac_save_CC="$CC"
saved_CFLAGS=$CFLAGS
diff -Nru wine-development-5.5/debian/patches/ntdll-Builtin_Prot/0001-ntdll-Fix-holes-in-ELF-mappings.patch wine-development-5.5/debian/patches/ntdll-Builtin_Prot/0001-ntdll-Fix-holes-in-ELF-mappings.patch
--- wine-development-5.5/debian/patches/ntdll-Builtin_Prot/0001-ntdll-Fix-holes-in-ELF-mappings.patch 1970-01-01 01:00:00.000000000 +0100
+++ wine-development-5.5/debian/patches/ntdll-Builtin_Prot/0001-ntdll-Fix-holes-in-ELF-mappings.patch 2020-05-04 01:33:29.000000000 +0100
@@ -0,0 +1,83 @@
+From 7c2a302a95f6be16dbb5f6b3379e57d411a5310a Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
+Date: Thu, 1 Jun 2017 06:04:53 +0200
+Subject: ntdll: Fix holes in ELF mappings. (v2)
+
+Based on a patch by Andrew Wesie.
+---
+ dlls/ntdll/virtual.c | 23 +++++++++++++++++++++++
+ dlls/psapi/tests/psapi_main.c | 14 +++++++++++++-
+ 2 files changed, 36 insertions(+), 1 deletion(-)
+
+--- a/dlls/ntdll/virtual.c
++++ b/dlls/ntdll/virtual.c
+@@ -476,6 +476,16 @@
+
+
+ /***********************************************************************
++ * is_system_range
++ */
++static inline BOOL is_system_range( const void *addr, size_t size )
++{
++ struct file_view *view = VIRTUAL_FindView( addr, size );
++ return view && (view->protect & VPROT_SYSTEM);
++}
++
++
++/***********************************************************************
+ * find_view_range
+ *
+ * Find the first view overlapping at least part of the specified range.
+@@ -2245,6 +2255,19 @@
+ if (VIRTUAL_GetUnixProt( get_page_vprot( page )) & PROT_READ) ret = STATUS_SUCCESS;
+ else update_shared_data = FALSE;
+ }
++ else if (!err && (VIRTUAL_GetUnixProt( vprot ) & PROT_READ) && is_system_range( page, page_size ))
++ {
++ int unix_prot = VIRTUAL_GetUnixProt( vprot );
++ unsigned char vec;
++
++ mprotect_range( page, page_size, 0, 0 );
++ if (!mincore( page, page_size, &vec ) && (vec & 1))
++ ret = STATUS_SUCCESS;
++ else if (wine_anon_mmap( page, page_size, unix_prot, MAP_FIXED ) == page)
++ ret = STATUS_SUCCESS;
++ else
++ set_page_vprot_bits( page, page_size, 0, VPROT_READ | VPROT_EXEC );
++ }
+ server_leave_uninterrupted_section( &csVirtual, &sigset );
+
+ if (update_shared_data)
+--- a/dlls/psapi/tests/psapi_main.c
++++ b/dlls/psapi/tests/psapi_main.c
+@@ -195,6 +195,7 @@
+ static void test_GetModuleInformation(void)
+ {
+ HMODULE hMod = GetModuleHandleA(NULL);
++ DWORD *tmp, counter = 0;
+ MODULEINFO info;
+ DWORD ret;
+
+@@ -214,10 +215,21 @@
+ GetModuleInformation(hpQV, hMod, &info, sizeof(info)-1);
+ ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "expected error=ERROR_INSUFFICIENT_BUFFER but got %d\n", GetLastError());
+
+- SetLastError(0xdeadbeef);
+ ret = GetModuleInformation(hpQV, hMod, &info, sizeof(info));
+ ok(ret == 1, "failed with %d\n", GetLastError());
+ ok(info.lpBaseOfDll == hMod, "lpBaseOfDll=%p hMod=%p\n", info.lpBaseOfDll, hMod);
++
++ hMod = LoadLibraryA("shell32.dll");
++ ok(hMod != NULL, "Failed to load shell32.dll, error: %u\n", GetLastError());
++
++ ret = GetModuleInformation(hpQV, hMod, &info, sizeof(info));
++ ok(ret == 1, "failed with %d\n", GetLastError());
++ info.SizeOfImage /= sizeof(DWORD);
++ for (tmp = (DWORD *)hMod; info.SizeOfImage; info.SizeOfImage--)
++ counter ^= *tmp++;
++ trace("xor of shell32: %08x\n", counter);
++
++ FreeLibrary(hMod);
+ }
+
+ static BOOL check_with_margin(SIZE_T perf, SIZE_T sysperf, int margin)
diff -Nru wine-development-5.5/debian/patches/ntdll-Builtin_Prot/definition wine-development-5.5/debian/patches/ntdll-Builtin_Prot/definition
--- wine-development-5.5/debian/patches/ntdll-Builtin_Prot/definition 1970-01-01 01:00:00.000000000 +0100
+++ wine-development-5.5/debian/patches/ntdll-Builtin_Prot/definition 2020-05-04 01:33:29.000000000 +0100
@@ -0,0 +1,2 @@
+Fixes: [44650] Fix holes in ELF mappings
+Depends: ntdll-User_Shared_Data
diff -Nru wine-development-5.5/debian/patches/ntdll-Hide_Wine_Exports/0001-ntdll-Add-support-for-hiding-wine-version-informatio.patch wine-development-5.5/debian/patches/ntdll-Hide_Wine_Exports/0001-ntdll-Add-support-for-hiding-wine-version-informatio.patch
--- wine-development-5.5/debian/patches/ntdll-Hide_Wine_Exports/0001-ntdll-Add-support-for-hiding-wine-version-informatio.patch 1970-01-01 01:00:00.000000000 +0100
+++ wine-development-5.5/debian/patches/ntdll-Hide_Wine_Exports/0001-ntdll-Add-support-for-hiding-wine-version-informatio.patch 2020-05-04 01:33:29.000000000 +0100
@@ -0,0 +1,169 @@
+From 55a04c83c276864d4f442c3e9c33b36b4e9bdfb6 Mon Sep 17 00:00:00 2001
+From: Sebastian Lackner <sebastian@fds-team.de>
+Date: Sat, 30 May 2015 02:23:15 +0200
+Subject: [PATCH] ntdll: Add support for hiding wine version information from
+ applications.
+
+---
+ dlls/ntdll/loader.c | 100 +++++++++++++++++++++++++++++++++++++++-
+ dlls/ntdll/ntdll_misc.h | 5 ++
+ 2 files changed, 104 insertions(+), 1 deletion(-)
+
+--- a/dlls/ntdll/loader.c
++++ b/dlls/ntdll/loader.c
+@@ -70,6 +70,7 @@
+ const WCHAR syswow64_dir[] = {'C',':','\\','w','i','n','d','o','w','s','\\',
+ 's','y','s','w','o','w','6','4','\\',0};
+
++
+ /* system search path */
+ static const WCHAR system_path[] =
+ {'C',':','\\','w','i','n','d','o','w','s','\\','s','y','s','t','e','m','3','2',';',
+@@ -78,6 +79,9 @@
+
+ static const WCHAR dotW[] = {'.',0};
+
++#define IS_OPTION_TRUE(ch) ((ch) == 'y' || (ch) == 'Y' || (ch) == 't' || (ch) == 'T' || (ch) == '1')
++
++
+ static BOOL imports_fixup_done = FALSE; /* set once the imports have been fixed up, before attaching them */
+ static BOOL process_detaching = FALSE; /* set on process detach to avoid deadlocks with thread detach */
+ static int free_lib_count; /* recursion depth of LdrUnloadDll calls */
+@@ -94,6 +98,8 @@
+
+ static struct list dll_dir_list = LIST_INIT( dll_dir_list ); /* extra dirs from LdrAddDllDirectory */
+
++static BOOL hide_wine_exports = FALSE; /* try to hide ntdll wine exports from applications */
++
+ struct ldr_notification
+ {
+ struct list entry;
+@@ -1707,6 +1713,96 @@
+ }
+
+
++/***********************************************************************
++ * hidden_exports_init
++ *
++ * Initializes the hide_wine_exports options.
++ */
++static void hidden_exports_init( const WCHAR *appname )
++{
++ static const WCHAR configW[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e',0};
++ static const WCHAR appdefaultsW[] = {'A','p','p','D','e','f','a','u','l','t','s','\\',0};
++ static const WCHAR hideWineExports[] = {'H','i','d','e','W','i','n','e','E','x','p','o','r','t','s',0};
++ OBJECT_ATTRIBUTES attr;
++ UNICODE_STRING nameW;
++ HANDLE root, config_key, hkey;
++ BOOL got_hide_wine_exports = FALSE;
++ char tmp[80];
++ DWORD dummy;
++
++ RtlOpenCurrentUser( KEY_ALL_ACCESS, &root );
++ attr.Length = sizeof(attr);
++ attr.RootDirectory = root;
++ attr.ObjectName = &nameW;
++ attr.Attributes = OBJ_CASE_INSENSITIVE;
++ attr.SecurityDescriptor = NULL;
++ attr.SecurityQualityOfService = NULL;
++ RtlInitUnicodeString( &nameW, configW );
++
++ /* @@ Wine registry key: HKCU\Software\Wine */
++ if (NtOpenKey( &config_key, KEY_QUERY_VALUE, &attr )) config_key = 0;
++ NtClose( root );
++ if (!config_key) return;
++
++ if (appname && *appname)
++ {
++ const WCHAR *p;
++ WCHAR appversion[MAX_PATH+20];
++
++ if ((p = strrchrW( appname, '/' ))) appname = p + 1;
++ if ((p = strrchrW( appname, '\\' ))) appname = p + 1;
++
++ strcpyW( appversion, appdefaultsW );
++ strcatW( appversion, appname );
++ RtlInitUnicodeString( &nameW, appversion );
++ attr.RootDirectory = config_key;
++
++ /* @@ Wine registry key: HKCU\Software\Wine\AppDefaults\app.exe */
++ if (!NtOpenKey( &hkey, KEY_QUERY_VALUE, &attr ))
++ {
++ TRACE( "getting HideWineExports from %s\n", debugstr_w(appversion) );
++
++ RtlInitUnicodeString( &nameW, hideWineExports );
++ if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy ))
++ {
++ WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
++ hide_wine_exports = IS_OPTION_TRUE( str[0] );
++ got_hide_wine_exports = TRUE;
++ }
++
++ NtClose( hkey );
++ }
++ }
++
++ if (!got_hide_wine_exports)
++ {
++ TRACE( "getting default HideWineExports\n" );
++
++ RtlInitUnicodeString( &nameW, hideWineExports );
++ if (!NtQueryValueKey( config_key, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy ))
++ {
++ WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
++ hide_wine_exports = IS_OPTION_TRUE( str[0] );
++ }
++ }
++
++ NtClose( config_key );
++}
++
++
++/***********************************************************************
++ * is_hidden_export
++ *
++ * Checks if a specific export should be hidden.
++ */
++static BOOL is_hidden_export( void *proc )
++{
++ return hide_wine_exports && (proc == &NTDLL_wine_get_version ||
++ proc == &NTDLL_wine_get_build_id ||
++ proc == &NTDLL_wine_get_host_version);
++}
++
++
+ /******************************************************************
+ * LdrGetProcedureAddress (NTDLL.@)
+ */
+@@ -1727,7 +1823,7 @@
+ LPCWSTR load_path = NtCurrentTeb()->Peb->ProcessParameters->DllPath.Buffer;
+ void *proc = name ? find_named_export( module, exports, exp_size, name->Buffer, -1, load_path )
+ : find_ordinal_export( module, exports, exp_size, ord - exports->Base, load_path );
+- if (proc)
++ if (proc && !is_hidden_export( proc ))
+ {
+ *address = proc;
+ ret = STATUS_SUCCESS;
+@@ -4352,6 +4448,8 @@
+ NtTerminateProcess( GetCurrentProcess(), status );
+ }
+
++ hidden_exports_init( wm->ldr.FullDllName.Buffer );
++
+ virtual_set_large_address_space();
+
+ /* elevate process if necessary */
+--- a/dlls/ntdll/ntdll_misc.h
++++ b/dlls/ntdll/ntdll_misc.h
+@@ -273,6 +273,11 @@
+ NTSTATUS WINAPI RtlHashUnicodeString(PCUNICODE_STRING,BOOLEAN,ULONG,ULONG*);
+ void WINAPI LdrInitializeThunk(CONTEXT*,void**,ULONG_PTR,ULONG_PTR);
+
++/* version */
++extern const char * CDECL NTDLL_wine_get_version(void);
++extern const char * CDECL NTDLL_wine_get_build_id(void);
++extern void CDECL NTDLL_wine_get_host_version( const char **sysname, const char **release );
++
+ /* process / thread time */
+ extern BOOL read_process_time(int unix_pid, int unix_tid, unsigned long clk_tck,
+ LARGE_INTEGER *kernel, LARGE_INTEGER *user) DECLSPEC_HIDDEN;
diff -Nru wine-development-5.5/debian/patches/ntdll-Hide_Wine_Exports/definition wine-development-5.5/debian/patches/ntdll-Hide_Wine_Exports/definition
--- wine-development-5.5/debian/patches/ntdll-Hide_Wine_Exports/definition 1970-01-01 01:00:00.000000000 +0100
+++ wine-development-5.5/debian/patches/ntdll-Hide_Wine_Exports/definition 2020-05-04 01:33:29.000000000 +0100
@@ -0,0 +1,3 @@
+Fixes: [38656] Add support for hiding wine version information from applications
+Depends: ntdll-ThreadTime
+Depends: advapi32-Token_Integrity_Level
diff -Nru wine-development-5.5/debian/patches/ntdll-ThreadTime/0001-ntdll-Return-correct-values-in-GetThreadTimes-for-al.patch wine-development-5.5/debian/patches/ntdll-ThreadTime/0001-ntdll-Return-correct-values-in-GetThreadTimes-for-al.patch
--- wine-development-5.5/debian/patches/ntdll-ThreadTime/0001-ntdll-Return-correct-values-in-GetThreadTimes-for-al.patch 1970-01-01 01:00:00.000000000 +0100
+++ wine-development-5.5/debian/patches/ntdll-ThreadTime/0001-ntdll-Return-correct-values-in-GetThreadTimes-for-al.patch 2020-05-04 01:33:29.000000000 +0100
@@ -0,0 +1,154 @@
+From 4b31157383a5e422660c17d47fd4cda511a991a4 Mon Sep 17 00:00:00 2001
+From: Sebastian Lackner <sebastian@fds-team.de>
+Date: Fri, 7 Nov 2014 03:26:18 +0100
+Subject: [PATCH] ntdll: Return correct values in GetThreadTimes() for all
+ threads.
+
+Based on a patch by Ray Hinchliffe <ray@pobox.co.uk>.
+---
+ dlls/ntdll/thread.c | 82 ++++++++++++++++++++++++++++++++++++++++++-----------
+ server/protocol.def | 2 ++
+ server/thread.c | 2 ++
+ 3 files changed, 69 insertions(+), 17 deletions(-)
+
+--- a/dlls/ntdll/thread.c
++++ b/dlls/ntdll/thread.c
+@@ -23,6 +23,8 @@
+
+ #include <assert.h>
+ #include <stdarg.h>
++#include <string.h>
++#include <stdio.h>
+ #include <limits.h>
+ #include <sys/types.h>
+ #ifdef HAVE_SYS_MMAN_H
+@@ -936,7 +938,10 @@
+ case ThreadTimes:
+ {
+ KERNEL_USER_TIMES kusrt;
++ int unix_pid, unix_tid;
+
++ /* We need to do a server call to get the creation time, exit time, PID and TID */
++ /* This works on any thread */
+ SERVER_START_REQ( get_thread_times )
+ {
+ req->handle = wine_server_obj_handle( handle );
+@@ -945,36 +950,79 @@
+ {
+ kusrt.CreateTime.QuadPart = reply->creation_time;
+ kusrt.ExitTime.QuadPart = reply->exit_time;
++ unix_pid = reply->unix_pid;
++ unix_tid = reply->unix_tid;
+ }
+ }
+ SERVER_END_REQ;
+ if (status == STATUS_SUCCESS)
+ {
+- /* We call times(2) for kernel time or user time */
+- /* We can only (portably) do this for the current thread */
+- if (handle == GetCurrentThread())
++ unsigned long clk_tck = sysconf(_SC_CLK_TCK);
++ BOOL filled_times = FALSE;
++
++#ifdef __linux__
++ /* only /proc provides exact values for a specific thread */
++ if (unix_pid != -1 && unix_tid != -1)
+ {
+- struct tms time_buf;
+- long clocks_per_sec = sysconf(_SC_CLK_TCK);
++ unsigned long usr, sys;
++ char buf[512], *pos;
++ FILE *fp;
++ int i;
++
++ /* based on https://github.com/torvalds/linux/blob/master/fs/proc/array.c */
++ sprintf( buf, "/proc/%u/task/%u/stat", unix_pid, unix_tid );
++ if ((fp = fopen( buf, "r" )))
++ {
++ pos = fgets( buf, sizeof(buf), fp );
++ fclose( fp );
+
++ /* format of first chunk is "%d (%s) %c" - we have to skip to the last ')'
++ * to avoid misinterpreting the string. */
++ if (pos) pos = strrchr( pos, ')' );
++ if (pos) pos = strchr( pos + 1, ' ' );
++ if (pos) pos++;
++
++ /* skip over the following fields: state, ppid, pgid, sid, tty_nr, tty_pgrp,
++ * task->flags, min_flt, cmin_flt, maj_flt, cmaj_flt */
++ for (i = 0; (i < 11) && pos; i++)
++ {
++ pos = strchr( pos + 1, ' ' );
++ if (pos) pos++;
++ }
++
++ /* the next two values are user and system time */
++ if (pos && (sscanf( pos, "%lu %lu", &usr, &sys ) == 2))
++ {
++ kusrt.KernelTime.QuadPart = (ULONGLONG)sys * 10000000 / clk_tck;
++ kusrt.UserTime.QuadPart = (ULONGLONG)usr * 10000000 / clk_tck;
++ filled_times = TRUE;
++ }
++ }
++ }
++#endif
++
++ /* get values for current process instead */
++ if (!filled_times && handle == GetCurrentThread())
++ {
++ struct tms time_buf;
+ times(&time_buf);
+- kusrt.KernelTime.QuadPart = (ULONGLONG)time_buf.tms_stime * 10000000 / clocks_per_sec;
+- kusrt.UserTime.QuadPart = (ULONGLONG)time_buf.tms_utime * 10000000 / clocks_per_sec;
++
++ kusrt.KernelTime.QuadPart = (ULONGLONG)time_buf.tms_stime * 10000000 / clk_tck;
++ kusrt.UserTime.QuadPart = (ULONGLONG)time_buf.tms_utime * 10000000 / clk_tck;
++ filled_times = TRUE;
+ }
+- else
++
++ /* unable to determine exact values, fill with zero */
++ if (!filled_times)
+ {
+- static BOOL reported = FALSE;
++ static int once;
++ if (!once++)
++ FIXME("Cannot get kerneltime or usertime of other threads\n");
+
+ kusrt.KernelTime.QuadPart = 0;
+- kusrt.UserTime.QuadPart = 0;
+- if (reported)
+- TRACE("Cannot get kerneltime or usertime of other threads\n");
+- else
+- {
+- FIXME("Cannot get kerneltime or usertime of other threads\n");
+- reported = TRUE;
+- }
++ kusrt.UserTime.QuadPart = 0;
+ }
++
+ if (data) memcpy( data, &kusrt, min( length, sizeof(kusrt) ));
+ if (ret_len) *ret_len = min( length, sizeof(kusrt) );
+ }
+--- a/server/protocol.def
++++ b/server/protocol.def
+@@ -958,6 +958,8 @@
+ @REPLY
+ timeout_t creation_time; /* thread creation time */
+ timeout_t exit_time; /* thread exit time */
++ int unix_pid; /* thread native pid */
++ int unix_tid; /* thread native pid */
+ @END
+
+
+--- a/server/thread.c
++++ b/server/thread.c
+@@ -1487,6 +1487,8 @@
+ {
+ reply->creation_time = thread->creation_time;
+ reply->exit_time = thread->exit_time;
++ reply->unix_pid = thread->unix_pid;
++ reply->unix_tid = thread->unix_tid;
+
+ release_object( thread );
+ }
diff -Nru wine-development-5.5/debian/patches/ntdll-ThreadTime/0002-ntdll-Set-correct-thread-creation-time-for-SystemPro.patch wine-development-5.5/debian/patches/ntdll-ThreadTime/0002-ntdll-Set-correct-thread-creation-time-for-SystemPro.patch
--- wine-development-5.5/debian/patches/ntdll-ThreadTime/0002-ntdll-Set-correct-thread-creation-time-for-SystemPro.patch 1970-01-01 01:00:00.000000000 +0100
+++ wine-development-5.5/debian/patches/ntdll-ThreadTime/0002-ntdll-Set-correct-thread-creation-time-for-SystemPro.patch 2020-05-04 01:33:29.000000000 +0100
@@ -0,0 +1,63 @@
+From e6832d1b0f923e7589424ade7571cc67dc768c4d Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
+Date: Thu, 9 Mar 2017 00:00:46 +0100
+Subject: ntdll: Set correct thread creation time for SystemProcessInformation
+ in NtQuerySystemInformation.
+
+---
+ dlls/ntdll/nt.c | 2 +-
+ server/protocol.def | 1 +
+ server/snapshot.c | 11 ++++++-----
+ server/thread.h | 1 +
+ 4 files changed, 9 insertions(+), 6 deletions(-)
+
+--- a/dlls/ntdll/nt.c
++++ b/dlls/ntdll/nt.c
+@@ -2833,7 +2833,7 @@
+
+ memset(&spi->ti[i], 0, sizeof(spi->ti));
+
+- spi->ti[i].CreateTime.QuadPart = 0xdeadbeef;
++ spi->ti[i].CreateTime.QuadPart = reply->creation_time;
+ spi->ti[i].ClientId.UniqueProcess = UlongToHandle(reply->pid);
+ spi->ti[i].ClientId.UniqueThread = UlongToHandle(reply->tid);
+ spi->ti[i].dwCurrentPriority = reply->base_pri + reply->delta_pri;
+--- a/server/protocol.def
++++ b/server/protocol.def
+@@ -1901,6 +1901,7 @@
+ int count; /* thread usage count */
+ process_id_t pid; /* process id */
+ thread_id_t tid; /* thread id */
++ timeout_t creation_time; /* thread creation time */
+ int base_pri; /* base priority */
+ int delta_pri; /* delta priority */
+ @END
+--- a/server/snapshot.c
++++ b/server/snapshot.c
+@@ -145,11 +145,12 @@
+ return 0;
+ }
+ ptr = &snapshot->threads[snapshot->thread_pos++];
+- reply->count = ptr->count;
+- reply->pid = get_process_id( ptr->thread->process );
+- reply->tid = get_thread_id( ptr->thread );
+- reply->base_pri = ptr->priority;
+- reply->delta_pri = 0; /* FIXME */
++ reply->count = ptr->count;
++ reply->pid = get_process_id( ptr->thread->process );
++ reply->tid = get_thread_id( ptr->thread );
++ reply->creation_time = get_thread_creation_time( ptr->thread );
++ reply->base_pri = ptr->priority;
++ reply->delta_pri = 0; /* FIXME */
+ return 1;
+ }
+
+--- a/server/thread.h
++++ b/server/thread.h
+@@ -151,5 +151,6 @@
+ static inline void set_win32_error( unsigned int err ) { set_error( 0xc0010000 | err ); }
+
+ static inline thread_id_t get_thread_id( struct thread *thread ) { return thread->id; }
++static inline timeout_t get_thread_creation_time( struct thread *thread ) { return thread->creation_time; }
+
+ #endif /* __WINE_SERVER_THREAD_H */
diff -Nru wine-development-5.5/debian/patches/ntdll-ThreadTime/0003-ntdll-Fill-process-kernel-and-user-time.patch wine-development-5.5/debian/patches/ntdll-ThreadTime/0003-ntdll-Fill-process-kernel-and-user-time.patch
--- wine-development-5.5/debian/patches/ntdll-ThreadTime/0003-ntdll-Fill-process-kernel-and-user-time.patch 1970-01-01 01:00:00.000000000 +0100
+++ wine-development-5.5/debian/patches/ntdll-ThreadTime/0003-ntdll-Fill-process-kernel-and-user-time.patch 2020-05-04 01:33:29.000000000 +0100
@@ -0,0 +1,153 @@
+From 097c8310c57f8f5cbcd83da40436a35703f9c1cf Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
+Date: Thu, 9 Mar 2017 16:27:23 +0100
+Subject: [PATCH] ntdll: Fill process kernel and user time.
+
+---
+ dlls/ntdll/nt.c | 6 ++-
+ dlls/ntdll/ntdll_misc.h | 4 ++
+ dlls/ntdll/thread.c | 84 +++++++++++++++++++++++------------------
+ 3 files changed, 57 insertions(+), 37 deletions(-)
+
+--- a/dlls/ntdll/nt.c
++++ b/dlls/ntdll/nt.c
+@@ -2743,6 +2743,7 @@
+ {
+ SYSTEM_PROCESS_INFORMATION* spi = SystemInformation;
+ SYSTEM_PROCESS_INFORMATION* last = NULL;
++ unsigned long clk_tck = sysconf(_SC_CLK_TCK);
+ HANDLE hSnap = 0;
+ WCHAR procname[1024];
+ WCHAR* exename;
+@@ -2780,7 +2781,7 @@
+
+ if (Length >= len + procstructlen)
+ {
+- /* ftCreationTime, ftUserTime, ftKernelTime;
++ /* ftCreationTime;
+ * vmCounters, ioCounters
+ */
+
+@@ -2798,6 +2799,9 @@
+
+ /* spi->ti will be set later on */
+
++ if (reply->unix_pid != -1)
++ read_process_time(reply->unix_pid, -1, clk_tck,
++ &spi->KernelTime, &spi->UserTime);
+ }
+ len += procstructlen;
+ }
+--- a/dlls/ntdll/ntdll_misc.h
++++ b/dlls/ntdll/ntdll_misc.h
+@@ -273,6 +273,10 @@
+ NTSTATUS WINAPI RtlHashUnicodeString(PCUNICODE_STRING,BOOLEAN,ULONG,ULONG*);
+ void WINAPI LdrInitializeThunk(CONTEXT*,void**,ULONG_PTR,ULONG_PTR);
+
++/* process / thread time */
++extern BOOL read_process_time(int unix_pid, int unix_tid, unsigned long clk_tck,
++ LARGE_INTEGER *kernel, LARGE_INTEGER *user) DECLSPEC_HIDDEN;
++
+ /* string functions */
+ int __cdecl NTDLL_tolower( int c );
+ int __cdecl _stricmp( LPCSTR str1, LPCSTR str2 );
+--- a/dlls/ntdll/thread.c
++++ b/dlls/ntdll/thread.c
+@@ -153,6 +153,53 @@
+ #endif
+
+
++
++BOOL read_process_time(int unix_pid, int unix_tid, unsigned long clk_tck,
++ LARGE_INTEGER *kernel, LARGE_INTEGER *user)
++{
++#ifdef __linux__
++ unsigned long usr, sys;
++ char buf[512], *pos;
++ FILE *fp;
++ int i;
++
++ /* based on https://github.com/torvalds/linux/blob/master/fs/proc/array.c */
++ if (unix_tid != -1)
++ sprintf( buf, "/proc/%u/task/%u/stat", unix_pid, unix_tid );
++ else
++ sprintf( buf, "/proc/%u/stat", unix_pid );
++ if ((fp = fopen( buf, "r" )))
++ {
++ pos = fgets( buf, sizeof(buf), fp );
++ fclose( fp );
++
++ /* format of first chunk is "%d (%s) %c" - we have to skip to the last ')'
++ * to avoid misinterpreting the string. */
++ if (pos) pos = strrchr( pos, ')' );
++ if (pos) pos = strchr( pos + 1, ' ' );
++ if (pos) pos++;
++
++ /* skip over the following fields: state, ppid, pgid, sid, tty_nr, tty_pgrp,
++ * task->flags, min_flt, cmin_flt, maj_flt, cmaj_flt */
++ for (i = 0; (i < 11) && pos; i++)
++ {
++ pos = strchr( pos + 1, ' ' );
++ if (pos) pos++;
++ }
++
++ /* the next two values are user and system time */
++ if (pos && (sscanf( pos, "%lu %lu", &usr, &sys ) == 2))
++ {
++ kernel->QuadPart = (ULONGLONG)sys * 10000000 / clk_tck;
++ user->QuadPart = (ULONGLONG)usr * 10000000 / clk_tck;
++ return TRUE;
++ }
++ }
++#endif
++ return FALSE;
++}
++
++
+ /***********************************************************************
+ * set_process_name
+ *
+@@ -963,42 +1010,7 @@
+ #ifdef __linux__
+ /* only /proc provides exact values for a specific thread */
+ if (unix_pid != -1 && unix_tid != -1)
+- {
+- unsigned long usr, sys;
+- char buf[512], *pos;
+- FILE *fp;
+- int i;
+-
+- /* based on https://github.com/torvalds/linux/blob/master/fs/proc/array.c */
+- sprintf( buf, "/proc/%u/task/%u/stat", unix_pid, unix_tid );
+- if ((fp = fopen( buf, "r" )))
+- {
+- pos = fgets( buf, sizeof(buf), fp );
+- fclose( fp );
+-
+- /* format of first chunk is "%d (%s) %c" - we have to skip to the last ')'
+- * to avoid misinterpreting the string. */
+- if (pos) pos = strrchr( pos, ')' );
+- if (pos) pos = strchr( pos + 1, ' ' );
+- if (pos) pos++;
+-
+- /* skip over the following fields: state, ppid, pgid, sid, tty_nr, tty_pgrp,
+- * task->flags, min_flt, cmin_flt, maj_flt, cmaj_flt */
+- for (i = 0; (i < 11) && pos; i++)
+- {
+- pos = strchr( pos + 1, ' ' );
+- if (pos) pos++;
+- }
+-
+- /* the next two values are user and system time */
+- if (pos && (sscanf( pos, "%lu %lu", &usr, &sys ) == 2))
+- {
+- kusrt.KernelTime.QuadPart = (ULONGLONG)sys * 10000000 / clk_tck;
+- kusrt.UserTime.QuadPart = (ULONGLONG)usr * 10000000 / clk_tck;
+- filled_times = TRUE;
+- }
+- }
+- }
++ filled_times = read_process_time(unix_pid, unix_tid, clk_tck, &kusrt.KernelTime, &kusrt.UserTime);
+ #endif
+
+ /* get values for current process instead */
diff -Nru wine-development-5.5/debian/patches/ntdll-ThreadTime/0004-ntdll-Set-process-start-time.patch wine-development-5.5/debian/patches/ntdll-ThreadTime/0004-ntdll-Set-process-start-time.patch
--- wine-development-5.5/debian/patches/ntdll-ThreadTime/0004-ntdll-Set-process-start-time.patch 1970-01-01 01:00:00.000000000 +0100
+++ wine-development-5.5/debian/patches/ntdll-ThreadTime/0004-ntdll-Set-process-start-time.patch 2020-05-04 01:33:29.000000000 +0100
@@ -0,0 +1,55 @@
+From e048ad0cd3879fb8f752af7e2eeda770864f9982 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
+Date: Thu, 9 Mar 2017 16:32:59 +0100
+Subject: ntdll: Set process start time.
+
+---
+ dlls/ntdll/nt.c | 1 +
+ server/protocol.def | 1 +
+ server/snapshot.c | 15 ++++++++-------
+ 3 files changed, 10 insertions(+), 7 deletions(-)
+
+--- a/dlls/ntdll/nt.c
++++ b/dlls/ntdll/nt.c
+@@ -2796,6 +2796,7 @@
+ spi->UniqueProcessId = UlongToHandle(reply->pid);
+ spi->ParentProcessId = UlongToHandle(reply->ppid);
+ spi->HandleCount = reply->handles;
++ spi->CreationTime.QuadPart = reply->start_time;
+
+ /* spi->ti will be set later on */
+
+--- a/server/protocol.def
++++ b/server/protocol.def
+@@ -1889,6 +1889,7 @@
+ int priority; /* process priority */
+ int handles; /* number of handles */
+ int unix_pid; /* Unix pid */
++ timeout_t start_time; /* start time */
+ VARARG(filename,unicode_str); /* file name of main exe */
+ @END
+
+--- a/server/snapshot.c
++++ b/server/snapshot.c
+@@ -114,13 +114,14 @@
+ return 0;
+ }
+ ptr = &snapshot->processes[snapshot->process_pos++];
+- reply->count = ptr->count;
+- reply->pid = get_process_id( ptr->process );
+- reply->ppid = ptr->process->parent_id;
+- reply->threads = ptr->threads;
+- reply->priority = ptr->priority;
+- reply->handles = ptr->handles;
+- reply->unix_pid = ptr->process->unix_pid;
++ reply->count = ptr->count;
++ reply->pid = get_process_id( ptr->process );
++ reply->ppid = ptr->process->parent_id;
++ reply->threads = ptr->threads;
++ reply->priority = ptr->priority;
++ reply->handles = ptr->handles;
++ reply->unix_pid = ptr->process->unix_pid;
++ reply->start_time = ptr->process->start_time;
+ if ((exe_module = get_process_exe_module( ptr->process )) && exe_module->filename)
+ {
+ data_size_t len = min( exe_module->namelen, get_reply_max_size() );
diff -Nru wine-development-5.5/debian/patches/ntdll-ThreadTime/0005-ntdll-Fill-out-thread-times-in-process-enumeration.patch wine-development-5.5/debian/patches/ntdll-ThreadTime/0005-ntdll-Fill-out-thread-times-in-process-enumeration.patch
--- wine-development-5.5/debian/patches/ntdll-ThreadTime/0005-ntdll-Fill-out-thread-times-in-process-enumeration.patch 1970-01-01 01:00:00.000000000 +0100
+++ wine-development-5.5/debian/patches/ntdll-ThreadTime/0005-ntdll-Fill-out-thread-times-in-process-enumeration.patch 2020-05-04 01:33:29.000000000 +0100
@@ -0,0 +1,71 @@
+From 6c3b7e0065c239b488bb224c1c67ff971562fdca Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
+Date: Thu, 9 Mar 2017 21:14:13 +0100
+Subject: ntdll: Fill out thread times in process enumeration.
+
+---
+ dlls/ntdll/nt.c | 6 ++++++
+ server/protocol.def | 1 +
+ server/snapshot.c | 1 +
+ server/thread.h | 1 +
+ 4 files changed, 9 insertions(+)
+
+--- a/dlls/ntdll/nt.c
++++ b/dlls/ntdll/nt.c
+@@ -2749,6 +2749,7 @@
+ WCHAR* exename;
+ DWORD wlen = 0;
+ DWORD procstructlen = 0;
++ int unix_pid = -1;
+
+ SERVER_START_REQ( create_snapshot )
+ {
+@@ -2803,6 +2804,7 @@
+ if (reply->unix_pid != -1)
+ read_process_time(reply->unix_pid, -1, clk_tck,
+ &spi->KernelTime, &spi->UserTime);
++ unix_pid = reply->unix_pid;
+ }
+ len += procstructlen;
+ }
+@@ -2843,6 +2845,10 @@
+ spi->ti[i].ClientId.UniqueThread = UlongToHandle(reply->tid);
+ spi->ti[i].dwCurrentPriority = reply->base_pri + reply->delta_pri;
+ spi->ti[i].dwBasePriority = reply->base_pri;
++
++ if (unix_pid != -1 && reply->unix_tid != -1)
++ read_process_time(unix_pid, reply->unix_tid, clk_tck,
++ &spi->ti[i].KernelTime, &spi->ti[i].UserTime);
+ i++;
+ }
+ }
+--- a/server/protocol.def
++++ b/server/protocol.def
+@@ -1905,6 +1905,7 @@
+ timeout_t creation_time; /* thread creation time */
+ int base_pri; /* base priority */
+ int delta_pri; /* delta priority */
++ int unix_tid; /* Unix tid */
+ @END
+
+
+--- a/server/snapshot.c
++++ b/server/snapshot.c
+@@ -152,6 +152,7 @@
+ reply->creation_time = get_thread_creation_time( ptr->thread );
+ reply->base_pri = ptr->priority;
+ reply->delta_pri = 0; /* FIXME */
++ reply->unix_tid = get_thread_unix_tid( ptr->thread );
+ return 1;
+ }
+
+--- a/server/thread.h
++++ b/server/thread.h
+@@ -151,6 +151,7 @@
+ static inline void set_win32_error( unsigned int err ) { set_error( 0xc0010000 | err ); }
+
+ static inline thread_id_t get_thread_id( struct thread *thread ) { return thread->id; }
++static inline int get_thread_unix_tid( struct thread *thread ) { return thread->unix_tid; }
+ static inline timeout_t get_thread_creation_time( struct thread *thread ) { return thread->creation_time; }
+
+ #endif /* __WINE_SERVER_THREAD_H */
diff -Nru wine-development-5.5/debian/patches/ntdll-ThreadTime/0006-ntdll-Fill-process-virtual-memory-counters-in-NtQuer.patch wine-development-5.5/debian/patches/ntdll-ThreadTime/0006-ntdll-Fill-process-virtual-memory-counters-in-NtQuer.patch
--- wine-development-5.5/debian/patches/ntdll-ThreadTime/0006-ntdll-Fill-process-virtual-memory-counters-in-NtQuer.patch 1970-01-01 01:00:00.000000000 +0100
+++ wine-development-5.5/debian/patches/ntdll-ThreadTime/0006-ntdll-Fill-process-virtual-memory-counters-in-NtQuer.patch 2020-05-04 01:33:29.000000000 +0100
@@ -0,0 +1,94 @@
+From 1b90b687170f3a00093fcdf0914c9f89aea3a3bd Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
+Date: Thu, 9 Mar 2017 22:56:45 +0100
+Subject: [PATCH] ntdll: Fill process virtual memory counters in
+ NtQuerySystemInformation.
+
+FIXME: fill_VM_COUNTERS now uses a different method ... which one is better?
+---
+ dlls/ntdll/nt.c | 3 +++
+ dlls/ntdll/ntdll_misc.h | 1 +
+ dlls/ntdll/process.c | 2 +-
+ dlls/ntdll/thread.c | 36 ++++++++++++++++++++++++++++++++++++
+ 4 files changed, 41 insertions(+), 1 deletion(-)
+
+--- a/dlls/ntdll/nt.c
++++ b/dlls/ntdll/nt.c
+@@ -2802,8 +2802,11 @@
+ /* spi->ti will be set later on */
+
+ if (reply->unix_pid != -1)
++ {
+ read_process_time(reply->unix_pid, -1, clk_tck,
+ &spi->KernelTime, &spi->UserTime);
++ read_process_memory_stats(reply->unix_pid, &spi->vmCounters);
++ }
+ unix_pid = reply->unix_pid;
+ }
+ len += procstructlen;
+--- a/dlls/ntdll/ntdll_misc.h
++++ b/dlls/ntdll/ntdll_misc.h
+@@ -276,6 +276,7 @@
+ /* process / thread time */
+ extern BOOL read_process_time(int unix_pid, int unix_tid, unsigned long clk_tck,
+ LARGE_INTEGER *kernel, LARGE_INTEGER *user) DECLSPEC_HIDDEN;
++extern BOOL read_process_memory_stats(int unix_pid, VM_COUNTERS *pvmi) DECLSPEC_HIDDEN;
+
+ /* string functions */
+ int __cdecl NTDLL_tolower( int c );
+--- a/dlls/ntdll/process.c
++++ b/dlls/ntdll/process.c
+@@ -210,7 +210,7 @@
+
+ static void fill_VM_COUNTERS(VM_COUNTERS* pvmi)
+ {
+- /* FIXME : real data */
++ read_process_memory_stats(getpid(), pvmi);
+ }
+
+ #endif
+--- a/dlls/ntdll/thread.c
++++ b/dlls/ntdll/thread.c
+@@ -366,6 +366,42 @@
+ return teb;
+ }
+
++BOOL read_process_memory_stats(int unix_pid, VM_COUNTERS *pvmi)
++{
++ BOOL ret = FALSE;
++#ifdef __linux__
++ unsigned long size, resident, shared, trs, drs, lrs, dt;
++ char buf[512];
++ FILE *fp;
++
++ sprintf( buf, "/proc/%u/statm", unix_pid );
++ if ((fp = fopen( buf, "r" )))
++ {
++ if (fscanf( fp, "%lu %lu %lu %lu %lu %lu %lu",
++ &size, &resident, &shared, &trs, &drs, &lrs, &dt ) == 7)
++ {
++ pvmi->VirtualSize = size * page_size;
++ pvmi->WorkingSetSize = resident * page_size;
++ pvmi->PrivatePageCount = size - shared;
++
++ /* these values are not available through /proc/pid/statm */
++ pvmi->PeakVirtualSize = pvmi->VirtualSize;
++ pvmi->PageFaultCount = 0;
++ pvmi->PeakWorkingSetSize = pvmi->WorkingSetSize;
++ pvmi->QuotaPagedPoolUsage = pvmi->VirtualSize;
++ pvmi->QuotaPeakPagedPoolUsage = pvmi->QuotaPagedPoolUsage;
++ pvmi->QuotaPeakNonPagedPoolUsage = 0;
++ pvmi->QuotaNonPagedPoolUsage = 0;
++ pvmi->PagefileUsage = 0;
++ pvmi->PeakPagefileUsage = 0;
++
++ ret = TRUE;
++ }
++ fclose( fp );
++ }
++#endif
++ return ret;
++}
+
+ /***********************************************************************
+ * free_thread_data
diff -Nru wine-development-5.5/debian/patches/ntdll-ThreadTime/definition wine-development-5.5/debian/patches/ntdll-ThreadTime/definition
--- wine-development-5.5/debian/patches/ntdll-ThreadTime/definition 1970-01-01 01:00:00.000000000 +0100
+++ wine-development-5.5/debian/patches/ntdll-ThreadTime/definition 2020-05-04 01:33:29.000000000 +0100
@@ -0,0 +1,3 @@
+Fixes: [20230] Return correct values for GetThreadTimes function
+Fixes: Return correct thread creation time in SystemProcessInformation
+Fixes: Fill process virtual memory counters in NtQuerySystemInformation
diff -Nru wine-development-5.5/debian/patches/ntdll-User_Shared_Data/0001-ntdll-Move-code-to-update-user-shared-data-into-a-se.patch wine-development-5.5/debian/patches/ntdll-User_Shared_Data/0001-ntdll-Move-code-to-update-user-shared-data-into-a-se.patch
--- wine-development-5.5/debian/patches/ntdll-User_Shared_Data/0001-ntdll-Move-code-to-update-user-shared-data-into-a-se.patch 1970-01-01 01:00:00.000000000 +0100
+++ wine-development-5.5/debian/patches/ntdll-User_Shared_Data/0001-ntdll-Move-code-to-update-user-shared-data-into-a-se.patch 2020-05-04 01:33:29.000000000 +0100
@@ -0,0 +1,72 @@
+From aefe1725320bd3053c7c51020b92cc9dfc22c7b4 Mon Sep 17 00:00:00 2001
+From: Sebastian Lackner <sebastian@fds-team.de>
+Date: Wed, 26 Nov 2014 10:46:09 +0100
+Subject: [PATCH] ntdll: Move code to update user shared data into a separate
+ function.
+
+---
+ dlls/ntdll/ntdll.spec | 3 +++
+ dlls/ntdll/thread.c | 28 +++++++++++++++++++++-------
+ 2 files changed, 24 insertions(+), 7 deletions(-)
+
+--- a/dlls/ntdll/ntdll.spec
++++ b/dlls/ntdll/ntdll.spec
+@@ -1585,3 +1585,6 @@
+ # Filesystem
+ @ cdecl wine_nt_to_unix_file_name(ptr ptr long long)
+ @ cdecl wine_unix_to_nt_file_name(ptr ptr)
++
++# User shared data
++@ cdecl __wine_user_shared_data()
+--- a/dlls/ntdll/thread.c
++++ b/dlls/ntdll/thread.c
+@@ -275,7 +275,6 @@
+ TEB *teb;
+ void *addr;
+ SIZE_T size;
+- LARGE_INTEGER now;
+ NTSTATUS status;
+ struct ntdll_thread_data *thread_data;
+
+@@ -350,7 +349,26 @@
+ debug_init();
+ set_process_name( __wine_main_argc, __wine_main_argv );
+
+- /* initialize time values in user_shared_data */
++ /* initialize user_shared_data */
++ __wine_user_shared_data();
++ fill_cpu_info();
++
++ virtual_get_system_info( &sbi );
++ user_shared_data->NumberOfPhysicalPages = sbi.MmNumberOfPhysicalPages;
++
++ return teb;
++}
++
++
++
++/**************************************************************************
++ * __wine_user_shared_data (NTDLL.@)
++ *
++ * Update user shared data and return the address of the structure.
++ */
++BYTE* CDECL __wine_user_shared_data(void)
++{
++ LARGE_INTEGER now;
+ NtQuerySystemTime( &now );
+ user_shared_data->SystemTime.LowPart = now.u.LowPart;
+ user_shared_data->SystemTime.High1Time = user_shared_data->SystemTime.High2Time = now.u.HighPart;
+@@ -358,12 +376,8 @@
+ user_shared_data->u.TickCount.High2Time = user_shared_data->u.TickCount.High1Time;
+ user_shared_data->TickCountLowDeprecated = user_shared_data->u.TickCount.LowPart;
+ user_shared_data->TickCountMultiplier = 1 << 24;
+- fill_cpu_info();
+
+- virtual_get_system_info( &sbi );
+- user_shared_data->NumberOfPhysicalPages = sbi.MmNumberOfPhysicalPages;
+-
+- return teb;
++ return (BYTE *)user_shared_data;
+ }
+
+ BOOL read_process_memory_stats(int unix_pid, VM_COUNTERS *pvmi)
diff -Nru wine-development-5.5/debian/patches/ntdll-User_Shared_Data/0002-ntoskrnl-Update-USER_SHARED_DATA-before-accessing-me.patch wine-development-5.5/debian/patches/ntdll-User_Shared_Data/0002-ntoskrnl-Update-USER_SHARED_DATA-before-accessing-me.patch
--- wine-development-5.5/debian/patches/ntdll-User_Shared_Data/0002-ntoskrnl-Update-USER_SHARED_DATA-before-accessing-me.patch 1970-01-01 01:00:00.000000000 +0100
+++ wine-development-5.5/debian/patches/ntdll-User_Shared_Data/0002-ntoskrnl-Update-USER_SHARED_DATA-before-accessing-me.patch 2020-05-04 01:33:29.000000000 +0100
@@ -0,0 +1,71 @@
+From 9e1ef78fd1ba5fbdd660d2d9ee735f811c65cf9a Mon Sep 17 00:00:00 2001
+From: Sebastian Lackner <sebastian@fds-team.de>
+Date: Fri, 19 Jun 2015 15:57:14 +0200
+Subject: [PATCH] ntoskrnl: Update USER_SHARED_DATA before accessing memory.
+
+---
+ dlls/ntoskrnl.exe/instr.c | 23 +++++------------------
+ 1 file changed, 5 insertions(+), 18 deletions(-)
+
+--- a/dlls/ntoskrnl.exe/instr.c
++++ b/dlls/ntoskrnl.exe/instr.c
+@@ -481,8 +481,7 @@
+ #define SIB_INDEX( sib, rex ) (((sib) >> 3) & 7) | (((rex) & REX_X) ? 8 : 0)
+ #define SIB_BASE( sib, rex ) (((sib) & 7) | (((rex) & REX_B) ? 8 : 0))
+
+-/* keep in sync with dlls/ntdll/thread.c:thread_init */
+-static const BYTE *wine_user_shared_data = (BYTE *)0x7ffe0000;
++extern BYTE* CDECL __wine_user_shared_data(void);
+ static const BYTE *user_shared_data = (BYTE *)0xfffff78000000000;
+
+ static inline DWORD64 *get_int_reg( CONTEXT *context, int index )
+@@ -593,15 +592,6 @@
+ }
+
+
+-static void update_shared_data(void)
+-{
+- struct _KUSER_SHARED_DATA *shared_data = (struct _KUSER_SHARED_DATA *)wine_user_shared_data;
+-
+- shared_data->u.TickCountQuad = GetTickCount64();
+- shared_data->u.TickCount.High2Time = shared_data->u.TickCount.High1Time;
+-}
+-
+-
+ /***********************************************************************
+ * emulate_instruction
+ *
+@@ -802,8 +792,7 @@
+ if (offset <= sizeof(KSHARED_USER_DATA) - data_size)
+ {
+ ULONGLONG temp = 0;
+- update_shared_data();
+- memcpy( &temp, wine_user_shared_data + offset, data_size );
++ memcpy( &temp, __wine_user_shared_data() + offset, data_size );
+ store_reg_word( context, instr[2], (BYTE *)&temp, long_op, rex );
+ context->Rip += prefixlen + len + 2;
+ return ExceptionContinueExecution;
+@@ -823,11 +812,10 @@
+
+ if (offset <= sizeof(KSHARED_USER_DATA) - data_size)
+ {
+- update_shared_data();
+ switch (*instr)
+ {
+- case 0x8a: store_reg_byte( context, instr[1], wine_user_shared_data + offset, rex ); break;
+- case 0x8b: store_reg_word( context, instr[1], wine_user_shared_data + offset, long_op, rex ); break;
++ case 0x8a: store_reg_byte( context, instr[1], __wine_user_shared_data() + offset, rex ); break;
++ case 0x8b: store_reg_word( context, instr[1], __wine_user_shared_data() + offset, long_op, rex ); break;
+ }
+ context->Rip += prefixlen + len + 1;
+ return ExceptionContinueExecution;
+@@ -845,8 +833,7 @@
+
+ if (offset <= sizeof(KSHARED_USER_DATA) - data_size)
+ {
+- update_shared_data();
+- memcpy( &context->Rax, wine_user_shared_data + offset, data_size );
++ memcpy( &context->Rax, __wine_user_shared_data() + offset, data_size );
+ context->Rip += prefixlen + len + 1;
+ return ExceptionContinueExecution;
+ }
diff -Nru wine-development-5.5/debian/patches/ntdll-User_Shared_Data/0003-ntdll-Create-thread-to-update-user_shared_data-time-.patch wine-development-5.5/debian/patches/ntdll-User_Shared_Data/0003-ntdll-Create-thread-to-update-user_shared_data-time-.patch
--- wine-development-5.5/debian/patches/ntdll-User_Shared_Data/0003-ntdll-Create-thread-to-update-user_shared_data-time-.patch 1970-01-01 01:00:00.000000000 +0100
+++ wine-development-5.5/debian/patches/ntdll-User_Shared_Data/0003-ntdll-Create-thread-to-update-user_shared_data-time-.patch 2020-05-04 01:33:29.000000000 +0100
@@ -0,0 +1,212 @@
+From 7564fa0a561d40d940c36485e51dae017d883444 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
+Date: Fri, 5 May 2017 05:40:50 +0200
+Subject: [PATCH] ntdll: Create thread to update user_shared_data time values
+ when necessary.
+
+---
+ dlls/ntdll/loader.c | 31 ++++++++++++++++++
+ dlls/ntdll/ntdll_misc.h | 3 ++
+ dlls/ntdll/thread.c | 70 ++++++++++++++++++++++++++++++++++++-----
+ dlls/ntdll/virtual.c | 17 ++++++++++
+ 4 files changed, 113 insertions(+), 8 deletions(-)
+
+--- a/dlls/ntdll/loader.c
++++ b/dlls/ntdll/loader.c
+@@ -3827,6 +3827,36 @@
+ }
+
+
++/***********************************************************************
++ * user_shared_data_init
++ *
++ * Initializes a user shared
++ */
++static void user_shared_data_init(void)
++{
++ void *addr = user_shared_data_external;
++ SIZE_T data_size = page_size;
++ ULONG old_prot;
++
++ /* initialize time fields */
++ __wine_user_shared_data();
++
++ /* invalidate high times to prevent race conditions */
++ user_shared_data->SystemTime.High2Time = 0;
++ user_shared_data->SystemTime.High1Time = -1;
++
++ user_shared_data->InterruptTime.High2Time = 0;
++ user_shared_data->InterruptTime.High1Time = -1;
++
++ user_shared_data->u.TickCount.High2Time = 0;
++ user_shared_data->u.TickCount.High1Time = -1;
++
++ /* copy to correct address and make it non accessible */
++ memcpy(user_shared_data_external, user_shared_data, sizeof(*user_shared_data));
++ NtProtectVirtualMemory( NtCurrentProcess(), &addr, &data_size, PAGE_NOACCESS, &old_prot );
++}
++
++
+ /******************************************************************
+ * LdrInitializeThunk (NTDLL.@)
+ *
+@@ -4448,6 +4478,7 @@
+ NtTerminateProcess( GetCurrentProcess(), status );
+ }
+
++ user_shared_data_init();
+ hidden_exports_init( wm->ldr.FullDllName.Buffer );
+
+ virtual_set_large_address_space();
+--- a/dlls/ntdll/ntdll_misc.h
++++ b/dlls/ntdll/ntdll_misc.h
+@@ -200,6 +200,9 @@
+ extern void virtual_fill_image_information( const pe_image_info_t *pe_info,
+ SECTION_IMAGE_INFORMATION *info ) DECLSPEC_HIDDEN;
+ extern struct _KUSER_SHARED_DATA *user_shared_data DECLSPEC_HIDDEN;
++extern struct _KUSER_SHARED_DATA *user_shared_data_external DECLSPEC_HIDDEN;
++extern void create_user_shared_data_thread(void) DECLSPEC_HIDDEN;
++extern BYTE* CDECL __wine_user_shared_data(void);
+
+ /* completion */
+ extern NTSTATUS NTDLL_AddCompletion( HANDLE hFile, ULONG_PTR CompletionValue,
+--- a/dlls/ntdll/thread.c
++++ b/dlls/ntdll/thread.c
+@@ -47,6 +47,7 @@
+ #include "wine/library.h"
+ #include "wine/server.h"
+ #include "wine/debug.h"
++#include "winbase.h"
+ #include "ntdll_misc.h"
+ #include "ddk/wdm.h"
+ #include "wine/exception.h"
+@@ -57,7 +58,9 @@
+ #define PTHREAD_STACK_MIN 16384
+ #endif
+
+-struct _KUSER_SHARED_DATA *user_shared_data = NULL;
++static struct _KUSER_SHARED_DATA user_shared_data_internal;
++struct _KUSER_SHARED_DATA *user_shared_data_external;
++struct _KUSER_SHARED_DATA *user_shared_data = &user_shared_data_internal;
+ static const WCHAR default_windirW[] = {'C',':','\\','w','i','n','d','o','w','s',0};
+
+ void (WINAPI *kernel32_start_process)(LPTHREAD_START_ROUTINE,void*) = NULL;
+@@ -291,7 +294,7 @@
+ MESSAGE( "wine: failed to map the shared user data: %08x\n", status );
+ exit(1);
+ }
+- user_shared_data = addr;
++ user_shared_data_external = addr;
+ memcpy( user_shared_data->NtSystemRoot, default_windirW, sizeof(default_windirW) );
+
+ /* allocate and initialize the PEB */
+@@ -368,18 +371,69 @@
+ */
+ BYTE* CDECL __wine_user_shared_data(void)
+ {
+- LARGE_INTEGER now;
++ static int spinlock;
++ ULARGE_INTEGER interrupt;
++ LARGE_INTEGER now;
++
++ while (interlocked_cmpxchg( &spinlock, 1, 0 ) != 0);
++
+ NtQuerySystemTime( &now );
+- user_shared_data->SystemTime.LowPart = now.u.LowPart;
+- user_shared_data->SystemTime.High1Time = user_shared_data->SystemTime.High2Time = now.u.HighPart;
+- user_shared_data->u.TickCountQuad = (now.QuadPart - server_start_time) / 10000;
+- user_shared_data->u.TickCount.High2Time = user_shared_data->u.TickCount.High1Time;
+- user_shared_data->TickCountLowDeprecated = user_shared_data->u.TickCount.LowPart;
++ user_shared_data->SystemTime.High2Time = now.u.HighPart;
++ user_shared_data->SystemTime.LowPart = now.u.LowPart;
++ user_shared_data->SystemTime.High1Time = now.u.HighPart;
++
++ RtlQueryUnbiasedInterruptTime( &interrupt.QuadPart );
++ user_shared_data->InterruptTime.High2Time = interrupt.HighPart;
++ user_shared_data->InterruptTime.LowPart = interrupt.LowPart;
++ user_shared_data->InterruptTime.High1Time = interrupt.HighPart;
++
++ interrupt.QuadPart /= 10000;
++ user_shared_data->u.TickCount.High2Time = interrupt.HighPart;
++ user_shared_data->u.TickCount.LowPart = interrupt.LowPart;
++ user_shared_data->u.TickCount.High1Time = interrupt.HighPart;
++ user_shared_data->TickCountLowDeprecated = interrupt.LowPart;
+ user_shared_data->TickCountMultiplier = 1 << 24;
+
++ spinlock = 0;
+ return (BYTE *)user_shared_data;
+ }
+
++static void *user_shared_data_thread(void *arg)
++{
++ struct timeval tv;
++
++ while (TRUE)
++ {
++ __wine_user_shared_data();
++
++ tv.tv_sec = 0;
++ tv.tv_usec = 15600;
++ select(0, NULL, NULL, NULL, &tv);
++ }
++ return NULL;
++}
++
++
++void create_user_shared_data_thread(void)
++{
++ static int thread_created;
++ pthread_attr_t attr;
++ pthread_t thread;
++
++ if (interlocked_cmpxchg(&thread_created, 1, 0) != 0)
++ return;
++
++ TRACE("Creating user shared data update thread.\n");
++
++ user_shared_data = user_shared_data_external;
++ __wine_user_shared_data();
++
++ pthread_attr_init(&attr);
++ pthread_attr_setstacksize(&attr, 0x10000);
++ pthread_create(&thread, &attr, user_shared_data_thread, NULL);
++ pthread_attr_destroy(&attr);
++}
++
+ BOOL read_process_memory_stats(int unix_pid, VM_COUNTERS *pvmi)
+ {
+ BOOL ret = FALSE;
+--- a/dlls/ntdll/virtual.c
++++ b/dlls/ntdll/virtual.c
+@@ -2207,6 +2207,7 @@
+ {
+ NTSTATUS ret = STATUS_ACCESS_VIOLATION;
+ void *page = ROUND_ADDR( addr, page_mask );
++ BOOL update_shared_data = FALSE;
+ sigset_t sigset;
+ BYTE vprot;
+
+@@ -2232,7 +2233,23 @@
+ ret = STATUS_SUCCESS;
+ }
+ }
++ else if (!err && page == user_shared_data_external)
++ {
++ if (!(vprot & VPROT_READ))
++ {
++ set_page_vprot_bits( page, page_size, VPROT_READ | VPROT_WRITE, 0 );
++ mprotect_range( page, page_size, 0, 0 );
++ update_shared_data = TRUE;
++ }
++ /* ignore fault if page is readable now */
++ if (VIRTUAL_GetUnixProt( get_page_vprot( page )) & PROT_READ) ret = STATUS_SUCCESS;
++ else update_shared_data = FALSE;
++ }
+ server_leave_uninterrupted_section( &csVirtual, &sigset );
++
++ if (update_shared_data)
++ create_user_shared_data_thread();
++
+ return ret;
+ }
+
diff -Nru wine-development-5.5/debian/patches/ntdll-User_Shared_Data/0004-ntdll-tests-Test-updating-TickCount-in-user_shared_d.patch wine-development-5.5/debian/patches/ntdll-User_Shared_Data/0004-ntdll-tests-Test-updating-TickCount-in-user_shared_d.patch
--- wine-development-5.5/debian/patches/ntdll-User_Shared_Data/0004-ntdll-tests-Test-updating-TickCount-in-user_shared_d.patch 1970-01-01 01:00:00.000000000 +0100
+++ wine-development-5.5/debian/patches/ntdll-User_Shared_Data/0004-ntdll-tests-Test-updating-TickCount-in-user_shared_d.patch 2020-05-04 01:33:29.000000000 +0100
@@ -0,0 +1,73 @@
+From 6a1a8685b7ee9fa485a796963d9b2a3430067b14 Mon Sep 17 00:00:00 2001
+From: Andrew Wesie <awesie@gmail.com>
+Date: Tue, 2 May 2017 21:19:03 -0500
+Subject: ntdll/tests: Test updating TickCount in user_shared_data.
+
+---
+ dlls/ntdll/tests/time.c | 28 ++++++++++++++++++++++++++++
+ 1 file changed, 28 insertions(+)
+
+--- a/dlls/ntdll/tests/time.c
++++ b/dlls/ntdll/tests/time.c
+@@ -18,7 +18,9 @@
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
++#define NONAMELESSUNION
+ #include "ntdll_test.h"
++#include "ddk/wdm.h"
+
+ #define TICKSPERSEC 10000000
+ #define TICKSPERMSEC 10000
+@@ -29,6 +31,7 @@
+ static NTSTATUS (WINAPI *pNtQueryPerformanceCounter)( LARGE_INTEGER *counter, LARGE_INTEGER *frequency );
+ static NTSTATUS (WINAPI *pRtlQueryTimeZoneInformation)( RTL_TIME_ZONE_INFORMATION *);
+ static NTSTATUS (WINAPI *pRtlQueryDynamicTimeZoneInformation)( RTL_DYNAMIC_TIME_ZONE_INFORMATION *);
++static ULONG (WINAPI *pNtGetTickCount)(void);
+
+ static const int MonthLengths[2][12] =
+ {
+@@ -153,12 +156,36 @@
+ wine_dbgstr_w(tzinfo.DaylightName));
+ }
+
++static void test_NtGetTickCount(void)
++{
++#ifndef _WIN64
++ KSHARED_USER_DATA *user_shared_data = (void *)0x7ffe0000;
++ LONG diff;
++ int i;
++
++ if (!pNtGetTickCount)
++ {
++ win_skip("NtGetTickCount is not available\n");
++ return;
++ }
++
++ for (i = 0; i < 5; ++i)
++ {
++ diff = (user_shared_data->u.TickCountQuad * user_shared_data->TickCountMultiplier) >> 24;
++ diff = pNtGetTickCount() - diff;
++ ok(diff < 32, "NtGetTickCount - TickCountQuad too high, expected < 32 got %d\n", diff);
++ Sleep(50);
++ }
++#endif
++}
++
+ START_TEST(time)
+ {
+ HMODULE mod = GetModuleHandleA("ntdll.dll");
+ pRtlTimeToTimeFields = (void *)GetProcAddress(mod,"RtlTimeToTimeFields");
+ pRtlTimeFieldsToTime = (void *)GetProcAddress(mod,"RtlTimeFieldsToTime");
+ pNtQueryPerformanceCounter = (void *)GetProcAddress(mod, "NtQueryPerformanceCounter");
++ pNtGetTickCount = (void *)GetProcAddress(mod,"NtGetTickCount");
+ pRtlQueryTimeZoneInformation =
+ (void *)GetProcAddress(mod, "RtlQueryTimeZoneInformation");
+ pRtlQueryDynamicTimeZoneInformation =
+@@ -169,5 +196,6 @@
+ else
+ win_skip("Required time conversion functions are not available\n");
+ test_NtQueryPerformanceCounter();
++ test_NtGetTickCount();
+ test_RtlQueryTimeZoneInformation();
+ }
diff -Nru wine-development-5.5/debian/patches/ntdll-User_Shared_Data/definition wine-development-5.5/debian/patches/ntdll-User_Shared_Data/definition
--- wine-development-5.5/debian/patches/ntdll-User_Shared_Data/definition 1970-01-01 01:00:00.000000000 +0100
+++ wine-development-5.5/debian/patches/ntdll-User_Shared_Data/definition 2020-05-04 01:33:29.000000000 +0100
@@ -0,0 +1,2 @@
+Fixes: [29168] Update user shared data at realtime
+Depends: ntdll-Hide_Wine_Exports
diff -Nru wine-development-5.5/debian/patches/series wine-development-5.5/debian/patches/series
--- wine-development-5.5/debian/patches/series 2020-04-01 05:09:20.000000000 +0100
+++ wine-development-5.5/debian/patches/series 2020-05-04 01:33:29.000000000 +0100
@@ -1,3 +1,47 @@
+#Staging/0001-kernel32-Add-winediag-message-to-show-warning-that-t.patch
+#Staging/0002-winelib-Append-Staging-at-the-end-of-the-version-s.patch
+#Staging/0003-loader-Add-commandline-option-patches-to-show-the-pa.patch
+#Staging/0004-loader-Add-commandline-option-check-libs.patch
+#Staging/0005-loader-Print-library-paths-for-check-libs-on-Mac-OS-.patch
+advapi32-CreateRestrictedToken/0001-ntdll-Implement-NtFilterToken.patch
+advapi32-CreateRestrictedToken/0002-advapi32-Implement-CreateRestrictedToken.patch
+advapi32-Token_Integrity_Level/0001-advapi32-tests-Extend-security-label-token-integrity.patch
+advapi32-Token_Integrity_Level/0002-server-Implement-token-elevation-information.patch
+advapi32-Token_Integrity_Level/0003-server-Correctly-treat-zero-access-mask-in-duplicate.patch
+advapi32-Token_Integrity_Level/0004-server-Implement-token-integrity-level.patch
+advapi32-Token_Integrity_Level/0005-server-Use-all-group-attributes-in-create_token.patch
+advapi32-Token_Integrity_Level/0006-ntdll-Add-function-to-create-new-tokens-for-elevatio.patch
+advapi32-Token_Integrity_Level/0007-shell32-Implement-process-elevation-using-runas-verb.patch
+advapi32-Token_Integrity_Level/0008-ntdll-Implement-process-token-elevation-through-mani.patch
+advapi32-Token_Integrity_Level/0010-server-Implement-support-for-creating-processes-usin.patch
+advapi32-Token_Integrity_Level/0012-user32-Start-explorer.exe-using-limited-rights.patch
+advapi32-Token_Integrity_Level/0013-server-Correctly-assign-security-labels-for-tokens.patch
+advapi32-Token_Integrity_Level/0014-programs-runas-Basic-implementation-for-starting-pro.patch
+advapi32-Token_Integrity_Level/0015-ntdll-Add-semi-stub-for-TokenLinkedToken-info-class.patch
+ntdll-ThreadTime/0001-ntdll-Return-correct-values-in-GetThreadTimes-for-al.patch
+ntdll-ThreadTime/0002-ntdll-Set-correct-thread-creation-time-for-SystemPro.patch
+ntdll-ThreadTime/0003-ntdll-Fill-process-kernel-and-user-time.patch
+ntdll-ThreadTime/0004-ntdll-Set-process-start-time.patch
+ntdll-ThreadTime/0005-ntdll-Fill-out-thread-times-in-process-enumeration.patch
+ntdll-ThreadTime/0006-ntdll-Fill-process-virtual-memory-counters-in-NtQuer.patch
+ntdll-Hide_Wine_Exports/0001-ntdll-Add-support-for-hiding-wine-version-informatio.patch
+ntdll-User_Shared_Data/0001-ntdll-Move-code-to-update-user-shared-data-into-a-se.patch
+ntdll-User_Shared_Data/0002-ntoskrnl-Update-USER_SHARED_DATA-before-accessing-me.patch
+ntdll-User_Shared_Data/0003-ntdll-Create-thread-to-update-user_shared_data-time-.patch
+ntdll-User_Shared_Data/0004-ntdll-tests-Test-updating-TickCount-in-user_shared_d.patch
+winebuild-Fake_Dlls/0001-kernel32-tests-Add-basic-tests-for-fake-dlls.patch
+winebuild-Fake_Dlls/0002-krnl386.exe16-Do-not-abuse-WOW32Reserved-field-for-1.patch
+winebuild-Fake_Dlls/0003-winebuild-Generate-syscall-thunks-for-ntdll-exports.patch
+winebuild-Fake_Dlls/0004-winebuild-Use-multipass-label-system-to-generate-fak.patch
+winebuild-Fake_Dlls/0005-winebuild-Add-stub-functions-in-fake-dlls.patch
+winebuild-Fake_Dlls/0006-winebuild-Add-syscall-thunks-in-fake-dlls.patch
+winebuild-Fake_Dlls/0007-winebuild-Fix-size-of-relocation-information-in-fake.patch
+winebuild-Fake_Dlls/0008-winebuild-Try-to-make-sure-RVA-matches-between-fake-.patch
+winebuild-Fake_Dlls/0009-libs-wine-Use-same-file-alignment-for-fake-and-built.patch
+winebuild-Fake_Dlls/0010-tools-winebuild-Add-syscall-thunks-for-64-bit.patch
+winebuild-Fake_Dlls/0011-ntdll-Call-NtOpenFile-through-syscall-thunk.patch
+ntdll-Builtin_Prot/0001-ntdll-Fix-holes-in-ELF-mappings.patch
+
debianization/mingw.patch
debianization/addons.patch
debianization/makefile.patch
diff -Nru wine-development-5.5/debian/patches/Staging/0001-kernel32-Add-winediag-message-to-show-warning-that-t.patch wine-development-5.5/debian/patches/Staging/0001-kernel32-Add-winediag-message-to-show-warning-that-t.patch
--- wine-development-5.5/debian/patches/Staging/0001-kernel32-Add-winediag-message-to-show-warning-that-t.patch 1970-01-01 01:00:00.000000000 +0100
+++ wine-development-5.5/debian/patches/Staging/0001-kernel32-Add-winediag-message-to-show-warning-that-t.patch 2020-05-04 01:33:29.000000000 +0100
@@ -0,0 +1,36 @@
+From 9e585de1f2f28e1ef18c1edca875779c491375cb Mon Sep 17 00:00:00 2001
+From: Sebastian Lackner <sebastian@fds-team.de>
+Date: Thu, 2 Oct 2014 19:44:31 +0200
+Subject: [PATCH] kernel32: Add winediag message to show warning, that this
+ isn't vanilla wine.
+
+---
+ dlls/kernel32/process.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/dlls/kernel32/process.c
++++ b/dlls/kernel32/process.c
+@@ -61,6 +61,7 @@
+
+ WINE_DEFAULT_DEBUG_CHANNEL(process);
+ WINE_DECLARE_DEBUG_CHANNEL(relay);
++WINE_DECLARE_DEBUG_CHANNEL(winediag);
+
+ typedef struct
+ {
+@@ -145,6 +146,15 @@
+
+ __TRY
+ {
++ if (CreateEventA(0, 0, 0, "__winestaging_warn_event") && GetLastError() != ERROR_ALREADY_EXISTS)
++ {
++ FIXME_(winediag)("Wine Staging %s is a testing version containing experimental patches.\n", wine_get_version());
++ FIXME_(winediag)("Please mention your exact version when filing bug reports on winehq.org.\n");
++ }
++ else
++ WARN_(winediag)("Wine Staging %s is a testing version containing experimental patches.\n", wine_get_version());
++
++
+ if (!CheckRemoteDebuggerPresent( GetCurrentProcess(), &being_debugged ))
+ being_debugged = FALSE;
+
diff -Nru wine-development-5.5/debian/patches/Staging/0002-winelib-Append-Staging-at-the-end-of-the-version-s.patch wine-development-5.5/debian/patches/Staging/0002-winelib-Append-Staging-at-the-end-of-the-version-s.patch
--- wine-development-5.5/debian/patches/Staging/0002-winelib-Append-Staging-at-the-end-of-the-version-s.patch 1970-01-01 01:00:00.000000000 +0100
+++ wine-development-5.5/debian/patches/Staging/0002-winelib-Append-Staging-at-the-end-of-the-version-s.patch 2020-05-04 01:33:29.000000000 +0100
@@ -0,0 +1,25 @@
+From 05ca39b029f8f710ca53aeafc36384fd39fd6b89 Mon Sep 17 00:00:00 2001
+From: Sebastian Lackner <sebastian@fds-team.de>
+Date: Thu, 2 Oct 2014 19:53:46 +0200
+Subject: [PATCH] winelib: Append '(Staging)' at the end of the version string.
+
+---
+ libs/wine/Makefile.in | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/libs/wine/Makefile.in b/libs/wine/Makefile.in
+index 4833eb5..3cfa4f4 100644
+--- a/libs/wine/Makefile.in
++++ b/libs/wine/Makefile.in
+@@ -31,7 +31,7 @@ libwine_LDFLAGS = $(LIBWINE_LDFLAGS)
+ libwine_DEPS = $(LIBWINE_DEPENDS)
+
+ version.c: dummy
+- version=`(GIT_DIR=$(top_srcdir)/.git git describe HEAD 2>/dev/null || echo "wine-$(PACKAGE_VERSION)") | sed -n -e '$$s/\(.*\)/const char wine_build[] = "\1";/p'` && (echo $$version | cmp -s - $@) || echo $$version >$@ || (rm -f $@ && exit 1)
++ version=`(GIT_DIR=$(top_srcdir)/.git git describe HEAD 2>/dev/null || echo "wine-$(PACKAGE_VERSION)") | sed -n -e '$$s/\(.*\)/const char wine_build[] = "\1 (Staging)";/p'` && (echo $$version | cmp -s - $@) || echo $$version >$@ || (rm -f $@ && exit 1)
+
+ dummy:
+ .PHONY: dummy
+--
+1.9.1
+
diff -Nru wine-development-5.5/debian/patches/Staging/0003-loader-Add-commandline-option-patches-to-show-the-pa.patch wine-development-5.5/debian/patches/Staging/0003-loader-Add-commandline-option-patches-to-show-the-pa.patch
--- wine-development-5.5/debian/patches/Staging/0003-loader-Add-commandline-option-patches-to-show-the-pa.patch 1970-01-01 01:00:00.000000000 +0100
+++ wine-development-5.5/debian/patches/Staging/0003-loader-Add-commandline-option-patches-to-show-the-pa.patch 2020-05-04 01:33:29.000000000 +0100
@@ -0,0 +1,135 @@
+From d216f85a593a09e7983d9178fb3e1f20bfcf08cc Mon Sep 17 00:00:00 2001
+From: Sebastian Lackner <sebastian@fds-team.de>
+Date: Thu, 29 May 2014 23:43:45 +0200
+Subject: [PATCH] loader: Add commandline option --patches to show the patch
+ list.
+
+---
+ dlls/ntdll/misc.c | 8 ++++++++
+ dlls/ntdll/ntdll.spec | 1 +
+ include/wine/library.h | 1 +
+ libs/wine/config.c | 6 ++++++
+ libs/wine/wine.map | 1 +
+ loader/main.c | 42 +++++++++++++++++++++++++++++++++++++++++-
+ 6 files changed, 58 insertions(+), 1 deletion(-)
+
+--- a/dlls/ntdll/misc.c
++++ b/dlls/ntdll/misc.c
+@@ -61,6 +61,14 @@
+ }
+
+ /*********************************************************************
++ * wine_get_patches (NTDLL.@)
++ */
++const void * CDECL NTDLL_wine_get_patches(void)
++{
++ return wine_get_patches();
++}
++
++/*********************************************************************
+ * wine_get_build_id (NTDLL.@)
+ */
+ const char * CDECL NTDLL_wine_get_build_id(void)
+--- a/dlls/ntdll/ntdll.spec
++++ b/dlls/ntdll/ntdll.spec
+@@ -1570,6 +1570,7 @@
+
+ # Version
+ @ cdecl wine_get_version() NTDLL_wine_get_version
++@ cdecl wine_get_patches() NTDLL_wine_get_patches
+ @ cdecl wine_get_build_id() NTDLL_wine_get_build_id
+ @ cdecl wine_get_host_version(ptr ptr) NTDLL_wine_get_host_version
+
+--- a/include/wine/library.h
++++ b/include/wine/library.h
+@@ -47,6 +47,7 @@
+ extern const char *wine_get_server_dir(void);
+ extern const char *wine_get_user_name(void);
+ extern const char *wine_get_version(void);
++extern const void *wine_get_patches(void);
+ extern const char *wine_get_build_id(void);
+ extern void wine_init_argv0_path( const char *argv0 );
+ extern void wine_exec_wine_binary( const char *name, char **argv, const char *env_var );
+--- a/libs/wine/config.c
++++ b/libs/wine/config.c
+@@ -504,6 +504,12 @@
+ return PACKAGE_VERSION;
+ }
+
++/* return the applied non-standard patches */
++const void *wine_get_patches(void)
++{
++ return NULL;
++}
++
+ /* return the build id string */
+ const char *wine_get_build_id(void)
+ {
+--- a/libs/wine/wine.map
++++ b/libs/wine/wine.map
+@@ -28,6 +28,7 @@
+ wine_get_ss;
+ wine_get_user_name;
+ wine_get_version;
++ wine_get_patches;
+ wine_init;
+ wine_init_argv0_path;
+ wine_ldt_alloc_entries;
+--- a/loader/main.c
++++ b/loader/main.c
+@@ -53,7 +53,8 @@
+ static const char usage[] =
+ "Usage: wine PROGRAM [ARGUMENTS...] Run the specified program\n"
+ " wine --help Display this help and exit\n"
+- " wine --version Output version information and exit";
++ " wine --version Output version information and exit\n"
++ " wine --patches Output patch information and exit";
+
+ if (argc <= 1)
+ {
+@@ -70,6 +71,45 @@
+ printf( "%s\n", wine_get_build_id() );
+ exit(0);
+ }
++ if (!strcmp( argv[1], "--patches" ))
++ {
++ const struct
++ {
++ const char *author;
++ const char *subject;
++ int revision;
++ }
++ *next, *cur = wine_get_patches();
++
++ if (!cur)
++ {
++ fprintf( stderr, "Patchlist not available.\n" );
++ exit(1);
++ }
++
++ while (cur->author)
++ {
++ next = cur + 1;
++ while (next->author)
++ {
++ if (strcmp( cur->author, next->author )) break;
++ next++;
++ }
++
++ printf( "%s (%d):\n", cur->author, (int)(next - cur) );
++ while (cur < next)
++ {
++ printf( " %s", cur->subject );
++ if (cur->revision != 1)
++ printf( " [rev %d]", cur->revision );
++ printf( "\n" );
++ cur++;
++ }
++ printf( "\n" );
++ }
++
++ exit(0);
++ }
+ }
+
+
diff -Nru wine-development-5.5/debian/patches/Staging/0004-loader-Add-commandline-option-check-libs.patch wine-development-5.5/debian/patches/Staging/0004-loader-Add-commandline-option-check-libs.patch
--- wine-development-5.5/debian/patches/Staging/0004-loader-Add-commandline-option-check-libs.patch 1970-01-01 01:00:00.000000000 +0100
+++ wine-development-5.5/debian/patches/Staging/0004-loader-Add-commandline-option-check-libs.patch 2020-05-04 01:33:29.000000000 +0100
@@ -0,0 +1,300 @@
+From df12fdb8d4cdf11d9f72a068923a5b0097e36bdb Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
+Date: Wed, 28 May 2014 19:50:51 +0200
+Subject: [PATCH] loader: Add commandline option --check-libs.
+
+---
+ include/wine/library.h | 2 +
+ libs/wine/config.c | 124 +++++++++++++++++++++++++++++++++++++++++
+ libs/wine/loader.c | 36 ++++++++++++
+ libs/wine/wine.map | 2 +
+ loader/main.c | 50 ++++++++++++++++-
+ 5 files changed, 213 insertions(+), 1 deletion(-)
+
+--- a/include/wine/library.h
++++ b/include/wine/library.h
+@@ -44,6 +44,7 @@
+ extern const char *wine_get_build_dir(void);
+ extern const char *wine_get_config_dir(void);
+ extern const char *wine_get_data_dir(void);
++extern const char **wine_get_libs(void);
+ extern const char *wine_get_server_dir(void);
+ extern const char *wine_get_user_name(void);
+ extern const char *wine_get_version(void);
+@@ -56,6 +57,7 @@
+
+ typedef void (*load_dll_callback_t)( void *, const char * );
+
++extern int wine_dladdr( void *addr, void *info, char *error, size_t errorsize );
+ extern void *wine_dlopen( const char *filename, int flag, char *error, size_t errorsize );
+ extern void *wine_dlsym( void *handle, const char *symbol, char *error, size_t errorsize );
+ extern int wine_dlclose( void *handle, char *error, size_t errorsize );
+--- a/libs/wine/config.c
++++ b/libs/wine/config.c
+@@ -470,6 +470,130 @@
+ return build_dir;
+ }
+
++const char *wine_libs[] = {
++#ifdef SONAME_LIBCAIRO
++ SONAME_LIBCAIRO,
++#endif
++#ifdef SONAME_LIBCAPI20
++ SONAME_LIBCAPI20,
++#endif
++#ifdef SONAME_LIBCUPS
++ SONAME_LIBCUPS,
++#endif
++#ifdef SONAME_LIBCURSES
++ SONAME_LIBCURSES,
++#endif
++#ifdef SONAME_LIBDBUS_1
++ SONAME_LIBDBUS_1,
++#endif
++#ifdef SONAME_LIBFONTCONFIG
++ SONAME_LIBFONTCONFIG,
++#endif
++#ifdef SONAME_LIBFREETYPE
++ SONAME_LIBFREETYPE,
++#endif
++#ifdef SONAME_LIBGL
++ SONAME_LIBGL,
++#endif
++#ifdef SONAME_LIBGNUTLS
++ SONAME_LIBGNUTLS,
++#endif
++#ifdef SONAME_LIBGOBJECT_2_0
++ SONAME_LIBGOBJECT_2_0,
++#endif
++#ifdef SONAME_LIBGSM
++ SONAME_LIBGSM,
++#endif
++#ifdef SONAME_LIBGTK_3
++ SONAME_LIBGTK_3,
++#endif
++#ifdef SONAME_LIBHAL
++ SONAME_LIBHAL,
++#endif
++#ifdef SONAME_LIBJPEG
++ SONAME_LIBJPEG,
++#endif
++#ifdef SONAME_LIBNCURSES
++ SONAME_LIBNCURSES,
++#endif
++#ifdef SONAME_LIBNETAPI
++ SONAME_LIBNETAPI,
++#endif
++#ifdef SONAME_LIBODBC
++ SONAME_LIBODBC,
++#endif
++#ifdef SONAME_LIBOSMESA
++ SONAME_LIBOSMESA,
++#endif
++#ifdef SONAME_LIBPCAP
++ SONAME_LIBPCAP,
++#endif
++#ifdef SONAME_LIBPNG
++ SONAME_LIBPNG,
++#endif
++#ifdef SONAME_LIBSANE
++ SONAME_LIBSANE,
++#endif
++#ifdef SONAME_LIBTIFF
++ SONAME_LIBTIFF,
++#endif
++#ifdef SONAME_LIBTXC_DXTN
++ SONAME_LIBTXC_DXTN,
++#endif
++#ifdef SONAME_LIBV4L1
++ SONAME_LIBV4L1,
++#endif
++#ifdef SONAME_LIBVA
++ SONAME_LIBVA,
++#endif
++#ifdef SONAME_LIBVA_DRM
++ SONAME_LIBVA_DRM,
++#endif
++#ifdef SONAME_LIBVA_X11
++ SONAME_LIBVA_X11,
++#endif
++#ifdef SONAME_LIBX11
++ SONAME_LIBX11,
++#endif
++#ifdef SONAME_LIBX11_XCB
++ SONAME_LIBX11_XCB,
++#endif
++#ifdef SONAME_LIBXCOMPOSITE
++ SONAME_LIBXCOMPOSITE,
++#endif
++#ifdef SONAME_LIBXCURSOR
++ SONAME_LIBXCURSOR,
++#endif
++#ifdef SONAME_LIBXEXT
++ SONAME_LIBXEXT,
++#endif
++#ifdef SONAME_LIBXI
++ SONAME_LIBXI,
++#endif
++#ifdef SONAME_LIBXINERAMA
++ SONAME_LIBXINERAMA,
++#endif
++#ifdef SONAME_LIBXRANDR
++ SONAME_LIBXRANDR,
++#endif
++#ifdef SONAME_LIBXRENDER
++ SONAME_LIBXRENDER,
++#endif
++#ifdef SONAME_LIBXSLT
++ SONAME_LIBXSLT,
++#endif
++#ifdef SONAME_LIBXXF86VM
++ SONAME_LIBXXF86VM,
++#endif
++ NULL
++};
++
++/* return the list of shared libs used by wine */
++const char **wine_get_libs(void)
++{
++ return &wine_libs[0];
++}
++
+ /* return the full name of the server directory (the one containing the socket) */
+ const char *wine_get_server_dir(void)
+ {
+--- a/libs/wine/loader.c
++++ b/libs/wine/loader.c
+@@ -1073,6 +1073,42 @@
+ }
+
+ /***********************************************************************
++ * wine_dladdr
++ */
++int wine_dladdr( void *addr, void *info, char *error, size_t errorsize )
++{
++#ifdef HAVE_DLADDR
++ int ret;
++ const char *s;
++ dlerror(); dlerror();
++ ret = dladdr( addr, (Dl_info *)info );
++ s = dlerror();
++ if (error && errorsize)
++ {
++ if (s)
++ {
++ size_t len = strlen(s);
++ if (len >= errorsize) len = errorsize - 1;
++ memcpy( error, s, len );
++ error[len] = 0;
++ }
++ else error[0] = 0;
++ }
++ dlerror();
++ return ret;
++#else
++ if (error)
++ {
++ static const char msg[] = "dladdr interface not detected by configure";
++ size_t len = min( errorsize, sizeof(msg) );
++ memcpy( error, msg, len );
++ error[len - 1] = 0;
++ }
++ return 0;
++#endif
++}
++
++/***********************************************************************
+ * wine_dlsym
+ */
+ void *wine_dlsym( void *handle, const char *symbol, char *error, size_t errorsize )
+--- a/libs/wine/wine.map
++++ b/libs/wine/wine.map
+@@ -9,6 +9,7 @@
+ wine_anon_mmap;
+ wine_casemap_lower;
+ wine_casemap_upper;
++ wine_dladdr;
+ wine_dlclose;
+ wine_dll_enum_load_path;
+ wine_dll_set_callback;
+@@ -24,6 +25,7 @@
+ wine_get_es;
+ wine_get_fs;
+ wine_get_gs;
++ wine_get_libs;
+ wine_get_server_dir;
+ wine_get_ss;
+ wine_get_user_name;
+--- a/loader/main.c
++++ b/loader/main.c
+@@ -36,6 +36,12 @@
+ #ifdef HAVE_UNISTD_H
+ # include <unistd.h>
+ #endif
++#ifdef HAVE_DLADDR
++# include <dlfcn.h>
++#endif
++#ifdef HAVE_LINK_H
++# include <link.h>
++#endif
+
+ #include "wine/library.h"
+ #include "main.h"
+@@ -54,7 +60,8 @@
+ "Usage: wine PROGRAM [ARGUMENTS...] Run the specified program\n"
+ " wine --help Display this help and exit\n"
+ " wine --version Output version information and exit\n"
+- " wine --patches Output patch information and exit";
++ " wine --patches Output patch information and exit\n"
++ " wine --check-libs Checks if shared libs are installed";
+
+ if (argc <= 1)
+ {
+@@ -110,6 +117,47 @@
+
+ exit(0);
+ }
++ if (!strcmp( argv[1], "--check-libs" ))
++ {
++ void* lib_handle;
++ int ret = 0;
++ const char **wine_libs = wine_get_libs();
++
++ for(; *wine_libs; wine_libs++)
++ {
++ lib_handle = wine_dlopen( *wine_libs, RTLD_NOW, NULL, 0 );
++ if (lib_handle)
++ {
++ #ifdef HAVE_DLADDR
++ Dl_info libinfo;
++ void* symbol;
++
++ #ifdef HAVE_LINK_H
++ struct link_map *lm = (struct link_map *)lib_handle;
++ symbol = (void *)lm->l_addr;
++ #else
++ symbol = wine_dlsym( lib_handle, "_init", NULL, 0 );
++ #endif
++ if (symbol && wine_dladdr( symbol, &libinfo, NULL, 0 ))
++ {
++ printf( "%s: %s\n", *wine_libs, libinfo.dli_fname );
++ }
++ else
++ #endif
++ {
++ printf( "%s: found\n", *wine_libs );
++ }
++ wine_dlclose( lib_handle, NULL, 0 );
++ }
++ else
++ {
++ printf( "%s: missing\n", *wine_libs );
++ ret = 1;
++ }
++ }
++
++ exit(ret);
++ }
+ }
+
+
diff -Nru wine-development-5.5/debian/patches/Staging/0005-loader-Print-library-paths-for-check-libs-on-Mac-OS-.patch wine-development-5.5/debian/patches/Staging/0005-loader-Print-library-paths-for-check-libs-on-Mac-OS-.patch
--- wine-development-5.5/debian/patches/Staging/0005-loader-Print-library-paths-for-check-libs-on-Mac-OS-.patch 1970-01-01 01:00:00.000000000 +0100
+++ wine-development-5.5/debian/patches/Staging/0005-loader-Print-library-paths-for-check-libs-on-Mac-OS-.patch 2020-05-04 01:33:29.000000000 +0100
@@ -0,0 +1,55 @@
+From 07ca5e888c3265c57c88ef1758e6c47fbea4fb07 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
+Date: Sat, 27 Jun 2015 19:28:51 +0200
+Subject: loader: Print library paths for --check-libs on Mac OS X.
+
+---
+ loader/main.c | 30 +++++++++++++++++++++++++++++-
+ 1 file changed, 29 insertions(+), 1 deletion(-)
+
+--- a/loader/main.c
++++ b/loader/main.c
+@@ -49,6 +49,30 @@
+ /* the preloader will set this variable */
+ const struct wine_preload_info *wine_main_preload_info = NULL;
+
++#ifdef __APPLE__
++#include <mach-o/dyld.h>
++
++static const char *get_macho_library_path( const char *libname )
++{
++ unsigned int path_len, libname_len = strlen( libname );
++ uint32_t i, count = _dyld_image_count();
++
++ for (i = 0; i < count; i++)
++ {
++ const char *path = _dyld_get_image_name( i );
++ if (!path) continue;
++
++ path_len = strlen( path );
++ if (path_len < libname_len + 1) continue;
++ if (path[path_len - libname_len - 1] != '/') continue;
++ if (strcmp( path + path_len - libname_len, libname )) continue;
++
++ return path;
++ }
++ return NULL;
++}
++#endif
++
+ /***********************************************************************
+ * check_command_line
+ *
+@@ -145,7 +169,11 @@
+ else
+ #endif
+ {
+- printf( "%s: found\n", *wine_libs );
++ const char *path = NULL;
++ #ifdef __APPLE__
++ path = get_macho_library_path( *wine_libs );
++ #endif
++ printf( "%s: %s\n", *wine_libs, path ? path : "found");
+ }
+ wine_dlclose( lib_handle, NULL, 0 );
+ }
diff -Nru wine-development-5.5/debian/patches/winebuild-Fake_Dlls/0001-kernel32-tests-Add-basic-tests-for-fake-dlls.patch wine-development-5.5/debian/patches/winebuild-Fake_Dlls/0001-kernel32-tests-Add-basic-tests-for-fake-dlls.patch
--- wine-development-5.5/debian/patches/winebuild-Fake_Dlls/0001-kernel32-tests-Add-basic-tests-for-fake-dlls.patch 1970-01-01 01:00:00.000000000 +0100
+++ wine-development-5.5/debian/patches/winebuild-Fake_Dlls/0001-kernel32-tests-Add-basic-tests-for-fake-dlls.patch 2020-05-04 01:33:29.000000000 +0100
@@ -0,0 +1,116 @@
+From 1d5ed7be366c36c9ca16a8783e4fb7dfc7e9bc73 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
+Date: Thu, 25 May 2017 07:02:46 +0200
+Subject: [PATCH] kernel32/tests: Add basic tests for fake dlls.
+
+---
+ dlls/kernel32/tests/loader.c | 91 ++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 91 insertions(+)
+
+--- a/dlls/kernel32/tests/loader.c
++++ b/dlls/kernel32/tests/loader.c
+@@ -1535,6 +1535,96 @@
+ DeleteFileA( long_path );
+ }
+
++static void test_FakeDLL(void)
++{
++#ifdef __i386__
++ NTSTATUS (WINAPI *pNtSetEvent)(HANDLE, ULONG *) = NULL;
++ IMAGE_EXPORT_DIRECTORY *dir;
++ HMODULE module = GetModuleHandleA("ntdll.dll");
++ HANDLE file, map, event;
++ WCHAR path[MAX_PATH];
++ DWORD *names, *funcs;
++ WORD *ordinals;
++ ULONG size;
++ void *ptr;
++ int i;
++
++ GetModuleFileNameW(module, path, MAX_PATH);
++
++ file = CreateFileW(path, GENERIC_READ | GENERIC_EXECUTE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
++ ok(file != INVALID_HANDLE_VALUE, "Failed to open %s (error %u)\n", wine_dbgstr_w(path), GetLastError());
++
++ map = CreateFileMappingW(file, NULL, PAGE_EXECUTE_READ | SEC_IMAGE, 0, 0, NULL);
++ ok(map != NULL, "CreateFileMapping failed with error %u\n", GetLastError());
++ ptr = MapViewOfFile(map, FILE_MAP_READ | FILE_MAP_EXECUTE, 0, 0, 0);
++ ok(ptr != NULL, "MapViewOfFile failed with error %u\n", GetLastError());
++
++ dir = RtlImageDirectoryEntryToData(ptr, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &size);
++todo_wine
++ ok(dir != NULL, "RtlImageDirectoryEntryToData failed\n");
++ if (dir == NULL) goto done;
++
++ names = RVAToAddr(dir->AddressOfNames, ptr);
++ ordinals = RVAToAddr(dir->AddressOfNameOrdinals, ptr);
++ funcs = RVAToAddr(dir->AddressOfFunctions, ptr);
++ ok(dir->NumberOfNames > 0, "Could not find any exported functions\n");
++
++ for (i = 0; i < dir->NumberOfNames; i++)
++ {
++ DWORD map_rva, dll_rva, map_offset, dll_offset;
++ char *func_name = RVAToAddr(names[i], ptr);
++ BYTE *dll_func, *map_func;
++
++ /* check only Nt functions for now */
++ if (strncmp(func_name, "Zw", 2) && strncmp(func_name, "Nt", 2))
++ continue;
++
++ dll_func = (BYTE *)GetProcAddress(module, func_name);
++ ok(dll_func != NULL, "%s: GetProcAddress returned NULL\n", func_name);
++ if (dll_func[0] == 0x90 && dll_func[1] == 0x90 &&
++ dll_func[2] == 0x90 && dll_func[3] == 0x90)
++ {
++ todo_wine ok(0, "%s: Export is a stub-function, skipping\n", func_name);
++ continue;
++ }
++
++ /* check position in memory */
++ dll_rva = (DWORD_PTR)dll_func - (DWORD_PTR)module;
++ map_rva = funcs[ordinals[i]];
++ ok(map_rva == dll_rva, "%s: Rva of mapped function (0x%x) does not match dll (0x%x)\n",
++ func_name, dll_rva, map_rva);
++
++ /* check position in file */
++ map_offset = (DWORD_PTR)RtlImageRvaToVa(RtlImageNtHeader(ptr), ptr, map_rva, NULL) - (DWORD_PTR)ptr;
++ dll_offset = (DWORD_PTR)RtlImageRvaToVa(RtlImageNtHeader(module), module, dll_rva, NULL) - (DWORD_PTR)module;
++ ok(map_offset == dll_offset, "%s: File offset of mapped function (0x%x) does not match dll (0x%x)\n",
++ func_name, map_offset, dll_offset);
++
++ /* check function content */
++ map_func = RVAToAddr(map_rva, ptr);
++ ok(!memcmp(map_func, dll_func, 0x20), "%s: Function content does not match!\n", func_name);
++
++ if (!strcmp(func_name, "NtSetEvent"))
++ pNtSetEvent = (void *)map_func;
++ }
++
++ ok(pNtSetEvent != NULL, "Could not find NtSetEvent export\n");
++ if (pNtSetEvent)
++ {
++ event = CreateEventA(NULL, TRUE, FALSE, NULL);
++ ok(event != NULL, "CreateEvent failed with error %u\n", GetLastError());
++ pNtSetEvent(event, 0);
++ ok(WaitForSingleObject(event, 0) == WAIT_OBJECT_0, "Event was not signaled\n");
++ CloseHandle(event);
++ }
++
++done:
++ UnmapViewOfFile(ptr);
++ CloseHandle(map);
++ CloseHandle(file);
++#endif
++}
++
+ /* Verify linking style of import descriptors */
+ static void test_ImportDescriptors(void)
+ {
+@@ -3997,6 +4087,7 @@
+ return;
+ }
+
++ test_FakeDLL();
+ test_filenames();
+ test_ResolveDelayLoadedAPI();
+ test_ImportDescriptors();
diff -Nru wine-development-5.5/debian/patches/winebuild-Fake_Dlls/0002-krnl386.exe16-Do-not-abuse-WOW32Reserved-field-for-1.patch wine-development-5.5/debian/patches/winebuild-Fake_Dlls/0002-krnl386.exe16-Do-not-abuse-WOW32Reserved-field-for-1.patch
--- wine-development-5.5/debian/patches/winebuild-Fake_Dlls/0002-krnl386.exe16-Do-not-abuse-WOW32Reserved-field-for-1.patch 1970-01-01 01:00:00.000000000 +0100
+++ wine-development-5.5/debian/patches/winebuild-Fake_Dlls/0002-krnl386.exe16-Do-not-abuse-WOW32Reserved-field-for-1.patch 2020-05-04 01:33:29.000000000 +0100
@@ -0,0 +1,625 @@
+From 7d097bf5d20c03203d455501bb04151c3faf3dcb Mon Sep 17 00:00:00 2001
+From: Sebastian Lackner <sebastian@fds-team.de>
+Date: Tue, 16 May 2017 04:37:52 +0200
+Subject: [PATCH] krnl386.exe16: Do not abuse WOW32Reserved field for 16-bit
+ stack address.
+
+---
+ dlls/dbghelp/cpu_i386.c | 6 ++---
+ dlls/krnl386.exe16/kernel.c | 6 ++---
+ dlls/krnl386.exe16/kernel16_private.h | 11 ++++----
+ dlls/krnl386.exe16/ne_module.c | 6 ++---
+ dlls/krnl386.exe16/ne_segment.c | 20 +++++++--------
+ dlls/krnl386.exe16/task.c | 14 +++++------
+ dlls/krnl386.exe16/thunk.c | 36 +++++++++++++--------------
+ dlls/krnl386.exe16/wowthunk.c | 20 +++++++--------
+ dlls/ntdll/signal_i386.c | 2 +-
+ dlls/system.drv16/system.c | 2 +-
+ dlls/toolhelp.dll16/toolhelp.c | 6 ++---
+ dlls/user.exe16/message.c | 16 ++++++------
+ dlls/user.exe16/user.c | 4 +--
+ dlls/user.exe16/window.c | 2 +-
+ include/winternl.h | 2 +-
+ tools/winebuild/relay.c | 2 +-
+ 16 files changed, 78 insertions(+), 77 deletions(-)
+
+--- a/dlls/dbghelp/cpu_i386.c
++++ b/dlls/dbghelp/cpu_i386.c
+@@ -213,16 +213,16 @@
+ /* Init done */
+ set_curr_mode((frame->AddrPC.Mode == AddrModeFlat) ? stm_32bit : stm_16bit);
+
+- /* cur_switch holds address of WOW32Reserved field in TEB in debuggee
++ /* cur_switch holds address of SystemReserved1[0] field in TEB in debuggee
+ * address space
+ */
+ if (NtQueryInformationThread(csw->hThread, ThreadBasicInformation, &info,
+ sizeof(info), NULL) == STATUS_SUCCESS)
+ {
+- curr_switch = (DWORD_PTR)info.TebBaseAddress + FIELD_OFFSET(TEB, WOW32Reserved);
++ curr_switch = (DWORD_PTR)info.TebBaseAddress + FIELD_OFFSET(TEB, SystemReserved1[0]);
+ if (!sw_read_mem(csw, curr_switch, &p, sizeof(p)))
+ {
+- WARN("Can't read TEB:WOW32Reserved\n");
++ WARN("Can't read TEB:SystemReserved1[0]\n");
+ goto done_err;
+ }
+ next_switch = p;
+--- a/dlls/krnl386.exe16/kernel.c
++++ b/dlls/krnl386.exe16/kernel.c
+@@ -45,8 +45,8 @@
+ /* allocate the 16-bit stack (FIXME: should be done lazily) */
+ HGLOBAL16 hstack = WOWGlobalAlloc16( GMEM_FIXED, 0x10000 );
+ kernel_get_thread_data()->stack_sel = GlobalHandleToSel16( hstack );
+- NtCurrentTeb()->WOW32Reserved = (void *)MAKESEGPTR( kernel_get_thread_data()->stack_sel,
+- 0x10000 - sizeof(STACK16FRAME) );
++ NtCurrentTeb()->SystemReserved1[0] = (void *)MAKESEGPTR( kernel_get_thread_data()->stack_sel,
++ 0x10000 - sizeof(STACK16FRAME) );
+ memset( (char *)GlobalLock16(hstack) + 0x10000 - sizeof(STACK16FRAME), 0, sizeof(STACK16FRAME) );
+ }
+
+@@ -58,7 +58,7 @@
+ {
+ /* free the 16-bit stack */
+ WOWGlobalFree16( kernel_get_thread_data()->stack_sel );
+- NtCurrentTeb()->WOW32Reserved = 0;
++ NtCurrentTeb()->SystemReserved1[0] = 0;
+ if (NtCurrentTeb()->Tib.SubSystemTib) TASK_ExitTask();
+ }
+
+--- a/dlls/krnl386.exe16/kernel16_private.h
++++ b/dlls/krnl386.exe16/kernel16_private.h
+@@ -170,7 +170,7 @@
+ (((offset)+(size) <= pModule->mapping_size) ? \
+ (memcpy( buffer, (const char *)pModule->mapping + (offset), (size) ), TRUE) : FALSE)
+
+-#define CURRENT_STACK16 ((STACK16FRAME*)MapSL(PtrToUlong(NtCurrentTeb()->WOW32Reserved)))
++#define CURRENT_STACK16 ((STACK16FRAME*)MapSL(PtrToUlong(NtCurrentTeb()->SystemReserved1[0])))
+ #define CURRENT_DS (CURRENT_STACK16->ds)
+
+ /* push bytes on the 16-bit stack of a thread; return a segptr to the first pushed byte */
+@@ -178,8 +178,8 @@
+ {
+ STACK16FRAME *frame = CURRENT_STACK16;
+ memmove( (char*)frame - size, frame, sizeof(*frame) );
+- NtCurrentTeb()->WOW32Reserved = (char *)NtCurrentTeb()->WOW32Reserved - size;
+- return (SEGPTR)((char *)NtCurrentTeb()->WOW32Reserved + sizeof(*frame));
++ NtCurrentTeb()->SystemReserved1[0] = (char *)NtCurrentTeb()->SystemReserved1[0] - size;
++ return (SEGPTR)((char *)NtCurrentTeb()->SystemReserved1[0] + sizeof(*frame));
+ }
+
+ /* pop bytes from the 16-bit stack of a thread */
+@@ -187,7 +187,7 @@
+ {
+ STACK16FRAME *frame = CURRENT_STACK16;
+ memmove( (char*)frame + size, frame, sizeof(*frame) );
+- NtCurrentTeb()->WOW32Reserved = (char *)NtCurrentTeb()->WOW32Reserved + size;
++ NtCurrentTeb()->SystemReserved1[0] = (char *)NtCurrentTeb()->SystemReserved1[0] + size;
+ }
+
+ /* dosmem.c */
+@@ -273,11 +273,12 @@
+
+ struct kernel_thread_data
+ {
++ void *reserved; /* stack segment pointer */
+ WORD stack_sel; /* 16-bit stack selector */
+ WORD htask16; /* Win16 task handle */
+ DWORD sys_count[4]; /* syslevel mutex entry counters */
+ struct tagSYSLEVEL *sys_mutex[4]; /* syslevel mutex pointers */
+- void *pad[45]; /* change this if you add fields! */
++ void *pad[44]; /* change this if you add fields! */
+ };
+
+ static inline struct kernel_thread_data *kernel_get_thread_data(void)
+--- a/dlls/krnl386.exe16/ne_module.c
++++ b/dlls/krnl386.exe16/ne_module.c
+@@ -1217,7 +1217,7 @@
+ sp = pSegTable[SELECTOROF(pModule->ne_sssp)-1].minsize + pModule->ne_stack;
+ sp &= ~1;
+ sp -= sizeof(STACK16FRAME);
+- NtCurrentTeb()->WOW32Reserved = (void *)MAKESEGPTR( GlobalHandleToSel16(hInstance), sp );
++ NtCurrentTeb()->SystemReserved1[0] = (void *)MAKESEGPTR( GlobalHandleToSel16(hInstance), sp );
+
+ /* Registers at initialization must be:
+ * ax zero
+@@ -1245,8 +1245,8 @@
+
+ TRACE("Starting main program: cs:ip=%04x:%04x ds=%04x ss:sp=%04x:%04x\n",
+ context.SegCs, context.Eip, context.SegDs,
+- SELECTOROF(NtCurrentTeb()->WOW32Reserved),
+- OFFSETOF(NtCurrentTeb()->WOW32Reserved) );
++ SELECTOROF(NtCurrentTeb()->SystemReserved1[0]),
++ OFFSETOF(NtCurrentTeb()->SystemReserved1[0]) );
+
+ WOWCallback16Ex( 0, WCB16_REGS, 0, NULL, (DWORD *)&context );
+ ExitThread( LOWORD(context.Eax) );
+--- a/dlls/krnl386.exe16/ne_segment.c
++++ b/dlls/krnl386.exe16/ne_segment.c
+@@ -378,9 +378,9 @@
+ DWORD ret;
+
+ selfloadheader = MapSL( MAKESEGPTR(SEL(pSegTable->hSeg),0) );
+- oldstack = NtCurrentTeb()->WOW32Reserved;
+- NtCurrentTeb()->WOW32Reserved = (void *)MAKESEGPTR(pModule->self_loading_sel,
+- 0xff00 - sizeof(STACK16FRAME));
++ oldstack = NtCurrentTeb()->SystemReserved1[0];
++ NtCurrentTeb()->SystemReserved1[0] = (void *)MAKESEGPTR(pModule->self_loading_sel,
++ 0xff00 - sizeof(STACK16FRAME));
+
+ hFile16 = NE_OpenFile( pModule );
+ TRACE_(dll)("Call LoadAppSegProc(hmodule=0x%04x,hf=%x,segnum=%d)\n",
+@@ -392,7 +392,7 @@
+ pSeg->hSeg = LOWORD(ret);
+ TRACE_(dll)("Ret LoadAppSegProc: hSeg=0x%04x\n", pSeg->hSeg);
+ _lclose16( hFile16 );
+- NtCurrentTeb()->WOW32Reserved = oldstack;
++ NtCurrentTeb()->SystemReserved1[0] = oldstack;
+
+ pSeg->flags |= NE_SEGFLAGS_LOADED;
+ return TRUE;
+@@ -484,9 +484,9 @@
+ sel = GlobalAlloc16( GMEM_ZEROINIT, 0xFF00 );
+ pModule->self_loading_sel = SEL(sel);
+ FarSetOwner16( sel, pModule->self );
+- oldstack = NtCurrentTeb()->WOW32Reserved;
+- NtCurrentTeb()->WOW32Reserved = (void *)MAKESEGPTR(pModule->self_loading_sel,
+- 0xff00 - sizeof(STACK16FRAME) );
++ oldstack = NtCurrentTeb()->SystemReserved1[0];
++ NtCurrentTeb()->SystemReserved1[0] = (void *)MAKESEGPTR(pModule->self_loading_sel,
++ 0xff00 - sizeof(STACK16FRAME) );
+
+ hFile16 = NE_OpenFile(pModule);
+ TRACE_(dll)("CallBootAppProc(hModule=0x%04x,hf=0x%04x)\n",
+@@ -496,7 +496,7 @@
+ WOWCallback16Ex( (DWORD)selfloadheader->BootApp, WCB16_PASCAL, sizeof(args), args, NULL );
+ TRACE_(dll)("Return from CallBootAppProc\n");
+ _lclose16(hFile16);
+- NtCurrentTeb()->WOW32Reserved = oldstack;
++ NtCurrentTeb()->SystemReserved1[0] = oldstack;
+
+ for (i = 2; i <= pModule->ne_cseg; i++)
+ if (!NE_LoadSegment( pModule, i )) return FALSE;
+@@ -691,7 +691,7 @@
+ context.SegEs = ds; /* who knows ... */
+ context.SegCs = SEL(pSegTable[SELECTOROF(pModule->ne_csip)-1].hSeg);
+ context.Eip = OFFSETOF(pModule->ne_csip);
+- context.Ebp = OFFSETOF(NtCurrentTeb()->WOW32Reserved) + FIELD_OFFSET(STACK16FRAME,bp);
++ context.Ebp = OFFSETOF(NtCurrentTeb()->SystemReserved1[0]) + FIELD_OFFSET(STACK16FRAME,bp);
+
+ pModule->ne_csip = 0; /* Don't initialize it twice */
+ TRACE_(dll)("Calling LibMain for %.*s, cs:ip=%04x:%04x ds=%04x di=%04x cx=%04x\n",
+@@ -794,7 +794,7 @@
+ context.SegEs = ds; /* who knows ... */
+ context.SegCs = HIWORD(entryPoint);
+ context.Eip = LOWORD(entryPoint);
+- context.Ebp = OFFSETOF(NtCurrentTeb()->WOW32Reserved) + FIELD_OFFSET(STACK16FRAME,bp);
++ context.Ebp = OFFSETOF(NtCurrentTeb()->SystemReserved1[0]) + FIELD_OFFSET(STACK16FRAME,bp);
+
+ args[7] = HIWORD(dwReason);
+ args[6] = LOWORD(dwReason);
+--- a/dlls/krnl386.exe16/task.c
++++ b/dlls/krnl386.exe16/task.c
+@@ -630,7 +630,7 @@
+
+ /* Initialize the INSTANCEDATA structure */
+ pinstance = MapSL( MAKESEGPTR(CURRENT_DS, 0) );
+- pinstance->stackmin = OFFSETOF(NtCurrentTeb()->WOW32Reserved) + sizeof( STACK16FRAME );
++ pinstance->stackmin = OFFSETOF(NtCurrentTeb()->SystemReserved1[0]) + sizeof( STACK16FRAME );
+ pinstance->stackbottom = pinstance->stackmin; /* yup, that's right. Confused me too. */
+ pinstance->stacktop = ( pinstance->stackmin > LOWORD(context->Ebx) ?
+ pinstance->stackmin - LOWORD(context->Ebx) : 0 ) + 150;
+@@ -1101,14 +1101,14 @@
+
+ if (!(pData = GlobalLock16( seg ))) return;
+ TRACE("old=%04x:%04x new=%04x:%04x\n",
+- SELECTOROF( NtCurrentTeb()->WOW32Reserved ),
+- OFFSETOF( NtCurrentTeb()->WOW32Reserved ), seg, ptr );
++ SELECTOROF( NtCurrentTeb()->SystemReserved1[0] ),
++ OFFSETOF( NtCurrentTeb()->SystemReserved1[0] ), seg, ptr );
+
+ /* Save the old stack */
+
+ oldFrame = CURRENT_STACK16;
+ /* pop frame + args and push bp */
+- pData->old_ss_sp = (SEGPTR)NtCurrentTeb()->WOW32Reserved + sizeof(STACK16FRAME)
++ pData->old_ss_sp = (SEGPTR)NtCurrentTeb()->SystemReserved1[0] + sizeof(STACK16FRAME)
+ + 2 * sizeof(WORD);
+ *(WORD *)MapSL(pData->old_ss_sp) = oldFrame->bp;
+ pData->stacktop = top;
+@@ -1122,7 +1122,7 @@
+ */
+ copySize = oldFrame->bp - OFFSETOF(pData->old_ss_sp);
+ copySize += 3 * sizeof(WORD) + sizeof(STACK16FRAME);
+- NtCurrentTeb()->WOW32Reserved = (void *)MAKESEGPTR( seg, ptr - copySize );
++ NtCurrentTeb()->SystemReserved1[0] = (void *)MAKESEGPTR( seg, ptr - copySize );
+ newFrame = CURRENT_STACK16;
+
+ /* Copy the stack frame and the local variables to the new stack */
+@@ -1141,7 +1141,7 @@
+ STACK16FRAME *oldFrame, *newFrame;
+ INSTANCEDATA *pData;
+
+- if (!(pData = GlobalLock16(SELECTOROF(NtCurrentTeb()->WOW32Reserved))))
++ if (!(pData = GlobalLock16(SELECTOROF(NtCurrentTeb()->SystemReserved1[0]))))
+ return;
+ if (!pData->old_ss_sp)
+ {
+@@ -1160,7 +1160,7 @@
+
+ /* Switch back to the old stack */
+
+- NtCurrentTeb()->WOW32Reserved = (void *)(pData->old_ss_sp - sizeof(STACK16FRAME));
++ NtCurrentTeb()->SystemReserved1[0] = (void *)(pData->old_ss_sp - sizeof(STACK16FRAME));
+ context->SegSs = SELECTOROF(pData->old_ss_sp);
+ context->Esp = OFFSETOF(pData->old_ss_sp) - sizeof(DWORD); /*ret addr*/
+ pData->old_ss_sp = 0;
+--- a/dlls/krnl386.exe16/thunk.c
++++ b/dlls/krnl386.exe16/thunk.c
+@@ -435,7 +435,7 @@
+ context16.Eip = LOWORD(context->Edx);
+ /* point EBP to the STACK16FRAME on the stack
+ * for the call_to_16 to set up the register content on calling */
+- context16.Ebp = OFFSETOF(NtCurrentTeb()->WOW32Reserved) + FIELD_OFFSET(STACK16FRAME,bp);
++ context16.Ebp = OFFSETOF(NtCurrentTeb()->SystemReserved1[0]) + FIELD_OFFSET(STACK16FRAME,bp);
+
+ /*
+ * used to be (problematic):
+@@ -457,7 +457,7 @@
+ * the number of parameters that the Win16 function
+ * accepted (that it popped from the corresponding Win16 stack) */
+ context->Esp += LOWORD(context16.Esp) -
+- ( OFFSETOF(NtCurrentTeb()->WOW32Reserved) - argsize );
++ ( OFFSETOF(NtCurrentTeb()->SystemReserved1[0]) - argsize );
+ }
+ DEFINE_REGS_ENTRYPOINT( QT_Thunk )
+
+@@ -561,7 +561,7 @@
+
+ context16.SegCs = HIWORD(callTarget);
+ context16.Eip = LOWORD(callTarget);
+- context16.Ebp = OFFSETOF(NtCurrentTeb()->WOW32Reserved) + FIELD_OFFSET(STACK16FRAME,bp);
++ context16.Ebp = OFFSETOF(NtCurrentTeb()->SystemReserved1[0]) + FIELD_OFFSET(STACK16FRAME,bp);
+
+ argsize = context->Ebp-context->Esp-0x40;
+ if (argsize > sizeof(newstack)) argsize = sizeof(newstack);
+@@ -573,8 +573,8 @@
+ if (mapESPrelative & (1 << i))
+ {
+ SEGPTR *arg = (SEGPTR *)newstack[i];
+- *arg = MAKESEGPTR(SELECTOROF(NtCurrentTeb()->WOW32Reserved),
+- OFFSETOF(NtCurrentTeb()->WOW32Reserved) - argsize
++ *arg = MAKESEGPTR(SELECTOROF(NtCurrentTeb()->SystemReserved1[0]),
++ OFFSETOF(NtCurrentTeb()->SystemReserved1[0]) - argsize
+ + (*(LPBYTE *)arg - oldstack));
+ }
+
+@@ -584,7 +584,7 @@
+ context->Ecx = context16.Ecx;
+
+ context->Esp += LOWORD(context16.Esp) -
+- ( OFFSETOF(NtCurrentTeb()->WOW32Reserved) - argsize );
++ ( OFFSETOF(NtCurrentTeb()->SystemReserved1[0]) - argsize );
+
+ /* Copy modified buffers back to 32-bit stack */
+ memcpy( oldstack, newstack, argsize );
+@@ -719,7 +719,7 @@
+ context16.Edi = LOWORD(context->Ecx);
+ context16.SegCs = HIWORD(context->Eax);
+ context16.Eip = LOWORD(context->Eax);
+- context16.Ebp = OFFSETOF(NtCurrentTeb()->WOW32Reserved) + FIELD_OFFSET(STACK16FRAME,bp);
++ context16.Ebp = OFFSETOF(NtCurrentTeb()->SystemReserved1[0]) + FIELD_OFFSET(STACK16FRAME,bp);
+
+ argsize = HIWORD(context->Edx) * 4;
+
+@@ -775,7 +775,7 @@
+
+ context16.SegCs = HIWORD(context->Edx);
+ context16.Eip = LOWORD(context->Edx);
+- context16.Ebp = OFFSETOF(NtCurrentTeb()->WOW32Reserved) + FIELD_OFFSET(STACK16FRAME,bp);
++ context16.Ebp = OFFSETOF(NtCurrentTeb()->SystemReserved1[0]) + FIELD_OFFSET(STACK16FRAME,bp);
+
+ argsize = 2 * *(WORD *)context->Esp + 2;
+
+@@ -788,7 +788,7 @@
+ (LPBYTE)CURRENT_STACK16 - argsize, argsize );
+
+ context->Esp += LOWORD(context16.Esp) -
+- ( OFFSETOF(NtCurrentTeb()->WOW32Reserved) - argsize );
++ ( OFFSETOF(NtCurrentTeb()->SystemReserved1[0]) - argsize );
+ }
+ DEFINE_REGS_ENTRYPOINT( OT_32ThkLSF )
+
+@@ -1240,26 +1240,26 @@
+ DWORD argSize = context->Ebp - context->Esp;
+ char *stack16 = (char *)context->Esp - 4;
+ STACK16FRAME *frame16 = (STACK16FRAME *)stack16 - 1;
+- STACK32FRAME *frame32 = NtCurrentTeb()->WOW32Reserved;
++ STACK32FRAME *frame32 = NtCurrentTeb()->SystemReserved1[0];
+ char *stack32 = (char *)frame32 - argSize;
+ WORD stackSel = SELECTOROF(frame32->frame16);
+ DWORD stackBase = GetSelectorBase(stackSel);
+
+ TRACE("before SYSTHUNK hack: EBP: %08x ESP: %08x cur_stack: %p\n",
+- context->Ebp, context->Esp, NtCurrentTeb()->WOW32Reserved);
++ context->Ebp, context->Esp, NtCurrentTeb()->SystemReserved1[0]);
+
+ memset(frame16, '\0', sizeof(STACK16FRAME));
+ frame16->frame32 = frame32;
+ frame16->ebp = context->Ebp;
+
+ memcpy(stack32, stack16, argSize);
+- NtCurrentTeb()->WOW32Reserved = (void *)MAKESEGPTR(stackSel, (DWORD)frame16 - stackBase);
++ NtCurrentTeb()->SystemReserved1[0] = (void *)MAKESEGPTR(stackSel, (DWORD)frame16 - stackBase);
+
+ context->Esp = (DWORD)stack32 + 4;
+ context->Ebp = context->Esp + argSize;
+
+ TRACE("after SYSTHUNK hack: EBP: %08x ESP: %08x cur_stack: %p\n",
+- context->Ebp, context->Esp, NtCurrentTeb()->WOW32Reserved);
++ context->Ebp, context->Esp, NtCurrentTeb()->SystemReserved1[0]);
+ }
+
+ /* entry_point is never used again once the entry point has
+@@ -1282,7 +1282,7 @@
+ if ( code[5] == 0xFF && code[6] == 0x55 && code[7] == 0xFC
+ && code[13] == 0x66 && code[14] == 0xCB)
+ {
+- STACK16FRAME *frame16 = MapSL((SEGPTR)NtCurrentTeb()->WOW32Reserved);
++ STACK16FRAME *frame16 = MapSL((SEGPTR)NtCurrentTeb()->SystemReserved1[0]);
+ char *stack16 = (char *)(frame16 + 1);
+ DWORD argSize = frame16->ebp - (DWORD)stack16;
+ char *stack32 = (char *)frame16->frame32 - argSize;
+@@ -1290,15 +1290,15 @@
+ DWORD nArgsPopped = context->Esp - (DWORD)stack32;
+
+ TRACE("before SYSTHUNK hack: EBP: %08x ESP: %08x cur_stack: %p\n",
+- context->Ebp, context->Esp, NtCurrentTeb()->WOW32Reserved);
++ context->Ebp, context->Esp, NtCurrentTeb()->SystemReserved1[0]);
+
+- NtCurrentTeb()->WOW32Reserved = frame16->frame32;
++ NtCurrentTeb()->SystemReserved1[0] = frame16->frame32;
+
+ context->Esp = (DWORD)stack16 + nArgsPopped;
+ context->Ebp = frame16->ebp;
+
+ TRACE("after SYSTHUNK hack: EBP: %08x ESP: %08x cur_stack: %p\n",
+- context->Ebp, context->Esp, NtCurrentTeb()->WOW32Reserved);
++ context->Ebp, context->Esp, NtCurrentTeb()->SystemReserved1[0]);
+ }
+ }
+ DEFINE_REGS_ENTRYPOINT( K32Thk1632Epilog )
+@@ -2313,7 +2313,7 @@
+ frame32 = pFrame->frame32;
+ while (frame32 && frame32->frame16)
+ {
+- if (OFFSETOF(frame32->frame16) < OFFSETOF(NtCurrentTeb()->WOW32Reserved))
++ if (OFFSETOF(frame32->frame16) < OFFSETOF(NtCurrentTeb()->SystemReserved1[0]))
+ break; /* Something strange is going on */
+ if (OFFSETOF(frame32->frame16) > lpbuf[2])
+ {
+--- a/dlls/krnl386.exe16/wowthunk.c
++++ b/dlls/krnl386.exe16/wowthunk.c
+@@ -135,7 +135,7 @@
+ {
+ /* unwinding: restore the stack pointer in the TEB, and leave the Win16 mutex */
+ STACK32FRAME *frame32 = CONTAINING_RECORD(frame, STACK32FRAME, frame);
+- NtCurrentTeb()->WOW32Reserved = (void *)frame32->frame16;
++ NtCurrentTeb()->SystemReserved1[0] = (void *)frame32->frame16;
+ _LeaveWin16Lock();
+ }
+ else if (record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION ||
+@@ -420,8 +420,8 @@
+ TRACE_(relay)( "\1CallTo16(func=%04x:%04x", context->SegCs, LOWORD(context->Eip) );
+ while (count) TRACE_(relay)( ",%04x", wstack[--count] );
+ TRACE_(relay)( ") ss:sp=%04x:%04x ax=%04x bx=%04x cx=%04x dx=%04x si=%04x di=%04x bp=%04x ds=%04x es=%04x\n",
+- SELECTOROF(NtCurrentTeb()->WOW32Reserved),
+- OFFSETOF(NtCurrentTeb()->WOW32Reserved),
++ SELECTOROF(NtCurrentTeb()->SystemReserved1[0]),
++ OFFSETOF(NtCurrentTeb()->SystemReserved1[0]),
+ (WORD)context->Eax, (WORD)context->Ebx, (WORD)context->Ecx,
+ (WORD)context->Edx, (WORD)context->Esi, (WORD)context->Edi,
+ (WORD)context->Ebp, (WORD)context->SegDs, (WORD)context->SegEs );
+@@ -453,8 +453,8 @@
+ if (TRACE_ON(relay))
+ {
+ TRACE_(relay)( "\1RetFrom16() ss:sp=%04x:%04x ax=%04x bx=%04x cx=%04x dx=%04x bp=%04x sp=%04x\n",
+- SELECTOROF(NtCurrentTeb()->WOW32Reserved),
+- OFFSETOF(NtCurrentTeb()->WOW32Reserved),
++ SELECTOROF(NtCurrentTeb()->SystemReserved1[0]),
++ OFFSETOF(NtCurrentTeb()->SystemReserved1[0]),
+ (WORD)context->Eax, (WORD)context->Ebx, (WORD)context->Ecx,
+ (WORD)context->Edx, (WORD)context->Ebp, (WORD)context->Esp );
+ SYSLEVEL_CheckNotLevel( 2 );
+@@ -470,10 +470,10 @@
+ WORD * wstack = (WORD *)stack;
+
+ TRACE_(relay)( "\1CallTo16(func=%04x:%04x,ds=%04x",
+- HIWORD(vpfn16), LOWORD(vpfn16), SELECTOROF(NtCurrentTeb()->WOW32Reserved) );
++ HIWORD(vpfn16), LOWORD(vpfn16), SELECTOROF(NtCurrentTeb()->SystemReserved1[0]) );
+ while (count) TRACE_(relay)( ",%04x", wstack[--count] );
+- TRACE_(relay)( ") ss:sp=%04x:%04x\n", SELECTOROF(NtCurrentTeb()->WOW32Reserved),
+- OFFSETOF(NtCurrentTeb()->WOW32Reserved) );
++ TRACE_(relay)( ") ss:sp=%04x:%04x\n", SELECTOROF(NtCurrentTeb()->SystemReserved1[0]),
++ OFFSETOF(NtCurrentTeb()->SystemReserved1[0]) );
+ SYSLEVEL_CheckNotLevel( 2 );
+ }
+
+@@ -496,8 +496,8 @@
+ if (TRACE_ON(relay))
+ {
+ TRACE_(relay)( "\1RetFrom16() ss:sp=%04x:%04x retval=%08x\n",
+- SELECTOROF(NtCurrentTeb()->WOW32Reserved),
+- OFFSETOF(NtCurrentTeb()->WOW32Reserved), ret );
++ SELECTOROF(NtCurrentTeb()->SystemReserved1[0]),
++ OFFSETOF(NtCurrentTeb()->SystemReserved1[0]), ret );
+ SYSLEVEL_CheckNotLevel( 2 );
+ }
+ }
+--- a/dlls/ntdll/signal_i386.c
++++ b/dlls/ntdll/signal_i386.c
+@@ -856,7 +856,7 @@
+ * SS is still non-system segment. This is why both CS and SS
+ * are checked.
+ */
+- return teb->WOW32Reserved;
++ return teb->SystemReserved1[0];
+ }
+ return (void *)(ESP_sig(sigcontext) & ~3);
+ }
+--- a/dlls/system.drv16/system.c
++++ b/dlls/system.drv16/system.c
+@@ -70,7 +70,7 @@
+ memset( &context, 0, sizeof(context) );
+ context.SegCs = SELECTOROF( proc );
+ context.Eip = OFFSETOF( proc );
+- context.Ebp = OFFSETOF(NtCurrentTeb()->WOW32Reserved) + FIELD_OFFSET(STACK16FRAME, bp);
++ context.Ebp = OFFSETOF(NtCurrentTeb()->SystemReserved1[0]) + FIELD_OFFSET(STACK16FRAME, bp);
+ context.Eax = i + 1;
+
+ WOWCallback16Ex( 0, WCB16_REGS, 0, NULL, (DWORD *)&context );
+--- a/dlls/toolhelp.dll16/toolhelp.c
++++ b/dlls/toolhelp.dll16/toolhelp.c
+@@ -491,8 +491,8 @@
+ lpte->hTaskParent = pTask->hParent;
+ lpte->hInst = pTask->hInstance;
+ lpte->hModule = pTask->hModule;
+- lpte->wSS = SELECTOROF( pTask->teb->WOW32Reserved );
+- lpte->wSP = OFFSETOF( pTask->teb->WOW32Reserved );
++ lpte->wSS = SELECTOROF( pTask->teb->SystemReserved1[0] );
++ lpte->wSP = OFFSETOF( pTask->teb->SystemReserved1[0] );
+ lpte->wStackTop = pInstData->stacktop;
+ lpte->wStackMinimum = pInstData->stackmin;
+ lpte->wStackBottom = pInstData->stackbottom;
+@@ -718,7 +718,7 @@
+ */
+ BOOL16 WINAPI SystemHeapInfo16( SYSHEAPINFO *pHeapInfo )
+ {
+- STACK16FRAME* stack16 = MapSL((SEGPTR)NtCurrentTeb()->WOW32Reserved);
++ STACK16FRAME* stack16 = MapSL((SEGPTR)NtCurrentTeb()->SystemReserved1[0]);
+ HANDLE16 oldDS = stack16->ds;
+ WORD user = LoadLibrary16( "USER.EXE" );
+ WORD gdi = LoadLibrary16( "GDI.EXE" );
+--- a/dlls/user.exe16/message.c
++++ b/dlls/user.exe16/message.c
+@@ -240,11 +240,11 @@
+ /* Window procedures want ax = hInstance, ds = es = ss */
+
+ memset(&context, 0, sizeof(context));
+- context.SegDs = context.SegEs = SELECTOROF(NtCurrentTeb()->WOW32Reserved);
++ context.SegDs = context.SegEs = SELECTOROF(NtCurrentTeb()->SystemReserved1[0]);
+ if (!(context.Eax = GetWindowWord( HWND_32(hwnd), GWLP_HINSTANCE ))) context.Eax = context.SegDs;
+ context.SegCs = SELECTOROF(func);
+ context.Eip = OFFSETOF(func);
+- context.Ebp = OFFSETOF(NtCurrentTeb()->WOW32Reserved) + FIELD_OFFSET(STACK16FRAME, bp);
++ context.Ebp = OFFSETOF(NtCurrentTeb()->SystemReserved1[0]) + FIELD_OFFSET(STACK16FRAME, bp);
+
+ if (lParam)
+ {
+@@ -267,7 +267,7 @@
+ if (size)
+ {
+ memcpy( &args.u, MapSL(lParam), size );
+- lParam = PtrToUlong(NtCurrentTeb()->WOW32Reserved) - size;
++ lParam = PtrToUlong(NtCurrentTeb()->SystemReserved1[0]) - size;
+ }
+ }
+
+@@ -2092,7 +2092,7 @@
+
+ static void edit_lock_buffer( HWND hwnd )
+ {
+- STACK16FRAME* stack16 = MapSL(PtrToUlong(NtCurrentTeb()->WOW32Reserved));
++ STACK16FRAME* stack16 = MapSL(PtrToUlong(NtCurrentTeb()->SystemReserved1[0]));
+ HLOCAL16 hloc16 = GetWindowWord( hwnd, GWW_HANDLE16 );
+ HANDLE16 oldDS;
+ HLOCAL hloc32;
+@@ -2118,7 +2118,7 @@
+
+ static void edit_unlock_buffer( HWND hwnd )
+ {
+- STACK16FRAME* stack16 = MapSL(PtrToUlong(NtCurrentTeb()->WOW32Reserved));
++ STACK16FRAME* stack16 = MapSL(PtrToUlong(NtCurrentTeb()->SystemReserved1[0]));
+ HLOCAL16 hloc16 = GetWindowWord( hwnd, GWW_HANDLE16 );
+ HANDLE16 oldDS;
+ HLOCAL hloc32;
+@@ -2155,7 +2155,7 @@
+ if (!(hloc = (HLOCAL)wow_handlers32.edit_proc( hwnd, EM_GETHANDLE, 0, 0, FALSE ))) return 0;
+ alloc_size = LocalSize( hloc );
+
+- stack16 = MapSL(PtrToUlong(NtCurrentTeb()->WOW32Reserved));
++ stack16 = MapSL(PtrToUlong(NtCurrentTeb()->SystemReserved1[0]));
+ oldDS = stack16->ds;
+ stack16->ds = GetWindowLongPtrW( hwnd, GWLP_HINSTANCE );
+
+@@ -2193,7 +2193,7 @@
+
+ static void edit_set_handle( HWND hwnd, HLOCAL16 hloc16 )
+ {
+- STACK16FRAME* stack16 = MapSL(PtrToUlong(NtCurrentTeb()->WOW32Reserved));
++ STACK16FRAME* stack16 = MapSL(PtrToUlong(NtCurrentTeb()->SystemReserved1[0]));
+ HINSTANCE16 hInstance = GetWindowLongPtrW( hwnd, GWLP_HINSTANCE );
+ HANDLE16 oldDS = stack16->ds;
+ HLOCAL hloc32;
+@@ -2223,7 +2223,7 @@
+ HLOCAL16 hloc16 = GetWindowWord( hwnd, GWW_HANDLE16 );
+ if (hloc16)
+ {
+- STACK16FRAME* stack16 = MapSL(PtrToUlong(NtCurrentTeb()->WOW32Reserved));
++ STACK16FRAME* stack16 = MapSL(PtrToUlong(NtCurrentTeb()->SystemReserved1[0]));
+ HANDLE16 oldDS = stack16->ds;
+
+ stack16->ds = GetWindowLongPtrW( hwnd, GWLP_HINSTANCE );
+--- a/dlls/user.exe16/user.c
++++ b/dlls/user.exe16/user.c
+@@ -1394,7 +1394,7 @@
+ */
+ DWORD WINAPI UserSeeUserDo16(WORD wReqType, WORD wParam1, WORD wParam2, WORD wParam3)
+ {
+- STACK16FRAME* stack16 = MapSL((SEGPTR)NtCurrentTeb()->WOW32Reserved);
++ STACK16FRAME* stack16 = MapSL((SEGPTR)NtCurrentTeb()->SystemReserved1[0]);
+ HANDLE16 oldDS = stack16->ds;
+ DWORD ret = (DWORD)-1;
+
+@@ -1787,7 +1787,7 @@
+ */
+ WORD WINAPI GetFreeSystemResources16( WORD resType )
+ {
+- STACK16FRAME* stack16 = MapSL((SEGPTR)NtCurrentTeb()->WOW32Reserved);
++ STACK16FRAME* stack16 = MapSL((SEGPTR)NtCurrentTeb()->SystemReserved1[0]);
+ HANDLE16 oldDS = stack16->ds;
+ int userPercent, gdiPercent;
+
+--- a/dlls/user.exe16/window.c
++++ b/dlls/user.exe16/window.c
+@@ -456,7 +456,7 @@
+ */
+ BOOL16 WINAPI IsWindow16( HWND16 hwnd )
+ {
+- STACK16FRAME *frame = MapSL( (SEGPTR)NtCurrentTeb()->WOW32Reserved );
++ STACK16FRAME *frame = MapSL( (SEGPTR)NtCurrentTeb()->SystemReserved1[0] );
+ frame->es = USER_HeapSel;
+ /* don't use WIN_Handle32 here, we don't care about the full handle */
+ return IsWindow( HWND_32(hwnd) );
+--- a/include/winternl.h
++++ b/include/winternl.h
+@@ -362,7 +362,7 @@
+ PVOID WOW32Reserved; /* 0c0/0100 */
+ ULONG CurrentLocale; /* 0c4/0108 */
+ ULONG FpSoftwareStatusRegister; /* 0c8/010c */
+- PVOID SystemReserved1[54]; /* 0cc/0110 used for kernel32 private data in Wine */
++ PVOID SystemReserved1[54]; /* 0cc/0110 used for krnl386.exe16 private data in Wine */
+ LONG ExceptionCode; /* 1a4/02c0 */
+ ACTIVATION_CONTEXT_STACK ActivationContextStack; /* 1a8/02c8 */
+ BYTE SpareBytes1[24]; /* 1bc/02e8 */
+--- a/tools/winebuild/relay.c
++++ b/tools/winebuild/relay.c
+@@ -31,7 +31,7 @@
+ #include "build.h"
+
+ /* offset of the stack pointer relative to %fs:(0) */
+-#define STACKOFFSET 0xc0 /* FIELD_OFFSET(TEB,WOW32Reserved) */
++#define STACKOFFSET 0xcc /* FIELD_OFFSET(TEB,SystemReserved1[0]) */
+
+ /* fix this if the x86_thread_data structure is changed */
+ #define GS_OFFSET 0x1d8 /* FIELD_OFFSET(TEB,SystemReserved2) + FIELD_OFFSET(struct x86_thread_data,gs) */
diff -Nru wine-development-5.5/debian/patches/winebuild-Fake_Dlls/0003-winebuild-Generate-syscall-thunks-for-ntdll-exports.patch wine-development-5.5/debian/patches/winebuild-Fake_Dlls/0003-winebuild-Generate-syscall-thunks-for-ntdll-exports.patch
--- wine-development-5.5/debian/patches/winebuild-Fake_Dlls/0003-winebuild-Generate-syscall-thunks-for-ntdll-exports.patch 1970-01-01 01:00:00.000000000 +0100
+++ wine-development-5.5/debian/patches/winebuild-Fake_Dlls/0003-winebuild-Generate-syscall-thunks-for-ntdll-exports.patch 2020-05-04 01:33:29.000000000 +0100
@@ -0,0 +1,441 @@
+From 0dbb12f12b3637dbf512cd0c0d719c901d57e63d Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
+Date: Thu, 11 May 2017 05:32:55 +0200
+Subject: [PATCH] winebuild: Generate syscall thunks for ntdll exports.
+
+Based on a patch by Erich E. Hoover.
+---
+ dlls/ntdll/signal_i386.c | 6 +-
+ dlls/ntdll/tests/exception.c | 2 +
+ include/winternl.h | 2 +-
+ tools/winebuild/build.h | 7 +++
+ tools/winebuild/import.c | 10 ++--
+ tools/winebuild/parser.c | 59 ++++++++++++++++++++
+ tools/winebuild/spec16.c | 22 +-------
+ tools/winebuild/spec32.c | 104 +++++++++++++++++++++++++++++++++++
+ tools/winebuild/utils.c | 21 +++++++
+ 9 files changed, 206 insertions(+), 27 deletions(-)
+
+--- a/dlls/ntdll/signal_i386.c
++++ b/dlls/ntdll/signal_i386.c
+@@ -442,6 +442,9 @@
+
+ static wine_signal_handler handlers[256];
+
++extern void DECLSPEC_NORETURN __wine_syscall_dispatcher( void );
++extern NTSTATUS WINAPI __syscall_NtGetContextThread( HANDLE handle, CONTEXT *context );
++
+ enum i386_trap_code
+ {
+ TRAP_x86_UNKNOWN = -1, /* Unknown fault (TRAP_sig not defined) */
+@@ -1458,7 +1461,7 @@
+ {
+ context->Ebp = ebp;
+ context->Esp = (DWORD)&retaddr;
+- context->Eip = *(&edi - 1);
++ context->Eip = (DWORD)__syscall_NtGetContextThread + 18;
+ context->SegCs = wine_get_cs();
+ context->SegSs = wine_get_ss();
+ context->EFlags = eflags;
+@@ -2303,6 +2306,7 @@
+ *teb = addr;
+ (*teb)->Tib.Self = &(*teb)->Tib;
+ (*teb)->Tib.ExceptionList = (void *)~0UL;
++ (*teb)->WOW32Reserved = __wine_syscall_dispatcher;
+ thread_data = (struct x86_thread_data *)(*teb)->SystemReserved2;
+ if (!(thread_data->fs = wine_ldt_alloc_fs()))
+ {
+--- a/dlls/ntdll/tests/exception.c
++++ b/dlls/ntdll/tests/exception.c
+@@ -1643,6 +1643,8 @@
+ ok( (char *)context.Eip >= (char *)pNtGetContextThread - 0x10000 &&
+ (char *)context.Eip <= (char *)pNtGetContextThread + 0x10000,
+ "wrong Eip %08x/%08x\n", context.Eip, (DWORD)pNtGetContextThread );
++ ok( *(WORD *)context.Eip == 0xc483 || *(WORD *)context.Eip == 0x08c2 || *(WORD *)context.Eip == 0x8dc3,
++ "expected 0xc483 or 0x08c2 or 0x8dc3, got %04x\n", *(WORD *)context.Eip );
+ /* segment registers clear the high word */
+ ok( context.SegCs == LOWORD(expect.SegCs), "wrong SegCs %08x/%08x\n", context.SegCs, expect.SegCs );
+ ok( context.SegDs == LOWORD(expect.SegDs), "wrong SegDs %08x/%08x\n", context.SegDs, expect.SegDs );
+--- a/include/winternl.h
++++ b/include/winternl.h
+@@ -359,7 +359,7 @@
+ PVOID CsrClientThread; /* 03c/0070 */
+ PVOID Win32ThreadInfo; /* 040/0078 */
+ ULONG Win32ClientInfo[31]; /* 044/0080 used for user32 private data in Wine */
+- PVOID WOW32Reserved; /* 0c0/0100 */
++ PVOID WOW32Reserved; /* 0c0/0100 used for ntdll syscall thunks */
+ ULONG CurrentLocale; /* 0c4/0108 */
+ ULONG FpSoftwareStatusRegister; /* 0c8/010c */
+ PVOID SystemReserved1[54]; /* 0cc/0110 used for krnl386.exe16 private data in Wine */
+--- a/tools/winebuild/build.h
++++ b/tools/winebuild/build.h
+@@ -105,6 +105,7 @@
+ int flags;
+ char *name; /* public name of this function */
+ char *link_name; /* name of the C symbol to link to */
++ char *impl_name; /* name of the C symbol of the real implementation (thunks only) */
+ char *export_name; /* name exported under for noname exports */
+ union
+ {
+@@ -131,6 +132,7 @@
+ int alloc_entry_points; /* number of allocated entry points */
+ int nb_names; /* number of entry points with names */
+ unsigned int nb_resources; /* number of resources */
++ int nb_syscalls; /* number of syscalls */
+ int characteristics; /* characteristics for the PE header */
+ int dll_characteristics;/* DLL characteristics for the PE header */
+ int subsystem; /* subsystem id */
+@@ -140,6 +142,7 @@
+ ORDDEF **names; /* array of entry point names (points into entry_points) */
+ ORDDEF **ordinals; /* array of dll ordinals (points into entry_points) */
+ struct resource *resources; /* array of dll resources (format differs between Win16/Win32) */
++ ORDDEF **syscalls; /* array of syscalls (points into entry_points) */
+ } DLLSPEC;
+
+ enum target_cpu
+@@ -182,8 +185,10 @@
+ #define FLAG_FORWARD 0x1000 /* function is a forwarded name */
+ #define FLAG_EXT_LINK 0x2000 /* function links to an external symbol */
+ #define FLAG_EXPORT32 0x4000 /* 32-bit export in 16-bit spec file */
++#define FLAG_SYSCALL 0x8000 /* function should be called through a syscall thunk */
+
+ #define FLAG_CPU(cpu) (0x10000 << (cpu))
++
+ #define FLAG_CPU_MASK (FLAG_CPU(CPU_LAST + 1) - FLAG_CPU(0))
+ #define FLAG_CPU_WIN64 (FLAG_CPU(CPU_x86_64) | FLAG_CPU(CPU_ARM64))
+ #define FLAG_CPU_WIN32 (FLAG_CPU_MASK & ~FLAG_CPU_WIN64)
+@@ -326,6 +331,8 @@
+ extern int parse_spec_file( FILE *file, DLLSPEC *spec );
+ extern int parse_def_file( FILE *file, DLLSPEC *spec );
+
++extern int sort_func_list( ORDDEF **list, int count, int (*compare)(const void *, const void *) );
++
+ /* buffer management */
+
+ extern int byte_swapped;
+--- a/tools/winebuild/import.c
++++ b/tools/winebuild/import.c
+@@ -531,6 +531,7 @@
+ /* flag the dll exports that link to an undefined symbol */
+ static void check_undefined_exports( DLLSPEC *spec )
+ {
++ const char *name;
+ int i;
+
+ for (i = 0; i < spec->nb_entry_points; i++)
+@@ -538,7 +539,8 @@
+ ORDDEF *odp = &spec->entry_points[i];
+ if (odp->type == TYPE_STUB || odp->type == TYPE_ABS || odp->type == TYPE_VARIABLE) continue;
+ if (odp->flags & FLAG_FORWARD) continue;
+- if (find_name( odp->link_name, &undef_symbols ))
++ name = odp->impl_name ? odp->impl_name : odp->link_name;
++ if (find_name( name, &undef_symbols ))
+ {
+ switch(odp->type)
+ {
+@@ -549,14 +551,14 @@
+ if (link_ext_symbols)
+ {
+ odp->flags |= FLAG_EXT_LINK;
+- strarray_add( &ext_link_imports, odp->link_name, NULL );
++ strarray_add( &ext_link_imports, name, NULL );
+ }
+ else error( "%s:%d: function '%s' not defined\n",
+- spec->src_name, odp->lineno, odp->link_name );
++ spec->src_name, odp->lineno, name );
+ break;
+ default:
+ error( "%s:%d: external symbol '%s' is not a function\n",
+- spec->src_name, odp->lineno, odp->link_name );
++ spec->src_name, odp->lineno, name );
+ break;
+ }
+ }
+--- a/tools/winebuild/parser.c
++++ b/tools/winebuild/parser.c
+@@ -543,6 +543,24 @@
+ }
+
+
++static int needs_syscall( ORDDEF *odp, DLLSPEC *spec )
++{
++ if (target_cpu != CPU_x86)
++ return 0;
++ if (odp->flags & (FLAG_FORWARD | FLAG_REGISTER))
++ return 0;
++ if (odp->type != TYPE_STDCALL)
++ return 0;
++ if (!spec->dll_name || strcmp(spec->dll_name, "ntdll"))
++ return 0;
++ if (!odp->name)
++ return 0;
++ if (strncmp(odp->name, "Nt", 2) && strncmp(odp->name, "Zw", 2))
++ return 0;
++ return 1;
++}
++
++
+ /*******************************************************************
+ * parse_spec_ordinal
+ *
+@@ -618,6 +636,14 @@
+ assert( 0 );
+ }
+
++ if (needs_syscall( odp, spec ))
++ {
++ char *link_name = strmake( "__syscall_%s", odp->link_name );
++ odp->impl_name = odp->link_name;
++ odp->link_name = link_name;
++ odp->flags |= FLAG_SYSCALL;
++ }
++
+ if ((odp->flags & FLAG_CPU_MASK) && !(odp->flags & FLAG_CPU(target_cpu)))
+ {
+ /* ignore this entry point */
+@@ -815,6 +841,37 @@
+ }
+
+
++static int link_name_compare( const void *e1, const void *e2 )
++{
++ const ORDDEF *odp1 = *(const ORDDEF * const *)e1;
++ const ORDDEF *odp2 = *(const ORDDEF * const *)e2;
++ return strcmp(odp1->link_name, odp2->link_name);
++}
++
++
++static void assign_syscalls( DLLSPEC *spec )
++{
++ int i;
++
++ spec->syscalls = xmalloc( (spec->limit - spec->base + 1) * sizeof(*spec->syscalls) );
++ spec->nb_syscalls = 0;
++
++ for (i = 0; i <= spec->limit; i++)
++ {
++ ORDDEF *odp = spec->ordinals[i];
++ if (!odp || !(odp->flags & FLAG_SYSCALL)) continue;
++ spec->syscalls[spec->nb_syscalls++] = odp;
++ }
++
++ spec->nb_syscalls = sort_func_list( spec->syscalls, spec->nb_syscalls, link_name_compare );
++ if (!spec->nb_syscalls)
++ {
++ free( spec->syscalls );
++ spec->syscalls = NULL;
++ }
++}
++
++
+ /*******************************************************************
+ * add_16bit_exports
+ *
+@@ -916,6 +973,8 @@
+ current_line = 0; /* no longer parsing the input file */
+ assign_names( spec );
+ assign_ordinals( spec );
++ assign_syscalls( spec );
++
+ return !nb_errors;
+ }
+
+--- a/tools/winebuild/spec16.c
++++ b/tools/winebuild/spec16.c
+@@ -496,27 +496,6 @@
+
+
+ /*******************************************************************
+- * sort_func_list
+- *
+- * Sort a list of functions, removing duplicates.
+- */
+-static int sort_func_list( ORDDEF **list, int count,
+- int (*compare)(const void *, const void *) )
+-{
+- int i, j;
+-
+- if (!count) return 0;
+- qsort( list, count, sizeof(*list), compare );
+-
+- for (i = j = 0; i < count; i++)
+- {
+- if (compare( &list[j], &list[i] )) list[++j] = list[i];
+- }
+- return j + 1;
+-}
+-
+-
+-/*******************************************************************
+ * output_module16
+ *
+ * Output code for a 16-bit module.
+@@ -544,6 +523,7 @@
+ entry_point->flags = FLAG_REGISTER;
+ entry_point->name = NULL;
+ entry_point->link_name = xstrdup( spec->init_func );
++ entry_point->impl_name = NULL;
+ entry_point->export_name = NULL;
+ entry_point->u.func.nb_args = 0;
+ assert( !spec->ordinals[0] );
+--- a/tools/winebuild/spec32.c
++++ b/tools/winebuild/spec32.c
+@@ -375,6 +375,109 @@
+ }
+
+ /*******************************************************************
++ * output_syscall_thunks
++ *
++ * Output entry points for system call functions
++ */
++static void output_syscall_thunks( DLLSPEC *spec )
++{
++ int i;
++
++ if (!spec->nb_syscalls)
++ return;
++
++ output( "\n/* syscall thunks */\n\n" );
++ output( "\t.text\n" );
++
++ for (i = 0; i < spec->nb_syscalls; i++)
++ {
++ ORDDEF *odp = spec->syscalls[i];
++ const char *name = odp->link_name;
++
++ /* Chromium attempts to hook system call thunks. It expects them to
++ * have a very specific form, or it will fail. The below matches what
++ * Chromium expects from 64-bit Windows 8. */
++
++ output( "\t.balign 16, 0\n" );
++ output( "\t%s\n", func_declaration(name) );
++ output( "%s\n", asm_globl(name) );
++ output_cfi( ".cfi_startproc" );
++ output( "\t.byte 0xb8\n" ); /* mov eax, SYSCALL */
++ output( "\t.long %d\n", i );
++ output( "\t.byte 0x64,0xff,0x15,0xc0,0x00,0x00,0x00\n" ); /* call dword ptr fs:[0C0h] */
++ output( "\t.byte 0xc2\n" ); /* ret X */
++ output( "\t.short %d\n", get_args_size(odp) );
++ output_cfi( ".cfi_endproc" );
++ output_function_size( name );
++ }
++
++ for (i = 0; i < 0x20; i++)
++ output( "\t.byte 0\n" );
++
++ output( "\n/* syscall table */\n\n" );
++ output( "\t.data\n" );
++ output( "%s\n", asm_globl("__wine_syscall_table") );
++ for (i = 0; i < spec->nb_syscalls; i++)
++ {
++ ORDDEF *odp = spec->syscalls[i];
++ output ("\t%s %s\n", get_asm_ptr_keyword(), asm_name(odp->impl_name) );
++ }
++
++ output( "\n/* syscall argument stack size table */\n\n" );
++ output( "\t.data\n" );
++ output( "%s\n", asm_globl("__wine_syscall_stack_size") );
++ for (i = 0; i < spec->nb_syscalls; i++)
++ {
++ ORDDEF *odp = spec->syscalls[i];
++ output( "\t.byte %d\n", get_args_size(odp) );
++ }
++
++ output( "\n/* syscall dispatcher */\n\n" );
++ output( "\t.text\n" );
++ output( "\t.align %d\n", get_alignment(16) );
++ output( "\t%s\n", func_declaration("__wine_syscall_dispatcher") );
++ output( "%s\n", asm_globl("__wine_syscall_dispatcher") );
++ output_cfi( ".cfi_startproc" );
++ output( "\tpushl %%ebp\n" );
++ output_cfi( ".cfi_adjust_cfa_offset 4\n" );
++ output_cfi( ".cfi_rel_offset %%ebp,0\n" );
++ output( "\tmovl %%esp,%%ebp\n" );
++ output_cfi( ".cfi_def_cfa_register %%ebp\n" );
++ output( "\tpushl %%esi\n" );
++ output_cfi( ".cfi_rel_offset %%esi,-4\n" );
++ output( "\tpushl %%edi\n" );
++ output_cfi( ".cfi_rel_offset %%edi,-8\n" );
++ output( "\tleal 12(%%ebp),%%esi\n" );
++ if (UsePIC)
++ {
++ output( "\tcall 1f\n" );
++ output( "1:\tpopl %%edx\n" );
++ output( "movzbl (%s-1b)(%%edx,%%eax,1),%%ecx\n", asm_name("__wine_syscall_stack_size") );
++ }
++ else
++ output( "movzbl %s(%%eax),%%ecx\n", asm_name("__wine_syscall_stack_size") );
++
++ output( "\tsubl %%ecx,%%esp\n" );
++ output( "\tshrl $2,%%ecx\n" );
++ output( "\tmovl %%esp,%%edi\n" );
++ output( "\trep; movsl\n" );
++ if (UsePIC)
++ output( "\tcall *(%s-1b)(%%edx,%%eax,%d)\n", asm_name("__wine_syscall_table"), get_ptr_size() );
++ else
++ output( "\tcall *%s(,%%eax,%d)\n", asm_name("__wine_syscall_table"), get_ptr_size() );
++ output( "\tpop %%edi\n" );
++ output_cfi( ".cfi_same_value %%edi\n" );
++ output( "\tpop %%esi\n" );
++ output_cfi( ".cfi_same_value %%esi\n" );
++ output( "\tleave\n" );
++ output_cfi( ".cfi_def_cfa %%esp,4\n" );
++ output_cfi( ".cfi_same_value %%ebp\n" );
++ output( "\tret\n" );
++ output_cfi( ".cfi_endproc" );
++ output_function_size( "__wine_syscall_dispatcher" );
++}
++
++/*******************************************************************
+ * output_exports
+ *
+ * Output the export table for a Win32 module.
+@@ -770,6 +873,7 @@
+ open_output_file();
+ output_standard_file_header();
+ output_module( spec );
++ output_syscall_thunks( spec );
+ output_stubs( spec );
+ output_exports( spec );
+ output_imports( spec );
+--- a/tools/winebuild/utils.c
++++ b/tools/winebuild/utils.c
+@@ -854,6 +854,7 @@
+ free( odp->name );
+ free( odp->export_name );
+ free( odp->link_name );
++ free( odp->impl_name );
+ }
+ free( spec->file_name );
+ free( spec->dll_name );
+@@ -863,6 +864,7 @@
+ free( spec->names );
+ free( spec->ordinals );
+ free( spec->resources );
++ free( spec->syscalls );
+ free( spec );
+ }
+
+@@ -1281,3 +1283,22 @@
+ default: return ".section .rodata";
+ }
+ }
++
++/*******************************************************************
++ * sort_func_list
++ *
++ * Sort a list of functions, removing duplicates.
++ */
++int sort_func_list( ORDDEF **list, int count, int (*compare)(const void *, const void *) )
++{
++ int i, j;
++
++ if (!count) return 0;
++ qsort( list, count, sizeof(*list), compare );
++
++ for (i = j = 0; i < count; i++)
++ {
++ if (compare( &list[j], &list[i] )) list[++j] = list[i];
++ }
++ return j + 1;
++}
diff -Nru wine-development-5.5/debian/patches/winebuild-Fake_Dlls/0004-winebuild-Use-multipass-label-system-to-generate-fak.patch wine-development-5.5/debian/patches/winebuild-Fake_Dlls/0004-winebuild-Use-multipass-label-system-to-generate-fak.patch
--- wine-development-5.5/debian/patches/winebuild-Fake_Dlls/0004-winebuild-Use-multipass-label-system-to-generate-fak.patch 1970-01-01 01:00:00.000000000 +0100
+++ wine-development-5.5/debian/patches/winebuild-Fake_Dlls/0004-winebuild-Use-multipass-label-system-to-generate-fak.patch 2020-05-04 01:33:29.000000000 +0100
@@ -0,0 +1,419 @@
+From 24441c46a4496982ff9ce2f1243f2cd8b52616b6 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
+Date: Mon, 15 May 2017 02:05:49 +0200
+Subject: [PATCH] winebuild: Use multipass label system to generate fake dlls.
+
+---
+ tools/winebuild/build.h | 6 ++
+ tools/winebuild/res32.c | 1 -
+ tools/winebuild/spec32.c | 145 ++++++++++++++++++++++-----------------
+ tools/winebuild/utils.c | 92 +++++++++++++++++++++++++
+ 4 files changed, 181 insertions(+), 63 deletions(-)
+
+--- a/tools/winebuild/build.h
++++ b/tools/winebuild/build.h
+@@ -342,6 +342,7 @@
+ extern size_t input_buffer_size;
+ extern unsigned char *output_buffer;
+ extern size_t output_buffer_pos;
++extern size_t output_buffer_rva;
+ extern size_t output_buffer_size;
+
+ extern void init_input_buffer( const char *file );
+@@ -357,6 +358,11 @@
+ extern void put_qword( unsigned int val );
+ extern void put_pword( unsigned int val );
+ extern void align_output( unsigned int align );
++extern void align_output_rva( unsigned int file_align, unsigned int rva_align );
++extern size_t label_pos( const char *name );
++extern size_t label_rva( const char *name );
++extern size_t label_rva_align( const char *name );
++extern void put_label( const char *name );
+
+ /* global variables */
+
+--- a/tools/winebuild/res32.c
++++ b/tools/winebuild/res32.c
+@@ -539,7 +539,6 @@
+ if (!spec->nb_resources) return;
+
+ tree = build_resource_tree( spec, &data_offset );
+- init_output_buffer();
+
+ /* output the resource directories */
+
+--- a/tools/winebuild/spec32.c
++++ b/tools/winebuild/spec32.c
+@@ -885,11 +885,11 @@
+
+
+ /*******************************************************************
+- * output_fake_module
++ * output_fake_module_pass
+ *
+- * Build a fake binary module from a spec file.
++ * Helper to create a fake binary module from a spec file.
+ */
+-void output_fake_module( DLLSPEC *spec )
++static void output_fake_module_pass( DLLSPEC *spec )
+ {
+ static const unsigned char dll_code_section[] = { 0x31, 0xc0, /* xor %eax,%eax */
+ 0xc2, 0x0c, 0x00 }; /* ret $12 */
+@@ -901,21 +901,8 @@
+ const unsigned int section_align = page_size;
+ const unsigned int file_align = 0x200;
+ const unsigned int reloc_size = 8;
+- const unsigned int lfanew = 0x40 + sizeof(fakedll_signature);
++ const unsigned int lfanew = (0x40 + sizeof(fakedll_signature) + 15) & ~15;
+ const unsigned int nb_sections = 2 + (spec->nb_resources != 0);
+- const unsigned int text_size = (spec->characteristics & IMAGE_FILE_DLL) ?
+- sizeof(dll_code_section) : sizeof(exe_code_section);
+- unsigned char *resources;
+- unsigned int resources_size;
+- unsigned int image_size = 3 * section_align;
+-
+- resolve_imports( spec );
+- output_bin_resources( spec, 3 * section_align );
+- resources = output_buffer;
+- resources_size = output_buffer_pos;
+- if (resources_size) image_size += (resources_size + section_align - 1) & ~(section_align - 1);
+-
+- init_output_buffer();
+
+ put_word( 0x5a4d ); /* e_magic */
+ put_word( 0x40 ); /* e_cblp */
+@@ -943,6 +930,7 @@
+ put_dword( lfanew );
+
+ put_data( fakedll_signature, sizeof(fakedll_signature) );
++ align_output_rva( 16, 16 );
+
+ put_dword( 0x4550 ); /* Signature */
+ switch(target_cpu)
+@@ -966,11 +954,11 @@
+ IMAGE_NT_OPTIONAL_HDR32_MAGIC ); /* Magic */
+ put_byte( 7 ); /* MajorLinkerVersion */
+ put_byte( 10 ); /* MinorLinkerVersion */
+- put_dword( text_size ); /* SizeOfCode */
++ put_dword( label_pos("text_end") - label_pos("text_start") ); /* SizeOfCode */
+ put_dword( 0 ); /* SizeOfInitializedData */
+ put_dword( 0 ); /* SizeOfUninitializedData */
+- put_dword( section_align ); /* AddressOfEntryPoint */
+- put_dword( section_align ); /* BaseOfCode */
++ put_dword( label_rva("entrypoint") ); /* AddressOfEntryPoint */
++ put_dword( label_rva("text_start") ); /* BaseOfCode */
+ if (get_ptr_size() == 4) put_dword( 0 ); /* BaseOfData */
+ put_pword( 0x10000000 ); /* ImageBase */
+ put_dword( section_align ); /* SectionAlignment */
+@@ -982,8 +970,8 @@
+ put_word( spec->subsystem_major ); /* MajorSubsystemVersion */
+ put_word( spec->subsystem_minor ); /* MinorSubsystemVersion */
+ put_dword( 0 ); /* Win32VersionValue */
+- put_dword( image_size ); /* SizeOfImage */
+- put_dword( file_align ); /* SizeOfHeaders */
++ put_dword( label_rva_align("file_end") ); /* SizeOfImage */
++ put_dword( label_pos("header_end") ); /* SizeOfHeaders */
+ put_dword( 0 ); /* CheckSum */
+ put_word( spec->subsystem ); /* Subsystem */
+ put_word( spec->dll_characteristics ); /* DllCharacteristics */
+@@ -996,10 +984,10 @@
+
+ put_dword( 0 ); put_dword( 0 ); /* DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT] */
+ put_dword( 0 ); put_dword( 0 ); /* DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT] */
+- if (resources_size) /* DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE] */
++ if (spec->nb_resources) /* DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE] */
+ {
+- put_dword( 3 * section_align );
+- put_dword( resources_size );
++ put_dword( label_rva("res_start") );
++ put_dword( label_pos("res_end") - label_pos("res_start") );
+ }
+ else
+ {
+@@ -1009,8 +997,8 @@
+
+ put_dword( 0 ); put_dword( 0 ); /* DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION] */
+ put_dword( 0 ); put_dword( 0 ); /* DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY] */
+- put_dword( 2 * section_align ); /* DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC] */
+- put_dword( reloc_size );
++ put_dword( label_rva("reloc_start") ); /* DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC] */
++ put_dword( label_pos("reloc_end") - label_pos("reloc_start") );
+ put_dword( 0 ); put_dword( 0 ); /* DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG] */
+ put_dword( 0 ); put_dword( 0 ); /* DataDirectory[IMAGE_DIRECTORY_ENTRY_COPYRIGHT] */
+ put_dword( 0 ); put_dword( 0 ); /* DataDirectory[IMAGE_DIRECTORY_ENTRY_GLOBALPTR] */
+@@ -1023,62 +1011,95 @@
+ put_dword( 0 ); put_dword( 0 ); /* DataDirectory[15] */
+
+ /* .text section */
+- put_data( ".text\0\0", 8 ); /* Name */
+- put_dword( section_align ); /* VirtualSize */
+- put_dword( section_align ); /* VirtualAddress */
+- put_dword( text_size ); /* SizeOfRawData */
+- put_dword( file_align ); /* PointerToRawData */
+- put_dword( 0 ); /* PointerToRelocations */
+- put_dword( 0 ); /* PointerToLinenumbers */
+- put_word( 0 ); /* NumberOfRelocations */
+- put_word( 0 ); /* NumberOfLinenumbers */
+- put_dword( 0x60000020 /* CNT_CODE|MEM_EXECUTE|MEM_READ */ ); /* Characteristics */
++ put_data( ".text\0\0", 8 ); /* Name */
++ put_dword( label_rva_align("text_end") - label_rva("text_start") ); /* VirtualSize */
++ put_dword( label_rva("text_start") ); /* VirtualAddress */
++ put_dword( label_pos("text_end") - label_pos("text_start") ); /* SizeOfRawData */
++ put_dword( label_pos("text_start") ); /* PointerToRawData */
++ put_dword( 0 ); /* PointerToRelocations */
++ put_dword( 0 ); /* PointerToLinenumbers */
++ put_word( 0 ); /* NumberOfRelocations */
++ put_word( 0 ); /* NumberOfLinenumbers */
++ put_dword( 0x60000020 /* CNT_CODE|MEM_EXECUTE|MEM_READ */ ); /* Characteristics */
+
+ /* .reloc section */
+- put_data( ".reloc\0", 8 ); /* Name */
+- put_dword( section_align ); /* VirtualSize */
+- put_dword( 2 * section_align );/* VirtualAddress */
+- put_dword( reloc_size ); /* SizeOfRawData */
+- put_dword( 2 * file_align ); /* PointerToRawData */
+- put_dword( 0 ); /* PointerToRelocations */
+- put_dword( 0 ); /* PointerToLinenumbers */
+- put_word( 0 ); /* NumberOfRelocations */
+- put_word( 0 ); /* NumberOfLinenumbers */
++ put_data( ".reloc\0", 8 ); /* Name */
++ put_dword( label_rva_align("reloc_end") - label_rva("reloc_start") ); /* VirtualSize */
++ put_dword( label_rva("reloc_start") ); /* VirtualAddress */
++ put_dword( label_pos("reloc_end") - label_pos("reloc_start") ); /* SizeOfRawData */
++ put_dword( label_pos("reloc_start") ); /* PointerToRawData */
++ put_dword( 0 ); /* PointerToRelocations */
++ put_dword( 0 ); /* PointerToLinenumbers */
++ put_word( 0 ); /* NumberOfRelocations */
++ put_word( 0 ); /* NumberOfLinenumbers */
+ put_dword( 0x42000040 /* CNT_INITIALIZED_DATA|MEM_DISCARDABLE|MEM_READ */ ); /* Characteristics */
+
+ /* .rsrc section */
+- if (resources_size)
++ if (spec->nb_resources)
+ {
+- put_data( ".rsrc\0\0", 8 ); /* Name */
+- put_dword( (resources_size + section_align - 1) & ~(section_align - 1) ); /* VirtualSize */
+- put_dword( 3 * section_align );/* VirtualAddress */
+- put_dword( resources_size ); /* SizeOfRawData */
+- put_dword( 3 * file_align ); /* PointerToRawData */
+- put_dword( 0 ); /* PointerToRelocations */
+- put_dword( 0 ); /* PointerToLinenumbers */
+- put_word( 0 ); /* NumberOfRelocations */
+- put_word( 0 ); /* NumberOfLinenumbers */
+- put_dword( 0x40000040 /* CNT_INITIALIZED_DATA|MEM_READ */ ); /* Characteristics */
++ put_data( ".rsrc\0\0", 8 ); /* Name */
++ put_dword( label_rva_align("res_end") - label_rva("res_start") ); /* VirtualSize */
++ put_dword( label_rva("res_start") ); /* VirtualAddress */
++ put_dword( label_pos("res_end") - label_pos("res_start") ); /* SizeOfRawData */
++ put_dword( label_pos("res_start") ); /* PointerToRawData */
++ put_dword( 0 ); /* PointerToRelocations */
++ put_dword( 0 ); /* PointerToLinenumbers */
++ put_word( 0 ); /* NumberOfRelocations */
++ put_word( 0 ); /* NumberOfLinenumbers */
++ put_dword( 0x40000040 /* CNT_INITIALIZED_DATA|MEM_READ */ ); /* Characteristics */
+ }
+
++ align_output_rva( file_align, file_align );
++ put_label( "header_end" );
++
+ /* .text contents */
+- align_output( file_align );
++ align_output_rva( file_align, section_align );
++ put_label( "text_start" );
++ put_label( "entrypoint" );
+ if (spec->characteristics & IMAGE_FILE_DLL)
+ put_data( dll_code_section, sizeof(dll_code_section) );
+ else
+ put_data( exe_code_section, sizeof(exe_code_section) );
++ put_label( "text_end" );
+
+ /* .reloc contents */
+- align_output( file_align );
++ align_output_rva( file_align, section_align );
++ put_label( "reloc_start" );
+ put_dword( 0 ); /* VirtualAddress */
+ put_dword( 0 ); /* SizeOfBlock */
++ put_label( "reloc_end" );
+
+ /* .rsrc contents */
+- if (resources_size)
++ if (spec->nb_resources)
+ {
+- align_output( file_align );
+- put_data( resources, resources_size );
++ align_output_rva( file_align, section_align );
++ put_label( "res_start" );
++ output_bin_resources( spec, label_rva("res_start") );
++ put_label( "res_end" );
+ }
++
++ put_label( "file_end" );
++}
++
++
++/*******************************************************************
++ * output_fake_module
++ *
++ * Build a fake binary module from a spec file.
++ */
++void output_fake_module( DLLSPEC *spec )
++{
++ resolve_imports( spec );
++
++ /* First pass */
++ init_output_buffer();
++ output_fake_module_pass( spec );
++
++ /* Second pass */
++ output_buffer_pos = 0;
++ output_buffer_rva = 0;
++ output_fake_module_pass( spec );
++
+ flush_output_buffer();
+ }
+
+--- a/tools/winebuild/utils.c
++++ b/tools/winebuild/utils.c
+@@ -34,6 +34,7 @@
+ # include <sys/stat.h>
+ #endif
+
++#include "wine/list.h"
+ #include "build.h"
+
+ #if defined(_WIN32) && !defined(__CYGWIN__)
+@@ -542,8 +543,86 @@
+ size_t input_buffer_size;
+ unsigned char *output_buffer;
+ size_t output_buffer_pos;
++size_t output_buffer_rva;
+ size_t output_buffer_size;
+
++struct label
++{
++ struct list entry;
++ const char *name;
++ size_t pos;
++ size_t rva;
++};
++
++static struct list labels = LIST_INIT( labels );
++
++struct label *get_label( const char *name )
++{
++ struct label *label;
++
++ LIST_FOR_EACH_ENTRY( label, &labels, struct label, entry )
++ {
++ if (!strcmp(name, label->name))
++ return label;
++ }
++
++ label = xmalloc( sizeof(*label) );
++ label->name = name;
++ label->pos = 0;
++ label->rva = 0;
++
++ list_add_tail( &labels, &label->entry );
++
++ return label;
++}
++
++size_t label_pos( const char *name )
++{
++ struct label *label = get_label( name );
++ return label->pos;
++}
++
++size_t label_rva( const char *name )
++{
++ struct label *label = get_label( name );
++ return label->rva;
++}
++
++size_t label_rva_align( const char *name )
++{
++ const unsigned int page_size = get_page_size();
++ size_t rva = label_rva( name );
++ size_t size = page_size - (rva % page_size);
++
++ if (size != page_size) rva += size;
++ return rva;
++}
++
++void put_label( const char *name )
++{
++ struct label *label = get_label( name );
++
++ if (label->pos || label->rva)
++ {
++ assert( label->pos == output_buffer_pos );
++ assert( label->rva == output_buffer_rva );
++ }
++
++ label->pos = output_buffer_pos;
++ label->rva = output_buffer_rva;
++}
++
++void free_labels( void )
++{
++ struct label *label, *label2;
++
++ LIST_FOR_EACH_ENTRY_SAFE( label, label2, &labels, struct label, entry )
++ {
++ list_remove( &label->entry );
++ free( label );
++ }
++}
++
+ static void check_output_buffer_space( size_t size )
+ {
+ if (output_buffer_pos + size >= output_buffer_size)
+@@ -575,7 +654,9 @@
+ {
+ output_buffer_size = 1024;
+ output_buffer_pos = 0;
++ output_buffer_rva = 0;
+ output_buffer = xmalloc( output_buffer_size );
++ free_labels();
+ }
+
+ void flush_output_buffer(void)
+@@ -585,6 +666,7 @@
+ fatal_error( "Error writing to %s\n", output_file_name );
+ close_output_file();
+ free( output_buffer );
++ free_labels();
+ }
+
+ unsigned char get_byte(void)
+@@ -624,12 +706,14 @@
+ check_output_buffer_space( size );
+ memcpy( output_buffer + output_buffer_pos, data, size );
+ output_buffer_pos += size;
++ output_buffer_rva += size;
+ }
+
+ void put_byte( unsigned char val )
+ {
+ check_output_buffer_space( 1 );
+ output_buffer[output_buffer_pos++] = val;
++ output_buffer_rva++;
+ }
+
+ void put_word( unsigned short val )
+@@ -676,6 +760,14 @@
+ output_buffer_pos += size;
+ }
+
++void align_output_rva( unsigned int file_align, unsigned int rva_align )
++{
++ size_t size = rva_align - (output_buffer_rva % rva_align);
++
++ if (size != rva_align) output_buffer_rva += size;
++ align_output( file_align );
++}
++
+ /* output a standard header for generated files */
+ void output_standard_file_header(void)
+ {
diff -Nru wine-development-5.5/debian/patches/winebuild-Fake_Dlls/0005-winebuild-Add-stub-functions-in-fake-dlls.patch wine-development-5.5/debian/patches/winebuild-Fake_Dlls/0005-winebuild-Add-stub-functions-in-fake-dlls.patch
--- wine-development-5.5/debian/patches/winebuild-Fake_Dlls/0005-winebuild-Add-stub-functions-in-fake-dlls.patch 1970-01-01 01:00:00.000000000 +0100
+++ wine-development-5.5/debian/patches/winebuild-Fake_Dlls/0005-winebuild-Add-stub-functions-in-fake-dlls.patch 2020-05-04 01:33:29.000000000 +0100
@@ -0,0 +1,425 @@
+From 4855e0338f57525304221ba1c29c3926a9f16263 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
+Date: Mon, 15 May 2017 16:27:56 +0200
+Subject: [PATCH] winebuild: Add stub functions in fake dlls.
+
+---
+ dlls/kernel32/tests/loader.c | 8 +-
+ dlls/ntdll/signal_i386.c | 34 ++++++
+ include/winternl.h | 2 +-
+ tools/winebuild/build.h | 1 +
+ tools/winebuild/spec32.c | 209 +++++++++++++++++++++++++++++++++--
+ tools/winebuild/utils.c | 10 +-
+ 6 files changed, 249 insertions(+), 15 deletions(-)
+
+--- a/dlls/kernel32/tests/loader.c
++++ b/dlls/kernel32/tests/loader.c
+@@ -1560,9 +1560,7 @@
+ ok(ptr != NULL, "MapViewOfFile failed with error %u\n", GetLastError());
+
+ dir = RtlImageDirectoryEntryToData(ptr, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &size);
+-todo_wine
+ ok(dir != NULL, "RtlImageDirectoryEntryToData failed\n");
+- if (dir == NULL) goto done;
+
+ names = RVAToAddr(dir->AddressOfNames, ptr);
+ ordinals = RVAToAddr(dir->AddressOfNameOrdinals, ptr);
+@@ -1591,17 +1589,20 @@
+ /* check position in memory */
+ dll_rva = (DWORD_PTR)dll_func - (DWORD_PTR)module;
+ map_rva = funcs[ordinals[i]];
++ todo_wine
+ ok(map_rva == dll_rva, "%s: Rva of mapped function (0x%x) does not match dll (0x%x)\n",
+ func_name, dll_rva, map_rva);
+
+ /* check position in file */
+ map_offset = (DWORD_PTR)RtlImageRvaToVa(RtlImageNtHeader(ptr), ptr, map_rva, NULL) - (DWORD_PTR)ptr;
+ dll_offset = (DWORD_PTR)RtlImageRvaToVa(RtlImageNtHeader(module), module, dll_rva, NULL) - (DWORD_PTR)module;
++ todo_wine
+ ok(map_offset == dll_offset, "%s: File offset of mapped function (0x%x) does not match dll (0x%x)\n",
+ func_name, map_offset, dll_offset);
+
+ /* check function content */
+ map_func = RVAToAddr(map_rva, ptr);
++ todo_wine
+ ok(!memcmp(map_func, dll_func, 0x20), "%s: Function content does not match!\n", func_name);
+
+ if (!strcmp(func_name, "NtSetEvent"))
+@@ -1615,10 +1616,11 @@
+ ok(event != NULL, "CreateEvent failed with error %u\n", GetLastError());
+ pNtSetEvent(event, 0);
+ ok(WaitForSingleObject(event, 0) == WAIT_OBJECT_0, "Event was not signaled\n");
++ pNtSetEvent(event, 0);
++ ok(WaitForSingleObject(event, 0) == WAIT_OBJECT_0, "Event was not signaled\n");
+ CloseHandle(event);
+ }
+
+-done:
+ UnmapViewOfFile(ptr);
+ CloseHandle(map);
+ CloseHandle(file);
+--- a/dlls/ntdll/signal_i386.c
++++ b/dlls/ntdll/signal_i386.c
+@@ -445,6 +445,39 @@
+ extern void DECLSPEC_NORETURN __wine_syscall_dispatcher( void );
+ extern NTSTATUS WINAPI __syscall_NtGetContextThread( HANDLE handle, CONTEXT *context );
+
++static void* WINAPI __wine_fakedll_dispatcher( const char *module, ULONG ord )
++{
++ UNICODE_STRING name;
++ NTSTATUS status;
++ HMODULE base;
++ WCHAR *moduleW;
++ void *proc = NULL;
++ DWORD len = strlen(module);
++
++ TRACE( "(%s, %u)\n", debugstr_a(module), ord );
++
++ if (!(moduleW = RtlAllocateHeap( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) )))
++ return NULL;
++
++ ascii_to_unicode( moduleW, module, len );
++ moduleW[ len ] = 0;
++ RtlInitUnicodeString( &name, moduleW );
++
++ status = LdrGetDllHandle( NULL, 0, &name, &base );
++ if (status == STATUS_DLL_NOT_FOUND)
++ status = LdrLoadDll( NULL, 0, &name, &base );
++ if (status == STATUS_SUCCESS)
++ status = LdrAddRefDll( LDR_ADDREF_DLL_PIN, base );
++ if (status == STATUS_SUCCESS)
++ status = LdrGetProcedureAddress( base, NULL, ord, &proc );
++
++ if (status)
++ FIXME( "No procedure address found for %s.#%u, status %x\n", debugstr_a(module), ord, status );
++
++ RtlFreeHeap( GetProcessHeap(), 0, moduleW );
++ return proc;
++}
++
+ enum i386_trap_code
+ {
+ TRAP_x86_UNKNOWN = -1, /* Unknown fault (TRAP_sig not defined) */
+@@ -2307,6 +2340,7 @@
+ (*teb)->Tib.Self = &(*teb)->Tib;
+ (*teb)->Tib.ExceptionList = (void *)~0UL;
+ (*teb)->WOW32Reserved = __wine_syscall_dispatcher;
++ (*teb)->Spare2 = (ULONG)__wine_fakedll_dispatcher;
+ thread_data = (struct x86_thread_data *)(*teb)->SystemReserved2;
+ if (!(thread_data->fs = wine_ldt_alloc_fs()))
+ {
+--- a/include/winternl.h
++++ b/include/winternl.h
+@@ -398,7 +398,7 @@
+ PVOID Instrumentation[16]; /* f2c/16b8 */
+ PVOID WinSockData; /* f6c/1738 */
+ ULONG GdiBatchCount; /* f70/1740 */
+- ULONG Spare2; /* f74/1744 */
++ ULONG Spare2; /* f74/1744 used for fakedll thunks */
+ ULONG GuaranteedStackBytes; /* f78/1748 */
+ PVOID ReservedForPerf; /* f7c/1750 */
+ PVOID ReservedForOle; /* f80/1758 */
+--- a/tools/winebuild/build.h
++++ b/tools/winebuild/build.h
+@@ -357,6 +357,7 @@
+ extern void put_dword( unsigned int val );
+ extern void put_qword( unsigned int val );
+ extern void put_pword( unsigned int val );
++extern void put_str( const char *str );
+ extern void align_output( unsigned int align );
+ extern void align_output_rva( unsigned int file_align, unsigned int rva_align );
+ extern size_t label_pos( const char *name );
+--- a/tools/winebuild/spec32.c
++++ b/tools/winebuild/spec32.c
+@@ -884,6 +884,163 @@
+ }
+
+
++static int needs_stub_exports( DLLSPEC *spec )
++{
++ if (target_cpu != CPU_x86)
++ return 0;
++ if (!(spec->characteristics & IMAGE_FILE_DLL))
++ return 0;
++ if (!spec->nb_entry_points)
++ return 0;
++ return 1;
++}
++
++
++static void create_stub_exports_text( DLLSPEC *spec )
++{
++ int i, nr_exports = spec->base <= spec->limit ? spec->limit - spec->base + 1 : 0;
++ size_t rva, thunk;
++
++ /* output stub code for exports */
++ for (i = 0; i < spec->nb_entry_points; i++)
++ {
++ ORDDEF *odp = &spec->entry_points[i];
++ const char *name = get_stub_name( odp, spec );
++
++ align_output_rva( 16, 16 );
++ put_label( name );
++ put_byte( 0x8b ); put_byte( 0xff ); /* mov edi, edi */
++ put_byte( 0x55 ); /* push ebp */
++ put_byte( 0x8b ); put_byte( 0xec ); /* mov ebp, esp */
++ put_byte( 0x68 ); put_dword( 0 ); /* push dword 0 */
++ put_byte( 0x68 ); put_dword( odp->ordinal ); /* push ORDINAL */
++ rva = output_buffer_rva + 5;
++ put_byte( 0xe8 ); put_dword( label_rva("_forward") - rva ); /* call _forward */
++ put_byte( 0x89 ); put_byte( 0xec ); /* mov esp, ebp */
++ put_byte( 0x5d ); /* pop ebp */
++ if (odp->type == TYPE_STDCALL)
++ {
++ put_byte( 0xc2 ); put_word( get_args_size(odp) ); /* ret X */
++ }
++ else
++ {
++ put_byte( 0xc3 ); /* ret */
++ }
++ }
++
++ /* output entry point */
++ align_output_rva( 16, 16 );
++ put_label( "entrypoint" );
++ put_byte( 0xb8 ); put_dword( 1 ); /* mov eax, 1 */
++ put_byte( 0xc2 ); put_word( 12 ); /* ret 12 */
++
++ /* output forward function */
++ align_output_rva( 16, 16 );
++ put_label( "_forward" );
++ put_byte( 0x8b ); put_byte( 0x6d ); put_byte( 0x00 ); /* mov ebp, dword[ebp] */
++ put_byte( 0x89 ); put_byte( 0x44 ); /* mov dword[esp+8], eax */
++ put_byte( 0x24 ); put_byte( 0x08 );
++ put_byte( 0x89 ); put_byte( 0x14 ); put_byte( 0x24 ); /* mov dword[esp], edx */
++ put_byte( 0x8b ); put_byte( 0x54 ); /* mov edx, dword[esp+4] */
++ put_byte( 0x24 ); put_byte( 0x04 );
++ put_byte( 0x89 ); put_byte( 0x4c ); /* mov dword[esp+4], ecx */
++ put_byte( 0x24 ); put_byte( 0x04 );
++ put_byte( 0xe8 ); put_dword( 0 ); /* call 1f */
++ thunk = output_buffer_rva;
++ put_byte( 0x59 ); /* pop ecx */
++ put_byte( 0x8b ); put_byte( 0x84 ); put_byte( 0x91 ); /* mov eax, dword[_functions + 4 * (edx - BASE)] */
++ put_dword( label_rva("_functions") - thunk - 4 * spec->base );
++ put_byte( 0x09 ); put_byte( 0xc0 ); /* or eax, eax */
++ rva = output_buffer_rva + 2;
++ put_byte( 0x74 ); put_byte( label_rva("_forward_load") - rva ); /* je _forward_load */
++
++ put_label( "_forward_done" );
++ put_byte( 0x89 ); put_byte( 0x44 ); /* mov dword[esp+12], eax */
++ put_byte( 0x24 ); put_byte( 0x0c );
++ put_byte( 0x5a ); /* pop edx */
++ put_byte( 0x59 ); /* pop ecx */
++ put_byte( 0x58 ); /* pop eax */
++ put_byte( 0xc3 ); /* ret */
++
++ align_output_rva( 16, 16 );
++ put_label( "_forward_load" );
++ put_byte( 0x8d ); put_byte( 0x84 ); put_byte( 0x91 ); /* lea eax, [_functions + 4 * (edx - BASE)] */
++ put_dword( label_rva("_functions") - thunk - 4 * spec->base );
++ put_byte( 0x50 ); /* push eax */
++ put_byte( 0x52 ); /* push edx */
++ put_byte( 0x8d ); put_byte( 0x81 ); /* lea eax, [dll_name] */
++ put_dword( label_rva("dll_name") - thunk );
++ put_byte( 0x50 ); /* push eax */
++ put_byte( 0x64 ); put_byte( 0xff ); /* call dword ptr fs:[0F74h] */
++ put_byte( 0x15 ); put_dword( 0xf74 );
++ put_byte( 0x5a ); /* pop edx */
++ put_byte( 0x89 ); put_byte( 0x02 ); /* mov dword[edx], eax */
++ rva = output_buffer_rva + 2;
++ put_byte( 0xeb ); put_byte( label_rva("_forward_done") - rva ); /* jmp _forward_done */
++
++ /* export directory */
++ align_output_rva( 16, 16 );
++ put_label( "export_start" );
++ put_dword( 0 ); /* Characteristics */
++ put_dword( 0 ); /* TimeDateStamp */
++ put_dword( 0 ); /* MajorVersion/MinorVersion */
++ put_dword( label_rva("dll_name") ); /* Name */
++ put_dword( spec->base ); /* Base */
++ put_dword( nr_exports ); /* NumberOfFunctions */
++ put_dword( spec->nb_names ); /* NumberOfNames */
++ put_dword( label_rva("export_funcs") ); /* AddressOfFunctions */
++ put_dword( label_rva("export_names") ); /* AddressOfNames */
++ put_dword( label_rva("export_ordinals") ); /* AddressOfNameOrdinals */
++
++ put_label( "export_funcs" );
++ for (i = spec->base; i <= spec->limit; i++)
++ {
++ ORDDEF *odp = spec->ordinals[i];
++ if (odp)
++ {
++ const char *name = get_stub_name( odp, spec );
++ put_dword( label_rva( name ) );
++ }
++ else
++ put_dword( 0 );
++ }
++
++ if (spec->nb_names)
++ {
++ put_label( "export_names" );
++ for (i = 0; i < spec->nb_names; i++)
++ put_dword( label_rva(strmake("str_%s", get_stub_name(spec->names[i], spec))) );
++
++ put_label( "export_ordinals" );
++ for (i = 0; i < spec->nb_names; i++)
++ put_word( spec->names[i]->ordinal - spec->base );
++ if (spec->nb_names % 2)
++ put_word( 0 );
++ }
++
++ put_label( "dll_name" );
++ put_str( spec->file_name );
++
++ for (i = 0; i < spec->nb_names; i++)
++ {
++ put_label( strmake("str_%s", get_stub_name(spec->names[i], spec)) );
++ put_str( spec->names[i]->name );
++ }
++
++ put_label( "export_end" );
++}
++
++
++static void create_stub_exports_data( DLLSPEC *spec )
++{
++ int i;
++
++ put_label( "_functions" );
++ for (i = spec->base; i <= spec->limit; i++)
++ put_dword( 0 );
++}
++
++
+ /*******************************************************************
+ * output_fake_module_pass
+ *
+@@ -902,7 +1059,7 @@
+ const unsigned int file_align = 0x200;
+ const unsigned int reloc_size = 8;
+ const unsigned int lfanew = (0x40 + sizeof(fakedll_signature) + 15) & ~15;
+- const unsigned int nb_sections = 2 + (spec->nb_resources != 0);
++ const unsigned int nb_sections = 2 + (needs_stub_exports( spec ) != 0) + (spec->nb_resources != 0);
+
+ put_word( 0x5a4d ); /* e_magic */
+ put_word( 0x40 ); /* e_cblp */
+@@ -959,7 +1116,7 @@
+ put_dword( 0 ); /* SizeOfUninitializedData */
+ put_dword( label_rva("entrypoint") ); /* AddressOfEntryPoint */
+ put_dword( label_rva("text_start") ); /* BaseOfCode */
+- if (get_ptr_size() == 4) put_dword( 0 ); /* BaseOfData */
++ if (get_ptr_size() == 4) put_dword( label_rva("data_start") ); /* BaseOfData */
+ put_pword( 0x10000000 ); /* ImageBase */
+ put_dword( section_align ); /* SectionAlignment */
+ put_dword( file_align ); /* FileAlignment */
+@@ -982,7 +1139,8 @@
+ put_dword( 0 ); /* LoaderFlags */
+ put_dword( 16 ); /* NumberOfRvaAndSizes */
+
+- put_dword( 0 ); put_dword( 0 ); /* DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT] */
++ put_dword( label_rva("export_start") ); /* DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT] */
++ put_dword( label_pos("export_end") - label_pos("export_start") );
+ put_dword( 0 ); put_dword( 0 ); /* DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT] */
+ if (spec->nb_resources) /* DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE] */
+ {
+@@ -1022,6 +1180,21 @@
+ put_word( 0 ); /* NumberOfLinenumbers */
+ put_dword( 0x60000020 /* CNT_CODE|MEM_EXECUTE|MEM_READ */ ); /* Characteristics */
+
++ /* .data section */
++ if (needs_stub_exports( spec ))
++ {
++ put_data( ".data\0\0", 8 ); /* Name */
++ put_dword( label_rva_align("data_end") - label_rva("data_start") ); /* VirtualSize */
++ put_dword( label_rva("data_start") ); /* VirtualAddress */
++ put_dword( label_pos("data_end") - label_pos("data_start") ); /* SizeOfRawData */
++ put_dword( label_pos("data_start") ); /* PointerToRawData */
++ put_dword( 0 ); /* PointerToRelocations */
++ put_dword( 0 ); /* PointerToLinenumbers */
++ put_word( 0 ); /* NumberOfRelocations */
++ put_word( 0 ); /* NumberOfLinenumbers */
++ put_dword( 0xc0000040 /* CNT_INITIALIZED_DATA|MEM_READ|MEM_WRITE */ ); /* Characteristics */
++ }
++
+ /* .reloc section */
+ put_data( ".reloc\0", 8 ); /* Name */
+ put_dword( label_rva_align("reloc_end") - label_rva("reloc_start") ); /* VirtualSize */
+@@ -1054,13 +1227,31 @@
+
+ /* .text contents */
+ align_output_rva( file_align, section_align );
+- put_label( "text_start" );
+- put_label( "entrypoint" );
+- if (spec->characteristics & IMAGE_FILE_DLL)
+- put_data( dll_code_section, sizeof(dll_code_section) );
++ if (needs_stub_exports( spec ))
++ {
++ put_label( "text_start" );
++ create_stub_exports_text( spec );
++ put_label( "text_end" );
++ }
+ else
+- put_data( exe_code_section, sizeof(exe_code_section) );
+- put_label( "text_end" );
++ {
++ put_label( "text_start" );
++ put_label( "entrypoint" );
++ if (spec->characteristics & IMAGE_FILE_DLL)
++ put_data( dll_code_section, sizeof(dll_code_section) );
++ else
++ put_data( exe_code_section, sizeof(exe_code_section) );
++ put_label( "text_end" );
++ }
++
++ /* .data contents */
++ align_output_rva( file_align, section_align );
++ if (needs_stub_exports( spec ))
++ {
++ put_label( "data_start" );
++ create_stub_exports_data( spec );
++ put_label( "data_end" );
++ }
+
+ /* .reloc contents */
+ align_output_rva( file_align, section_align );
+--- a/tools/winebuild/utils.c
++++ b/tools/winebuild/utils.c
+@@ -549,7 +549,7 @@
+ struct label
+ {
+ struct list entry;
+- const char *name;
++ char *name;
+ size_t pos;
+ size_t rva;
+ };
+@@ -567,7 +567,7 @@
+ }
+
+ label = xmalloc( sizeof(*label) );
+- label->name = name;
++ label->name = xstrdup( name );
+ label->pos = 0;
+ label->rva = 0;
+
+@@ -619,6 +619,7 @@
+ LIST_FOR_EACH_ENTRY_SAFE( label, label2, &labels, struct label, entry )
+ {
+ list_remove( &label->entry );
++ free( label->name );
+ free( label );
+ }
+ }
+@@ -750,6 +751,11 @@
+ else put_dword( val );
+ }
+
++void put_str( const char *str )
++{
++ put_data( str, strlen(str) + 1 );
++}
++
+ void align_output( unsigned int align )
+ {
+ size_t size = align - (output_buffer_pos % align);
diff -Nru wine-development-5.5/debian/patches/winebuild-Fake_Dlls/0006-winebuild-Add-syscall-thunks-in-fake-dlls.patch wine-development-5.5/debian/patches/winebuild-Fake_Dlls/0006-winebuild-Add-syscall-thunks-in-fake-dlls.patch
--- wine-development-5.5/debian/patches/winebuild-Fake_Dlls/0006-winebuild-Add-syscall-thunks-in-fake-dlls.patch 1970-01-01 01:00:00.000000000 +0100
+++ wine-development-5.5/debian/patches/winebuild-Fake_Dlls/0006-winebuild-Add-syscall-thunks-in-fake-dlls.patch 2020-05-04 01:33:29.000000000 +0100
@@ -0,0 +1,69 @@
+From 4e2ff25e0e50d37975ec152bcc40fa130ff130b9 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
+Date: Mon, 15 May 2017 17:56:48 +0200
+Subject: [PATCH] winebuild: Add syscall thunks in fake dlls.
+
+---
+ dlls/kernel32/tests/loader.c | 1 -
+ tools/winebuild/spec32.c | 27 +++++++++++++++++++++++++--
+ 2 files changed, 25 insertions(+), 3 deletions(-)
+
+--- a/dlls/kernel32/tests/loader.c
++++ b/dlls/kernel32/tests/loader.c
+@@ -1602,7 +1602,6 @@
+
+ /* check function content */
+ map_func = RVAToAddr(map_rva, ptr);
+- todo_wine
+ ok(!memcmp(map_func, dll_func, 0x20), "%s: Function content does not match!\n", func_name);
+
+ if (!strcmp(func_name, "NtSetEvent"))
+--- a/tools/winebuild/spec32.c
++++ b/tools/winebuild/spec32.c
+@@ -901,13 +901,36 @@
+ int i, nr_exports = spec->base <= spec->limit ? spec->limit - spec->base + 1 : 0;
+ size_t rva, thunk;
+
++ /* output syscalls */
++ for (i = 0; i < spec->nb_syscalls; i++)
++ {
++ ORDDEF *odp = spec->syscalls[i];
++
++ align_output_rva( 16, 16 );
++ put_label( odp->link_name );
++ put_byte( 0xb8 ); put_dword( i ); /* mov eax, SYSCALL */
++ put_byte( 0x64 ); put_byte( 0xff ); /* call dword ptr fs:[0C0h] */
++ put_byte( 0x15 ); put_dword( 0xc0 );
++ put_byte( 0xc2 ); put_word( get_args_size(odp) ); /* ret X */
++ }
++
++ if (spec->nb_syscalls)
++ {
++ for (i = 0; i < 0x20; i++)
++ put_byte( 0 );
++ }
++
+ /* output stub code for exports */
+ for (i = 0; i < spec->nb_entry_points; i++)
+ {
+ ORDDEF *odp = &spec->entry_points[i];
+- const char *name = get_stub_name( odp, spec );
++ const char *name;
++
++ if (odp->flags & FLAG_SYSCALL)
++ continue;
+
+ align_output_rva( 16, 16 );
++ name = get_stub_name( odp, spec );
+ put_label( name );
+ put_byte( 0x8b ); put_byte( 0xff ); /* mov edi, edi */
+ put_byte( 0x55 ); /* push ebp */
+@@ -998,7 +1021,7 @@
+ ORDDEF *odp = spec->ordinals[i];
+ if (odp)
+ {
+- const char *name = get_stub_name( odp, spec );
++ const char *name = (odp->flags & FLAG_SYSCALL) ? odp->link_name : get_stub_name( odp, spec );
+ put_dword( label_rva( name ) );
+ }
+ else
diff -Nru wine-development-5.5/debian/patches/winebuild-Fake_Dlls/0007-winebuild-Fix-size-of-relocation-information-in-fake.patch wine-development-5.5/debian/patches/winebuild-Fake_Dlls/0007-winebuild-Fix-size-of-relocation-information-in-fake.patch
--- wine-development-5.5/debian/patches/winebuild-Fake_Dlls/0007-winebuild-Fix-size-of-relocation-information-in-fake.patch 1970-01-01 01:00:00.000000000 +0100
+++ wine-development-5.5/debian/patches/winebuild-Fake_Dlls/0007-winebuild-Fix-size-of-relocation-information-in-fake.patch 2020-05-04 01:33:29.000000000 +0100
@@ -0,0 +1,22 @@
+From 72e217f735af13a8a7026688fd46f353c24e93ab Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
+Date: Thu, 25 May 2017 03:22:25 +0200
+Subject: winebuild: Fix size of relocation information in fake dlls.
+
+---
+ tools/winebuild/spec32.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/tools/winebuild/spec32.c
++++ b/tools/winebuild/spec32.c
+@@ -1279,8 +1279,8 @@
+ /* .reloc contents */
+ align_output_rva( file_align, section_align );
+ put_label( "reloc_start" );
+- put_dword( 0 ); /* VirtualAddress */
+- put_dword( 0 ); /* SizeOfBlock */
++ put_dword( label_rva("text_start") ); /* VirtualAddress */
++ put_dword( 8 ); /* SizeOfBlock */
+ put_label( "reloc_end" );
+
+ /* .rsrc contents */
diff -Nru wine-development-5.5/debian/patches/winebuild-Fake_Dlls/0008-winebuild-Try-to-make-sure-RVA-matches-between-fake-.patch wine-development-5.5/debian/patches/winebuild-Fake_Dlls/0008-winebuild-Try-to-make-sure-RVA-matches-between-fake-.patch
--- wine-development-5.5/debian/patches/winebuild-Fake_Dlls/0008-winebuild-Try-to-make-sure-RVA-matches-between-fake-.patch 1970-01-01 01:00:00.000000000 +0100
+++ wine-development-5.5/debian/patches/winebuild-Fake_Dlls/0008-winebuild-Try-to-make-sure-RVA-matches-between-fake-.patch 2020-05-04 01:33:29.000000000 +0100
@@ -0,0 +1,90 @@
+From b9dbb8650b4b339de5e71cf5dab5c3ec321def58 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
+Date: Thu, 25 May 2017 21:46:27 +0200
+Subject: [PATCH] winebuild: Try to make sure RVA matches between fake and
+ builtin DLLs.
+
+---
+ dlls/kernel32/tests/loader.c | 1 -
+ libs/wine/loader.c | 13 +++++++++++--
+ tools/winebuild/spec32.c | 17 +++++++++++++++--
+ 3 files changed, 26 insertions(+), 5 deletions(-)
+
+--- a/dlls/kernel32/tests/loader.c
++++ b/dlls/kernel32/tests/loader.c
+@@ -1589,7 +1589,6 @@
+ /* check position in memory */
+ dll_rva = (DWORD_PTR)dll_func - (DWORD_PTR)module;
+ map_rva = funcs[ordinals[i]];
+- todo_wine
+ ok(map_rva == dll_rva, "%s: Rva of mapped function (0x%x) does not match dll (0x%x)\n",
+ func_name, dll_rva, map_rva);
+
+--- a/libs/wine/loader.c
++++ b/libs/wine/loader.c
+@@ -335,8 +335,12 @@
+ assert( size <= page_size );
+
+ /* module address must be aligned on 64K boundary */
+- addr = (BYTE *)((nt_descr->OptionalHeader.ImageBase + 0xffff) & ~0xffff);
+- if (wine_anon_mmap( addr, page_size, PROT_READ|PROT_WRITE, MAP_FIXED ) != addr) return NULL;
++ addr = *(BYTE **)&nt_descr->OptionalHeader.DataDirectory[15];
++ if (!addr || ((ULONG_PTR)addr & 0xffff) || mprotect( addr, page_size, PROT_READ | PROT_WRITE ))
++ {
++ addr = (BYTE *)((nt_descr->OptionalHeader.ImageBase + 0xffff) & ~0xffff);
++ if (wine_anon_mmap( addr, page_size, PROT_READ|PROT_WRITE, MAP_FIXED ) != addr) return NULL;
++ }
+
+ dos = (IMAGE_DOS_HEADER *)addr;
+ nt = (IMAGE_NT_HEADERS *)(dos + 1);
+@@ -383,6 +387,11 @@
+ nt->OptionalHeader.SizeOfImage = data_end;
+ nt->OptionalHeader.ImageBase = (ULONG_PTR)addr;
+
++ /* Clear DataDirectory[15] */
++
++ nt->OptionalHeader.DataDirectory[15].VirtualAddress = 0;
++ nt->OptionalHeader.DataDirectory[15].Size = 0;
++
+ /* Build the code section */
+
+ memcpy( sec->Name, ".text", sizeof(".text") );
+--- a/tools/winebuild/spec32.c
++++ b/tools/winebuild/spec32.c
+@@ -381,14 +381,25 @@
+ */
+ static void output_syscall_thunks( DLLSPEC *spec )
+ {
++ const unsigned int page_size = get_page_size();
+ int i;
+
+ if (!spec->nb_syscalls)
+ return;
+
+- output( "\n/* syscall thunks */\n\n" );
+- output( "\t.text\n" );
++ /* Reserve space for PE header directly before syscalls. */
++ if (target_platform == PLATFORM_APPLE)
++ output( "\t.text\n" );
++ else
++ output( "\n\t.section \".text.startup\"\n" );
++
++ output( "\t.align %d\n", get_alignment(65536) );
++ output( "__wine_spec_pe_header_syscalls:\n" );
++ output( "__wine_spec_pe_header_syscalls_end:\n" );
++ output( "\t.byte 0\n" );
++ output( "\t.balign %d, 0\n", page_size );
+
++ output( "\n/* syscall thunks */\n\n" );
+ for (i = 0; i < spec->nb_syscalls; i++)
+ {
+ ORDDEF *odp = spec->syscalls[i];
+@@ -849,6 +860,8 @@
+ data_dirs[1] = ".L__wine_spec_imports"; /* DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT] */
+ if (spec->nb_resources)
+ data_dirs[2] = ".L__wine_spec_resources"; /* DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE] */
++ if (spec->nb_syscalls)
++ data_dirs[15] = "__wine_spec_pe_header_syscalls";
+
+ output_data_directories( data_dirs );
+
diff -Nru wine-development-5.5/debian/patches/winebuild-Fake_Dlls/0009-libs-wine-Use-same-file-alignment-for-fake-and-built.patch wine-development-5.5/debian/patches/winebuild-Fake_Dlls/0009-libs-wine-Use-same-file-alignment-for-fake-and-built.patch
--- wine-development-5.5/debian/patches/winebuild-Fake_Dlls/0009-libs-wine-Use-same-file-alignment-for-fake-and-built.patch 1970-01-01 01:00:00.000000000 +0100
+++ wine-development-5.5/debian/patches/winebuild-Fake_Dlls/0009-libs-wine-Use-same-file-alignment-for-fake-and-built.patch 2020-05-04 01:33:29.000000000 +0100
@@ -0,0 +1,31 @@
+From 87cbe344d00e41b46df4c9e44419b8c14cd49620 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
+Date: Thu, 25 May 2017 21:56:06 +0200
+Subject: [PATCH] libs/wine: Use same file alignment for fake and builtin DLLs.
+
+---
+ dlls/kernel32/tests/loader.c | 1 -
+ libs/wine/loader.c | 2 +-
+ 2 files changed, 1 insertion(+), 2 deletions(-)
+
+--- a/dlls/kernel32/tests/loader.c
++++ b/dlls/kernel32/tests/loader.c
+@@ -1595,7 +1595,6 @@
+ /* check position in file */
+ map_offset = (DWORD_PTR)RtlImageRvaToVa(RtlImageNtHeader(ptr), ptr, map_rva, NULL) - (DWORD_PTR)ptr;
+ dll_offset = (DWORD_PTR)RtlImageRvaToVa(RtlImageNtHeader(module), module, dll_rva, NULL) - (DWORD_PTR)module;
+- todo_wine
+ ok(map_offset == dll_offset, "%s: File offset of mapped function (0x%x) does not match dll (0x%x)\n",
+ func_name, map_offset, dll_offset);
+
+--- a/libs/wine/loader.c
++++ b/libs/wine/loader.c
+@@ -398,7 +398,7 @@
+ sec->SizeOfRawData = code_end - code_start;
+ sec->Misc.VirtualSize = sec->SizeOfRawData;
+ sec->VirtualAddress = code_start;
+- sec->PointerToRawData = code_start;
++ sec->PointerToRawData = 0x200; /* file alignment */
+ sec->Characteristics = (IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ);
+ sec++;
+
diff -Nru wine-development-5.5/debian/patches/winebuild-Fake_Dlls/0010-tools-winebuild-Add-syscall-thunks-for-64-bit.patch wine-development-5.5/debian/patches/winebuild-Fake_Dlls/0010-tools-winebuild-Add-syscall-thunks-for-64-bit.patch
--- wine-development-5.5/debian/patches/winebuild-Fake_Dlls/0010-tools-winebuild-Add-syscall-thunks-for-64-bit.patch 1970-01-01 01:00:00.000000000 +0100
+++ wine-development-5.5/debian/patches/winebuild-Fake_Dlls/0010-tools-winebuild-Add-syscall-thunks-for-64-bit.patch 2020-05-04 01:33:29.000000000 +0100
@@ -0,0 +1,447 @@
+From 76abfa6c07701466a7a14bfeeaad64e357f54a1c Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
+Date: Thu, 7 Sep 2017 00:38:09 +0200
+Subject: [PATCH] tools/winebuild: Add syscall thunks for 64 bit.
+
+---
+ dlls/kernel32/tests/loader.c | 7 +-
+ dlls/ntdll/signal_x86_64.c | 2 +
+ dlls/ntdll/thread.c | 10 ++
+ libs/wine/loader.c | 4 +
+ tools/winebuild/parser.c | 2 +-
+ tools/winebuild/spec32.c | 285 ++++++++++++++++++++++++++++++++++-
+ 6 files changed, 302 insertions(+), 8 deletions(-)
+
+--- a/dlls/kernel32/tests/loader.c
++++ b/dlls/kernel32/tests/loader.c
+@@ -1537,7 +1537,7 @@
+
+ static void test_FakeDLL(void)
+ {
+-#ifdef __i386__
++#if defined(__i386__) || defined(__x86_64__)
+ NTSTATUS (WINAPI *pNtSetEvent)(HANDLE, ULONG *) = NULL;
+ IMAGE_EXPORT_DIRECTORY *dir;
+ HMODULE module = GetModuleHandleA("ntdll.dll");
+@@ -1579,8 +1579,13 @@
+
+ dll_func = (BYTE *)GetProcAddress(module, func_name);
+ ok(dll_func != NULL, "%s: GetProcAddress returned NULL\n", func_name);
++#if defined(__i386__)
+ if (dll_func[0] == 0x90 && dll_func[1] == 0x90 &&
+ dll_func[2] == 0x90 && dll_func[3] == 0x90)
++#elif defined(__x86_64__)
++ if (dll_func[0] == 0x48 && dll_func[1] == 0x83 &&
++ dll_func[2] == 0xec && dll_func[3] == 0x08)
++#endif
+ {
+ todo_wine ok(0, "%s: Export is a stub-function, skipping\n", func_name);
+ continue;
+--- a/dlls/ntdll/signal_x86_64.c
++++ b/dlls/ntdll/signal_x86_64.c
+@@ -355,6 +355,7 @@
+ #endif
+ }
+
++extern void DECLSPEC_NORETURN __wine_syscall_dispatcher( void );
+
+ /***********************************************************************
+ * Definitions for Win32 unwind tables
+@@ -3133,6 +3134,7 @@
+ {
+ (*teb)->Tib.Self = &(*teb)->Tib;
+ (*teb)->Tib.ExceptionList = (void *)~0UL;
++ (*teb)->WOW32Reserved = __wine_syscall_dispatcher;
+ }
+ return status;
+ }
+--- a/dlls/ntdll/thread.c
++++ b/dlls/ntdll/thread.c
+@@ -63,6 +63,8 @@
+ struct _KUSER_SHARED_DATA *user_shared_data = &user_shared_data_internal;
+ static const WCHAR default_windirW[] = {'C',':','\\','w','i','n','d','o','w','s',0};
+
++extern void DECLSPEC_NORETURN __wine_syscall_dispatcher( void );
++
+ void (WINAPI *kernel32_start_process)(LPTHREAD_START_ROUTINE,void*) = NULL;
+
+ /* info passed to a starting thread */
+@@ -327,6 +329,14 @@
+ InitializeListHead( &ldr.InInitializationOrderModuleList );
+ *(ULONG_PTR *)peb->Reserved = get_image_addr();
+
++#if defined(__APPLE__) && defined(__x86_64__)
++ *((DWORD*)((char*)user_shared_data_external + 0x1000)) = __wine_syscall_dispatcher;
++#endif
++ /* Pretend we don't support the SYSCALL instruction on x86-64. Needed for
++ * Chromium; see output_syscall_thunks_x64() in winebuild. */
++ user_shared_data->SystemCallPad[0] = 1;
++ user_shared_data_external->SystemCallPad[0] = 1;
++
+ /*
+ * Starting with Vista, the first user to log on has session id 1.
+ * Session id 0 is for processes that don't interact with the user (like services).
+--- a/libs/wine/loader.c
++++ b/libs/wine/loader.c
+@@ -398,7 +398,11 @@
+ sec->SizeOfRawData = code_end - code_start;
+ sec->Misc.VirtualSize = sec->SizeOfRawData;
+ sec->VirtualAddress = code_start;
++#ifdef _WIN64
++ sec->PointerToRawData = 0x400; /* file alignment */
++#else
+ sec->PointerToRawData = 0x200; /* file alignment */
++#endif
+ sec->Characteristics = (IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ);
+ sec++;
+
+--- a/tools/winebuild/parser.c
++++ b/tools/winebuild/parser.c
+@@ -545,7 +545,7 @@
+
+ static int needs_syscall( ORDDEF *odp, DLLSPEC *spec )
+ {
+- if (target_cpu != CPU_x86)
++ if (target_cpu != CPU_x86 && target_cpu != CPU_x86_64)
+ return 0;
+ if (odp->flags & (FLAG_FORWARD | FLAG_REGISTER))
+ return 0;
+--- a/tools/winebuild/spec32.c
++++ b/tools/winebuild/spec32.c
+@@ -375,11 +375,11 @@
+ }
+
+ /*******************************************************************
+- * output_syscall_thunks
++ * output_syscall_thunks_x86
+ *
+ * Output entry points for system call functions
+ */
+-static void output_syscall_thunks( DLLSPEC *spec )
++static void output_syscall_thunks_x86( DLLSPEC *spec )
+ {
+ const unsigned int page_size = get_page_size();
+ int i;
+@@ -489,6 +489,157 @@
+ }
+
+ /*******************************************************************
++ * output_syscall_thunks_x64
++ *
++ * Output entry points for system call functions
++ */
++static void output_syscall_thunks_x64( DLLSPEC *spec )
++{
++ const unsigned int page_size = get_page_size();
++ int i;
++
++ if (!spec->nb_syscalls)
++ return;
++
++ /* Reserve space for PE header directly before syscalls. */
++ if (target_platform == PLATFORM_APPLE)
++ output( "\t.text\n" );
++ else
++ output( "\n\t.section \".text.startup\"\n" );
++
++ output( "\t.align %d\n", get_alignment(65536) );
++ output( "__wine_spec_pe_header_syscalls:\n" );
++ output( "__wine_spec_pe_header_syscalls_end:\n" );
++ output( "\t.byte 0\n" );
++ output( "\t.balign %d, 0\n", page_size );
++
++ output( "\n/* syscall thunks */\n\n" );
++ for (i = 0; i < spec->nb_syscalls; i++)
++ {
++ ORDDEF *odp = spec->syscalls[i];
++ const char *name = odp->link_name;
++
++ /* Chromium depends on syscall thunks having the same form as on
++ * Windows. For 64-bit systems the only viable form we can emulate is
++ * having an int $0x2e fallback. Since actually using an interrupt is
++ * expensive, and since for some reason Chromium doesn't actually
++ * validate that instruction, we can just put a jmp there instead. */
++
++ output( "\t.balign 16, 0\n" );
++ output( "\t%s\n", func_declaration(name) );
++ output( "%s\n", asm_globl(name) );
++ output_cfi( ".cfi_startproc" );
++ output( "\t.byte 0x4c,0x8b,0xd1\n" ); /* mov r10, rcx */
++ output( "\t.byte 0xb8\n" ); /* mov eax, SYSCALL */
++ output( "\t.long %d\n", i );
++ output( "\t.byte 0xf6,0x04,0x25,0x08,0x03,0xfe,0x7f,0x01\n" ); /* test byte ptr [0x7ffe0308], 1 */
++ output( "\t.byte 0x75,0x03\n" ); /* jne (over syscall) */
++ output( "\t.byte 0x0f,0x05\n" ); /* syscall */
++ output( "\t.byte 0xc3\n" ); /* ret */
++ output( "\t.byte 0xeb,0x01\n" ); /* jmp over ret */
++ output( "\t.byte 0xc3\n" ); /* ret */
++ if (target_platform == PLATFORM_APPLE)
++ {
++ output( "\t.byte 0xff,0x14,0x25\n" ); /* call [0x7ffe1000] */
++ output( "\t.long 0x7ffe1000\n" );
++ }
++ else
++ {
++ output( "\t.byte 0x65,0xff,0x14,0x25\n" ); /* call qword ptr gs:[0x100] */
++ output( "\t.long 0x100\n");
++ }
++ /* This RET is never reached, but Legends of Runeterra demands that it
++ * exist anyway. */
++ output( "\t.byte 0xc3\n" ); /* ret */
++ output_cfi( ".cfi_endproc" );
++ output_function_size( name );
++ }
++
++ for (i = 0; i < 0x20; i++)
++ output( "\t.byte 0\n" );
++
++ output( "\n/* syscall table */\n\n" );
++ output( "\t.data\n" );
++ output( "%s\n", asm_globl("__wine_syscall_table") );
++ for (i = 0; i < spec->nb_syscalls; i++)
++ {
++ ORDDEF *odp = spec->syscalls[i];
++ output ("\t%s %s\n", get_asm_ptr_keyword(), asm_name(odp->impl_name) );
++ }
++
++ output( "\n/* syscall argument stack size table */\n\n" );
++ output( "\t.data\n" );
++ output( "%s\n", asm_globl("__wine_syscall_stack_size") );
++ for (i = 0; i < spec->nb_syscalls; i++)
++ {
++ ORDDEF *odp = spec->syscalls[i];
++ output( "\t.byte %d\n", max(get_args_size(odp), 32) - 32 );
++ }
++
++ output( "\n/* syscall dispatcher */\n\n" );
++ output( "\t.text\n" );
++ output( "\t.align %d\n", get_alignment(16) );
++ output( "\t%s\n", func_declaration("__wine_syscall_dispatcher") );
++ output( "%s\n", asm_globl("__wine_syscall_dispatcher") );
++
++ /* prologue */
++ output_cfi( ".cfi_startproc" );
++ output( "\tpushq %%rbp\n" );
++ output_cfi( ".cfi_adjust_cfa_offset 8" );
++ output_cfi( ".cfi_rel_offset %%rbp,0" );
++ output( "\tmovq %%rsp,%%rbp\n" );
++ output_cfi( ".cfi_def_cfa_register %%rbp" );
++ output( "\tpushq %%rsi\n" );
++ output_cfi( ".cfi_rel_offset %%rsi,-8" );
++ output( "\tpushq %%rdi\n" );
++ output_cfi( ".cfi_rel_offset %%rdi,-16" );
++
++ /* Legends of Runeterra hooks the first system call return instruction, and
++ * depends on us returning to it. Adjust the return address accordingly. */
++ if (target_platform == PLATFORM_APPLE)
++ output( "\tsubq $0xb,0x8(%%rbp)\n" );
++ else
++ output( "\tsubq $0xc,0x8(%%rbp)\n" );
++
++ /* copy over any arguments on the stack */
++ output( "\tleaq 0x38(%%rbp),%%rsi\n" );
++ if (UsePIC)
++ {
++ output( "\tleaq (%%rip), %%r11\n" );
++ output( "1:\tmovzbq (%s-1b)(%%r11,%%rax,1),%%rcx\n", asm_name("__wine_syscall_stack_size") );
++ }
++ else
++ output( "\tmovzbq %s(%%rax),%%rcx\n", asm_name("__wine_syscall_stack_size") );
++ output( "\tsubq %%rcx,%%rsp\n" );
++ output( "\tand $~0xf,%%rsp\n\t" ); /* ensure stack alignment. */
++ output( "\tshrq $3,%%rcx\n" );
++ output( "\tmovq %%rsp,%%rdi\n" );
++ output( "\trep; movsq\n" );
++
++ /* call the function */
++ output( "\tmovq %%r10,%%rcx\n" );
++ output( "\tsubq $0x20,%%rsp\n" );
++ if (UsePIC)
++ output( "\tcallq *(%s-1b)(%%r11,%%rax,%d)\n", asm_name("__wine_syscall_table"), get_ptr_size() );
++ else
++ output( "\tcallq *%s(,%%rax,%d)\n", asm_name("__wine_syscall_table"), get_ptr_size() );
++ output( "\tleaq -0x10(%%rbp),%%rsp\n" );
++
++ /* epilogue */
++ output( "\tpopq %%rdi\n" );
++ output_cfi( ".cfi_same_value %%rdi" );
++ output( "\tpopq %%rsi\n" );
++ output_cfi( ".cfi_same_value %%rsi" );
++ output_cfi( ".cfi_def_cfa_register %%rsp" );
++ output( "\tpopq %%rbp\n" );
++ output_cfi( ".cfi_adjust_cfa_offset -8" );
++ output_cfi( ".cfi_same_value %%rbp" );
++ output( "\tret\n" );
++ output_cfi( ".cfi_endproc" );
++ output_function_size( "__wine_syscall_dispatcher" );
++}
++
++/*******************************************************************
+ * output_exports
+ *
+ * Output the export table for a Win32 module.
+@@ -886,7 +1037,10 @@
+ open_output_file();
+ output_standard_file_header();
+ output_module( spec );
+- output_syscall_thunks( spec );
++ if (target_cpu == CPU_x86)
++ output_syscall_thunks_x86( spec );
++ else if (target_cpu == CPU_x86_64)
++ output_syscall_thunks_x64( spec );
+ output_stubs( spec );
+ output_exports( spec );
+ output_imports( spec );
+@@ -899,7 +1053,7 @@
+
+ static int needs_stub_exports( DLLSPEC *spec )
+ {
+- if (target_cpu != CPU_x86)
++ if (target_cpu != CPU_x86 && target_cpu != CPU_x86_64)
+ return 0;
+ if (!(spec->characteristics & IMAGE_FILE_DLL))
+ return 0;
+@@ -909,7 +1063,7 @@
+ }
+
+
+-static void create_stub_exports_text( DLLSPEC *spec )
++static void create_stub_exports_text_x86( DLLSPEC *spec )
+ {
+ int i, nr_exports = spec->base <= spec->limit ? spec->limit - spec->base + 1 : 0;
+ size_t rva, thunk;
+@@ -1067,6 +1221,122 @@
+ }
+
+
++static void create_stub_exports_text_x64( DLLSPEC *spec )
++{
++ int i, nr_exports = spec->base <= spec->limit ? spec->limit - spec->base + 1 : 0;
++
++ /* output syscalls */
++ for (i = 0; i < spec->nb_syscalls; i++)
++ {
++ ORDDEF *odp = spec->syscalls[i];
++
++ align_output_rva( 16, 16 );
++ put_label( odp->link_name );
++ put_byte( 0x4c ); put_byte( 0x8b ); put_byte( 0xd1 ); /* mov r10, rcx */
++ put_byte( 0xb8 ); put_dword( i ); /* mov eax, SYSCALL */
++ put_byte( 0xf6 ); put_byte( 0x04 ); put_byte( 0x25 ); /* test byte ptr [0x7ffe0308], 1 */
++ put_byte( 0x08 ); put_byte( 0x03 ); put_byte( 0xfe );
++ put_byte( 0x7f ); put_byte( 0x01 );
++ put_byte( 0x75 ); put_byte( 0x03 ); /* jne */
++ put_byte( 0x0f ); put_byte( 0x05 ); /* syscall */
++ put_byte( 0xc3 ); /* ret */
++ put_byte( 0xeb ); put_byte( 0x01 ); /* jmp */
++ put_byte( 0xc3 ); /* ret */
++ if (target_platform == PLATFORM_APPLE)
++ {
++ put_byte( 0xff ); put_byte( 0x14 ); /* call [0x7ffe1000] */
++ put_byte( 0x25 ); put_dword( 0x7ffe1000 );
++ }
++ else
++ {
++ put_byte( 0x65 ); put_byte( 0xff ); /* call ptr gs:[0x100] */
++ put_byte( 0x14 ); put_byte( 0x25 ); put_dword( 0x100 );
++
++ }
++ put_byte( 0xc3 ); /* ret */
++ }
++
++ if (spec->nb_syscalls)
++ {
++ for (i = 0; i < 0x20; i++)
++ put_byte( 0 );
++ }
++
++ /* output stub code for exports */
++ for (i = 0; i < spec->nb_entry_points; i++)
++ {
++ ORDDEF *odp = &spec->entry_points[i];
++ const char *name;
++
++ if (odp->flags & FLAG_SYSCALL)
++ continue;
++
++ align_output_rva( 16, 16 );
++ name = get_stub_name( odp, spec );
++ put_label( name );
++ put_byte( 0xcc ); /* int $0x3 */
++ put_byte( 0xc3 ); /* ret */
++ }
++
++ /* output entry point */
++ align_output_rva( 16, 16 );
++ put_label( "entrypoint" );
++ put_byte( 0xb8 ); put_dword( 1 ); /* mov rax, 1 */
++ put_byte( 0xc3 ); /* ret */
++
++ /* export directory */
++ align_output_rva( 16, 16 );
++ put_label( "export_start" );
++ put_dword( 0 ); /* Characteristics */
++ put_dword( 0 ); /* TimeDateStamp */
++ put_dword( 0 ); /* MajorVersion/MinorVersion */
++ put_dword( label_rva("dll_name") ); /* Name */
++ put_dword( spec->base ); /* Base */
++ put_dword( nr_exports ); /* NumberOfFunctions */
++ put_dword( spec->nb_names ); /* NumberOfNames */
++ put_dword( label_rva("export_funcs") ); /* AddressOfFunctions */
++ put_dword( label_rva("export_names") ); /* AddressOfNames */
++ put_dword( label_rva("export_ordinals") ); /* AddressOfNameOrdinals */
++
++ put_label( "export_funcs" );
++ for (i = spec->base; i <= spec->limit; i++)
++ {
++ ORDDEF *odp = spec->ordinals[i];
++ if (odp)
++ {
++ const char *name = (odp->flags & FLAG_SYSCALL) ? odp->link_name : get_stub_name( odp, spec );
++ put_dword( label_rva( name ) );
++ }
++ else
++ put_dword( 0 );
++ }
++
++ if (spec->nb_names)
++ {
++ put_label( "export_names" );
++ for (i = 0; i < spec->nb_names; i++)
++ put_dword( label_rva(strmake("str_%s", get_stub_name(spec->names[i], spec))) );
++
++ put_label( "export_ordinals" );
++ for (i = 0; i < spec->nb_names; i++)
++ put_word( spec->names[i]->ordinal - spec->base );
++ if (spec->nb_names % 2)
++ put_word( 0 );
++ }
++
++ put_label( "dll_name" );
++ put_str( spec->file_name );
++
++ for (i = 0; i < spec->nb_names; i++)
++ {
++ put_label( strmake("str_%s", get_stub_name(spec->names[i], spec)) );
++ put_str( spec->names[i]->name );
++ }
++
++ put_label( "export_end" );
++}
++
++
+ static void create_stub_exports_data( DLLSPEC *spec )
+ {
+ int i;
+@@ -1266,7 +1536,10 @@
+ if (needs_stub_exports( spec ))
+ {
+ put_label( "text_start" );
+- create_stub_exports_text( spec );
++ if (target_cpu == CPU_x86)
++ create_stub_exports_text_x86( spec );
++ else if (target_cpu == CPU_x86_64)
++ create_stub_exports_text_x64( spec );
+ put_label( "text_end" );
+ }
+ else
diff -Nru wine-development-5.5/debian/patches/winebuild-Fake_Dlls/0011-ntdll-Call-NtOpenFile-through-syscall-thunk.patch wine-development-5.5/debian/patches/winebuild-Fake_Dlls/0011-ntdll-Call-NtOpenFile-through-syscall-thunk.patch
--- wine-development-5.5/debian/patches/winebuild-Fake_Dlls/0011-ntdll-Call-NtOpenFile-through-syscall-thunk.patch 1970-01-01 01:00:00.000000000 +0100
+++ wine-development-5.5/debian/patches/winebuild-Fake_Dlls/0011-ntdll-Call-NtOpenFile-through-syscall-thunk.patch 2020-05-04 01:33:29.000000000 +0100
@@ -0,0 +1,115 @@
+From 3d74d528e07008df764caef28993d551bfd934ba Mon Sep 17 00:00:00 2001
+From: Paul Gofman <gofmanp@gmail.com>
+Date: Fri, 3 Jan 2020 17:39:08 +0300
+Subject: [PATCH] ntdll: Call NtOpenFile through syscall thunk.
+
+Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=48410
+---
+ dlls/ntdll/actctx.c | 4 ++--
+ dlls/ntdll/directory.c | 2 +-
+ dlls/ntdll/loader.c | 2 +-
+ dlls/ntdll/locale.c | 4 ++--
+ dlls/ntdll/ntdll_misc.h | 8 ++++++++
+ dlls/ntdll/path.c | 2 +-
+ dlls/ntdll/process.c | 2 +-
+ 7 files changed, 16 insertions(+), 8 deletions(-)
+
+--- a/dlls/ntdll/actctx.c
++++ b/dlls/ntdll/actctx.c
+@@ -2890,7 +2890,7 @@
+ attr.ObjectName = name;
+ attr.SecurityDescriptor = NULL;
+ attr.SecurityQualityOfService = NULL;
+- return NtOpenFile( handle, GENERIC_READ | SYNCHRONIZE, &attr, &io, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_ALERT );
++ return __syscall_NtOpenFile( handle, GENERIC_READ | SYNCHRONIZE, &attr, &io, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_ALERT );
+ }
+
+ static NTSTATUS get_manifest_in_module( struct actctx_loader* acl, struct assembly_identity* ai,
+@@ -3207,7 +3207,7 @@
+ attr.SecurityDescriptor = NULL;
+ attr.SecurityQualityOfService = NULL;
+
+- if (!NtOpenFile( &handle, GENERIC_READ | SYNCHRONIZE, &attr, &io, FILE_SHARE_READ | FILE_SHARE_WRITE,
++ if (!__syscall_NtOpenFile( &handle, GENERIC_READ | SYNCHRONIZE, &attr, &io, FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT ))
+ {
+ sxs_ai = *ai;
+--- a/dlls/ntdll/directory.c
++++ b/dlls/ntdll/directory.c
+@@ -3000,7 +3000,7 @@
+ attr.SecurityDescriptor = NULL;
+ attr.SecurityQualityOfService = NULL;
+
+- status = NtOpenFile( &handle, SYNCHRONIZE, &attr, &io, 0,
++ status = __syscall_NtOpenFile( &handle, SYNCHRONIZE, &attr, &io, 0,
+ FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT );
+ RtlFreeUnicodeString( &dirW );
+ if (status != STATUS_SUCCESS) goto done;
+--- a/dlls/ntdll/loader.c
++++ b/dlls/ntdll/loader.c
+@@ -2372,7 +2372,7 @@
+ attr.ObjectName = nt_name;
+ attr.SecurityDescriptor = NULL;
+ attr.SecurityQualityOfService = NULL;
+- if ((status = NtOpenFile( &handle, GENERIC_READ | SYNCHRONIZE, &attr, &io,
++ if ((status = __syscall_NtOpenFile( &handle, GENERIC_READ | SYNCHRONIZE, &attr, &io,
+ FILE_SHARE_READ | FILE_SHARE_DELETE,
+ FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE )))
+ {
+--- a/dlls/ntdll/locale.c
++++ b/dlls/ntdll/locale.c
+@@ -659,7 +659,7 @@
+ return STATUS_NO_MEMORY;
+ valueW.Length = sprintfW( valueW.Buffer, pathfmtW, dir, name ) * sizeof(WCHAR);
+ InitializeObjectAttributes( &attr, &valueW, 0, 0, NULL );
+- status = NtOpenFile( file, GENERIC_READ, &attr, &io, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_ALERT );
++ status = __syscall_NtOpenFile( file, GENERIC_READ, &attr, &io, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_ALERT );
+ if (!status) TRACE( "found %s\n", debugstr_w( valueW.Buffer ));
+ RtlFreeUnicodeString( &valueW );
+ if (status != STATUS_OBJECT_NAME_NOT_FOUND) return status;
+@@ -683,7 +683,7 @@
+ strcatW( valueW.Buffer, name );
+ valueW.Length = strlenW(valueW.Buffer) * sizeof(WCHAR);
+ InitializeObjectAttributes( &attr, &valueW, 0, 0, NULL );
+- status = NtOpenFile( file, GENERIC_READ, &attr, &io, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_ALERT );
++ status = __syscall_NtOpenFile( file, GENERIC_READ, &attr, &io, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_ALERT );
+ if (!status) TRACE( "found %s\n", debugstr_w( valueW.Buffer ));
+ }
+ RtlFreeUnicodeString( &valueW );
+--- a/dlls/ntdll/ntdll_misc.h
++++ b/dlls/ntdll/ntdll_misc.h
+@@ -323,4 +323,12 @@
+ while (len--) *dst++ = (unsigned char)*src++;
+ }
+
++#if defined(__i386__) || defined(__x86_64__)
++NTSTATUS WINAPI __syscall_NtOpenFile( PHANDLE handle, ACCESS_MASK access,
++ POBJECT_ATTRIBUTES attr, PIO_STATUS_BLOCK io,
++ ULONG sharing, ULONG options );
++#else
++#define __syscall_NtOpenFile NtOpenFile
++#endif
++
+ #endif
+--- a/dlls/ntdll/path.c
++++ b/dlls/ntdll/path.c
+@@ -1021,7 +1021,7 @@
+ attr.SecurityDescriptor = NULL;
+ attr.SecurityQualityOfService = NULL;
+
+- nts = NtOpenFile( &handle, FILE_TRAVERSE | SYNCHRONIZE, &attr, &io, FILE_SHARE_READ | FILE_SHARE_WRITE,
++ nts = __syscall_NtOpenFile( &handle, FILE_TRAVERSE | SYNCHRONIZE, &attr, &io, FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT );
+ if (nts != STATUS_SUCCESS) goto out;
+
+--- a/dlls/ntdll/process.c
++++ b/dlls/ntdll/process.c
+@@ -1396,7 +1396,7 @@
+
+ memset( info, 0, sizeof(*info) );
+ InitializeObjectAttributes( &attr, path, attributes, 0, 0 );
+- if ((status = NtOpenFile( handle, GENERIC_READ, &attr, &io,
++ if ((status = __syscall_NtOpenFile( handle, GENERIC_READ, &attr, &io,
+ FILE_SHARE_READ | FILE_SHARE_DELETE, FILE_SYNCHRONOUS_IO_NONALERT )))
+ {
+ BOOL is_64bit;
diff -Nru wine-development-5.5/debian/patches/winebuild-Fake_Dlls/definition wine-development-5.5/debian/patches/winebuild-Fake_Dlls/definition
--- wine-development-5.5/debian/patches/winebuild-Fake_Dlls/definition 1970-01-01 01:00:00.000000000 +0100
+++ wine-development-5.5/debian/patches/winebuild-Fake_Dlls/definition 2020-05-04 01:33:29.000000000 +0100
@@ -0,0 +1,6 @@
+Fixes: [21232] Chromium-based browser engines (Chrome, Opera, Comodo Dragon, SRWare Iron) crash on startup unless '--no-sandbox' is used (native API sandboxing/hooking scheme incompatible with Wine)
+Fixes: [42741] StarCraft I: 1.18 PTR fails to initialize ClientSdk.dll
+Fixes: [45349] Multiple applications and games crash due to missing support for 64-bit syscall thunks (StreetFighter V)
+Fixes: [45573] League of Legends 8.12+ fails to start a game (anticheat engine, hooking of syscall return instructions)
+Fixes: [45650] chromium 32-bit sandbox expects different syscall thunks depending on Windows version
+Depends: ntdll-User_Shared_Data
diff -Nru wine-development-5.5/debian/rules wine-development-5.5/debian/rules
--- wine-development-5.5/debian/rules 2020-04-02 23:32:21.000000000 +0100
+++ wine-development-5.5/debian/rules 2020-05-04 01:33:29.000000000 +0100
@@ -44,6 +44,10 @@
# ignore all defined but unused function warnings
export DEB_CFLAGS_MAINT_APPEND+=-Wno-unused-function
+# ignore, patches for upstream #46586 need this
+export DEB_CFLAGS_MAINT_APPEND+=-Wno-unused-variable
+export DEB_CFLAGS_MAINT_APPEND+=-Wno-int-conversion
+
# ignore warning about deprecated CUPS API for now
export DEB_CFLAGS_MAINT_APPEND+=-Wno-deprecated-declarations
Reply to: