VirtualBox

Changeset 96599 in vbox


Ignore:
Timestamp:
Sep 5, 2022 2:05:21 AM (3 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
153476
Message:

IPRT/localipc-win.cpp: Eliminated need for ConvertStringSecurityDescriptorToSecurityDescriptorW, making the code work on NT4 and earlier too. bugref:10261

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/r3/win/localipc-win.cpp

    r96505 r96599  
    4343*********************************************************************************************************************************/
    4444#define LOG_GROUP RTLOGGROUP_LOCALIPC
    45 #ifdef _WIN32_WINNT
    46 # if _WIN32_WINNT < 0x0500
    47 #  undef _WIN32_WINNT
    48 #  define _WIN32_WINNT 0x0500       /* For ConvertStringSecurityDescriptorToSecurityDescriptor. */
    49 # endif
    50 #endif
    51 #define UNICODE                     /* For the SDDL_ strings. */
    52 #include <iprt/nt/nt-and-windows.h> /* Need NtCancelIoFile */
     45#include <iprt/nt/nt-and-windows.h> /* Need NtCancelIoFile and a few Rtl functions. */
    5346#include <sddl.h>
     47#include <aclapi.h>
    5448
    5549#include "internal/iprt.h"
     
    8074/** Pipe prefix string. */
    8175#define RTLOCALIPC_WIN_PREFIX   L"\\\\.\\pipe\\IPRT-"
    82 
    83 /** DACL for block all network access and local users other than the creator/owner.
    84  *
    85  * ACE format: (ace_type;ace_flags;rights;object_guid;inherit_object_guid;account_sid)
    86  *
    87  * Note! FILE_GENERIC_WRITE (SDDL_FILE_WRITE) is evil here because it includes
    88  *       the FILE_CREATE_PIPE_INSTANCE(=FILE_APPEND_DATA) flag. Thus the hardcoded
    89  *       value 0x0012019b in the client ACE. The server-side still needs
    90  *       setting FILE_CREATE_PIPE_INSTANCE although.
    91  *       It expands to:
    92  *          0x00000001 - FILE_READ_DATA
    93  *          0x00000008 - FILE_READ_EA
    94  *          0x00000080 - FILE_READ_ATTRIBUTES
    95  *          0x00020000 - READ_CONTROL
    96  *          0x00100000 - SYNCHRONIZE
    97  *          0x00000002 - FILE_WRITE_DATA
    98  *          0x00000010 - FILE_WRITE_EA
    99  *          0x00000100 - FILE_WRITE_ATTRIBUTES
    100  *       =  0x0012019b (client)
    101  *       + (only for server):
    102  *          0x00000004 - FILE_CREATE_PIPE_INSTANCE
    103  *       =  0x0012019f
    104  *
    105  * @todo Triple check this!
    106  * @todo EVERYONE -> AUTHENTICATED USERS or something more appropriate?
    107  * @todo Have trouble allowing the owner FILE_CREATE_PIPE_INSTANCE access, so for now I'm hacking
    108  *       it just to get progress - the service runs as local system.
    109  *       The CREATOR OWNER and PERSONAL SELF works (the former is only involved in inheriting
    110  *       it seems, which is why it won't work. The latter I've no idea about. Perhaps the solution
    111  *       is to go the annoying route of OpenProcessToken, QueryTokenInformation,
    112  *          ConvertSidToStringSid and then use the result... Suggestions are very welcome
    113  */
    114 #define RTLOCALIPC_WIN_SDDL_BASE \
    115         SDDL_DACL SDDL_DELIMINATOR \
    116         SDDL_ACE_BEGIN SDDL_ACCESS_DENIED L";;" SDDL_GENERIC_ALL L";;;" SDDL_NETWORK SDDL_ACE_END \
    117         SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED L";;" SDDL_FILE_ALL   L";;;" SDDL_LOCAL_SYSTEM SDDL_ACE_END
    118 
    119 #define RTLOCALIPC_WIN_SDDL_SERVER \
    120         RTLOCALIPC_WIN_SDDL_BASE \
    121         SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED L";;" L"0x0012019f"   L";;;" SDDL_EVERYONE SDDL_ACE_END
    122 
    123 #define RTLOCALIPC_WIN_SDDL_CLIENT \
    124         RTLOCALIPC_WIN_SDDL_BASE \
    125         SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED L";;" L"0x0012019b"   L";;;" SDDL_EVERYONE SDDL_ACE_END
    126 
    127 //        SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED L";;" SDDL_GENERIC_ALL L";;;" SDDL_PERSONAL_SELF SDDL_ACE_END \
    128 //        SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED L";CIOI;" SDDL_GENERIC_ALL L";;;" SDDL_CREATOR_OWNER SDDL_ACE_END
    129 //        SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED L";;" L"0x0012019b"    L";;;" SDDL_EVERYONE SDDL_ACE_END
    130 //        SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED L";;" SDDL_FILE_ALL L";;;" SDDL_LOCAL_SYSTEM SDDL_ACE_END
    13176
    13277
     
    220165
    221166
    222 /*********************************************************************************************************************************
    223 *   Global Variables                                                                                                             *
    224 *********************************************************************************************************************************/
    225 static bool volatile g_fResolvedApis = false;
    226 /** advapi32.dll API ConvertStringSecurityDescriptorToSecurityDescriptorW. */
    227 static decltype(ConvertStringSecurityDescriptorToSecurityDescriptorW) *g_pfnSSDLToSecDescW = NULL;
     167/**
     168 * DACL for block all network access and local users other than the creator/owner.
     169 *
     170 * ACE format: (ace_type;ace_flags;rights;object_guid;inherit_object_guid;account_sid)
     171 *
     172 * Note! FILE_GENERIC_WRITE (SDDL_FILE_WRITE) is evil here because it includes
     173 *       the FILE_CREATE_PIPE_INSTANCE(=FILE_APPEND_DATA) flag. Thus the hardcoded
     174 *       value 0x0012019b in the client ACE. The server-side still needs
     175 *       setting FILE_CREATE_PIPE_INSTANCE although.
     176 *       It expands to:
     177 *          0x00000001 - FILE_READ_DATA
     178 *          0x00000008 - FILE_READ_EA
     179 *          0x00000080 - FILE_READ_ATTRIBUTES
     180 *          0x00020000 - READ_CONTROL
     181 *          0x00100000 - SYNCHRONIZE
     182 *          0x00000002 - FILE_WRITE_DATA
     183 *          0x00000010 - FILE_WRITE_EA
     184 *          0x00000100 - FILE_WRITE_ATTRIBUTES
     185 *       =  0x0012019b (client)
     186 *       + (only for server):
     187 *          0x00000004 - FILE_CREATE_PIPE_INSTANCE
     188 *       =  0x0012019f
     189 *
     190 * @todo Triple check this!
     191 * @todo EVERYONE -> AUTHENTICATED USERS or something more appropriate?
     192 * @todo Have trouble allowing the owner FILE_CREATE_PIPE_INSTANCE access, so for now I'm hacking
     193 *       it just to get progress - the service runs as local system.
     194 *       The CREATOR OWNER and PERSONAL SELF works (the former is only involved in inheriting
     195 *       it seems, which is why it won't work. The latter I've no idea about. Perhaps the solution
     196 *       is to go the annoying route of OpenProcessToken, QueryTokenInformation,
     197 *          ConvertSidToStringSid and then use the result... Suggestions are very welcome
     198 */
     199#define RTLOCALIPC_WIN_SDDL_BASE \
     200        SDDL_DACL SDDL_DELIMINATOR \
     201        SDDL_ACE_BEGIN SDDL_ACCESS_DENIED L";;" SDDL_GENERIC_ALL L";;;" SDDL_NETWORK SDDL_ACE_END \
     202        SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED L";;" SDDL_FILE_ALL   L";;;" SDDL_LOCAL_SYSTEM SDDL_ACE_END
     203#define RTLOCALIPC_WIN_SDDL_SERVER \
     204        RTLOCALIPC_WIN_SDDL_BASE \
     205        SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED L";;" L"0x0012019f"   L";;;" SDDL_EVERYONE SDDL_ACE_END
     206#define RTLOCALIPC_WIN_SDDL_CLIENT \
     207        RTLOCALIPC_WIN_SDDL_BASE \
     208        SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED L";;" L"0x0012019b"   L";;;" SDDL_EVERYONE SDDL_ACE_END
     209static NTSTATUS rtLocalIpcBuildDacl(PACL pDacl, bool fServer)
     210{
     211    static SID_IDENTIFIER_AUTHORITY s_NtAuth    = SECURITY_NT_AUTHORITY;
     212    static SID_IDENTIFIER_AUTHORITY s_WorldAuth = SECURITY_WORLD_SID_AUTHORITY;
     213    union
     214    {
     215        SID     Sid;
     216        uint8_t abPadding[SECURITY_MAX_SID_SIZE];
     217    } Network, LocalSystem, Everyone;
     218
     219
     220    /* 1. SDDL_ACCESS_DENIED L";;" SDDL_GENERIC_ALL L";;;" SDDL_NETWORK */
     221    NTSTATUS rcNt = RtlInitializeSid(&Network.Sid, &s_NtAuth, 1);
     222    AssertReturn(NT_SUCCESS(rcNt), rcNt);
     223    *RtlSubAuthoritySid(&Network.Sid, 0) = SECURITY_NETWORK_RID;
     224
     225    rcNt = RtlAddAccessDeniedAce(pDacl, ACL_REVISION, GENERIC_ALL, &Network.Sid);
     226    AssertReturn(NT_SUCCESS(rcNt), rcNt);
     227
     228    /* 2. SDDL_ACCESS_ALLOWED L";;" SDDL_FILE_ALL   L";;;" SDDL_LOCAL_SYSTEM */
     229    rcNt = RtlInitializeSid(&LocalSystem.Sid, &s_NtAuth, 1);
     230    AssertReturn(NT_SUCCESS(rcNt), rcNt);
     231    *RtlSubAuthoritySid(&LocalSystem.Sid, 0) = SECURITY_LOCAL_SYSTEM_RID;
     232
     233    rcNt = RtlAddAccessAllowedAce(pDacl, ACL_REVISION, FILE_ALL_ACCESS, &Network.Sid);
     234    AssertReturn(NT_SUCCESS(rcNt), rcNt);
     235
     236
     237    /* 3. server: SDDL_ACCESS_ALLOWED L";;" L"0x0012019f"   L";;;" SDDL_EVERYONE
     238          client: SDDL_ACCESS_ALLOWED L";;" L"0x0012019b"   L";;;" SDDL_EVERYONE */
     239    rcNt = RtlInitializeSid(&Everyone.Sid, &s_NtAuth, 1);
     240    AssertReturn(NT_SUCCESS(rcNt), rcNt);
     241    *RtlSubAuthoritySid(&Everyone.Sid, 0) = SECURITY_WORLD_RID;
     242
     243    DWORD const fAccess = FILE_READ_DATA                       /* 0x00000001 */
     244                        | FILE_WRITE_DATA                      /* 0x00000002 */
     245                        | FILE_CREATE_PIPE_INSTANCE * fServer  /* 0x00000004 */
     246                        | FILE_READ_EA                         /* 0x00000008 */
     247                        | FILE_WRITE_EA                        /* 0x00000010 */
     248                        | FILE_READ_ATTRIBUTES                 /* 0x00000080 */
     249                        | FILE_WRITE_ATTRIBUTES                /* 0x00000100 */
     250                        | READ_CONTROL                         /* 0x00020000 */
     251                        | SYNCHRONIZE;                         /* 0x00100000*/
     252    Assert(fAccess == (fServer ? 0x0012019fU : 0x0012019bU));
     253
     254    rcNt = RtlAddAccessAllowedAce(pDacl, ACL_REVISION, fAccess, &Network.Sid);
     255    AssertReturn(NT_SUCCESS(rcNt), rcNt);
     256
     257    return true;
     258}
    228259
    229260
     
    238269static int rtLocalIpcServerWinAllocSecurityDescriptor(PSECURITY_DESCRIPTOR *ppDesc, bool fServer)
    239270{
     271    int rc;
     272    PSECURITY_DESCRIPTOR pSecDesc = NULL;
     273
     274#if 0
    240275    /*
    241276     * Resolve the API the first time around.
    242277     */
    243     if (!g_fResolvedApis)
    244     {
    245         g_pfnSSDLToSecDescW = (decltype(g_pfnSSDLToSecDescW))RTLdrGetSystemSymbol("advapi32.dll", "ConvertStringSecurityDescriptorToSecurityDescriptorW");
     278    static bool volatile s_fResolvedApis = false;
     279    /** advapi32.dll API ConvertStringSecurityDescriptorToSecurityDescriptorW. */
     280    static decltype(ConvertStringSecurityDescriptorToSecurityDescriptorW) *s_pfnSSDLToSecDescW = NULL;
     281
     282    if (!s_fResolvedApis)
     283    {
     284        s_pfnSSDLToSecDescW
     285            = (decltype(s_pfnSSDLToSecDescW))RTLdrGetSystemSymbol("advapi32.dll",
     286                                                                  "ConvertStringSecurityDescriptorToSecurityDescriptorW");
    246287        ASMCompilerBarrier();
    247         g_fResolvedApis = true;
    248     }
    249 
    250     int rc;
    251     PSECURITY_DESCRIPTOR pSecDesc = NULL;
    252     if (g_pfnSSDLToSecDescW)
     288        s_fResolvedApis = true;
     289    }
     290    if (s_pfnSSDLToSecDescW)
    253291    {
    254292        /*
     
    258296         * users from screwing around.
    259297         */
    260         PCRTUTF16 pwszSDDL = fServer ? RTLOCALIPC_WIN_SDDL_SERVER : RTLOCALIPC_WIN_SDDL_CLIENT;
    261         if (g_pfnSSDLToSecDescW(pwszSDDL, SDDL_REVISION_1, &pSecDesc, NULL))
    262         {
     298        PCRTUTF16 pwszSDDL  = fServer ? RTLOCALIPC_WIN_SDDL_SERVER : RTLOCALIPC_WIN_SDDL_CLIENT;
     299        ULONG     cbSecDesc = 0;
     300        SetLastError(0);
     301        if (s_pfnSSDLToSecDescW(pwszSDDL, SDDL_REVISION_1, &pSecDesc, &cbSecDesc))
     302        {
     303            DWORD dwErr = GetLastError(); RT_NOREF(dwErr);
    263304            AssertPtr(pSecDesc);
    264305            *ppDesc = pSecDesc;
     
    269310    }
    270311    else
    271     {
    272         /* Windows OSes < W2K SP2 not supported for now, bail out. */
    273         /** @todo Implement me! */
    274         rc = VERR_NOT_SUPPORTED;
     312#endif
     313    {
     314        /*
     315         * Manually construct the descriptor.
     316         *
     317         * This is a bit crude. The 8KB is probably 50+ times more than what we need.
     318         */
     319        uint32_t const cbAlloc = SECURITY_DESCRIPTOR_MIN_LENGTH * 2 + _8K;
     320        pSecDesc = LocalAlloc(LMEM_FIXED, cbAlloc);
     321        if (!pSecDesc)
     322            return VERR_NO_MEMORY;
     323        RT_BZERO(pSecDesc, cbAlloc);
     324
     325        uint32_t const cbDacl = cbAlloc - SECURITY_DESCRIPTOR_MIN_LENGTH * 2;
     326        PACL const     pDacl  = (PACL)((uint8_t *)pSecDesc + SECURITY_DESCRIPTOR_MIN_LENGTH * 2);
     327
     328        if (   InitializeSecurityDescriptor(pSecDesc, SECURITY_DESCRIPTOR_REVISION)
     329            && InitializeAcl(pDacl, cbDacl, ACL_REVISION))
     330        {
     331            if (rtLocalIpcBuildDacl(pDacl, fServer))
     332            {
     333                *ppDesc = pSecDesc;
     334                return VINF_SUCCESS;
     335            }
     336            rc = VERR_GENERAL_FAILURE;
     337        }
     338        else
     339            rc = RTErrConvertFromWin32(GetLastError());
     340        LocalFree(pSecDesc);
    275341    }
    276342    return rc;
     
    295361    *phNmPipe = INVALID_HANDLE_VALUE;
    296362
     363    /*
     364     * Create a security descriptor blocking access to the pipe via network.
     365     */
    297366    PSECURITY_DESCRIPTOR pSecDesc;
    298367    int rc = rtLocalIpcServerWinAllocSecurityDescriptor(&pSecDesc, fFirst /* Server? */);
    299368    if (RT_SUCCESS(rc))
    300369    {
     370#if 0
     371        { /* Just for checking the security descriptor out in the debugger (!sd <addr> doesn't work): */
     372            DWORD dwRet = LookupSecurityDescriptorPartsW(NULL, NULL, NULL, NULL, NULL, NULL, pSecDesc);
     373            __debugbreak(); RT_NOREF(dwRet);
     374
     375            PTRUSTEE_W          pOwner = NULL;
     376            PTRUSTEE_W          pGroup = NULL;
     377            ULONG               cAces  = 0;
     378            PEXPLICIT_ACCESS_W  paAces = NULL;
     379            ULONG               cAuditEntries = 0;
     380            PEXPLICIT_ACCESS_W  paAuditEntries = NULL;
     381            dwRet = LookupSecurityDescriptorPartsW(&pOwner, NULL, NULL, NULL, NULL, NULL, pSecDesc);
     382            dwRet = LookupSecurityDescriptorPartsW(NULL, &pGroup, NULL, NULL, NULL, NULL, pSecDesc);
     383            dwRet = LookupSecurityDescriptorPartsW(NULL, NULL, &cAces, &paAces, NULL, NULL, pSecDesc);
     384            dwRet = LookupSecurityDescriptorPartsW(NULL, NULL, NULL, NULL, &cAuditEntries, &paAuditEntries, pSecDesc);
     385            __debugbreak(); RT_NOREF(dwRet);
     386        }
     387#endif
     388
     389        /*
     390         * Now, create the pipe.
     391         */
    301392        SECURITY_ATTRIBUTES SecAttrs;
    302393        SecAttrs.nLength              = sizeof(SECURITY_ATTRIBUTES);
     
    321412                                          30*1000,                       /* nDefaultTimeOut = 30 sec */
    322413                                          &SecAttrs);                    /* lpSecurityAttributes */
    323         LocalFree(pSecDesc);
    324414        if (hNmPipe != INVALID_HANDLE_VALUE)
     415        {
     416#if 0 /* For checking access control stuff in windbg (doesn't work): */
     417            PSECURITY_DESCRIPTOR pSecDesc2 = NULL;
     418            PACL pDacl = NULL;
     419            DWORD dwRet;
     420            dwRet = GetSecurityInfo(hNmPipe, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, &pDacl, NULL, &pSecDesc2);
     421            PACL pSacl = NULL;
     422            dwRet = GetSecurityInfo(hNmPipe, SE_FILE_OBJECT, SACL_SECURITY_INFORMATION, NULL, NULL, NULL, &pSacl, &pSecDesc2);
     423            dwRet = GetSecurityInfo(hNmPipe, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION, NULL, NULL, &pDacl, &pSacl, &pSecDesc2);
     424            PSID pSidOwner = NULL;
     425            dwRet = GetSecurityInfo(hNmPipe, SE_FILE_OBJECT, OWNER_SECURITY_INFORMATION, &pSidOwner, NULL, NULL, NULL, &pSecDesc2);
     426            PSID pSidGroup = NULL;
     427            dwRet = GetSecurityInfo(hNmPipe, SE_FILE_OBJECT, OWNER_SECURITY_INFORMATION, NULL, &pSidGroup, NULL, NULL, &pSecDesc2);
     428            __debugbreak();
     429            RT_NOREF(dwRet);
     430#endif
    325431            *phNmPipe = hNmPipe;
     432            rc = VINF_SUCCESS;
     433        }
    326434        else
    327435            rc = RTErrConvertFromWin32(GetLastError());
    328     }
    329 
     436        LocalFree(pSecDesc);
     437    }
    330438    return rc;
    331439}
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette