Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

531 lines
16 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. loadunld.c
  5. Abstract:
  6. This module contains the code to implement the NtLoadDriver and
  7. NtUnLoadDriver system services for the NT I/O system.
  8. Author:
  9. Darryl E. Havens (darrylh) 5-Apr-1992
  10. Environment:
  11. Kernel mode only
  12. Revision History:
  13. --*/
  14. #include "iomgr.h"
  15. #ifdef ALLOC_PRAGMA
  16. #pragma alloc_text(PAGE, NtLoadDriver)
  17. #pragma alloc_text(PAGE, NtUnloadDriver)
  18. #endif
  19. NTSTATUS
  20. NtLoadDriver(
  21. IN PUNICODE_STRING DriverServiceName
  22. )
  23. /*++
  24. Routine Description:
  25. This service dynamically loads a device or file system driver into
  26. the currently running system. It requires that the caller have the
  27. appropriate privilege to execute this service.
  28. Arguments:
  29. DriverServiceName - Specifies the name of the node in the registry
  30. associated with the driver to be loaded.
  31. Return Value:
  32. The status returned is the final completion status of the load operation.
  33. --*/
  34. {
  35. KPROCESSOR_MODE requestorMode;
  36. UNICODE_STRING driverServiceName;
  37. PWCHAR nameBuffer = (PWCHAR) NULL;
  38. LOAD_PACKET loadPacket;
  39. PETHREAD CurrentThread;
  40. PAGED_CODE();
  41. //
  42. // Get the previous mode; i.e., the mode of the caller.
  43. //
  44. CurrentThread = PsGetCurrentThread ();
  45. requestorMode = KeGetPreviousModeByThread(&CurrentThread->Tcb);
  46. if (requestorMode != KernelMode) {
  47. //
  48. // The caller's access mode is not kernel so check to ensure that
  49. // the caller has the privilege to load a driver and probe and
  50. // capture the name of the driver service entry.
  51. //
  52. if (!SeSinglePrivilegeCheck( SeLoadDriverPrivilege, requestorMode )) {
  53. return STATUS_PRIVILEGE_NOT_HELD;
  54. }
  55. //
  56. // The caller has the appropriate privilege to load and unload
  57. // drivers, so capture the driver service name string so that it
  58. // can be used to locate the driver from the registry node.
  59. //
  60. try {
  61. driverServiceName = ProbeAndReadUnicodeString( DriverServiceName );
  62. if (!driverServiceName.Length) {
  63. return STATUS_INVALID_PARAMETER;
  64. }
  65. ProbeForRead( driverServiceName.Buffer,
  66. driverServiceName.Length,
  67. sizeof( WCHAR ) );
  68. nameBuffer = ExAllocatePoolWithQuota( PagedPool,
  69. driverServiceName.Length );
  70. RtlCopyMemory( nameBuffer,
  71. driverServiceName.Buffer,
  72. driverServiceName.Length );
  73. driverServiceName.Buffer = nameBuffer;
  74. } except(EXCEPTION_EXECUTE_HANDLER) {
  75. //
  76. // An exception was incurred while attempting to capture the
  77. // input name string or while attempting to allocate the name
  78. // string buffer. Simply clean everything up and return an
  79. // appropriate error status code.
  80. //
  81. if (nameBuffer) {
  82. ExFreePool( nameBuffer );
  83. }
  84. return GetExceptionCode();
  85. }
  86. } else {
  87. driverServiceName = *DriverServiceName;
  88. }
  89. //
  90. // Because drivers may wish to create a system thread and execute in
  91. // its context, the remainder of this service must be executed in the
  92. // context of the primary system process. This is accomplished by
  93. // queueing a request to one of the EX worker threads and having it
  94. // invoke the I/O system routine to complete this work.
  95. //
  96. // Fill in a request packet and queue it to the worker thread then, so
  97. // that it can actually do the load.
  98. //
  99. KeInitializeEvent( &loadPacket.Event, NotificationEvent, FALSE );
  100. loadPacket.DriverObject = (PDRIVER_OBJECT) NULL;
  101. loadPacket.DriverServiceName = &driverServiceName;
  102. if (PsGetCurrentProcessByThread(CurrentThread) == PsInitialSystemProcess) {
  103. //
  104. // If we are already in the system process, just use this thread.
  105. //
  106. IopLoadUnloadDriver(&loadPacket);
  107. } else {
  108. ExInitializeWorkItem( &loadPacket.WorkQueueItem,
  109. IopLoadUnloadDriver,
  110. &loadPacket );
  111. ExQueueWorkItem( &loadPacket.WorkQueueItem, DelayedWorkQueue );
  112. KeWaitForSingleObject( &loadPacket.Event,
  113. UserRequest,
  114. KernelMode,
  115. FALSE,
  116. (PLARGE_INTEGER) NULL );
  117. }
  118. //
  119. // The load operation is now complete. If a name buffer was allocated,
  120. // deallocate it now, and return the final status of the load operation.
  121. //
  122. if (nameBuffer) {
  123. ExFreePool( nameBuffer );
  124. }
  125. return loadPacket.FinalStatus;
  126. }
  127. NTSTATUS
  128. IopCheckUnloadDriver(
  129. IN PDRIVER_OBJECT driverObject,
  130. OUT PBOOLEAN unloadDriver
  131. )
  132. {
  133. PDEVICE_OBJECT deviceObject;
  134. KIRQL irql;
  135. //
  136. // Check to see whether the driver has already been marked for an unload
  137. // operation by anyone in the past.
  138. //
  139. irql = KeAcquireQueuedSpinLock( LockQueueIoDatabaseLock );
  140. if ((driverObject->DeviceObject == NULL &&
  141. (driverObject->Flags & DRVO_UNLOAD_INVOKED)) ||
  142. (!(driverObject->Flags & DRVO_BASE_FILESYSTEM_DRIVER) && driverObject->DeviceObject &&
  143. driverObject->DeviceObject->DeviceObjectExtension->ExtensionFlags
  144. & DOE_UNLOAD_PENDING)) {
  145. //
  146. // The driver has already been marked for unload or is being
  147. // unloaded. Simply return a successful completion status since
  148. // the driver is on its way out and therefore has been "marked for
  149. // unload".
  150. //
  151. KeReleaseQueuedSpinLock( LockQueueIoDatabaseLock, irql );
  152. ObDereferenceObject( driverObject );
  153. return STATUS_SUCCESS;
  154. }
  155. //
  156. // The driver exists, and it implements unload, and it has not, so far,
  157. // been marked for an unload operation. Simply mark all of the devices
  158. // that the driver owns as being marked for unload. While this is going
  159. // on, count the references for each of the devices. If all of the
  160. // devices have a zero reference count, then tell the driver that it
  161. // should unload itself.
  162. //
  163. deviceObject = driverObject->DeviceObject;
  164. *unloadDriver = TRUE;
  165. while (deviceObject) {
  166. deviceObject->DeviceObjectExtension->ExtensionFlags |= DOE_UNLOAD_PENDING;
  167. if (deviceObject->ReferenceCount || deviceObject->AttachedDevice) {
  168. *unloadDriver = FALSE;
  169. }
  170. deviceObject = deviceObject->NextDevice;
  171. }
  172. //
  173. // If this is a base filesystem driver then delay the unload until all its device objects
  174. // are deleted.
  175. //
  176. if (driverObject->Flags & DRVO_BASE_FILESYSTEM_DRIVER && driverObject->DeviceObject) {
  177. *unloadDriver = FALSE;
  178. }
  179. if (*unloadDriver) {
  180. driverObject->Flags |= DRVO_UNLOAD_INVOKED;
  181. }
  182. KeReleaseQueuedSpinLock( LockQueueIoDatabaseLock, irql );
  183. return STATUS_UNSUCCESSFUL;
  184. }
  185. NTSTATUS
  186. NtUnloadDriver(
  187. IN PUNICODE_STRING DriverServiceName
  188. )
  189. {
  190. return (IopUnloadDriver(DriverServiceName, FALSE));
  191. }
  192. NTSTATUS
  193. IopUnloadDriver(
  194. IN PUNICODE_STRING DriverServiceName,
  195. IN BOOLEAN InvokedByPnpMgr
  196. )
  197. /*++
  198. Routine Description:
  199. This service dynamically unloads a device or file system driver from
  200. the currently running system. It requires that the caller have the
  201. appropriate privilege to execute this service.
  202. Arguments:
  203. DriverServiceName - Specifies the name of the node in the registry
  204. associated with the driver to be unloaded.
  205. Return Value:
  206. The status returned is the final completion status of the operation.
  207. --*/
  208. {
  209. KPROCESSOR_MODE requestorMode;
  210. UNICODE_STRING driverServiceName;
  211. PWCHAR nameBuffer = (PWCHAR) NULL;
  212. NTSTATUS status;
  213. OBJECT_ATTRIBUTES objectAttributes;
  214. HANDLE keyHandle;
  215. UNICODE_STRING driverName;
  216. HANDLE driverHandle;
  217. PDRIVER_OBJECT driverObject;
  218. BOOLEAN unloadDriver;
  219. PAGED_CODE();
  220. //
  221. // Get the previous mode; i.e., the mode of the caller.
  222. //
  223. requestorMode = KeGetPreviousMode();
  224. if ((requestorMode != KernelMode) && (InvokedByPnpMgr == FALSE)) {
  225. //
  226. // The caller's access mode is not kernel so check to ensure that
  227. // the caller has the privilege to unload a driver and probe and
  228. // capture the name of the driver service entry.
  229. //
  230. if (!SeSinglePrivilegeCheck( SeLoadDriverPrivilege, requestorMode )) {
  231. return STATUS_PRIVILEGE_NOT_HELD;
  232. }
  233. //
  234. // The caller has the appropriate privilege to load and unload
  235. // drivers, so capture the driver service name string so that it
  236. // can be used to locate the driver from the registry node.
  237. //
  238. try {
  239. driverServiceName = ProbeAndReadUnicodeString( DriverServiceName );
  240. if (!driverServiceName.Length) {
  241. return STATUS_INVALID_PARAMETER;
  242. }
  243. ProbeForRead( driverServiceName.Buffer,
  244. driverServiceName.Length,
  245. sizeof( WCHAR ) );
  246. nameBuffer = ExAllocatePoolWithQuota( PagedPool,
  247. driverServiceName.Length );
  248. RtlCopyMemory( nameBuffer,
  249. driverServiceName.Buffer,
  250. driverServiceName.Length );
  251. driverServiceName.Buffer = nameBuffer;
  252. } except(EXCEPTION_EXECUTE_HANDLER) {
  253. //
  254. // An exception was incurred while attempting to capture the
  255. // input name string or while attempting to allocate the name
  256. // string buffer. Simply clean everything up and return an
  257. // appropriate error status code.
  258. //
  259. if (nameBuffer) {
  260. ExFreePool( nameBuffer );
  261. }
  262. return GetExceptionCode();
  263. }
  264. //
  265. // Now that the caller's parameters have been captured and everything
  266. // appears to have checked out, actually attempt to unload the driver.
  267. // This is done with a previous mode of kernel so that drivers will
  268. // not fail to unload because the caller didn't happen to have access
  269. // to some resource that the driver needs in order to complete its
  270. // unload operation.
  271. //
  272. status = ZwUnloadDriver( &driverServiceName );
  273. ExFreePool( nameBuffer );
  274. return status;
  275. }
  276. //
  277. // The caller's mode is now kernel mode. Attempt to actually unload the
  278. // driver specified by the indicated registry node. Begin by opening
  279. // the registry node for this driver.
  280. //
  281. status = IopOpenRegistryKey( &keyHandle,
  282. (HANDLE) NULL,
  283. DriverServiceName,
  284. KEY_READ,
  285. FALSE );
  286. if (!NT_SUCCESS( status )) {
  287. return status;
  288. }
  289. //
  290. // Get the optional object name for this driver from the value for this
  291. // key. If one exists, then its name overrides the default name of the
  292. // driver.
  293. //
  294. status = IopGetDriverNameFromKeyNode( keyHandle,
  295. &driverName );
  296. NtClose( keyHandle );
  297. if (!NT_SUCCESS( status )) {
  298. return status;
  299. }
  300. //
  301. // Now attempt to open the driver object for the specified driver.
  302. //
  303. InitializeObjectAttributes( &objectAttributes,
  304. &driverName,
  305. OBJ_CASE_INSENSITIVE,
  306. (HANDLE) NULL,
  307. (PSECURITY_DESCRIPTOR) NULL );
  308. status = ObOpenObjectByName( &objectAttributes,
  309. IoDriverObjectType,
  310. KernelMode,
  311. NULL,
  312. FILE_READ_DATA,
  313. (PVOID) NULL,
  314. &driverHandle );
  315. //
  316. // Perform some common cleanup by getting rid of buffers that have been
  317. // allocated up to this point so that error conditions do not have as
  318. // much work to do on each exit path.
  319. //
  320. ExFreePool( driverName.Buffer );
  321. //
  322. // If the driver object could not be located in the first place, then
  323. // return now before attempting to do anything else.
  324. //
  325. if (!NT_SUCCESS( status )) {
  326. return status;
  327. }
  328. //
  329. // The driver object was located, so convert the handle into a pointer
  330. // so that the driver object itself can be examined.
  331. //
  332. status = ObReferenceObjectByHandle( driverHandle,
  333. 0,
  334. IoDriverObjectType,
  335. KernelMode,
  336. (PVOID *) &driverObject,
  337. NULL );
  338. NtClose( driverHandle );
  339. if (!NT_SUCCESS( status )) {
  340. return status;
  341. }
  342. //
  343. // Check to see whether or not this driver implements unload. Also,
  344. // if the driver has no section associated with it, then it was loaded
  345. // be the OS loader and therefore cannot be unloaded. If either is true,
  346. // return an appropriate error status code.
  347. //
  348. if (driverObject->DriverUnload == (PDRIVER_UNLOAD) NULL ||
  349. !driverObject->DriverSection) {
  350. ObDereferenceObject( driverObject );
  351. return STATUS_INVALID_DEVICE_REQUEST;
  352. }
  353. if (!InvokedByPnpMgr && !IopIsLegacyDriver(driverObject)) {
  354. ObDereferenceObject( driverObject );
  355. return STATUS_INVALID_DEVICE_REQUEST;
  356. }
  357. //
  358. // Check to see whether the driver has already been marked for an unload
  359. // operation by anyone in the past.
  360. //
  361. status = IopCheckUnloadDriver(driverObject,&unloadDriver);
  362. if ( NT_SUCCESS(status) ) {
  363. return status;
  364. }
  365. if (unloadDriver) {
  366. if (PsGetCurrentProcess() == PsInitialSystemProcess) {
  367. //
  368. // The current thread is alrady executing in the context of the
  369. // system process, so simply invoke the driver's unload routine.
  370. //
  371. driverObject->DriverUnload( driverObject );
  372. } else {
  373. //
  374. // The current thread is not executing in the context of the system
  375. // process, which is required in order to invoke the driver's unload
  376. // routine. Queue a worker item to one of the worker threads to
  377. // get into the appropriate process context and then invoke the
  378. // routine.
  379. //
  380. LOAD_PACKET loadPacket;
  381. KeInitializeEvent( &loadPacket.Event, NotificationEvent, FALSE );
  382. loadPacket.DriverObject = driverObject;
  383. ExInitializeWorkItem( &loadPacket.WorkQueueItem,
  384. IopLoadUnloadDriver,
  385. &loadPacket );
  386. ExQueueWorkItem( &loadPacket.WorkQueueItem, DelayedWorkQueue );
  387. (VOID) KeWaitForSingleObject( &loadPacket.Event,
  388. Executive,
  389. KernelMode,
  390. FALSE,
  391. (PLARGE_INTEGER) NULL );
  392. }
  393. ObMakeTemporaryObject( driverObject );
  394. ObDereferenceObject( driverObject );
  395. }
  396. //
  397. // The driver has either been unloaded, or it has successfully been
  398. // marked for an unload operation. Simply dereference the pointer to
  399. // the object and return success.
  400. //
  401. ObDereferenceObject( driverObject );
  402. return STATUS_SUCCESS;
  403. }