[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

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( &params->ImagePathName, winevdm );
+     RtlInitUnicodeString( &params->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( &params->ImagePathName, comspec );
+     RtlInitUnicodeString( &params->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: