diff options
Diffstat (limited to 'src/pal/src/handlemgr/handleapi.cpp')
-rw-r--r-- | src/pal/src/handlemgr/handleapi.cpp | 338 |
1 files changed, 338 insertions, 0 deletions
diff --git a/src/pal/src/handlemgr/handleapi.cpp b/src/pal/src/handlemgr/handleapi.cpp new file mode 100644 index 0000000000..6b99a85cf7 --- /dev/null +++ b/src/pal/src/handlemgr/handleapi.cpp @@ -0,0 +1,338 @@ +// 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. + +/*++ + + + +Module Name: + + handleapi.cpp + +Abstract: + + Implementation of the handle management APIs + + + +--*/ + +#include "pal/handleapi.hpp" +#include "pal/handlemgr.hpp" +#include "pal/thread.hpp" +#include "pal/procobj.hpp" +#include "pal/dbgmsg.h" +#include "pal/process.h" + +using namespace CorUnix; + +SET_DEFAULT_DEBUG_CHANNEL(HANDLE); + +CAllowedObjectTypes aotDuplicateHandle(TRUE); + +PAL_ERROR +CloseSpecialHandle( + HANDLE hObject + ); + +/*++ +Function: + DuplicateHandle + +See MSDN doc. + +PAL-specific behavior : + -Source and Target process needs to be the current process. + -lpTargetHandle must be non-NULL + -dwDesiredAccess is ignored + -bInheritHandle must be FALSE + -dwOptions must be a combo of DUPLICATE_SAME_ACCESS and + DUPLICATE_CLOSE_SOURCE + +--*/ +BOOL +PALAPI +DuplicateHandle( + IN HANDLE hSourceProcessHandle, + IN HANDLE hSourceHandle, + IN HANDLE hTargetProcessHandle, + OUT LPHANDLE lpTargetHandle, + IN DWORD dwDesiredAccess, + IN BOOL bInheritHandle, + IN DWORD dwOptions) +{ + PAL_ERROR palError; + CPalThread *pThread; + + PERF_ENTRY(DuplicateHandle); + ENTRY("DuplicateHandle( hSrcProcHandle=%p, hSrcHandle=%p, " + "hTargetProcHandle=%p, lpTargetHandle=%p, dwAccess=%#x, " + "bInheritHandle=%d, dwOptions=%#x) \n", hSourceProcessHandle, + hSourceHandle, hTargetProcessHandle, lpTargetHandle, + dwDesiredAccess, bInheritHandle, dwOptions); + + pThread = InternalGetCurrentThread(); + + palError = InternalDuplicateHandle( + pThread, + hSourceProcessHandle, + hSourceHandle, + hTargetProcessHandle, + lpTargetHandle, + dwDesiredAccess, + bInheritHandle, + dwOptions + ); + + if (NO_ERROR != palError) + { + pThread->SetLastError(palError); + } + + LOGEXIT("DuplicateHandle returns BOOL %d\n", (NO_ERROR == palError)); + PERF_EXIT(DuplicateHandle); + return (NO_ERROR == palError); +} + +PAL_ERROR +CorUnix::InternalDuplicateHandle( + CPalThread *pThread, + HANDLE hSourceProcess, + HANDLE hSource, + HANDLE hTargetProcess, + LPHANDLE phDuplicate, + DWORD dwDesiredAccess, + BOOL bInheritHandle, + DWORD dwOptions + ) +{ + PAL_ERROR palError = NO_ERROR; + IPalObject *pobjSource = NULL; + + DWORD source_process_id; + DWORD target_process_id; + DWORD cur_process_id; + + cur_process_id = GetCurrentProcessId(); + source_process_id = PROCGetProcessIDFromHandle(hSourceProcess); + target_process_id = PROCGetProcessIDFromHandle(hTargetProcess); + + /* Check validity of process handles */ + if (0 == source_process_id || 0 == target_process_id) + { + ASSERT("Can't duplicate handle: invalid source or destination process"); + palError = ERROR_INVALID_PARAMETER; + goto InternalDuplicateHandleExit; + } + + /* At least source or target process should be the current process. */ + if (source_process_id != cur_process_id + && target_process_id != cur_process_id) + { + ASSERT("Can't duplicate handle : neither source or destination" + "processes are from current process"); + palError = ERROR_INVALID_PARAMETER; + goto InternalDuplicateHandleExit; + } + + if (FALSE != bInheritHandle) + { + ASSERT("Can't duplicate handle : bInheritHandle is not FALSE.\n"); + palError = ERROR_INVALID_PARAMETER; + goto InternalDuplicateHandleExit; + } + + if (dwOptions & ~(DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE)) + { + ASSERT( + "Can't duplicate handle : dwOptions is %#x which is not " + "a subset of (DUPLICATE_SAME_ACCESS|DUPLICATE_CLOSE_SOURCE) " + "(%#x).\n", + dwOptions, + DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); + palError = ERROR_INVALID_PARAMETER; + goto InternalDuplicateHandleExit; + } + + if (0 == (dwOptions & DUPLICATE_SAME_ACCESS)) + { + ASSERT( + "Can't duplicate handle : dwOptions is %#x which does not " + "include DUPLICATE_SAME_ACCESS (%#x).\n", + dwOptions, + DUPLICATE_SAME_ACCESS); + palError = ERROR_INVALID_PARAMETER; + goto InternalDuplicateHandleExit; + } + + if (NULL == phDuplicate) + { + ASSERT("Can't duplicate handle : lpTargetHandle is NULL.\n"); + goto InternalDuplicateHandleExit; + } + + /* Since handles can be remoted to others processes using PAL_LocalHsndleToRemote + and PAL_RemoteHandleToLocal, DuplicateHandle needs some special handling + when this scenario occurs. + + if hSourceProcessHandle is from another process OR + hTargetProcessHandle is from another process but both aren't + ( handled above ) return hSourceHandle. + */ + if (source_process_id != cur_process_id + || target_process_id != cur_process_id) + { + *phDuplicate = hSource; + palError = NO_ERROR; + goto InternalDuplicateHandleExit; + } + + // + // Obtain the source IPalObject + // + + if (!HandleIsSpecial(hSource)) + { + palError = g_pObjectManager->ReferenceObjectByHandle( + pThread, + hSource, + &aotDuplicateHandle, + dwDesiredAccess, + &pobjSource + ); + + if (NO_ERROR != palError) + { + ERROR("Unable to get object for source handle %p (%i)\n", hSource, palError); + goto InternalDuplicateHandleExit; + } + } + else if (hPseudoCurrentProcess == hSource) + { + TRACE("Duplicating process pseudo handle(%p)\n", hSource); + + pobjSource = g_pobjProcess; + pobjSource->AddReference(); + } + else if (hPseudoCurrentThread == hSource) + { + TRACE("Duplicating thread pseudo handle(%p)\n", hSource); + + pobjSource = pThread->GetThreadObject(); + pobjSource->AddReference(); + } + else + { + ASSERT("Duplication not supported for this special handle (%p)\n", hSource); + palError = ERROR_INVALID_HANDLE; + goto InternalDuplicateHandleExit; + } + + palError = g_pObjectManager->ObtainHandleForObject( + pThread, + pobjSource, + dwDesiredAccess, + bInheritHandle, + NULL, + phDuplicate + ); + +InternalDuplicateHandleExit: + + if (NULL != pobjSource) + { + pobjSource->ReleaseReference(pThread); + } + + if (dwOptions & DUPLICATE_CLOSE_SOURCE) + { + // + // Since DUPLICATE_CLOSE_SOURCE was specified the source handle + // MUST be closed, even if an error occurred during the duplication + // process + // + + TRACE("DuplicateHandle closing source handle %p\n", hSource); + InternalCloseHandle(pThread, hSource); + } + + return palError; +} + +/*++ +Function: + CloseHandle + +See MSDN doc. + +Note : according to MSDN, FALSE is returned in case of error. But also +according to MSDN, closing an invalid handle raises an exception when running a +debugger [or, alternately, if a special registry key is set]. This behavior is +not required in the PAL, so we'll always return FALSE. +--*/ +BOOL +PALAPI +CloseHandle( + IN OUT HANDLE hObject) +{ + CPalThread *pThread; + PAL_ERROR palError; + + PERF_ENTRY(CloseHandle); + ENTRY("CloseHandle (hObject=%p) \n", hObject); + + pThread = InternalGetCurrentThread(); + + palError = InternalCloseHandle( + pThread, + hObject + ); + + if (NO_ERROR != palError) + { + pThread->SetLastError(palError); + } + + LOGEXIT("CloseHandle returns BOOL %d\n", (NO_ERROR == palError)); + PERF_EXIT(CloseHandle); + return (NO_ERROR == palError); +} + +PAL_ERROR +CorUnix::InternalCloseHandle( + CPalThread * pThread, + HANDLE hObject + ) +{ + PAL_ERROR palError = NO_ERROR; + + if (!HandleIsSpecial(hObject)) + { + palError = g_pObjectManager->RevokeHandle( + pThread, + hObject + ); + } + else + { + palError = CloseSpecialHandle(hObject); + } + + return palError; +} + +PAL_ERROR +CloseSpecialHandle( + HANDLE hObject + ) +{ + if ((hObject == hPseudoCurrentThread) || + (hObject == hPseudoCurrentProcess)) + { + return NO_ERROR; + } + + return ERROR_INVALID_HANDLE; +} + |