📄 objdisp.c
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// This source code is licensed under Microsoft Shared Source License
// Version 1.0 for Windows CE.
// For a copy of the license visit http://go.microsoft.com/fwlink/?LinkId=3223.
//
/*+
objdisp.c - object call dispatch routines.
This file contains the routines for dispatching method calls to objects
implemented by protected system libraries, direct kernel functions,
and kernel mode threads.
*/
#include "kernel.h"
#include "winsock.h"
#ifndef _PREFAST_
#pragma warning(disable: 4068) // Disable pragma warnings
#endif
void SC_CloseAPISet(HANDLE hSet);
BOOL SC_RegisterAPISet(HANDLE hSet, DWORD dwSetID);
LPVOID SC_VerifyAPIHandle(HANDLE hSet, HANDLE h);
//void GoToUserTime(void);
//void GoToKernTime(void);
extern CRITICAL_SECTION LLcs;
const PFNVOID APISetMethods[] = {
(PFNVOID)SC_CloseAPISet,
(PFNVOID)SC_NotSupported,
(PFNVOID)SC_RegisterAPISet,
(PFNVOID)SC_CreateAPIHandle,
(PFNVOID)SC_VerifyAPIHandle,
};
const CINFO cinfAPISet = {
"APIS",
DISPATCH_KERNEL_PSL,
HT_APISET,
sizeof(APISetMethods)/sizeof(APISetMethods[0]),
APISetMethods,
};
// Head of double linked list of active handles in the system.
DList HandleList = { &HandleList, &HandleList };
// Serial # for handle values.
unsigned int HandleSerial;
// Array of pointers to system api sets.
const CINFO *SystemAPISets[NUM_SYSTEM_SETS];
extern const CINFO cinfThread;
//------------------------------------------------------------------------------
// Find a process index from an access lock.
//------------------------------------------------------------------------------
int
IndexFromLock(
ulong lock
)
{
ulong mask;
int inxRet;
int inx;
mask = 0x0000FFFFul;
for (inxRet = 0, inx = 16 ; inx ; inx >>= 1, mask >>= inx) {
if ((lock & mask) == 0) {
inxRet += inx;
lock >>= inx;
}
}
return inxRet;
}
//------------------------------------------------------------------------------
// Insert an item into a double linked list
//------------------------------------------------------------------------------
void
AddToDList(
DList *head,
DList *item
)
{
item->back = head;
item->fwd = head->fwd;
head->fwd->back = item;
head->fwd = item;
}
//------------------------------------------------------------------------------
// Remove an item from a double linked list
//------------------------------------------------------------------------------
void
RemoveDList(
DList *item
)
{
item->fwd->back = item->back;
item->back->fwd = item->fwd;
}
//------------------------------------------------------------------------------
// Convert a HANDLE to an HDATA pointer.
//
// HandleToPointer() is a function which can be used by other kernel modules.
//
// h2p() is an private macro used to speed up the internal processing of
// ObjectCall() and the various GetXXX/SetXXX functions.
//------------------------------------------------------------------------------
#define h2p(h, phdRet) \
do { \
if ((ulong)h < NUM_SYS_HANDLES+SYS_HANDLE_BASE && (ulong)h >= SYS_HANDLE_BASE) \
h = KData.ahSys[(uint)h-SYS_HANDLE_BASE]; \
if (h) { \
phdRet = (PHDATA)(((ulong)h & HANDLE_ADDRESS_MASK) + KData.handleBase); \
if (!IsValidKPtr(phdRet) || phdRet->hValue != h) \
phdRet = 0; \
} else \
phdRet = 0; \
} while (0)
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
PHDATA
HandleToPointer(
HANDLE h
)
{
PHDATA phdRet;
h2p(h, phdRet);
return phdRet;
}
PHDATA PhdPrevReturn, PhdNext;
//------------------------------------------------------------------------------
// Return the next handle to close.
//
// The active handle list is scanned for a handle which is referenced by the process
// whose procnum is (id). (hLast) is the previous return value from this
// routine. If a handle is found, its reference count for the process is forced
// to 1 so that it will be closed by a single call to CloseHandle(). To speed up the
// iterative process of scanning the entire table, a pointer to the next handle in
// the list is retained. The next call will use that value if the list is unchanged,
// except for the possible freeing of the handle previously returned. If the list
// has changed, the scan will restart at the beginning of the list.
//
//NOTE: This function is called via KCall().
//------------------------------------------------------------------------------
PHDATA
NextCloseHandle(
PHDATA *phdLast,
int ixProc
)
{
PHDATA phd;
KCALLPROFON(7);
if (!PhdPrevReturn || !PhdNext || (*phdLast != PhdNext))
phd = (PHDATA)HandleList.fwd;
else
phd = (PHDATA)PhdNext->linkage.fwd;
DEBUGCHK(phd != 0);
if (&phd->linkage == &HandleList) {
PhdPrevReturn = 0;
KCALLPROFOFF(7);
return 0;
}
PhdPrevReturn = phd;
if ((phd->lock & (1<<ixProc)) && (phd->hValue != hCurThread) && (phd->hValue != hCurProc)) {
// Force handle reference count for this process to one.
if (phd->ref.count < 0x10000)
phd->ref.count = 1;
else
phd->ref.pFr->usRefs[ixProc] = 1;
} else {
PhdNext = *phdLast = phd;
phd = (PHDATA)((ulong)phd | 1);
}
KCALLPROFOFF(7);
return phd;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void
SC_CloseAllHandles(void)
{
PHDATA phd, next;
int ixProc;
next = 0;
ixProc = pCurProc->procnum;
while (phd = (PHDATA)KCall((PKFN)NextCloseHandle, &next, ixProc))
if (!((DWORD)phd & 1)) {
if (!CloseHandle(phd->hValue)) {
DEBUGMSG (1, (L"SC_CloseAllHandles: CloseHandle(0x%8.8lx) Failed on Process exit, zapping the handle\r\n", phd->hValue));
// we're exiting, remove the access to the handle from the process
RemoveAccess (&phd->lock, pCurProc->aky);
// process exiting and CloseHandle returned FALSE; we'll just
// zap the handle if we're the last one referencing it.
if (!phd->lock) {
FreeHandle (phd->hValue);
} else {
// if we're not the last one referencing the handle, just revoke the
// access and set the per-proc refcnt to 0
// ASSUMPTION : NextCloseHandle can not get us to this point
// unless there is a full ref count structure.
DEBUGCHK ((phd->ref.count >= 0x10000) && (1 == phd->ref.pFr->usRefs[ixProc]));
phd->ref.pFr->usRefs[ixProc] = 0;
}
}
}
}
//------------------------------------------------------------------------------
// Non-preemtible handle setup for AllocHandle().
//------------------------------------------------------------------------------
BOOL
SetupHandle(
PHDATA phdNew,
PPROCESS pprc
)
{
KCALLPROFON(8);
phdNew->hValue = (HANDLE)(((ulong)phdNew & HANDLE_ADDRESS_MASK) | 2 | (randdw1 & 0xE0000000));
LockFromKey(&phdNew->lock, &pprc->aky);
// Zap PhdPrevReturn so to force a restart the next time
// NextCloseHandle() is called.
PhdPrevReturn = 0;
AddToDList(&HandleList, &phdNew->linkage);
KCALLPROFOFF(8);
return TRUE;
}
//------------------------------------------------------------------------------
// Non-preemtible handle cleanup for FreeHandle().
//------------------------------------------------------------------------------
PHDATA
ZapHandle(
HANDLE h
)
{
PHDATA phd;
KCALLPROFON(9);
h2p(h, phd);
if (phd) {
phd->lock = 0;
// make it so that the handle no longer matches existing handles given out
DEBUGCHK(((DWORD)phd->hValue & 0x1fffffff) == (((ulong)phd & HANDLE_ADDRESS_MASK) | 2));
phd->hValue = (HANDLE)((DWORD)phd->hValue+0x20000000);
// If freeing a handle other than the last one returned by
// NextCloseHandle(), then zap PhdPrevReturn so to force
// a restart the next time NextCloseHandle() is called.
if (phd != PhdPrevReturn)
PhdPrevReturn = 0;
if (phd == PhdNext)
PhdNext = 0;
RemoveDList(&phd->linkage);
}
KCALLPROFOFF(9);
return phd;
}
//------------------------------------------------------------------------------
// Create a new handle.
//------------------------------------------------------------------------------
HANDLE
AllocHandle(
const CINFO *pci,
PVOID pvObj,
PPROCESS pprc
)
{
PHDATA phdNew;
DEBUGMSG(ZONE_MEMORY, (TEXT("AllocHandle: pci=%8.8lx pvObj=%8.8lx pprc=%8.8lx\r\n"),
pci, pvObj, pprc));
if ((phdNew = AllocMem(HEAP_HDATA)) != 0) {
phdNew->pci = pci;
phdNew->pvObj = pvObj;
phdNew->dwInfo = 0;
phdNew->ref.count = 1;
if (KCall((PKFN)SetupHandle, phdNew, pprc)) {
DEBUGMSG(ZONE_MEMORY, (TEXT("AllocHandle: phd=%8.8lx hValue=%8.8lx\r\n"),
phdNew, phdNew->hValue));
return phdNew->hValue;
}
DEBUGMSG(ZONE_MEMORY, (TEXT("AllocHandle: SetupHandle Failed!\r\n")));
FreeMem(phdNew, HEAP_HDATA);
} else
DEBUGMSG(ZONE_MEMORY, (TEXT("AllocHandle: AllocMem Failed!\r\n")));
return 0;
}
//------------------------------------------------------------------------------
// Destroy a handle.
//------------------------------------------------------------------------------
BOOL
FreeHandle(
HANDLE h
)
{
PHDATA phd;
if ((phd = (PHDATA)KCall((PKFN)ZapHandle, h)) != 0) {
if (phd->ref.count >= 0x10000)
FreeMem(phd->ref.pFr, HEAP_FULLREF);
FreeMem(phd, HEAP_HDATA);
return TRUE;
}
return FALSE;
}
//------------------------------------------------------------------------------
// Non-preemtible: copies single refcount to FULLREF.
//------------------------------------------------------------------------------
BOOL
CopyRefs(
HANDLE h,
FULLREF *pFr
)
{
PHDATA phd;
int inx;
KCALLPROFON(12);
h2p(h, phd);
if (phd && phd->ref.count < 0x10000) {
inx = IndexFromLock(phd->lock);
pFr->usRefs[inx] = (ushort)phd->ref.count;
phd->ref.pFr = pFr;
KCALLPROFOFF(12);
return FALSE;
}
KCALLPROFOFF(12);
return TRUE;
}
//------------------------------------------------------------------------------
// Non-preemtible worker for IncRef().
//------------------------------------------------------------------------------
int
DoIncRef(
HANDLE h,
PPROCESS pprc,
BOOL fAddAccess
)
{
PHDATA phd;
ACCESSKEY aky;
int inx;
KCALLPROFON(11);
aky = pprc->aky;
inx = pprc->procnum;
h2p(h, phd);
if (phd) {
if (fAddAccess) {
AddAccess(&phd->lock, aky);
}
if (phd->lock != 0) {
if (phd->ref.count < 0x10000) {
if (TestAccess(&phd->lock, &aky)) {
++phd->ref.count;
KCALLPROFOFF(11);
return 1;
}
KCALLPROFOFF(11);
return 2; // Tell IncRef to allocate a FULLREF.
}
// There is a FULLREF structure. Increment the entry for this
// process and add it to the access key.
AddAccess(&phd->lock, aky);
++phd->ref.pFr->usRefs[inx];
KCALLPROFOFF(11);
return 1;
}
}
KCALLPROFOFF(11);
return 0;
}
//------------------------------------------------------------------------------
// Returns FALSE if handle not valid or refcnt==0.
//------------------------------------------------------------------------------
BOOL
IncRef(
HANDLE h,
PPROCESS pprc
)
{
FULLREF *pFr;
int ret;
while ((ret = KCall(DoIncRef, h, pprc, FALSE)) == 2) {
// Second process referencing handle. Must allocate
// a FULLREF structure to track references from
// multiple processes.
if ((pFr = AllocMem(HEAP_FULLREF)) == 0)
return FALSE;
memset(pFr,0,sizeof(FULLREF));
if (KCall(CopyRefs, h, pFr)) {
// Another thread already allocated a FULLREF for this handle.
FreeMem(pFr, HEAP_FULLREF);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -