Leaked source code of windows server 2003
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.

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