summaryrefslogtreecommitdiff
path: root/src/ipcman/ipcsharedsrc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/ipcman/ipcsharedsrc.cpp')
-rw-r--r--src/ipcman/ipcsharedsrc.cpp965
1 files changed, 965 insertions, 0 deletions
diff --git a/src/ipcman/ipcsharedsrc.cpp b/src/ipcman/ipcsharedsrc.cpp
new file mode 100644
index 0000000000..ed1e7dc1ba
--- /dev/null
+++ b/src/ipcman/ipcsharedsrc.cpp
@@ -0,0 +1,965 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+// ==++==
+//
+
+//
+// ==--==
+//*****************************************************************************
+// File: IPCSharedSrc.cpp
+//
+// Shared source for COM+ IPC Reader & Writer classes
+//
+//*****************************************************************************
+
+#include "stdafx.h"
+#include "ipcshared.h"
+#include "ipcmanagerinterface.h"
+
+#ifndef FEATURE_CORECLR
+#include "AppXUtil.h"
+#endif
+
+#if defined(FEATURE_IPCMAN)
+
+//-----------------------------------------------------------------------------
+// Close a handle and pointer to any memory mapped file
+//-----------------------------------------------------------------------------
+void IPCShared::CloseMemoryMappedFile(HANDLE & hMemFile, void * & pBlock)
+{
+ WRAPPER_NO_CONTRACT;
+
+ LOG((LF_CORDB, LL_INFO10, "IPCS::CloseMemoryMappedFile: closing 0x%08x\n", hMemFile));
+
+ if (pBlock != NULL) {
+ if (!UnmapViewOfFile(pBlock))
+ _ASSERTE(!"UnmapViewOfFile failed");
+ pBlock = NULL;
+ }
+
+ if (hMemFile != NULL) {
+ CloseHandle(hMemFile);
+ hMemFile = NULL;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Based on the pid, write a unique name for a memory mapped file
+//-----------------------------------------------------------------------------
+void IPCShared::GenerateName(DWORD pid, SString & sName)
+{
+ WRAPPER_NO_CONTRACT;
+
+ const WCHAR * szFormat = CorLegacyPrivateIPCBlock;
+ szFormat = L"Global\\" CorLegacyPrivateIPCBlock;
+
+ sName.Printf(szFormat, pid);
+}
+
+//-----------------------------------------------------------------------------
+// Based on the pid, write a unique name for a memory mapped file
+//-----------------------------------------------------------------------------
+void IPCShared::GenerateNameLegacyTempV4(DWORD pid, SString & sName)
+{
+ WRAPPER_NO_CONTRACT;
+
+ const WCHAR * szFormat = CorLegacyPrivateIPCBlockTempV4;
+ szFormat = L"Global\\" CorLegacyPrivateIPCBlockTempV4;
+
+ sName.Printf(szFormat, pid);
+}
+
+//-----------------------------------------------------------------------------
+// Based on the pid, write a unique name for a memory mapped file
+//-----------------------------------------------------------------------------
+void IPCShared::GenerateLegacyPublicName(DWORD pid, SString & sName)
+{
+ WRAPPER_NO_CONTRACT;
+
+ const WCHAR * szFormat = CorLegacyPublicIPCBlock;
+ szFormat = L"Global\\" CorLegacyPublicIPCBlock;
+
+ sName.Printf(szFormat, pid);
+}
+
+#ifndef DACCESS_COMPILE
+
+//-----------------------------------------------------------------------------
+// Based on the pid, write a unique name for the IPCBlockTable on Vista and Higher
+//-----------------------------------------------------------------------------
+HRESULT IPCShared::GenerateBlockTableName(DWORD pid, SString & sName, HANDLE & pBoundaryDesc, HANDLE & pPrivateNamespace, PSID* pSID, BOOL bCreate)
+{
+ WRAPPER_NO_CONTRACT;
+ HRESULT hr = E_FAIL;
+
+#define SIZE 100
+ const WCHAR * szFormat = CorSxSPublicIPCBlock;
+ static HMODULE hKernel32 = NULL;
+ if(hKernel32 == NULL)
+ hKernel32 = WszGetModuleHandle(L"kernel32.dll");
+ if(hKernel32 == NULL)
+ {
+ hr = HRESULT_FROM_GetLastError();
+ return hr;
+ }
+ //We are using static function pointers so that we dont call GetProcAddress every time
+ //We know that the Writer will call this function only once and the reader (perfmon) is a single
+ //threaded App. Therefore its safe to assign static local variables in this case.
+ typedef WINBASEAPI BOOL (WINAPI ADD_SID_TO_BOUNDARY_DESCRIPTOR)(HANDLE*, PSID);
+ static ADD_SID_TO_BOUNDARY_DESCRIPTOR * pAddSIDToBoundaryDescriptor = NULL;
+
+ typedef WINBASEAPI HANDLE (WINAPI CREATE_BOUNDARY_DESCRIPTOR)(LPCWSTR,ULONG);
+ static CREATE_BOUNDARY_DESCRIPTOR * pCreateBoundaryDescriptor = NULL;
+
+ typedef WINBASEAPI HANDLE (WINAPI CREATE_PRIVATE_NAMESPACE )(LPSECURITY_ATTRIBUTES, LPVOID, LPCWSTR);
+ static CREATE_PRIVATE_NAMESPACE * pCreatePrivateNamespace = NULL;
+
+ typedef WINBASEAPI HANDLE (WINAPI OPEN_PRIVATE_NAMESPACE)(LPVOID,LPCWSTR);
+ static OPEN_PRIVATE_NAMESPACE * pOpenPrivateNamespace = NULL;
+
+ if(pAddSIDToBoundaryDescriptor == NULL)
+ pAddSIDToBoundaryDescriptor = (ADD_SID_TO_BOUNDARY_DESCRIPTOR *)GetProcAddress(hKernel32, "AddSIDToBoundaryDescriptor");
+ if(pCreateBoundaryDescriptor == NULL)
+ pCreateBoundaryDescriptor = (CREATE_BOUNDARY_DESCRIPTOR *)GetProcAddress(hKernel32, "CreateBoundaryDescriptorW");
+ if(pCreatePrivateNamespace == NULL)
+ pCreatePrivateNamespace = (CREATE_PRIVATE_NAMESPACE *)GetProcAddress(hKernel32, "CreatePrivateNamespaceW");
+ if(pOpenPrivateNamespace==NULL)
+ pOpenPrivateNamespace = (OPEN_PRIVATE_NAMESPACE *)GetProcAddress(hKernel32, "OpenPrivateNamespaceW");
+ _ASSERTE((pAddSIDToBoundaryDescriptor != NULL) &&
+ (pCreateBoundaryDescriptor != NULL) &&
+ (pCreatePrivateNamespace != NULL) &&
+ (pOpenPrivateNamespace != NULL));
+
+ if ((pAddSIDToBoundaryDescriptor == NULL) ||
+ (pCreateBoundaryDescriptor == NULL) ||
+ (pCreatePrivateNamespace == NULL) ||
+ (pOpenPrivateNamespace == NULL))
+ {
+ return ERROR_PROC_NOT_FOUND;
+ }
+
+ WCHAR wsz[SIZE];
+ swprintf_s(wsz,SIZE, CorSxSBoundaryDescriptor, pid);
+
+ ULONG flags = 0;
+ if (RunningOnWin8())
+ {
+ // on win8 we specify this flag regardless if the process is inside an appcontainer, the kernel will do the right thing.
+ // note that for appcontainers this flag is necessary regardless of producer or consumer, ie you can't create a boundary
+ // descriptor in an appcontainer process without adding the appcontainer SID (the API call will fail).
+ flags |= CREATE_BOUNDARY_DESCRIPTOR_ADD_APPCONTAINER_SID;
+ }
+
+ pBoundaryDesc = (*pCreateBoundaryDescriptor)((LPCWSTR)&wsz, flags);
+ if(!pBoundaryDesc)
+ {
+ hr = HRESULT_FROM_GetLastError();
+ return hr;
+ }
+ SID_IDENTIFIER_AUTHORITY SIDWorldAuth = SECURITY_WORLD_SID_AUTHORITY;
+ if(!AllocateAndInitializeSid( &SIDWorldAuth, 1,SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, pSID))
+ {
+ hr = HRESULT_FROM_GetLastError();
+ return hr;
+ }
+ if(!(*pAddSIDToBoundaryDescriptor) (&pBoundaryDesc,*pSID))
+ {
+ hr = HRESULT_FROM_GetLastError();
+ return hr;
+ }
+
+#ifndef FEATURE_CORECLR
+ // when pid != GetCurrentProcessId() it means we're the consumer opening other process perf counter data
+ if (pid != GetCurrentProcessId())
+ {
+ // if the target process is inside an appcontainer we need to add the appcontainer SID to the boundary descriptor.
+ NewArrayHolder<BYTE> pbTokenMem;
+ hr = AppX::GetAppContainerTokenInfoForProcess(pid, pbTokenMem);
+
+ if (FAILED(hr))
+ {
+ // failed to open the target's process, continue on
+ // assuming that the process isn't in an AppContainer.
+ _ASSERTE(pbTokenMem == NULL);
+ }
+ else
+ {
+ if (hr == S_FALSE)
+ {
+ // not an appcontainer
+ _ASSERTE(pbTokenMem == NULL);
+ }
+ else
+ {
+ // process is an appcontainer so add the SID
+ PTOKEN_APPCONTAINER_INFORMATION pAppContainerTokenInfo =
+ reinterpret_cast<PTOKEN_APPCONTAINER_INFORMATION>(pbTokenMem.GetValue());
+ _ASSERTE(pAppContainerTokenInfo);
+ _ASSERTE(pAppContainerTokenInfo->TokenAppContainer);
+
+ if (!(*pAddSIDToBoundaryDescriptor)(&pBoundaryDesc, pAppContainerTokenInfo->TokenAppContainer))
+ return HRESULT_FROM_WIN32(GetLastError());
+ }
+ }
+ }
+#endif // FEATURE_CORECLR
+
+ if(bCreate)
+ {
+ SECURITY_ATTRIBUTES *pSA = NULL;
+ IPCShared::CreateWinNTDescriptor(pid, FALSE, &pSA, PrivateNamespace, eDescriptor_Public);
+ pPrivateNamespace = (*pCreatePrivateNamespace)(pSA, (VOID *)(pBoundaryDesc),
+ (LPCWSTR)CorSxSWriterPrivateNamespacePrefix);
+ if(!pPrivateNamespace)
+ {
+ hr = HRESULT_FROM_GetLastError();
+ }
+ IPCShared::DestroySecurityAttributes(pSA);
+
+ if(!pPrivateNamespace)
+ {
+ //if already created by a different version of the runtime we return OK.
+ if(hr ==HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS))
+ {
+ hr = S_OK;
+ }
+ else
+ {
+ return hr;
+ }
+ }
+ }
+ else
+ {
+ pPrivateNamespace = (*pOpenPrivateNamespace)((VOID *)(pBoundaryDesc), (LPCWSTR)CorSxSReaderPrivateNamespacePrefix);
+ if(!pPrivateNamespace)
+ {
+ hr = HRESULT_FROM_GetLastError();
+ return hr;
+ }
+ }
+ szFormat = (bCreate ? CorSxSWriterPrivateNamespacePrefix L"\\" CorSxSVistaPublicIPCBlock : CorSxSReaderPrivateNamespacePrefix L"\\" CorSxSVistaPublicIPCBlock);
+ sName.Printf(szFormat);
+ hr=S_OK;
+
+ return hr;
+}
+
+#endif
+
+//-----------------------------------------------------------------------------
+// Free's the handle to a boundary descriptor and a SID
+//-----------------------------------------------------------------------------
+HRESULT IPCShared::FreeHandles(HANDLE & hBoundaryDescriptor, PSID & pSID)
+{
+ WRAPPER_NO_CONTRACT;
+ HRESULT hr = S_OK;
+ if(hBoundaryDescriptor != NULL)
+ {
+ static HMODULE hKernel32 = NULL;
+ if(hKernel32 == NULL)
+ hKernel32 = WszGetModuleHandle(L"kernel32.dll");
+ if(hKernel32 == NULL)
+ {
+ hr = HRESULT_FROM_GetLastError();
+ return hr;
+ }
+ typedef WINBASEAPI VOID (WINAPI DELETE_BOUNDARY_DESCRIPTOR)(HANDLE);
+ static DELETE_BOUNDARY_DESCRIPTOR * pDeleteBoundaryDescriptor = NULL;
+ if(pDeleteBoundaryDescriptor == NULL)
+ pDeleteBoundaryDescriptor = (DELETE_BOUNDARY_DESCRIPTOR *)GetProcAddress(hKernel32, "DeleteBoundaryDescriptor");
+ _ASSERTE(pDeleteBoundaryDescriptor != NULL);
+ if (pDeleteBoundaryDescriptor == NULL)
+ {
+ hr = ERROR_PROC_NOT_FOUND;
+ }
+ else
+ {
+ (*pDeleteBoundaryDescriptor)(hBoundaryDescriptor);
+ hBoundaryDescriptor = NULL;
+
+ }
+ }
+ if(pSID != NULL)
+ {
+ FreeSid(pSID);
+ pSID = NULL;
+ }
+
+ return hr;
+}
+
+//--------------------------------------------------------------------------------------
+// Free's the handle to a boundary descriptor, a SID and a handle to a privatenamespace
+//--------------------------------------------------------------------------------------
+HRESULT IPCShared::FreeHandles(HANDLE & hBoundaryDescriptor, PSID & pSID, HANDLE & hPrivateNamespace)
+{
+ WRAPPER_NO_CONTRACT;
+ HRESULT hr = S_OK;
+
+ hr = IPCShared::FreeHandles(hBoundaryDescriptor,pSID);
+ if(!SUCCEEDED(hr))
+ return hr;
+ if(hPrivateNamespace != NULL)
+ {
+ static HMODULE hKernel32 = NULL;
+ if(hKernel32 == NULL)
+ hKernel32 = WszGetModuleHandle(L"kernel32.dll");
+ if(hKernel32 == NULL)
+ {
+ hr = HRESULT_FROM_GetLastError();
+ return hr;
+ }
+ typedef WINBASEAPI BOOL (WINAPI CLOSE_PRIVATE_NAMESPACE)(HANDLE, ULONG);
+ static CLOSE_PRIVATE_NAMESPACE * pClosePrivateNamespace;
+ if(pClosePrivateNamespace == NULL)
+ pClosePrivateNamespace = (CLOSE_PRIVATE_NAMESPACE *)GetProcAddress(hKernel32, "ClosePrivateNamespace");
+ _ASSERTE(pClosePrivateNamespace != NULL);
+ if (pClosePrivateNamespace == NULL)
+ {
+ hr = ERROR_PROC_NOT_FOUND;
+ }
+ else
+ {
+ BOOL isClosed = (*pClosePrivateNamespace)(hPrivateNamespace,0);
+ hPrivateNamespace = NULL;
+ if(!isClosed)
+ {
+ hr = HRESULT_FROM_GetLastError();
+ }
+
+ }
+ }
+
+ return hr;
+}
+
+HRESULT IPCShared::CreateWinNTDescriptor(DWORD pid, BOOL bRestrictiveACL, SECURITY_ATTRIBUTES **ppSA, KernelObject whatObject)
+{
+ WRAPPER_NO_CONTRACT;
+
+ return IPCShared::CreateWinNTDescriptor(pid, bRestrictiveACL, ppSA, whatObject, eDescriptor_Private);
+}
+
+//-----------------------------------------------------------------------------
+// Setup a security descriptor for the named kernel objects if we're on NT.
+//-----------------------------------------------------------------------------
+
+HRESULT IPCShared::CreateWinNTDescriptor(DWORD pid, BOOL bRestrictiveACL, SECURITY_ATTRIBUTES **ppSA, KernelObject whatObject, EDescriptorType descType)
+{
+ WRAPPER_NO_CONTRACT;
+
+ HRESULT hr = NO_ERROR;
+
+ // Gotta have a place to stick the new SA...
+ if (ppSA == NULL)
+ {
+ _ASSERTE(!"Caller must supply ppSA");
+ return E_INVALIDARG;
+ }
+
+ *ppSA = NULL;
+
+ ACL *pACL = NULL;
+ SECURITY_DESCRIPTOR *pSD = NULL;
+ SECURITY_ATTRIBUTES *pSA = NULL;
+
+ // Allocate a SD.
+ _ASSERTE (SECURITY_DESCRIPTOR_MIN_LENGTH == sizeof(SECURITY_DESCRIPTOR));
+ pSD = new (nothrow) SECURITY_DESCRIPTOR;
+
+ if (pSD == NULL)
+ {
+ hr = E_OUTOFMEMORY;
+ goto errExit;
+ }
+
+ // Do basic SD initialization
+ if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION))
+ {
+ hr = HRESULT_FROM_GetLastError();
+ goto errExit;
+ }
+
+ // Grab the ACL for the IPC block for the given process
+ if (!InitializeGenericIPCAcl(pid, bRestrictiveACL, &pACL, whatObject, descType))
+ {
+ hr = E_FAIL;
+ goto errExit;
+ }
+
+ // Add the ACL as the DACL for the SD.
+ if (!SetSecurityDescriptorDacl(pSD, TRUE, pACL, FALSE))
+ {
+ hr = HRESULT_FROM_GetLastError();
+ goto errExit;
+ }
+
+ // Allocate a SA.
+ pSA = new (nothrow) SECURITY_ATTRIBUTES;
+
+ if (pSA == NULL)
+ {
+ hr = E_OUTOFMEMORY;
+ goto errExit;
+ }
+
+ // Pass out the new SA.
+ *ppSA = pSA;
+
+ pSA->nLength = sizeof(SECURITY_ATTRIBUTES);
+ pSA->lpSecurityDescriptor = pSD;
+ pSA->bInheritHandle = FALSE;
+
+ // uncomment this line if you want to see the DACL being generated.
+ //DumpSD(pSD);
+
+errExit:
+ if (FAILED(hr))
+ {
+ if (pACL != NULL)
+ {
+ for(int i = 0; i < pACL->AceCount; i++)
+ DeleteAce(pACL, i);
+
+ delete [] pACL;
+ }
+
+ if (pSD != NULL)
+ delete pSD;
+ }
+
+ return hr;
+}
+
+//-----------------------------------------------------------------------------
+// Helper to destroy the security attributes for the shared memory for a given
+// process.
+//-----------------------------------------------------------------------------
+void IPCShared::DestroySecurityAttributes(SECURITY_ATTRIBUTES *pSA)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ }
+ CONTRACTL_END;
+
+ // We'll take a NULL param just to be nice.
+ if (pSA == NULL)
+ return;
+
+ // Cleanup the DACL in the SD.
+ SECURITY_DESCRIPTOR *pSD = (SECURITY_DESCRIPTOR*) pSA->lpSecurityDescriptor;
+
+ if (pSD != NULL)
+ {
+ // Grab the DACL
+ BOOL isDACLPresent = FALSE;
+ BOOL isDefaultDACL = FALSE;
+ ACL *pACL = NULL;
+
+ BOOL res = GetSecurityDescriptorDacl(pSD, &isDACLPresent, &pACL, &isDefaultDACL);
+
+ // If we got the DACL, then free the stuff inside of it.
+ if (res && isDACLPresent && (pACL != NULL) && !isDefaultDACL)
+ {
+ for(int i = 0; i < pACL->AceCount; i++)
+ DeleteAce(pACL, i);
+
+ delete [] pACL;
+ }
+
+ // Free the SD from within the SA.
+ delete pSD;
+ }
+
+ // Finally, free the SA.
+ delete pSA;
+}
+
+//-----------------------------------------------------------------------------
+// Given a PID, grab the SID for the owner of the process.
+//
+// NOTE:: Caller has to free *ppBufferToFreeByCaller.
+// This buffer is allocated to hold the PSID return by GetPrcoessTokenInformation.
+// The tkOwner field may contain a poniter into this allocated buffer. So we cannot free
+// the buffer in GetSidForProcess.
+//
+//-----------------------------------------------------------------------------
+HRESULT IPCShared::GetSidForProcess(HINSTANCE hDll,
+ DWORD pid,
+ PSID *ppSID,
+ __deref_out_opt char **ppBufferToFreeByCaller)
+{
+ WRAPPER_NO_CONTRACT;
+
+ HRESULT hr = S_OK;
+ HANDLE hProc = NULL;
+ HANDLE hToken = NULL;
+ PSID_IDENTIFIER_AUTHORITY pSID = NULL;
+ TOKEN_OWNER *ptkOwner = NULL;
+ DWORD dwRetLength;
+
+ LOG((LF_CORDB, LL_INFO10, "IPCWI::GSFP: GetSidForProcess 0x%x (%d)", pid, pid));
+
+ // Grab a handle to the target process.
+ hProc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
+
+ *ppBufferToFreeByCaller = NULL;
+
+ if (hProc == NULL)
+ {
+ hr = HRESULT_FROM_GetLastError();
+
+ LOG((LF_CORDB, LL_INFO10,
+ "IPCWI::GSFP: Unable to get SID for process. "
+ "OpenProcess(%d) failed: 0x%08x\n", pid, hr));
+
+ goto ErrorExit;
+ }
+
+ // Get the pointer to the requested function
+ FARPROC pProcAddr = GetProcAddress(hDll, "OpenProcessToken");
+
+ // If the proc address was not found, return error
+ if (pProcAddr == NULL)
+ {
+ hr = HRESULT_FROM_GetLastError();
+
+ LOG((LF_CORDB, LL_INFO10,
+ "IPCWI::GSFP: Unable to get SID for process. "
+ "GetProcAddr (OpenProcessToken) failed: 0x%08x\n", hr));
+
+ goto ErrorExit;
+ }
+
+ typedef BOOL WINAPI OPENPROCESSTOKEN(HANDLE, DWORD, PHANDLE);
+
+ // Retrieve a handle of the access token
+ if (!((OPENPROCESSTOKEN *)pProcAddr)(hProc, TOKEN_QUERY, &hToken))
+ {
+ hr = HRESULT_FROM_GetLastError();
+
+ LOG((LF_CORDB, LL_INFO100,
+ "IPCWI::GSFP: OpenProcessToken() failed: 0x%08x\n", hr));
+
+ goto ErrorExit;
+ }
+
+ // Get the pointer to the requested function
+ pProcAddr = GetProcAddress(hDll, "GetTokenInformation");
+
+ // If the proc address was not found, return error
+ if (pProcAddr == NULL)
+ {
+ hr = HRESULT_FROM_GetLastError();
+
+ LOG((LF_CORDB, LL_INFO10,
+ "IPCWI::GSFP: Unable to get SID for process. "
+ "GetProcAddr (GetTokenInformation) failed: 0x%08x\n", hr));
+
+ goto ErrorExit;
+ }
+
+ typedef BOOL GETTOKENINFORMATION(HANDLE, TOKEN_INFORMATION_CLASS, LPVOID,
+ DWORD, PDWORD);
+
+ // get the required size of buffer
+ ((GETTOKENINFORMATION *)pProcAddr) (hToken, TokenOwner, NULL,
+ 0, &dwRetLength);
+ _ASSERTE (dwRetLength);
+
+ *ppBufferToFreeByCaller = new (nothrow) char [dwRetLength];
+ if ((ptkOwner = (TOKEN_OWNER *) *ppBufferToFreeByCaller) == NULL)
+ {
+ hr = E_OUTOFMEMORY;
+
+ LOG((LF_CORDB, LL_INFO10,
+ "IPCWI::GSFP: OutOfMemory... "
+ "GetTokenInformation() failed.\n"));
+
+ goto ErrorExit;
+ }
+
+ if (!((GETTOKENINFORMATION *)pProcAddr) (hToken, TokenOwner, (LPVOID)ptkOwner,
+ dwRetLength, &dwRetLength))
+ {
+ hr = HRESULT_FROM_GetLastError();
+
+ LOG((LF_CORDB, LL_INFO10,
+ "IPCWI::GSFP: Unable to get SID for process. "
+ "GetTokenInformation() failed: 0x%08x\n", hr));
+
+ goto ErrorExit;
+ }
+
+ *ppSID = ptkOwner->Owner;
+
+ErrorExit:
+ if (hProc != NULL)
+ CloseHandle(hProc);
+
+ if (hToken != NULL)
+ CloseHandle(hToken);
+
+ return hr;
+}
+
+/* static */
+DWORD IPCShared::GetAccessFlagsForObject(KernelObject whatObject, BOOL bFullControlACL)
+{
+ _ASSERTE(whatObject >= 0 && whatObject < TotalKernelObjects);
+
+ DWORD dwAccessFlags = 0;
+
+ if (!bFullControlACL)
+ {
+ if (whatObject == Section)
+ dwAccessFlags = (STANDARD_RIGHTS_ALL | SECTION_MAP_READ) & ~WRITE_DAC & ~WRITE_OWNER & ~DELETE;
+ else if (whatObject == Event)
+ dwAccessFlags = (EVENT_ALL_ACCESS) & ~WRITE_DAC & ~WRITE_OWNER & ~DELETE;
+ else if (whatObject == PrivateNamespace)
+ dwAccessFlags = FILE_MAP_READ;
+ }
+ else
+ {
+ _ASSERTE(whatObject != PrivateNamespace);
+ if (whatObject == Section)
+ dwAccessFlags = CLR_IPC_GENERIC_RIGHT;
+ else if (whatObject == Event)
+ dwAccessFlags = EVENT_ALL_ACCESS;
+ }
+
+ _ASSERTE(dwAccessFlags != 0);
+ return dwAccessFlags;
+}
+
+
+//-----------------------------------------------------------------------------
+// This function will initialize the Access Control List with three
+// Access Control Entries:
+// The first ACE entry grants all permissions to "Administrators".
+// The second ACE grants all permissions to the monitoring users (for perfcounters).
+// The third ACE grants all permissions to "Owner" of the target process.
+//-----------------------------------------------------------------------------
+BOOL IPCShared::InitializeGenericIPCAcl(DWORD pid, BOOL bRestrictiveACL, PACL *ppACL, KernelObject whatObject, EDescriptorType descType)
+{
+ WRAPPER_NO_CONTRACT;
+
+ struct PermissionStruct
+ {
+ PSID rgPSID;
+ DWORD rgAccessFlags;
+ } PermStruct[MaxNumberACEs];
+
+ SID_IDENTIFIER_AUTHORITY SIDAuthNT = SECURITY_NT_AUTHORITY;
+ HRESULT hr = S_OK;
+ DWORD dwAclSize;
+ BOOL returnCode = false;
+ *ppACL = NULL;
+ DWORD i;
+ DWORD cActualACECount = 0;
+ char *pBufferToFreeByCaller = NULL;
+ int iSIDforAdmin = -1;
+ int iSIDforUsers = -1;
+ int iSIDforLoggingUsers = -1;
+#if !defined (DACCESS_COMPILE) && !defined(FEATURE_CORECLR)
+ NewArrayHolder<BYTE> pbTokenMem;
+ PTOKEN_APPCONTAINER_INFORMATION pAppContainerTokenInfo = NULL;
+#endif
+
+ PermStruct[0].rgPSID = NULL;
+
+ HINSTANCE hDll = WszGetModuleHandle(L"advapi32");
+
+ if (hDll == NULL)
+ {
+ LOG((LF_CORDB, LL_INFO10, "IPCWI::IGIPCA: Unable to generate ACL for IPC. LoadLibrary (advapi32) failed.\n"));
+ return false;
+ }
+ _ASSERTE(hDll != NULL);
+
+ // Get the pointer to the requested function
+ FARPROC pProcAddr = GetProcAddress(hDll, "AllocateAndInitializeSid");
+
+ // If the proc address was not found, return error
+ if (pProcAddr == NULL)
+ {
+ LOG((LF_CORDB, LL_INFO10,
+ "IPCWI::IGIPCA: Unable to generate ACL for IPC. "
+ "GetProcAddr (AllocateAndInitializeSid) failed.\n"));
+ goto ErrorExit;
+ }
+
+ typedef BOOL ALLOCATEANDINITIALIZESID(PSID_IDENTIFIER_AUTHORITY,
+ BYTE, DWORD, DWORD, DWORD, DWORD,
+ DWORD, DWORD, DWORD, DWORD, PSID *);
+
+
+ BOOL bGrantAllAccess = ((descType == eDescriptor_Private) ? TRUE : FALSE);
+ // Create a SID for the BUILTIN\Administrators group.
+ // SECURITY_BUILTIN_DOMAIN_RID + DOMAIN_ALIAS_RID_ADMINS = all Administrators. This translates to (A;;GA;;;BA).
+ if (!((ALLOCATEANDINITIALIZESID *) pProcAddr)(&SIDAuthNT,
+ 2,
+ SECURITY_BUILTIN_DOMAIN_RID,
+ DOMAIN_ALIAS_RID_ADMINS,
+ 0, 0, 0, 0, 0, 0,
+ &PermStruct[0].rgPSID))
+ {
+ hr = HRESULT_FROM_GetLastError();
+ _ASSERTE(SUCCEEDED(hr));
+
+ LOG((LF_CORDB, LL_INFO10,
+ "IPCWI::IGIPCA: failed to allocate AdminSid: 0x%08x\n", hr));
+
+ goto ErrorExit;
+ }
+ // GENERIC_ALL access for Administrators
+ PermStruct[cActualACECount].rgAccessFlags = GetAccessFlagsForObject(whatObject, bGrantAllAccess);
+
+ iSIDforAdmin = cActualACECount;
+ cActualACECount++;
+
+ // Next, we get the SID for the owner of the current process.
+ hr = GetSidForProcess(hDll, GetCurrentProcessId(), &(PermStruct[cActualACECount].rgPSID), &pBufferToFreeByCaller);
+ DWORD accessFlags = 0;
+ if (whatObject == Section) {
+ //special case, grant SECTION_MAP_WRITE for current owner just to support inProc SxS.
+ accessFlags = GetAccessFlagsForObject(whatObject, bGrantAllAccess) | SECTION_MAP_WRITE;
+ }
+ else {
+ accessFlags = GetAccessFlagsForObject(whatObject, bGrantAllAccess);
+ }
+ PermStruct[cActualACECount].rgAccessFlags = accessFlags;
+
+ // Don't fail out if we cannot get the SID for the owner of the current process. In this case, the
+ // share memory block will be created with only Admin (and optionall "Users") permissions.
+ // Currently we discovered the anonymous user doesn't have privilege to call OpenProcess. Without OpenProcess,
+ // we cannot get the SID...
+ //
+ if (SUCCEEDED(hr))
+ {
+ cActualACECount++;
+ }
+#if _DEBUG
+ else
+ LOG((LF_CORDB, LL_INFO100, "IPCWI::IGIPCA: GetSidForProcess() failed: 0x%08x\n", hr));
+#endif // _DEBUG
+
+
+ if (descType == eDescriptor_Public)
+ {
+ DWORD dwRet = ((ALLOCATEANDINITIALIZESID *) pProcAddr)(&SIDAuthNT,
+ 2,
+ SECURITY_BUILTIN_DOMAIN_RID,
+ DOMAIN_ALIAS_RID_MONITORING_USERS,
+ 0, 0, 0, 0, 0, 0,
+ &PermStruct[cActualACECount].rgPSID);
+
+ if (dwRet)
+ {
+ // "Users" shouldn't be able to write to block, delete object, change DACLs, or change ownership
+ PermStruct[cActualACECount].rgAccessFlags = GetAccessFlagsForObject(whatObject, FALSE);
+
+ iSIDforUsers = cActualACECount;
+ cActualACECount++;
+ }
+ else
+ {
+ hr = HRESULT_FROM_GetLastError();
+ _ASSERTE(SUCCEEDED(hr));
+
+ LOG((LF_CORDB, LL_INFO10,
+ "IPCWI::IGIPCA: failed to allocate Users Sid: 0x%08x\n", hr));
+
+ // non-fatal error, so don't goto errorexit
+ }
+
+ dwRet = ((ALLOCATEANDINITIALIZESID *) pProcAddr)(&SIDAuthNT,
+ 2,
+ SECURITY_BUILTIN_DOMAIN_RID,
+ DOMAIN_ALIAS_RID_LOGGING_USERS,
+ 0, 0, 0, 0, 0, 0,
+ &PermStruct[cActualACECount].rgPSID);
+ if (dwRet)
+ {
+ PermStruct[cActualACECount].rgAccessFlags = GetAccessFlagsForObject(whatObject, FALSE);
+
+ iSIDforLoggingUsers = cActualACECount;
+ cActualACECount++;
+ }
+ else
+ {
+ hr = HRESULT_FROM_GetLastError();
+ _ASSERTE(SUCCEEDED(hr));
+
+ LOG((LF_CORDB, LL_INFO10,
+ "IPCWI::IGIPCA: failed to allocate Domain Logging Users Sid: 0x%08x\n", hr));
+
+ // non-fatal error, so don't goto errorexit
+ }
+
+#if !defined(DACCESS_COMPILE) && !defined(FEATURE_CORECLR)
+ // when running on win8 if the process is an appcontainer then add the appcontainer SID to the ACL
+ // going down this code path means we're creating the descriptor for our current PID.
+ _ASSERTE(pid == GetCurrentProcessId());
+ hr = AppX::GetAppContainerTokenInfoForProcess(pid, pbTokenMem);
+
+ if (FAILED(hr))
+ {
+ // failed to open the target's process, continue on
+ // assuming that the process isn't in an AppContainer.
+ _ASSERTE(pbTokenMem == NULL);
+ }
+ else
+ {
+ if (hr == S_FALSE)
+ {
+ // not an appcontainer
+ _ASSERTE(pbTokenMem == NULL);
+ }
+ else
+ {
+ // process is an appcontainer so add the SID
+ pAppContainerTokenInfo =
+ reinterpret_cast<PTOKEN_APPCONTAINER_INFORMATION>(pbTokenMem.GetValue());
+ _ASSERTE(pAppContainerTokenInfo);
+ _ASSERTE(pAppContainerTokenInfo->TokenAppContainer);
+
+ PermStruct[cActualACECount].rgPSID = pAppContainerTokenInfo->TokenAppContainer;
+ PermStruct[cActualACECount].rgAccessFlags = GetAccessFlagsForObject(whatObject, FALSE);
+ ++cActualACECount;
+ }
+ }
+#endif // !defined(DACCESS_COMPILE) && !defined(FEATURE_CORECLR)
+ }
+
+ _ASSERTE(cActualACECount <= MaxNumberACEs);
+
+ // Now, create an Initialize an ACL and add the ACE entries to it. NOTE: We're not using "SetEntriesInAcl" because
+ // it loads a bunch of other dlls which can be avoided by using this roundabout way!!
+
+ // Get the pointer to the requested function
+ pProcAddr = GetProcAddress(hDll, "InitializeAcl");
+
+ // If the proc address was not found, return error
+ if (pProcAddr == NULL)
+ {
+ LOG((LF_CORDB, LL_INFO10,
+ "IPCWI::IGIPCA: Unable to generate ACL for IPC. "
+ "GetProcAddr (InitializeAcl) failed.\n"));
+ goto ErrorExit;
+ }
+
+ // Also calculate the memory required for ACE entries in the ACL using the
+ // following method:
+ // "sizeof (ACCESS_ALLOWED_ACE) - sizeof (ACCESS_ALLOWED_ACE.SidStart) + GetLengthSid (pAceSid);"
+
+ dwAclSize = sizeof (ACL) + (sizeof (ACCESS_ALLOWED_ACE) - sizeof (DWORD)) * cActualACECount;
+
+ for (i = 0; i < cActualACECount; i++)
+ {
+ dwAclSize += GetLengthSid(PermStruct[i].rgPSID);
+ }
+
+ // now allocate memory
+ if ((*ppACL = (PACL) new (nothrow) char[dwAclSize]) == NULL)
+ {
+ LOG((LF_CORDB, LL_INFO10, "IPCWI::IGIPCA: OutOfMemory... 'new Acl' failed.\n"));
+
+ goto ErrorExit;
+ }
+
+ typedef BOOL INITIALIZEACL(PACL, DWORD, DWORD);
+
+ if (!((INITIALIZEACL *)pProcAddr)(*ppACL, dwAclSize, ACL_REVISION))
+ {
+ hr = HRESULT_FROM_GetLastError();
+
+ LOG((LF_CORDB, LL_INFO100,
+ "IPCWI::IGIPCA: InitializeACL() failed: 0x%08x\n", hr));
+
+ goto ErrorExit;
+ }
+
+ // Get the pointer to the requested function
+ pProcAddr = GetProcAddress(hDll, "AddAccessAllowedAce");
+
+ // If the proc address was not found, return error
+ if (pProcAddr == NULL)
+ {
+ LOG((LF_CORDB, LL_INFO10,
+ "IPCWI::IGIPCA: Unable to generate ACL for IPC. "
+ "GetProcAddr (AddAccessAllowedAce) failed.\n"));
+ goto ErrorExit;
+ }
+
+ typedef BOOL ADDACCESSALLOWEDACE(PACL, DWORD, DWORD, PSID);
+
+ for (i=0; i < cActualACECount; i++)
+ {
+ if (!((ADDACCESSALLOWEDACE *)pProcAddr)(*ppACL,
+ ACL_REVISION,
+ PermStruct[i].rgAccessFlags,
+ PermStruct[i].rgPSID))
+
+ {
+ hr = HRESULT_FROM_GetLastError();
+
+ LOG((LF_CORDB, LL_INFO100,
+ "IPCWI::IGIPCA: AddAccessAllowedAce() failed: 0x%08x\n", hr));
+ goto ErrorExit;
+ }
+ }
+
+ returnCode = true;
+ goto NormalExit;
+
+
+ErrorExit:
+ returnCode = FALSE;
+
+ if (*ppACL)
+ {
+ delete [] (*ppACL);
+ *ppACL = NULL;
+ }
+
+NormalExit:
+
+ if (pBufferToFreeByCaller != NULL)
+ delete [] pBufferToFreeByCaller;
+
+ // Get the pointer to the requested function
+ pProcAddr = GetProcAddress(hDll, "FreeSid");
+
+ // If the proc address was not found, return error
+ if (pProcAddr == NULL)
+ {
+ LOG((LF_CORDB, LL_INFO10,
+ "IPCWI::IGIPCA: Unable to generate ACL for IPC. "
+ "GetProcAddr (FreeSid) failed.\n"));
+ return false;
+ }
+
+ typedef BOOL FREESID(PSID);
+
+ // Free the SID created earlier. Function does not return a value.
+ if( iSIDforAdmin != -1 )
+ ((FREESID *) pProcAddr)(PermStruct[iSIDforAdmin].rgPSID);
+
+ // free the SID for "Users"
+ if (iSIDforUsers != -1)
+ ((FREESID *) pProcAddr)(PermStruct[iSIDforUsers].rgPSID);
+
+ // free the SID for "Performance Logging Users"
+ if (iSIDforLoggingUsers != -1)
+ ((FREESID *) pProcAddr)(PermStruct[iSIDforLoggingUsers].rgPSID);
+
+ return returnCode;
+}
+
+#endif // FEATURE_IPCMAN