RE: Anything to be aware of when calling ZwOpenSemaph-ore, ZwOpenMutant, ZwOpenEvent?

I’ll try to answer by some new questions:

  1. You’re using C++ new/delete keywords. Is this absolutely safe?
  2. Must your objects have name? Is the name hardcoded in both
    the driver and service?
  3. I think it is not neccessary to use routines like ZwOpenMutant
    because you don’t need handles. Have you ever tried to use
    routines like ObReferenceObjectByName ?
    There is a little problem: only ExEventObjectType is exported.
    You must obtain pointers to other types by using the same routine
    (ObReferenceObjectByName) and names L"\ObjectType\Mutant"
    and L"\ObjectType\Semaphore" and store them to your global
    POBJECT_TYPE variables (you can choose their real names -
    ExMutantObjectType and ExSemaphoreObjectType).
    This code should be in the INIT section - called from DriverEntry.
    Try not forget to dereference all type pointers and all
    what you have referenced and already not need to be referenced.
    To maintain objects you can now use KeXxxx routines
    'cause you have pointers (for eg. KeReleaseMutant, KePulseEvent, …).
  4. You use spin lock in the SFilterCreate. Is this routine really in
    .text section (ie. not in any PAGEd section) ?

Try to think on this and let me know your suggestion.
If I forget something please remember me.

Paul

Paul,

The headers that I reference come from Nebbett that should be correct.
For unexported api like ZwOpenSemaphore & ZwOpenMutex, I follow
Prasad Dabak’s suggestion - dynamically detects the IDs in an User-Mode
service, then use IOCTL send them to filter driver before use.

In Kernel, I define

_declspec(naked)
NTSTATUS NTAPI
ZwOpenSemaphore(

)
{
_asm {
mov eax, GlobalSemId
lea edx, [esp+4]
int 2eh,
ret 0Ch
}
}

I believe the above work without problem because using SoftICE to trace,
all return success status.

The page fault is guaranteed to happen I do not set breakpoint in the
suspected section of code. Let me explain how I use them as clearly as
possible here.

All the creation of memory mapped file, event, mutex, semaphoe object
are done in User-mode service. The kernel mode filter driver’s role is
to open or read these kernel objects.

The single writer multiple readers guard is implemented exactly as what
was in Advanced Windows 3rd SWMRG by replacing win32 api with related
native win32 api using conditional compilation.

typedef struct SingleWriterMultiReaderGuard {
HANDLE hMutex;
HANDLE hEvent;
HANDLE hSemaphore;
} SWMRG, *PSWMRG;

In the constructor of the object that govern the memory-mapped section
that shared by all clients including the filesystem filter driver,
I do SWMRGInitialize to intialize these kernel object and in
destructor, I do the reverse to close the handle. The SWMRG is a member
of that class.

Before access the section, a SWMRGWaitToRead is issued and after
that SWMRGDoneReading is issued. Again the filter driver is only
concerning reading the data out of the section.

I use the sample as provided in Nagar’s NT Filesystem Internals as my
template. The place that I use the above object is when I got an
IRP_MJ_CREATE and it is handled in SFilterCreate in the sample.

If the SWMRG is disabled using conditional compilation, the below
pseudo code does not present any problem. If enabled, the page fault
seems can happen anywhere after the MYCACHE creation, even after the
final block.

NTSTATUS SFilterCreate(…)
{
__try {
…some standard stuff
ExAcquireResourceExclusiveLite(&(pDevExt->DevExtRes),TRUE);
AcquiredExtension = TRUE;

//my stuff is plugged below
if (IRP is directed to attached device)
{
bool bCheck = false;

//object to open the section and initialize SWMRG
MYCACHE* pmc = new MYCACHE(…);
if (pmc && mc->search(…)) {
bCheck = true; // continue to check
}
if (pmc)
delete pmc;

if (bCheck)
{
KeAcquireSpinLock(&(GlobalData.FilterSpinLock), &oldIrql);
// In SuspendCreate routine, I do the following
// pIrpList = allocate nonpagedpool space
// IoSetCancelRoutine(Irp, MyCancelRoutine);
// pIrpList = Irp;
// store pIrpList into internal queue
// Irp->IoStatus.Status = STATUS_PENDING;
// IoMarkIrpPending(Irp);
SuspendCreate(…);

// In ServeRequest routine, I do the following
// pIrpList = dequeue an IRP stored by the User-Mode service
// copy info into pIrpList->pIrp->AssociatedIrp.SystemBuffer
// pIrpList->pIrp->IoStatus.Status = STATUS_SUCCESS;
// pIrpList->pIrp->IoStatus.Information = …datasize;
// IoCompleteRequest(pIrpList->pIrp, IO_NO_INCREMENT);
// pIrpList->pIrp=0;
// ExFreePool(pIrpList);
ServeRequest(…);

KeReleaseSpinLock(&(GlobalData.FilterSpinLock), oldIrql);
RC = STATUS_PENDING;
}
if (AcquiredExtension)
{
SFilterReleaseResource(…);
AcquiredExtension = FALSE;
}
if (!bCheck)
{
// for request that is not queued, send to lower driver
RC = SFilterDefaultDispatch(DeviceObject, Irp);
}
} else if (target to filter driver itself) {
// I don’t care
CompleteIrp = TRUE;
RC = STATUS_SUCCESS;
} else {
CompleteIrp = TRUE;
RC = STATUS_INVALID_DEVICE_REQUEST;
}
} __finally {
if (AcquiredExtension) {…proper cleanup}
if (CompleteIrp) {
Irp->IoStatus.Status = RC;
Irp->IoStatus.Information = ReturnedInformation;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
}
}

I hope I’ve condensed my code to a reasonable form and let me know
if you need me to provide any more details.

I appreciate your patience and help !

Thanx,

Jack Cheng
(Curriculum Corp.)