📄 objdisp.c
字号:
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
HANDLE
SC_CreateAPIHandle(
HANDLE hSet,
LPVOID pvData
)
{
PAPISET pas;
HANDLE hRet;
DEBUGMSG (!pvData, (L"SC_CreateAPIHandle: pvData == NULL\r\n"));
if ((pas = HandleToAPISetPerm(hSet)) && (pas->cinfo.disp == DISPATCH_PSL)) {
if ((hRet = AllocHandle(&pas->cinfo, pvData, CalcHandleOwner())) != 0)
return hRet;
KSetLastError(pCurThread, ERROR_NOT_ENOUGH_MEMORY);
} else
KSetLastError(pCurThread, ERROR_INVALID_PARAMETER);
return 0;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
LPVOID
SC_VerifyAPIHandle(
HANDLE hSet,
HANDLE h
)
{
PAPISET pas;
PHDATA phd;
if ((pas = HandleToAPISet(hSet)) != 0) {
if ((phd = HandleToPointer(h)) != 0
&& TestAccess(&phd->lock, &pCurThread->aky)
&& phd->pci == &pas->cinfo)
return phd->pvObj;
KSetLastError(pCurThread, ERROR_INVALID_HANDLE);
} else
KSetLastError(pCurThread, ERROR_INVALID_PARAMETER);
return 0;
}
//------------------------------------------------------------------------------
//
// @func int | QueryAPISetID | Lookup an API Set index
// @rdesc Returns the index of the requested API set (-1 if not found)
// @parm PCHAR | pName | the name of the API Set (4 characters or less)
// @comm Looks in the table of registered API Sets to find an API set with
// the requested name. If one is found, the index of that set is returned.
// If no matching set is found, then -1 is returned.
//
//------------------------------------------------------------------------------
int
SC_QueryAPISetID(
char *pName
)
{
const CINFO *pci;
char acName[4];
int inx;
for (inx = 0 ; inx < sizeof(acName) ; ++inx) {
if ((acName[inx] = *pName) != 0)
pName++;
}
if (*pName == 0) {
for (inx = 0 ; inx < NUM_SYS_HANDLES ; ++inx) {
if ((pci = SystemAPISets[inx]) != 0
&& *(PDWORD)pci->acName == *(PDWORD)acName)
return inx;
}
}
return -1;
}
//------------------------------------------------------------------------------
//
// @func DWORD | PerformCallback | Performs a call into another address space
// @rdesc Returns the return value from the called function
// @parm PCALLBACKINFO | pcbi | the callback to perform
// @parmvar Zero or more parameters to pass to the function
// @comm Switches into the address space of the process specified in the callback,
// and then calls the specified function
//
// NOTE: PerformCallBack() is implemented directly by ObjectCall().
//
// SetBadHandleError - set error code based upon handle type
//
// SetBadHandleError uses the handle type from the API call and the method
// index to determine what value to return from an API call on an invalid handle.
// If there is not default behavior, then an exception is raised.
//
//------------------------------------------------------------------------------
uint
SetBadHandleError(
int type,
long iMethod
)
{
RETAILMSG(1, (TEXT("Invalid handle: Set=%d Method=%d\r\n"), type, iMethod));
KSetLastError(pCurThread, ERROR_INVALID_HANDLE);
switch (type) {
case HT_SOCKET:
return WSAENOTSOCK;
case HT_WNETENUM:
return ERROR_INVALID_HANDLE;
case HT_FILE:
if (iMethod == 4 || iMethod == 5)
return 0xFFFFFFFF;
return 0;
case SH_CURTHREAD:
switch (iMethod) {
case ID_THREAD_SUSPEND:
case ID_THREAD_RESUME:
return 0xFFFFFFFF;
case ID_THREAD_GETTHREADPRIO:
case ID_THREAD_CEGETPRIO:
return THREAD_PRIORITY_ERROR_RETURN;
}
return 0;
case SH_CURPROC:
case SH_CURTOKEN:
return FALSE;
case HT_DBFILE:
case HT_DBFIND:
case HT_FIND:
case HT_EVENT:
case HT_APISET:
case HT_MUTEX:
case HT_FSMAP:
case HT_SEMAPHORE:
return FALSE; // just return FALSE
}
// Fault the thread.
RaiseException(STATUS_INVALID_SYSTEM_SERVICE, EXCEPTION_NONCONTINUABLE, 1, &iMethod);
DEBUGCHK(0); /* shouldn't get here */
return 0;
}
//------------------------------------------------------------------------------
// ErrorReturn - return a error value from an invalid API call
//
// This function is invoked via ObjectCall as a kernel PSL. It extracts a
// return value from the CALLSTACK's access key.
//------------------------------------------------------------------------------
uint
ErrorReturn(void)
{
uint ret;
ret = pCurThread->pcstkTop->akyLast;
pCurThread->pcstkTop->akyLast = pCurThread->aky; // Make sure that ServerCallReturn frees the CALLSTACK
return ret;
}
#ifdef NKPROF
extern DWORD g_dwProfilerFlags;
extern void ProfilerHit(RETADDR ra);
#endif
BOOL TryCloseMappedHandle(HANDLE h);
void UpdateCallerInfo (PTHREAD pth, BOOL fInKMode)
{
PCALLSTACK pcstk = pth->pcstkTop;
PPROCESS pProc;
// skip the faked callstacks for exception dispatch
while (pcstk && ((DWORD) pcstk->pcstkNext & 1)) {
pcstk = (PCALLSTACK) ((DWORD) pcstk->pcstkNext & ~1);
}
pProc = pcstk? pcstk->pprcLast : pth->pOwnerProc;
KCALLERTRUST(pth) = pProc? pProc->bTrustLevel : KERN_TRUST_FULL;
KCALLERVMBASE(pth) = pProc? pProc->dwVMBase : SECURE_VMBASE;
if (fInKMode)
KTHRDINFO(pth) |= UTLS_INKMODE;
else
KTHRDINFO(pth) &= ~UTLS_INKMODE;
// tlsNonSecure can be 0 in NKTerminateThread
if ((pth->tlsNonSecure != pth->tlsSecure) && pth->tlsNonSecure){
pth->tlsNonSecure[PRETLS_THRDINFO] = 0;
}
}
BOOL DoCloseAPIHandle (HANDLE h)
{
BOOL fRet = FALSE, fFree;
PHDATA phd;
DEBUGMSG (ZONE_OBJDISP, (TEXT("DoCloseAPIHandle: closing=%8.8lx\r\n"), h));
// decrement the reference count first to avoid RACE condition
if (phd = (PHDATA) KCall ((FARPROC) TryDecRef, h, pCurThread->pcstkTop->pprcLast, &fFree)) {
DEBUGCHK (phd->pci);
DEBUGMSG (!phd->pvObj, (L"DoCloseAPIHandle: phd->pvObj == NULL\r\n"));
// invoke the Close function
__try {
fRet = ((BOOL (*) (HANDLE)) (phd->pci->ppfnMethods[0])) (phd->pvObj);
} __except (EXCEPTION_EXECUTE_HANDLER) {
KSetLastError(pCurThread, ERROR_INVALID_PARAMETER);
}
DEBUGMSG (!fRet, (TEXT("DoCloseAPIHandle: CloseHandle failed, h = %8.8lx, proc = %8.8lx, pvObj = %8.8lx\r\n"),
h, pCurThread->pcstkTop->pprcLast, phd->pvObj));
if (!fRet) {
// close handle failed, increment the ref count back,
// last error should've been set by the real CloseHandle function
KCall (DoIncRef, h, pCurThread->pcstkTop->pprcLast, TRUE);
} else if (fFree) {
// succeed, free the handle if we're the last one referencing it
FreeHandle (h);
}
} else {
KSetLastError (pCurThread, ERROR_INVALID_PARAMETER);
}
return fRet;
}
PFNVOID GetPSLPfnAndValidateArgs (const CINFO *pci, long iMethod, LPBYTE args)
{
if (!iMethod && (DISPATCH_I_PSL == pci->disp)) {
// PSLNotify, either 0 or hCurProc/hCurThread
HANDLE hProc, hThrd;
PHDATA phd = NULL;
NextArg (args, DWORD); // skip arg 0
hProc = Arg (args, HANDLE); // arg 1 == hProc
h2p (hProc, phd);
NextArg (args, DWORD);
hThrd = Arg (args, HANDLE); // arg 2 == hThrd
if ((hProc && (!phd || !TestAccess (&phd->lock, &pCurThread->aky)))
|| (hThrd && (hThrd != hCurThread))) {
DEBUGMSG(1, (TEXT("PSLNotify : invalid argument hProc=%8.8x, hThrd = %8.8lx\r\n"), hProc, hThrd));
KSetLastError(pCurThread, ERROR_INVALID_HANDLE);
return (PFNVOID)ErrorReturn; // void function, don't need to worry about return value
}
} else {
DWORD dwSig, dwVal;
DWORD dwBase = pCurProc->dwVMBase;
BOOL bTrusted = (KERN_TRUST_FULL == pCurProc->bTrustLevel);
for (dwSig = pci->pdwSig[iMethod] ; dwSig ; dwSig >>= ARG_TYPE_BITS) {
if ((dwSig & ARG_TYPE_MASK) == ARG_PTR) {
dwVal = Arg(args, DWORD);
if (!(dwVal>>VA_SECTION)) {
if (dwVal >= 0x10000)
WriteArg(args, DWORD, dwVal += dwBase);
} else if (!bTrusted && (SC_MapPtrWithSize ((LPVOID) dwVal, 1, hCurProc) != (LPVOID)dwVal)) {
CurAKey = pCurThread->aky = pCurThread->pcstkTop->akyLast;
// invalid argument for non-trusted app. Raise exception
DEBUGMSG(1, (TEXT("Invalid Pointer Arguement for PSL (1): %lx\r\n"), dwVal));
RaiseException(STATUS_INVALID_PARAMETER_MIX, EXCEPTION_NONCONTINUABLE,
1, &dwVal);
DEBUGCHK(0); /* shouldn't get here */
}
}
NextArg(args, DWORD);
}
}
return pci->ppfnMethods[iMethod];
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
#pragma prefast(disable: 11, "Exceptio would have been raised if pci is NULL")
RETADDR ObjectCall (POBJCALLSTRUCT pobs)
{
const HDATA *phd = NULL;
const CINFO *pci;
int inx;
HANDLE h;
PPROCESS pprc;
PCALLSTACK pcstk;
PTHREAD pth;
LPVOID lpvVal;
PFNVOID pfn;
long iMethod = pobs->method;
LPBYTE args = (LPBYTE) pobs->args;
#ifdef MIPS
DEBUGCHK (!((DWORD) pobs->args & (sizeof (REG_TYPE) -1)));
#endif
//DEBUGMSG(1, (TEXT("ObjectCall: ra=%8.8lx pMode=%8.8lx iMethod=%lx args=%8.8lx dwPrevSP=%8.8lx, *pMode = %8.8lx\r\n"),
// ra, pMode, iMethod, args, dwPrevSP, *pMode));
randdw1 = ((randdw1<<5) | (randdw1>>27)) ^ (CurMSec & 0x1f);
pth = pCurThread;
/** Setup a kernel PSL CALLSTACK structure. This is done here so that
* any exceptions are handled correctly.
*/
// If this fails, we'll fault on setting the retAddr - but we'd only raise an exception if we
// were checking, anyway.
pcstk = AllocMem(HEAP_CALLSTACK);
/* Save return address, previous access key, and extra CPU dependent info */
pcstk->retAddr = pobs->ra;
pcstk->dwPrevSP = pobs->prevSP;
pcstk->akyLast = pth->aky;
pcstk->extra = pobs->linkage;
/* Save previous kernel/user mode info */
pcstk->pprcLast = pth->pProc;
pcstk->dwPrcInfo = (KERNEL_MODE == pobs->mode)? 0 : CST_MODE_FROM_USER;
/* Link the CALLSTACK struct at the head of the thread's list */
pcstk->pcstkNext = pth->pcstkTop;
pth->pcstkTop = pcstk;
DEBUGMSG(ZONE_OBJDISP, (TEXT("ObjectCall: obs = %8.8lx, ra=%8.8lx h=%8.8lx iMethod=%lx mode=%x extra=%8.8lx, prevSP = %8.8lx\r\n"),
pobs, pobs->ra, Arg(args, HANDLE), iMethod, pobs->mode, pobs->linkage, pobs->prevSP));
inx = NUM_SYS_HANDLES;
if (iMethod < 0) {
/* API call to an implicit handle. In this case, bits 30-16 of the
* method index indicate which entry in the system handle table.
*/
iMethod = -iMethod;
if ((inx = iMethod>>HANDLE_SHIFT & HANDLE_MASK) >= NUM_SYS_HANDLES
|| (pci = SystemAPISets[inx]) == 0) {
DEBUGMSG(1, (TEXT("ObjectCall: Failed(1): %lx\r\n"), inx));
RaiseException(STATUS_INVALID_SYSTEM_SERVICE, EXCEPTION_NONCONTINUABLE,
1, &iMethod);
DEBUGCHK(0); /* shouldn't get here */
}
iMethod &= METHOD_MASK;
DEBUGCHK(pci->type == 0 || pci->type == inx);
inx = pci->type;
}
/* For handle based api calls, validate the handle argument. */
if (inx) {
/* validate handle argument and turn into HDATA pointer. */
h = Arg(args, HANDLE);
h2p(h, phd);
if (!phd || !TestAccess(&phd->lock, &pth->aky)) {
if (iMethod <= 1) {
DEBUGMSG(ZONE_OBJDISP, (TEXT("CloseHandle/WaitForSingleObject: invalid handle h=%x\r\n"),
Arg(args, HANDLE)));
KSetLastError(pth, ERROR_INVALID_HANDLE);
pcstk->akyLast = (ACCESSKEY)(iMethod==0 ? 0 : WAIT_FAILED);
return (PFNVOID)ErrorReturn;
}
DEBUGMSG(ZONE_OBJDISP, (TEXT("ObjectCall: Failed (2): h=%x\r\n"), Arg(args, HANDLE)));
pcstk->akyLast = (ACCESSKEY)SetBadHandleError(inx, iMethod);
return (PFNVOID)ErrorReturn;
}
pci = phd->pci;
if (pci->type != inx && (inx != NUM_SYS_HANDLES || iMethod > 1)) {
// The handle is valid but the type is wrong.
DEBUGMSG(ZONE_OBJDISP, (TEXT("ObjectCall: Failed(2a): h=%x t=%d shdb %d\r\n"),
Arg(args, HANDLE), pci->type, inx));
pcstk->akyLast = (ACCESSKEY)SetBadHandleError(inx, iMethod);
return (PFNVOID)ErrorReturn;
}
}
/* validate interface and method indicies. */
DEBUGMSG(ZONE_OBJDISP,
(TEXT("ObjectCall: %8.8lx '%.4a' API call #%d. disp=%d.\r\n"),
pci, pci->acName, iMethod, pci->disp));
if (iMethod >= pci->cMethods) {
DEBUGMSG(1,(TEXT("ObjectCall: Failed (3): %d %d\r\n"),
iMethod, pci->cMethods));
RaiseException(STATUS_INVALID_SYSTEM_SERVICE, EXCEPTION_NONCONTINUABLE, 1, &iMethod);
DEBUGCHK(0); /* shouldn't get here */
}
pfn = 0;
/* Dispatch api call based upon the dispatch type in the cinfo struct. */
switch (pci->disp) {
case DISPATCH_KERNEL_PSL:
case DISPATCH_I_KPSL:
pfn = pci->ppfnMethods[iMethod];
if ((pfn == (PFNVOID)-1) || (pfn == (PFNVOID)-2)) {
//pobs->ra = (RETADDR) SYSCALL_RETURN;
// If you hit the following exception, you're doing a PerformCall"Forward", which is
// no longer supported since it violates security rule.
RaiseException(STATUS_INVALID_PARAMETER, EXCEPTION_NONCONTINUABLE, 0, 0);
DEBUGCHK (0); // should never get here
} else {
/* Continue the thread in kernel mode */
pcstk->dwPrcInfo |= CST_IN_KERNEL;
// GoToKernTime();
}
DEBUGMSG(ZONE_OBJDISP, (TEXT("KPSLDispatch: pci %8.8lx, fnptr %8.8lx\r\n"),
pci, pfn));
#ifdef NKPROF
if (g_dwProfilerFlags & PROFILE_OBJCALL)
ProfilerHit(pfn);
#endif
return pfn;
case DISPATCH_PSL:
lpvVal = phd->pvObj;
if (iMethod == 0) {
/* Closing this handle, decrement the reference count */
if (!TestAccess(&phd->lock, &pCurProc->aky)) {
if ((phd->lock == 1) && (phd->ref.count == 1)) {
pcstk->akyLast = TryCloseMappedHandle(h);
return (PFNVOID)ErrorReturn;
}
KSetLastError(pth, ERROR_INVALID_HANDLE);
pcstk->akyLast = 0;
return (PFNVOID)ErrorReturn;
}
pfn = DoCloseAPIHandle;
} else {
WriteArg(args, LPVOID, lpvVal);
DEBUGMSG(ZONE_OBJDISP,(TEXT("PSLDispatch: info=%8.8lx\r\n"), phd->pvObj));
}
// fall through
case DISPATCH_I_PSL:
pprc = pci->pServer;
AddAccess(&pth->aky, pprc->aky);
if (!pfn) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -