| // |
| // Copyright (c) Microsoft. All rights reserved. |
| // Licensed under the MIT license. See LICENSE file in the project root for full license 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 PAL_GLOBAL(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; |
| } |
| |