@@ -11157,17 +11157,49 @@ void CordbProcess::HandleSetThreadContextNeeded(DWORD dwThreadId)
1115711157    LOG((LF_CORDB, LL_INFO10000, "RS HandleSetThreadContextNeeded\n"));
1115811158
1115911159#if defined(TARGET_WINDOWS) && defined(TARGET_AMD64)
11160-     HandleHolder hThread = OpenThread(
11161-         THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_QUERY_INFORMATION | THREAD_SUSPEND_RESUME,
11162-         FALSE, // thread handle is not inheritable.
11163-         dwThreadId);
11160+     // Before we can read the left side context information, we must:
11161+     // 1. obtain the thread handle
11162+     // 2. suspened the thread
11163+     // 3. read the thread context, and from that read the pointer to the left-side context and the size of the context
11164+     // 4. then we can perform the actual SetThreadContext operation
11165+     // 5. lastly, we must resume the thread
11166+     // For the first step of obtaining the thread handle, 
11167+     // we have previously attempted to use ::OpenThread to get a handle to the thread.
11168+     // However, there are situations where OpenThread can fail with an Access Denied error.
11169+     // From https://github.com/dotnet/runtime/issues/107263, the control-c handler in 
11170+     // Windows causes the process to have higher privileges. 
11171+     // We are now using the following approach to access the thread handle, which is the same
11172+     // approach used by CordbThread::RefreshHandle:
11173+     // 1. Get the thread handle from the DAC
11174+     // 2. Duplicate the handle to the current process
11175+ 
11176+     // lookup the CordbThread by thread ID, so that we can access the left-side thread handle
11177+     CordbThread * pThread = TryLookupOrCreateThreadByVolatileOSId(dwThreadId);
11178+ 
11179+     IDacDbiInterface* pDAC = GetDAC();
11180+     if (pDAC == NULL)
11181+     {
11182+         LOG((LF_CORDB, LL_INFO10000, "RS HandleSetThreadContextNeeded - DAC not initialized\n"));
11183+         ThrowHR(E_UNEXPECTED);
11184+     }
1116411185
11165-     if (hThread == NULL)
11186+     HANDLE hOutOfProcThread = pDAC->GetThreadHandle(pThread->m_vmThreadToken);
11187+     if (hOutOfProcThread == NULL)
1116611188    {
11167-         LOG((LF_CORDB, LL_INFO10000, "RS HandleSetThreadContextNeeded - Unexpected result from OpenThread \n"));
11189+         LOG((LF_CORDB, LL_INFO10000, "RS HandleSetThreadContextNeeded - Failed to get thread handle \n"));
1116811190        ThrowHR(E_UNEXPECTED);
1116911191    }
1117011192
11193+     // Duplicate the thread handle to the current process
11194+     HandleHolder hThread;
11195+     BOOL fSuccess = DuplicateHandle(UnsafeGetProcessHandle(), hOutOfProcThread, ::GetCurrentProcess(), &hThread, 0, FALSE, DUPLICATE_SAME_ACCESS);
11196+     if (!fSuccess)
11197+     {
11198+         LOG((LF_CORDB, LL_INFO10000, "RS HandleSetThreadContextNeeded - Unexpected result from DuplicateHandle\n"));
11199+         ThrowHR(HRESULT_FROM_GetLastError());
11200+     }
11201+ 
11202+     // Suspend the thread and so that we can read the thread context.
1117111203    DWORD previousSuspendCount = ::SuspendThread(hThread);
1117211204    if (previousSuspendCount == (DWORD)-1)
1117311205    {
@@ -11178,12 +11210,22 @@ void CordbProcess::HandleSetThreadContextNeeded(DWORD dwThreadId)
1117811210    DT_CONTEXT context = { 0 };
1117911211    context.ContextFlags = CONTEXT_FULL;
1118011212
11181-     HRESULT hr = GetDataTarget()->GetThreadContext(dwThreadId, CONTEXT_FULL, sizeof(DT_CONTEXT), reinterpret_cast<BYTE*> (&context));
11182-     IfFailThrow(hr);
11213+     // we originally used GetDataTarget()->GetThreadContext, but 
11214+     // the implementation uses ShimLocalDataTarget::GetThreadContext which 
11215+     // depends on OpenThread which might fail with an Access Denied error (see note above)
11216+     BOOL success = ::GetThreadContext(hThread, (CONTEXT*)(&context));
11217+     if (!success)
11218+     {
11219+         LOG((LF_CORDB, LL_INFO10000, "RS HandleSetThreadContextNeeded - Unexpected result from GetThreadContext\n"));
11220+         ThrowHR(HRESULT_FROM_GetLastError());
11221+     }
1118311222
11223+     // Read the pointer to the left-side context and the size of the context from the thread context.
1118411224    TADDR lsContextAddr = (TADDR)context.Rcx;
1118511225    DWORD contextSize = (DWORD)context.Rdx;
1118611226
11227+     // Read the expected Rip and Rsp from the thread context.  This is used to 
11228+     // validate the context read from the left-side.
1118711229    TADDR expectedRip = (TADDR)context.R8;
1118811230    TADDR expectedRsp = (TADDR)context.R9;
1118911231
@@ -11198,7 +11240,7 @@ void CordbProcess::HandleSetThreadContextNeeded(DWORD dwThreadId)
1119811240
1119911241    PCONTEXT pContext = (PCONTEXT)_alloca(contextSize);
1120011242    ULONG32 cbRead;
11201-     hr = GetDataTarget()->ReadVirtual(lsContextAddr, reinterpret_cast<BYTE*>(pContext), contextSize, &cbRead);
11243+     HRESULT  hr = GetDataTarget()->ReadVirtual(lsContextAddr, reinterpret_cast<BYTE*>(pContext), contextSize, &cbRead);
1120211244    if (FAILED(hr))
1120311245    {
1120411246        _ASSERTE(!"ReadVirtual failed");
@@ -11232,7 +11274,7 @@ void CordbProcess::HandleSetThreadContextNeeded(DWORD dwThreadId)
1123211274    // The initialize call should fail but return contextSize
1123311275    contextSize = 0;
1123411276    DWORD contextFlags = pContext->ContextFlags;
11235-     BOOL  success = InitializeContext(NULL, contextFlags, NULL, &contextSize);
11277+     success = InitializeContext(NULL, contextFlags, NULL, &contextSize);
1123611278
1123711279    if(success || GetLastError() != ERROR_INSUFFICIENT_BUFFER)
1123811280    {
@@ -11276,6 +11318,7 @@ void CordbProcess::HandleSetThreadContextNeeded(DWORD dwThreadId)
1127611318
1127711319    DWORD lastError = 0;
1127811320
11321+     // Perform the actual SetThreadContext operation.
1127911322    success = ::SetThreadContext(hThread, pFrameContext);
1128011323    if (!success)
1128111324    {
@@ -11285,6 +11328,7 @@ void CordbProcess::HandleSetThreadContextNeeded(DWORD dwThreadId)
1128511328    LOG((LF_CORDB, LL_INFO10000, "RS HandleSetThreadContextNeeded - Set Thread Context Completed: Success=%d GetLastError=%d hr=0x%X\n", success, lastError, HRESULT_FROM_WIN32(lastError)));
1128611329    _ASSERTE(success);
1128711330
11331+     // Now that we have completed the SetThreadContext, resume the thread
1128811332    DWORD suspendCount = ::ResumeThread(hThread);
1128911333    if (suspendCount == (DWORD)-1)
1129011334    {
0 commit comments