Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

loadunld.c File Reference

#include "iop.h"

Go to the source code of this file.

Functions

NTSTATUS NtLoadDriver (IN PUNICODE_STRING DriverServiceName)
NTSTATUS IopCheckUnloadDriver (IN PDRIVER_OBJECT driverObject, OUT PBOOLEAN unloadDriver)
NTSTATUS NtUnloadDriver (IN PUNICODE_STRING DriverServiceName)


Function Documentation

NTSTATUS IopCheckUnloadDriver IN PDRIVER_OBJECT  driverObject,
OUT PBOOLEAN  unloadDriver
 

Definition at line 181 of file loadunld.c.

References _DEVICE_OBJECT::AttachedDevice, _DEVICE_OBJECT::DeviceObjectExtension, DOE_UNLOAD_PENDING, DRVO_UNLOAD_INVOKED, _DEVOBJ_EXTENSION::ExtensionFlags, FALSE, _DEVICE_OBJECT::Flags, IopDatabaseLock, _DEVICE_OBJECT::NextDevice, NULL, ObDereferenceObject, _DEVICE_OBJECT::ReferenceCount, and TRUE.

Referenced by NtUnloadDriver().

00185 { 00186 PDEVICE_OBJECT deviceObject; 00187 KIRQL irql; 00188 00189 // 00190 // Check to see whether the driver has already been marked for an unload 00191 // operation by anyone in the past. 00192 // 00193 00194 ExAcquireSpinLock( &IopDatabaseLock, &irql ); 00195 00196 if ((driverObject->DeviceObject == NULL && 00197 (driverObject->Flags & DRVO_UNLOAD_INVOKED)) || 00198 (driverObject->DeviceObject && 00199 driverObject->DeviceObject->DeviceObjectExtension->ExtensionFlags 00200 & DOE_UNLOAD_PENDING)) { 00201 00202 // 00203 // The driver has already been marked for unload or is being 00204 // unloaded. Simply return a successful completion status since 00205 // the driver is on its way out and therefore has been "marked for 00206 // unload". 00207 // 00208 00209 ExReleaseSpinLock( &IopDatabaseLock, irql ); 00210 00211 ObDereferenceObject( driverObject ); 00212 return STATUS_SUCCESS; 00213 } 00214 00215 // 00216 // The driver exists, and it implements unload, and it has not, so far, 00217 // been marked for an unload operation. Simply mark all of the devices 00218 // that the driver owns as being marked for unload. While this is going 00219 // on, count the references for each of the devices. If all of the 00220 // devices have a zero reference count, then tell the driver that it 00221 // should unload itself. 00222 // 00223 00224 deviceObject = driverObject->DeviceObject; 00225 *unloadDriver = TRUE; 00226 00227 while (deviceObject) { 00228 deviceObject->DeviceObjectExtension->ExtensionFlags |= DOE_UNLOAD_PENDING; 00229 if (deviceObject->ReferenceCount || deviceObject->AttachedDevice) { 00230 *unloadDriver = FALSE; 00231 } 00232 deviceObject = deviceObject->NextDevice; 00233 } 00234 00235 if (*unloadDriver) { 00236 driverObject->Flags |= DRVO_UNLOAD_INVOKED; 00237 } 00238 00239 ExReleaseSpinLock( &IopDatabaseLock, irql ); 00240 return STATUS_UNSUCCESSFUL; 00241 }

NTSTATUS NtLoadDriver IN PUNICODE_STRING  DriverServiceName  ) 
 

Definition at line 35 of file loadunld.c.

References DelayedWorkQueue, _LOAD_PACKET::DriverObject, _LOAD_PACKET::DriverServiceName, _LOAD_PACKET::Event, ExAllocatePoolWithQuota, EXCEPTION_EXECUTE_HANDLER, ExFreePool(), ExInitializeWorkItem, ExQueueWorkItem(), FALSE, _LOAD_PACKET::FinalStatus, IopLoadUnloadDriver(), KeInitializeEvent, KernelMode, KeWaitForSingleObject(), KPROCESSOR_MODE, NULL, PAGED_CODE, PagedPool, ProbeAndReadUnicodeString, ProbeForRead, PsGetCurrentProcess, PsInitialSystemProcess, SeLoadDriverPrivilege, SeSinglePrivilegeCheck(), UserRequest, and _LOAD_PACKET::WorkQueueItem.

00041 : 00042 00043 This service dynamically loads a device or file system driver into 00044 the currently running system. It requires that the caller have the 00045 appropriate privilege to execute this service. 00046 00047 Arguments: 00048 00049 DriverServiceName - Specifies the name of the node in the registry 00050 associated with the driver to be loaded. 00051 00052 Return Value: 00053 00054 The status returned is the final completion status of the load operation. 00055 00056 --*/ 00057 00058 { 00059 KPROCESSOR_MODE requestorMode; 00060 UNICODE_STRING driverServiceName; 00061 PWCHAR nameBuffer = (PWCHAR) NULL; 00062 LOAD_PACKET loadPacket; 00063 00064 PAGED_CODE(); 00065 00066 // 00067 // Get the previous mode; i.e., the mode of the caller. 00068 // 00069 00070 requestorMode = KeGetPreviousMode(); 00071 00072 if (requestorMode != KernelMode) { 00073 00074 // 00075 // The caller's access mode is not kernel so check to ensure that 00076 // the caller has the privilege to load a driver and probe and 00077 // capture the name of the driver service entry. 00078 // 00079 00080 if (!SeSinglePrivilegeCheck( SeLoadDriverPrivilege, requestorMode )) { 00081 return STATUS_PRIVILEGE_NOT_HELD; 00082 } 00083 00084 // 00085 // The caller has the appropriate privilege to load and unload 00086 // drivers, so capture the driver service name string so that it 00087 // can be used to locate the driver from the registry node. 00088 // 00089 00090 try { 00091 00092 driverServiceName = ProbeAndReadUnicodeString( DriverServiceName ); 00093 00094 if (!driverServiceName.Length) { 00095 return STATUS_INVALID_PARAMETER; 00096 } 00097 00098 ProbeForRead( driverServiceName.Buffer, 00099 driverServiceName.Length, 00100 sizeof( WCHAR ) ); 00101 00102 nameBuffer = ExAllocatePoolWithQuota( PagedPool, 00103 driverServiceName.Length ); 00104 00105 RtlCopyMemory( nameBuffer, 00106 driverServiceName.Buffer, 00107 driverServiceName.Length ); 00108 00109 driverServiceName.Buffer = nameBuffer; 00110 00111 } except(EXCEPTION_EXECUTE_HANDLER) { 00112 00113 // 00114 // An exception was incurred while attempting to capture the 00115 // input name string or while attempting to allocate the name 00116 // string buffer. Simply clean everything up and return an 00117 // appropriate error status code. 00118 // 00119 00120 if (nameBuffer) { 00121 ExFreePool( nameBuffer ); 00122 } 00123 return GetExceptionCode(); 00124 } 00125 } else { 00126 driverServiceName = *DriverServiceName; 00127 } 00128 00129 // 00130 // Because drivers may wish to create a system thread and execute in 00131 // its context, the remainder of this service must be executed in the 00132 // context of the primary system process. This is accomplished by 00133 // queueing a request to one of the EX worker threads and having it 00134 // invoke the I/O system routine to complete this work. 00135 // 00136 // Fill in a request packet and queue it to the worker thread then, so 00137 // that it can actually do the load. 00138 // 00139 00140 KeInitializeEvent( &loadPacket.Event, NotificationEvent, FALSE ); 00141 loadPacket.DriverObject = (PDRIVER_OBJECT) NULL; 00142 loadPacket.DriverServiceName = &driverServiceName; 00143 00144 if (PsGetCurrentProcess() == PsInitialSystemProcess) { 00145 00146 // 00147 // If we are already in the system process, just use this thread. 00148 // 00149 00150 IopLoadUnloadDriver(&loadPacket); 00151 00152 } else { 00153 00154 ExInitializeWorkItem( &loadPacket.WorkQueueItem, 00155 IopLoadUnloadDriver, 00156 &loadPacket ); 00157 00158 ExQueueWorkItem( &loadPacket.WorkQueueItem, DelayedWorkQueue ); 00159 00160 KeWaitForSingleObject( &loadPacket.Event, 00161 UserRequest, 00162 KernelMode, 00163 FALSE, 00164 (PLARGE_INTEGER) NULL ); 00165 00166 } 00167 00168 // 00169 // The load operation is now complete. If a name buffer was allocated, 00170 // deallocate it now, and return the final status of the load operation. 00171 // 00172 00173 if (nameBuffer) { 00174 ExFreePool( nameBuffer ); 00175 } 00176 00177 return loadPacket.FinalStatus; 00178 }

NTSTATUS NtUnloadDriver IN PUNICODE_STRING  DriverServiceName  ) 
 

Definition at line 244 of file loadunld.c.

References DelayedWorkQueue, _LOAD_PACKET::DriverObject, _LOAD_PACKET::Event, ExAllocatePoolWithQuota, EXCEPTION_EXECUTE_HANDLER, Executive, ExFreePool(), ExInitializeWorkItem, ExQueueWorkItem(), FALSE, IoDriverObjectType, IopCheckUnloadDriver(), IopGetDriverNameFromKeyNode(), IopLoadUnloadDriver(), IopOpenRegistryKey(), KeInitializeEvent, KernelMode, KeWaitForSingleObject(), KPROCESSOR_MODE, NT_SUCCESS, NtClose(), NTSTATUS(), NULL, ObDereferenceObject, ObMakeTemporaryObject(), ObOpenObjectByName(), ObReferenceObjectByHandle(), PAGED_CODE, PagedPool, PDRIVER_UNLOAD, ProbeAndReadUnicodeString, ProbeForRead, PsGetCurrentProcess, PsInitialSystemProcess, SeLoadDriverPrivilege, SeSinglePrivilegeCheck(), VOID(), and _LOAD_PACKET::WorkQueueItem.

00250 : 00251 00252 This service dynamically unloads a device or file system driver from 00253 the currently running system. It requires that the caller have the 00254 appropriate privilege to execute this service. 00255 00256 Arguments: 00257 00258 DriverServiceName - Specifies the name of the node in the registry 00259 associated with the driver to be unloaded. 00260 00261 Return Value: 00262 00263 The status returned is the final completion status of the operation. 00264 00265 --*/ 00266 00267 { 00268 KPROCESSOR_MODE requestorMode; 00269 UNICODE_STRING driverServiceName; 00270 PWCHAR nameBuffer = (PWCHAR) NULL; 00271 NTSTATUS status; 00272 OBJECT_ATTRIBUTES objectAttributes; 00273 HANDLE keyHandle; 00274 UNICODE_STRING driverName; 00275 HANDLE driverHandle; 00276 PDRIVER_OBJECT driverObject; 00277 BOOLEAN unloadDriver; 00278 00279 PAGED_CODE(); 00280 00281 // 00282 // Get the previous mode; i.e., the mode of the caller. 00283 // 00284 00285 requestorMode = KeGetPreviousMode(); 00286 00287 if (requestorMode != KernelMode) { 00288 00289 // 00290 // The caller's access mode is not kernel so check to ensure that 00291 // the caller has the privilege to unload a driver and probe and 00292 // capture the name of the driver service entry. 00293 // 00294 00295 if (!SeSinglePrivilegeCheck( SeLoadDriverPrivilege, requestorMode )) { 00296 return STATUS_PRIVILEGE_NOT_HELD; 00297 } 00298 00299 // 00300 // The caller has the appropriate privilege to load and unload 00301 // drivers, so capture the driver service name string so that it 00302 // can be used to locate the driver from the registry node. 00303 // 00304 00305 try { 00306 00307 driverServiceName = ProbeAndReadUnicodeString( DriverServiceName ); 00308 00309 if (!driverServiceName.Length) { 00310 return STATUS_INVALID_PARAMETER; 00311 } 00312 00313 ProbeForRead( driverServiceName.Buffer, 00314 driverServiceName.Length, 00315 sizeof( WCHAR ) ); 00316 00317 nameBuffer = ExAllocatePoolWithQuota( PagedPool, 00318 driverServiceName.Length ); 00319 00320 RtlCopyMemory( nameBuffer, 00321 driverServiceName.Buffer, 00322 driverServiceName.Length ); 00323 00324 driverServiceName.Buffer = nameBuffer; 00325 00326 } except(EXCEPTION_EXECUTE_HANDLER) { 00327 00328 // 00329 // An exception was incurred while attempting to capture the 00330 // input name string or while attempting to allocate the name 00331 // string buffer. Simply clean everything up and return an 00332 // appropriate error status code. 00333 // 00334 00335 if (nameBuffer) { 00336 ExFreePool( nameBuffer ); 00337 } 00338 return GetExceptionCode(); 00339 } 00340 00341 // 00342 // Now that the caller's parameters have been captured and everything 00343 // appears to have checked out, actually attempt to unload the driver. 00344 // This is done with a previous mode of kernel so that drivers will 00345 // not fail to unload because the caller didn't happen to have access 00346 // to some resource that the driver needs in order to complete its 00347 // unload operation. 00348 // 00349 00350 status = ZwUnloadDriver( &driverServiceName ); 00351 ExFreePool( nameBuffer ); 00352 return status; 00353 } 00354 00355 // 00356 // The caller's mode is now kernel mode. Attempt to actually unload the 00357 // driver specified by the indicated registry node. Begin by opening 00358 // the registry node for this driver. 00359 // 00360 00361 status = IopOpenRegistryKey( &keyHandle, 00362 (HANDLE) NULL, 00363 DriverServiceName, 00364 KEY_READ, 00365 FALSE ); 00366 if (!NT_SUCCESS( status )) { 00367 return status; 00368 } 00369 00370 // 00371 // Get the optional object name for this driver from the value for this 00372 // key. If one exists, then its name overrides the default name of the 00373 // driver. 00374 // 00375 00376 status = IopGetDriverNameFromKeyNode( keyHandle, 00377 &driverName ); 00378 NtClose( keyHandle ); 00379 if (!NT_SUCCESS( status )) { 00380 return status; 00381 } 00382 00383 // 00384 // Now attempt to open the driver object for the specified driver. 00385 // 00386 00387 InitializeObjectAttributes( &objectAttributes, 00388 &driverName, 00389 OBJ_CASE_INSENSITIVE, 00390 (HANDLE) NULL, 00391 (PSECURITY_DESCRIPTOR) NULL ); 00392 00393 status = ObOpenObjectByName( &objectAttributes, 00394 IoDriverObjectType, 00395 KernelMode, 00396 NULL, 00397 FILE_READ_DATA, 00398 (PVOID) NULL, 00399 &driverHandle ); 00400 00401 // 00402 // Perform some common cleanup by getting rid of buffers that have been 00403 // allocated up to this point so that error conditions do not have as 00404 // much work to do on each exit path. 00405 // 00406 00407 ExFreePool( driverName.Buffer ); 00408 00409 // 00410 // If the driver object could not be located in the first place, then 00411 // return now before attempting to do anything else. 00412 // 00413 00414 if (!NT_SUCCESS( status )) { 00415 return status; 00416 } 00417 00418 // 00419 // The driver object was located, so convert the handle into a pointer 00420 // so that the driver object itself can be examined. 00421 // 00422 00423 status = ObReferenceObjectByHandle( driverHandle, 00424 0, 00425 IoDriverObjectType, 00426 KernelMode, 00427 (PVOID *) &driverObject, 00428 NULL ); 00429 NtClose( driverHandle ); 00430 00431 if (!NT_SUCCESS( status )) { 00432 return status; 00433 } 00434 00435 // 00436 // Check to see whether or not this driver implements unload. Also, 00437 // if the driver has no section associated with it, then it was loaded 00438 // be the OS loader and therefore cannot be unloaded. If either is true, 00439 // return an appropriate error status code. 00440 // 00441 00442 if (driverObject->DriverUnload == (PDRIVER_UNLOAD) NULL || 00443 !driverObject->DriverSection) { 00444 ObDereferenceObject( driverObject ); 00445 return STATUS_INVALID_DEVICE_REQUEST; 00446 } 00447 00448 // 00449 // Check to see whether the driver has already been marked for an unload 00450 // operation by anyone in the past. 00451 // 00452 00453 status = IopCheckUnloadDriver(driverObject,&unloadDriver); 00454 00455 if ( NT_SUCCESS(status) ) { 00456 return status; 00457 } 00458 00459 if (unloadDriver) { 00460 00461 if (PsGetCurrentProcess() == PsInitialSystemProcess) { 00462 00463 // 00464 // The current thread is alrady executing in the context of the 00465 // system process, so simply invoke the driver's unload routine. 00466 // 00467 00468 driverObject->DriverUnload( driverObject ); 00469 00470 } else { 00471 00472 // 00473 // The current thread is not executing in the context of the system 00474 // process, which is required in order to invoke the driver's unload 00475 // routine. Queue a worker item to one of the worker threads to 00476 // get into the appropriate process context and then invoke the 00477 // routine. 00478 // 00479 00480 LOAD_PACKET loadPacket; 00481 00482 KeInitializeEvent( &loadPacket.Event, NotificationEvent, FALSE ); 00483 loadPacket.DriverObject = driverObject; 00484 ExInitializeWorkItem( &loadPacket.WorkQueueItem, 00485 IopLoadUnloadDriver, 00486 &loadPacket ); 00487 ExQueueWorkItem( &loadPacket.WorkQueueItem, DelayedWorkQueue ); 00488 (VOID) KeWaitForSingleObject( &loadPacket.Event, 00489 Executive, 00490 KernelMode, 00491 FALSE, 00492 (PLARGE_INTEGER) NULL ); 00493 } 00494 ObMakeTemporaryObject( driverObject ); 00495 ObDereferenceObject( driverObject ); 00496 } 00497 00498 // 00499 // The driver has either been unloaded, or it has successfully been 00500 // marked for an unload operation. Simply dereference the pointer to 00501 // the object and return success. 00502 // 00503 00504 ObDereferenceObject( driverObject ); 00505 return STATUS_SUCCESS; 00506 } }


Generated on Sat May 15 19:44:33 2004 for test by doxygen 1.3.7