@@ -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