Mapping the User Space Memory

Hi All,

Im using APC mechanism to notify a user application from the kernel and using KeIntilizeAPC() and KeInsertQueueAPC().

I register a callback function and user level memory buffer using IOCTL.

Kernel notifies the user application of some event via this registered callback function and passes some data along with it. The event data it copies to the user level memory buffer using RtlCopyMemory().

But actually kernel fails to copy the data to the user memory buffer. Please suggest some mechanism so that the desired functionality is achieved.

Code to register APC callback function:

case IOCTL_VPE_REG_USER_APC:

{

UINT32 cap_status;

UINT32 *ret_val;

AR_PRegUserApc puser_apc;

puser_apc = ( AR_PRegUserApc ) user_buffer;

cap_status = cap_see_register_apc(puser_apc);

ret_val = (UINT16 * ) user_buffer;

*ret_val= cap_status;

Irp->IoStatus.Status = STATUS_SUCCESS;

Irp->IoStatus.Information = sizeof(UINT32);

IoCompleteRequest(Irp,IO_NO_INCREMENT);

return STATUS_SUCCESS;

}

AR_SEE_STATUS

cap_see_register_apc(AR_PRegUserApc puser_apc)

{

/* Should be global and in nonPaged Pool */

PKTHREAD pTargetThread = KeGetCurrentThread();

/**/

//PKNORMAL_ROUTINE gblNormalRtn;

pPoolTargetThread = (PKTHREAD)ExAllocatePool(NonPagedPool,sizeof(PKTHREAD));

pPoolTargetThread = pTargetThread;

gblAPCRtn = (PKNORMAL_ROUTINE)ExAllocatePool(NonPagedPool,sizeof(PKNORMAL_ROUTINE));

gblAPCRtn = (PKNORMAL_ROUTINE)puser_apc->target_proc;

gblEvtMemory = ExAllocatePool(NonPagedPool,sizeof(void *));

gblEvtMemory = puser_apc->evtMemory;

return AR_SEE_SUCCESS;

}

Code to queue apc and to copy data:


void QueueUserAPC(HANDLE pID,

unsigned long evtDev,

unsigned long evtType,

unsigned long evtLen,

void * data

)

{

PKAPC pKAPC;

PKKERNEL_ROUTINE lclKernelRtn = // Point to driver routine that will be used as kernel routine.

(PKKERNEL_ROUTINE)KrnlRoutine;

KAPC_ENVIRONMENT lclEnvironment;

UCHAR lclApcMode = UserMode;

// eventT ApcData;

struct APCData ApcData;

ApcData.data1 = 1;

ApcData.data2 = 2;

ApcData.devHandle = evtDev;

ApcData.digits[0] = ‘3’;

ApcData.evtDev = evtDev;

ApcData.evtLen = evtLen;

ApcData.evtType = evtType;

ApcData.opernResult = 4;

ApcData.pID = pID;

RtlCopyMemory(gblEvtMemory,(void *)&ApcData,sizeof(ApcData));

pKAPC = (PKAPC)ExAllocatePoolWithTag( // Allocate space for KAPC object.

NonPagedPool,

sizeof(KAPC),

‘jaja’

);

if (NULL==pKAPC)

{

return;

}

// Inasmuch as errors (BSODs) arose in KeInsertQueueApc with certain combinations of parameters in KeInitializeApc,

// clear the KAPC first.

memset(pKAPC, 0, sizeof(KAPC));

lclEnvironment = CurrentApcEnvironment;

/*

* this apc informs the user mode api that there is a pending evvent in the event queue of the kernel

* and that an ioctl must be issued to retreive it. Also the event dispatcher in the user mode

* is intelligent enough to decide , to whom this event is to be dispatched

*/

KeInitializeApc(

pKAPC,

pPoolTargetThread,

lclEnvironment,

lclKernelRtn,

NULL,

gblAPCRtn,

lclApcMode,

((PVOID)NULL)

);

KeInsertQueueApc(

pKAPC,

NULL,

NULL,

0);

*((unsigned char *)pPoolTargetThread+0x4a) = 1; // Set KAPC_STATE.UserApcPending on.

}

Regards,
Rajeev

Instead of using undocumented routines, implement a proper kernel to
user mode notification mechanism. There are plenty of documented ones
(complete a pending IOCTL from user-mode, signal a named event waited on
by user-mode, etc.); explore the articles at www.osronline.com for tips.

Rajeev Gaba wrote:

Hi All,

Im using APC mechanism to notify a user application from the kernel and
using KeIntilizeAPC() and KeInsertQueueAPC().

I register a callback function and user level memory buffer using IOCTL.

Kernel notifies the user application of some event via this registered
callback function and passes some data along with it. The event data it
copies to the user level memory buffer using RtlCopyMemory().

But actually kernel fails to copy the data to the user memory buffer.
Please suggest some mechanism so that the desired functionality is achieved.

Code to register APC callback function:

case IOCTL_VPE_REG_USER_APC:

{

UINT32 cap_status;

UINT32 *ret_val;

AR_PRegUserApc puser_apc;

puser_apc = ( AR_PRegUserApc ) user_buffer;

cap_status = cap_see_register_apc(puser_apc);

ret_val = (UINT16 * ) user_buffer;

*ret_val= cap_status;

Irp->IoStatus.Status = STATUS_SUCCESS;

Irp->IoStatus.Information = sizeof(UINT32);

IoCompleteRequest(Irp,IO_NO_INCREMENT);

return STATUS_SUCCESS;

}

AR_SEE_STATUS

cap_see_register_apc(AR_PRegUserApc puser_apc)

{

/* Should be global and in nonPaged Pool */

PKTHREAD pTargetThread = KeGetCurrentThread();

/**/

//PKNORMAL_ROUTINE gblNormalRtn;

pPoolTargetThread = (PKTHREAD)ExAllocatePool(NonPagedPool,sizeof(PKTHREAD));

pPoolTargetThread = pTargetThread;

gblAPCRtn =
(PKNORMAL_ROUTINE)ExAllocatePool(NonPagedPool,sizeof(PKNORMAL_ROUTINE));

gblAPCRtn = (PKNORMAL_ROUTINE)puser_apc->target_proc;

gblEvtMemory = ExAllocatePool(NonPagedPool,sizeof(void *));

gblEvtMemory = puser_apc->evtMemory;

return AR_SEE_SUCCESS;

}

Code to queue apc and to copy data:


void QueueUserAPC(HANDLE pID,

unsigned long evtDev,

unsigned long evtType,

unsigned long evtLen,

void * data

)

{

PKAPC pKAPC;

PKKERNEL_ROUTINE lclKernelRtn = // Point to driver routine that will be
used as kernel routine.

(PKKERNEL_ROUTINE)KrnlRoutine;

KAPC_ENVIRONMENT lclEnvironment;

UCHAR lclApcMode = UserMode;

// eventT ApcData;

struct APCData ApcData;

ApcData.data1 = 1;

ApcData.data2 = 2;

ApcData.devHandle = evtDev;

ApcData.digits[0] = ‘3’;

ApcData.evtDev = evtDev;

ApcData.evtLen = evtLen;

ApcData.evtType = evtType;

ApcData.opernResult = 4;

ApcData.pID = pID;

RtlCopyMemory(gblEvtMemory,(void *)&ApcData,sizeof(ApcData));

pKAPC = (PKAPC)ExAllocatePoolWithTag( // Allocate space for KAPC object.

NonPagedPool,

sizeof(KAPC),

‘jaja’

);

if (NULL==pKAPC)

{

return;

}

// Inasmuch as errors (BSODs) arose in KeInsertQueueApc with certain
combinations of parameters in KeInitializeApc,

// clear the KAPC first.

memset(pKAPC, 0, sizeof(KAPC));

lclEnvironment = CurrentApcEnvironment;

/*

* this apc informs the user mode api that there is a pending evvent in
the event queue of the kernel

* and that an ioctl must be issued to retreive it. Also the event
dispatcher in the user mode

* is intelligent enough to decide , to whom this event is to be dispatched

*/

KeInitializeApc(

pKAPC,

pPoolTargetThread,

lclEnvironment,

lclKernelRtn,

NULL,

gblAPCRtn,

lclApcMode,

((PVOID)NULL)

);

KeInsertQueueApc(

pKAPC,

NULL,

NULL,

0);

*((unsigned char *)pPoolTargetThread+0x4a) = 1; // Set
KAPC_STATE.UserApcPending on.

}

Regards,
Rajeev


Nick Ryan (MVP for DDK)