// Determine (if possible) whether a debugger is attached to the target process HRESULT WindowsNativePipeline::IsRemoteDebuggerPresent(DWORD processId, BOOL* pfDebuggerPresent) { #if !defined(FEATURE_CORESYSTEM) // Get a process handle for the process ID. HandleHolder hProc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, processId); if (hProc == NULL) return HRESULT_FROM_GetLastError(); // Delay-bind to CheckRemoteDebuggerPresent - WinXP SP1 and above only HModuleHolder hKernel32; hKernel32 = WszLoadLibrary(W("kernel32")); if (hKernel32 == NULL) return HRESULT_FROM_GetLastError(); typedef BOOL (*CheckRemoteDebuggerPresentSig) (HANDLE, PBOOL); CheckRemoteDebuggerPresentSig pCheckRemoteDebuggerPresent = reinterpret_cast<CheckRemoteDebuggerPresentSig>(GetProcAddress(hKernel32, "CheckRemoteDebuggerPresent")); if (pCheckRemoteDebuggerPresent == NULL) return HRESULT_FROM_GetLastError(); // API exists - call it if (!pCheckRemoteDebuggerPresent(hProc, pfDebuggerPresent)) return HRESULT_FROM_GetLastError(); return S_OK; #else //CoreSystem doesn't have this API return E_FAIL; #endif }
// Detach HRESULT WindowsNativePipeline::DebugActiveProcessStop(DWORD processId) { #if !defined(FEATURE_CORESYSTEM) // Late-bind to DebugActiveProcessStop since it's WinXP and above only HModuleHolder hKernel32; hKernel32 = WszLoadLibrary(W("kernel32")); if (hKernel32 == NULL) return HRESULT_FROM_GetLastError(); typedef BOOL (*DebugActiveProcessStopSig) (DWORD); DebugActiveProcessStopSig pDebugActiveProcessStop = reinterpret_cast<DebugActiveProcessStopSig>(GetProcAddress(hKernel32, "DebugActiveProcessStop")); // Win2K will fail here - can't find DebugActiveProcessStop if (pDebugActiveProcessStop == NULL) return HRESULT_FROM_GetLastError(); // Ok, the API exists, call it if (!pDebugActiveProcessStop(processId)) { // Detach itself failed return HRESULT_FROM_GetLastError(); } #else // The API exists, call it if (!::DebugActiveProcessStop(processId)) { // Detach itself failed return HRESULT_FROM_GetLastError(); } #endif return S_OK; }
// Resume any suspended threads (but just once) HRESULT WindowsNativePipeline::EnsureThreadsRunning() { #ifdef FEATURE_CORESYSTEM _ASSERTE("NYI"); return E_FAIL; #else _ASSERTE(m_dwProcessId != 0); // Take a snapshot of all running threads (similar to ShimProcess::QueueFakeThreadAttachEventsNativeOrder) // Alternately we could return thread creation/exit in WaitForDebugEvent. But we expect this to be used // very rarely, so no need to complicate more common codepaths. HANDLE hThreadSnap = INVALID_HANDLE_VALUE; THREADENTRY32 te32; hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); if (hThreadSnap == INVALID_HANDLE_VALUE) return HRESULT_FROM_GetLastError(); // HandleHolder doesn't deal with INVALID_HANDLE_VALUE, so we only assign if we have a legal value. HandleHolder hSnapshotHolder(hThreadSnap); // Fill in the size of the structure before using it. te32.dwSize = sizeof(THREADENTRY32); // Retrieve information about the first thread, and exit if unsuccessful if (!Thread32First(hThreadSnap, &te32)) return HRESULT_FROM_GetLastError(); // Now walk the thread list of the system and attempt to resume any that are part of this process // Ignore errors - this is a best effort (but ASSERT in CHK builds since we don't expect errors // in practice - we expect the process to be frozen at a debug event, so no races etc.) HRESULT hr = S_FALSE; // no thread was resumed do { if (te32.th32OwnerProcessID == m_dwProcessId) { HandleHolder hThread = ::OpenThread(THREAD_SUSPEND_RESUME, FALSE, te32.th32ThreadID); _ASSERTE(hThread != NULL); if (hThread != NULL) { // Resume each thread exactly once (if they were suspended multiple times, // then EnsureThreadsRunning would need to be called multiple times until it // returned S_FALSE. DWORD prevCount = ::ResumeThread(hThread); _ASSERTE(prevCount >= 0); if (prevCount >= 1) hr = S_OK; // some thread was resumed } } } while(Thread32Next(hThreadSnap, &te32)); return hr; #endif }
HRESULT DbgTransportTarget::CreateProcess(LPCWSTR lpApplicationName, LPCWSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation) { BOOL result = WszCreateProcess(lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation); if (!result) { return HRESULT_FROM_GetLastError(); } return S_OK; }
INT32 QCALLTYPE COMPrincipal::ImpersonateLoggedOnUser(HANDLE hToken) { QCALL_CONTRACT; HRESULT hr = S_OK; BEGIN_QCALL; #ifdef FEATURE_INCLUDE_ALL_INTERFACES IHostSecurityManager *pSM = CorHost2::GetHostSecurityManager(); if (pSM) { BEGIN_SO_TOLERANT_CODE_CALLING_HOST(GetThread()); hr = pSM->ImpersonateLoggedOnUser(hToken); END_SO_TOLERANT_CODE_CALLING_HOST; } else #endif // FEATURE_INCLUDE_ALL_INTERFACES { if (!::ImpersonateLoggedOnUser(hToken)) hr = HRESULT_FROM_GetLastError(); } STRESS_LOG2(LF_SECURITY, LL_INFO100, "COMPrincipal::ImpersonateLoggedOnUser called with hTokenSAFE = %d. Returning 0x%x\n",hToken,hr); END_QCALL; return hr; }
STDAPI GetRealProcAddress(LPCSTR pwszProcName, VOID** ppv) { if(!ppv) { return E_POINTER; } HMODULE hLib = GetLibrary(LIB_mscorwks); if(hLib == NULL) { return HRESULT_FROM_GetLastError(); } *ppv = (void*) GetProcAddress(hLib,pwszProcName); if(*ppv == NULL) { return HRESULT_FROM_GetLastError(); } return S_OK; }
//-------------------------------------------------------------------------------------- // 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; }
int LoadNativeStringResource(const NativeStringResourceTable &nativeStringResourceTable, unsigned int iResourceID, WCHAR* szBuffer, int iMax, int *pcwchUsed) { int len = 0; if (szBuffer && iMax) { // Search the sorted set of resources for the ID we're interested in. NativeStringResource searchEntry = {iResourceID, NULL}; NativeStringResource *resourceEntry = (NativeStringResource*)bsearch( &searchEntry, nativeStringResourceTable.table, nativeStringResourceTable.size, sizeof(NativeStringResource), CompareNativeStringResources); if (resourceEntry != NULL) { len = PAL_GetResourceString(NULL, resourceEntry->resourceString, szBuffer, iMax); if (len == 0) { int hr = HRESULT_FROM_GetLastError(); // Tell the caller if the buffer isn't big enough if (hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) && pcwchUsed) *pcwchUsed = iMax; return hr; } } else { // The resource ID wasn't found in our array. Fall back on returning the ID as a string. len = _snwprintf_s(szBuffer, iMax, _TRUNCATE, W("[Undefined resource string ID:0x%X]"), iResourceID); if (len < 0) { // The only possible failure is that that string didn't fit the buffer. So the buffer contains // partial string terminated by '\0' // We could return ERROR_INSUFFICIENT_BUFFER, but we'll error on the side of caution here and // actually show something (given that this is likely a scenario involving a bug/deployment issue) len = iMax - 1; } } } if (pcwchUsed) { *pcwchUsed = len; } return S_OK; }
// Attach the debugger to this process. HRESULT WindowsNativePipeline::DebugActiveProcess(MachineInfo machineInfo, DWORD processId) { HRESULT hr = E_FAIL; BOOL ret = ::DebugActiveProcess(processId); if (ret) { hr = S_OK; m_dwProcessId = processId; UpdateDebugSetProcessKillOnExit(); } else { hr = HRESULT_FROM_GetLastError(); // There are at least two scenarios in which DebugActiveProcess() returns E_INVALIDARG: // 1) if the specified process doesn't exist, or // 2) if the specified process already has a debugger atttached // We need to distinguish these two cases in order to return the correct HR. if (hr == E_INVALIDARG) { // Check whether a debugger is known to be already attached. // Note that this API won't work on some OSes, in which case we err on the side of returning E_INVALIDARG // even though a debugger may be attached. Another approach could be to assume that if // OpenProcess succeeded, then DebugActiveProcess must only have failed because a debugger is // attached. But I think it's better to only return the specific error code if we know for sure // the case is true. BOOL fIsDebuggerPresent = FALSE; if (SUCCEEDED(IsRemoteDebuggerPresent(processId, &fIsDebuggerPresent))) { if (fIsDebuggerPresent) { hr = CORDBG_E_DEBUGGER_ALREADY_ATTACHED; } } } } return hr; }
HRESULT FileOrDirectoryExists(PathString &path) { HRESULT hr = S_FALSE; DWORD dwFileAttributes = WszGetFileAttributes(path.GetUnicode()); if (dwFileAttributes == INVALID_FILE_ATTRIBUTES) { hr = HRESULT_FROM_GetLastError(); if ((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) || (hr == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND))) { hr = S_FALSE; } } else { hr = S_TRUE; } return hr; }
//----------------------------------------------------------------------------- // 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; }
// Create an process under the debugger. HRESULT WindowsNativePipeline::CreateProcessUnderDebugger( MachineInfo machineInfo, LPCWSTR lpApplicationName, LPCWSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation) { // This is always doing Native-debugging at the OS-level. dwCreationFlags |= (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS); BOOL ret = ::WszCreateProcess( lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation); if (!ret) { return HRESULT_FROM_GetLastError(); } m_dwProcessId = lpProcessInformation->dwProcessId; UpdateDebugSetProcessKillOnExit(); return S_OK; }
// Create an process under the debugger. HRESULT DbgTransportPipeline::CreateProcessUnderDebugger( MachineInfo machineInfo, LPCWSTR lpApplicationName, LPCWSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation) { // INativeEventPipeline has a 1:1 relationship with CordbProcess. _ASSERTE(!IsTransportRunning()); // We don't support interop-debugging on the Mac. _ASSERTE(!(dwCreationFlags & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS))); // When we're using a transport we can't deal with creating a suspended process (we need the process to // startup in order that it can start up a transport thread and reply to our messages). _ASSERTE(!(dwCreationFlags & CREATE_SUSPENDED)); // Connect to the debugger proxy on the remote machine and ask it to create a process for us. HRESULT hr = E_FAIL; m_pProxy = g_pDbgTransportTarget; hr = m_pProxy->CreateProcess(lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation); if (SUCCEEDED(hr)) { // Establish a connection to the actual runtime to be debugged. hr = m_pProxy->GetTransportForProcess(lpProcessInformation->dwProcessId, &m_pTransport, &m_hProcess); if (SUCCEEDED(hr)) { // Wait for the connection to become useable (or time out). if (!m_pTransport->WaitForSessionToOpen(10000)) { hr = CORDBG_E_TIMEOUT; } else { if (!m_pTransport->UseAsDebugger(&m_ticket)) { hr = CORDBG_E_DEBUGGER_ALREADY_ATTACHED; } } } } if (SUCCEEDED(hr)) { _ASSERTE((m_hProcess != NULL) && (m_hProcess != INVALID_HANDLE_VALUE)); m_dwProcessId = lpProcessInformation->dwProcessId; // For Mac remote debugging, we don't actually have a process handle to hand back to the debugger. // Instead, we return a handle to an event as the "process handle". The Win32 event thread also waits // on this event handle, and the event will be signaled when the proxy notifies us that the process // on the remote machine is terminated. However, normally the debugger calls CloseHandle() immediately // on the "process handle" after CreateProcess() returns. Doing so causes the Win32 event thread to // continue waiting on a closed event handle, and so it will never wake up. // (In fact, in Whidbey, we also duplicate the process handle in code:CordbProcess::Init.) if (!DuplicateHandle(GetCurrentProcess(), m_hProcess, GetCurrentProcess(), &(lpProcessInformation->hProcess), 0, // ignored since we are going to pass DUPLICATE_SAME_ACCESS FALSE, DUPLICATE_SAME_ACCESS)) { hr = HRESULT_FROM_GetLastError(); } } if (SUCCEEDED(hr)) { m_fRunning = TRUE; } else { Dispose(); } return hr; }
//----------------------------------------------------------------------------- // 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; }
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; }
// Given a PID attempt to find or create a DbgTransportSession instance to manage a connection to a runtime in // that process. Returns E_UNEXPECTED if the process can't be found. Also returns a handle that can be waited // on for process termination. HRESULT DbgTransportTarget::GetTransportForProcess(DWORD dwPID, DbgTransportSession **ppTransport, HANDLE *phProcessHandle) { RSLockHolder lock(&m_sLock); HRESULT hr = S_OK; ProcessEntry *entry = LocateProcessByPID(dwPID); if (entry == NULL) { NewHolder<ProcessEntry> newEntry = new(nothrow) ProcessEntry(); if (newEntry == NULL) return E_OUTOFMEMORY; NewHolder<DbgTransportSession> transport = new(nothrow) DbgTransportSession(); if (transport == NULL) { return E_OUTOFMEMORY; } HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID); if (hProcess == NULL) { transport->Shutdown(); return HRESULT_FROM_GetLastError(); } // Initialize it (this immediately starts the remote connection process). hr = transport->Init(dwPID, hProcess); if (FAILED(hr)) { transport->Shutdown(); CloseHandle(hProcess); return hr; } entry = newEntry; newEntry.SuppressRelease(); entry->m_dwPID = dwPID; entry->m_hProcess = hProcess; entry->m_transport = transport; transport.SuppressRelease(); entry->m_cProcessRef = 0; // Adding new entry to the list. entry->m_pNext = m_pProcessList; m_pProcessList = entry; } entry->m_cProcessRef++; _ASSERTE(entry->m_cProcessRef > 0); _ASSERTE(entry->m_transport != NULL); _ASSERTE(entry->m_hProcess > 0); *ppTransport = entry->m_transport; if (!DuplicateHandle(GetCurrentProcess(), entry->m_hProcess, GetCurrentProcess(), phProcessHandle, 0, // ignored since we are going to pass DUPLICATE_SAME_ACCESS FALSE, DUPLICATE_SAME_ACCESS)) { return HRESULT_FROM_GetLastError(); } return hr; }
HRESULT LoadDataAccessDll(HINSTANCE mscorModule, REFIID ifaceId, ICLRDataTarget* target, HMODULE* dllHandle, void** iface) { HRESULT status; WCHAR accessDllPath[MAX_PATH]; HMODULE accessDll; // // Load the access DLL from the same directory // as the runtime DLL. // if (!WszGetModuleFileName(mscorModule, accessDllPath, NumItems(accessDllPath))) { return HRESULT_FROM_GetLastError(); } PWSTR pathTail = wcsrchr(accessDllPath, '\\'); if (!pathTail) { return E_INVALIDARG; } pathTail++; PWSTR eeFlavor = L"wks"; if (_snwprintf_s(pathTail, _countof(accessDllPath) + (accessDllPath - pathTail), NumItems(accessDllPath) - (pathTail - accessDllPath), MAKEDLLNAME_W(L"mscordac%s"), eeFlavor) <= 0) { return E_INVALIDARG; } accessDll = WszLoadLibrary(accessDllPath); if (!accessDll) { return HRESULT_FROM_GetLastError(); } // // Get the access interface and have it // enumerate the interesting memory in the target process. // void* ifacePtr; PFN_CLRDataCreateInstance entry = (PFN_CLRDataCreateInstance) GetProcAddress(accessDll, "CLRDataCreateInstance"); if (!entry) { status = HRESULT_FROM_GetLastError(); FreeLibrary(accessDll); } else if ((status = entry(ifaceId, target, &ifacePtr)) != S_OK) { FreeLibrary(accessDll); } else { *dllHandle = accessDll; *iface = ifacePtr; } return status; }