Previous Next

Errors in Referencing User-Space Addresses

Any driver, whether supporting IRPs or fast I/O operations, should validate any address in user space before trying to use it. The I/O Manager does not validate such addresses, nor does it validate pointers that are embedded in buffers passed to drivers.

Failure to Validate Addresses Passed in METHOD_NEITHER IOCTLs and FSCTLs

The I/O Manager does no validation whatsoever for METHOD_NEITHER IOCTLs and FSCTLs. To ensure that user-space addresses are valid, the driver must use the ProbeForRead and ProbeForWrite routines, enclosing all buffer references in try/except blocks.

In the following example, the driver assumes that the value passed in the Type3InputBuffer represents a valid address.

   case IOCTL_GET_HANDLER: {
      PULONG EntryPoint;

      EntryPoint =
         IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
      *EntryPoint = (ULONG) DriverEntryPoint; 

The following code avoids this problem:

   case IOCTL_GET_HANDLER: {
      PULONG_PTR EntryPoint;

      EntryPoint =
         IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
                 
 try {                 
   if (Irp->RequestorMode != KernelMode) { 
       ProbeForWrite( EntryPoint,
                      sizeof( ULONG_PTR ),
                      TYPE_ALIGNMENT( ULONG_PTR ));
   }
   *EntryPoint = (ULONG_PTR)DriverEntryPoint;

 } except( EXCEPTION_EXECUTE_HANDLER ) {
…

Note also that the correct code casts DriverEntryPoint to a ULONG_PTR, instead of a ULONG. This change allows for use in a 64-bit Windows environment.

Failure to validate pointers embedded in buffered I/O requests

Often drivers embed pointers within buffered requests, as in the following example:

   struct ret_buf {
      void   *arg; // Pointer embedded in request
      int     rval;
   };

   pBuf = Irp->AssociatedIrp.SystemBuffer;
   ...
   arg = pBuf->arg; // Fetch the embedded pointer
   ...
   // If the pointer is invalid, 
   //this statement can corrupt the system.
   RtlMoveMemory(arg, &info, sizeof(info));

In this example, the driver should validate the embedded pointer by using the ProbeXxx routines enclosed in a try/except block in the same way as for the METHOD_NEITHER IOCTLs described earlier. Although embedding a pointer allows a driver to return extra information, a driver can more efficiently achieve the same result by using a relative offset or a variable length buffer.

For more information about using try/except blocks to handle invalid addresses, see Handling Exceptions.