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

Bug#959707: marked as done (wine-development: please consider wine-staging patches, needed for e.g. Blizzard games)



Your message dated Sun, 30 May 2021 21:41:57 -0400
with message-id <CANTw=MME5fBdD+kc95Z9E_zLCp6aLO=3DLZb2X1RDMGK2HJD7Q@mail.gmail.com>
and subject line Re: Bug#959707: wine-development: please consider wine-staging patches, needed for e.g. Blizzard games
has caused the Debian Bug report #959707,
regarding wine-development: please consider wine-staging patches, needed for e.g. Blizzard games
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact owner@bugs.debian.org
immediately.)


-- 
959707: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=959707
Debian Bug Tracking System
Contact owner@bugs.debian.org with problems
--- Begin Message ---
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
 

--- End Message ---
--- Begin Message ---
version: 5.9-1

On Mon, May 4, 2020 at 5:54 AM Ximin Luo wrote:
> 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

Fixed upstream in version 5.9.

Best wishes,
Mike

--- End Message ---

Reply to: