blob: 8cd88407ca9c85db87d9e82aeaf2247da2f54305 [file]
//
// 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;
}