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

objsup.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1989-1993 Microsoft Corporation 00004 00005 Module Name: 00006 00007 objsup.c 00008 00009 Abstract: 00010 00011 This module contains the object support routine for the NT I/O system. 00012 00013 Author: 00014 00015 Darryl E. Havens (darrylh) 30-May-1989 00016 00017 Environment: 00018 00019 Kernel mode only 00020 00021 Revision History: 00022 00023 00024 --*/ 00025 00026 #include "iop.h" 00027 00028 #ifdef ALLOC_PRAGMA 00029 #pragma alloc_text(PAGE, IopCloseFile) 00030 #pragma alloc_text(PAGE, IopDeleteDevice) 00031 #pragma alloc_text(PAGE, IopDeleteDriver) 00032 #pragma alloc_text(PAGE, IopGetSetSecurityObject) 00033 #endif 00034 00035 VOID 00036 IopCloseFile( 00037 IN PEPROCESS Process OPTIONAL, 00038 IN PVOID Object, 00039 IN ULONG GrantedAccess, 00040 IN ULONG ProcessHandleCount, 00041 IN ULONG SystemHandleCount 00042 ) 00043 00044 /*++ 00045 00046 Routine Description: 00047 00048 This routine is invoked whenever a handle to a file is deleted. If the 00049 handle being deleted is the last handle to the file (the ProcessHandleCount 00050 parameter is one), then all locks for the file owned by the specified 00051 process must be released. 00052 00053 Likewise, if the SystemHandleCount is one then this is the last handle 00054 for this for file object across all processes. For this case, the file 00055 system is notified so that it can perform any necessary cleanup on the 00056 file. 00057 00058 Arguments: 00059 00060 Process - A pointer to the process that closed the handle. 00061 00062 Object - A pointer to the file object that the handle referenced. 00063 00064 GrantedAccess - Access that was granted to the object through the handle. 00065 00066 ProcessHandleCount - Count of handles outstanding to the object for the 00067 process specified by the Process argument. If the count is one 00068 then this is the last handle to this file by that process. 00069 00070 SystemHandleCount - Count of handles outstanding to the object for the 00071 entire system. If the count is one then this is the last handle 00072 to this file in the system. 00073 00074 Return Value: 00075 00076 None. 00077 00078 --*/ 00079 00080 { 00081 PIRP irp; 00082 PIO_STACK_LOCATION irpSp; 00083 PDEVICE_OBJECT deviceObject; 00084 PFAST_IO_DISPATCH fastIoDispatch; 00085 NTSTATUS status; 00086 KEVENT event; 00087 PFILE_OBJECT fileObject; 00088 KIRQL irql; 00089 00090 UNREFERENCED_PARAMETER( Process ); 00091 UNREFERENCED_PARAMETER( GrantedAccess ); 00092 00093 PAGED_CODE(); 00094 00095 // 00096 // If the handle count is not one then this is not the last close of 00097 // this file for the specified process so there is nothing to do. 00098 // 00099 00100 if (ProcessHandleCount != 1) { 00101 return; 00102 } 00103 00104 fileObject = (PFILE_OBJECT) Object; 00105 00106 if (fileObject->LockOperation && SystemHandleCount != 1) { 00107 00108 IO_STATUS_BLOCK localIoStatus; 00109 00110 // 00111 // This is the last handle for the specified process and the process 00112 // called the NtLockFile or NtUnlockFile system services at least once. 00113 // Also, this is not the last handle for this file object system-wide 00114 // so unlock all of the pending locks for this process. Note that 00115 // this check causes an optimization so that if this is the last 00116 // system-wide handle to this file object the cleanup code will take 00117 // care of releasing any locks on the file rather than having to 00118 // send the file system two different packets to get them shut down. 00119 00120 // 00121 // Get the address of the target device object and the Fast I/O dispatch 00122 // 00123 00124 if (!(fileObject->Flags & FO_DIRECT_DEVICE_OPEN)) { 00125 deviceObject = IoGetRelatedDeviceObject( fileObject ); 00126 } else { 00127 deviceObject = IoGetAttachedDevice( fileObject->DeviceObject ); 00128 } 00129 fastIoDispatch = deviceObject->DriverObject->FastIoDispatch; 00130 00131 // 00132 // If this file is open for synchronous I/O, wait until this thread 00133 // owns it exclusively since there may still be a thread using it. 00134 // This occurs when a system service owns the file because it owns 00135 // the semaphore, but the I/O completion code has already dereferenced 00136 // the file object itself. Without waiting here for the same semaphore 00137 // there would be a race condition in the service who owns it now. The 00138 // service needs to be able to access the object w/o it going away after 00139 // its wait for the file event is satisfied. 00140 // 00141 00142 if (fileObject->Flags & FO_SYNCHRONOUS_IO) { 00143 00144 BOOLEAN interrupted; 00145 00146 if (!IopAcquireFastLock( fileObject )) { 00147 (VOID) IopAcquireFileObjectLock( fileObject, 00148 KernelMode, 00149 FALSE, 00150 &interrupted ); 00151 } 00152 } 00153 00154 // 00155 // Turbo unlock support. If the fast Io Dispatch specifies a fast lock 00156 // routine then we'll first try and calling it with the specified lock 00157 // parameters. If this is all successful then we do not need to do 00158 // the Irp based unlock all call. 00159 // 00160 00161 if (fastIoDispatch && 00162 fastIoDispatch->FastIoUnlockAll && 00163 fastIoDispatch->FastIoUnlockAll( fileObject, 00164 PsGetCurrentProcess(), 00165 &localIoStatus, 00166 deviceObject )) { 00167 00168 NOTHING; 00169 00170 } else { 00171 00172 // 00173 // Initialize the local event that will be used to synchronize access 00174 // to the driver completing this I/O operation. 00175 // 00176 00177 KeInitializeEvent( &event, SynchronizationEvent, FALSE ); 00178 00179 // 00180 // Reset the event in the file object. 00181 // 00182 00183 KeClearEvent( &fileObject->Event ); 00184 00185 // 00186 // Allocate and initialize the I/O Request Packet (IRP) for this 00187 // operation. 00188 // 00189 00190 irp = IopAllocateIrpMustSucceed( deviceObject->StackSize ); 00191 irp->Tail.Overlay.OriginalFileObject = fileObject; 00192 irp->Tail.Overlay.Thread = PsGetCurrentThread(); 00193 irp->RequestorMode = KernelMode; 00194 00195 // 00196 // Fill in the service independent parameters in the IRP. 00197 // 00198 00199 irp->UserEvent = &event; 00200 irp->UserIosb = &irp->IoStatus; 00201 irp->Flags = IRP_SYNCHRONOUS_API; 00202 irp->Overlay.AsynchronousParameters.UserApcRoutine = (PIO_APC_ROUTINE) NULL; 00203 00204 // 00205 // Get a pointer to the stack location for the first driver. This will 00206 // be used to pass the original function codes and parameters. No 00207 // function-specific parameters are required for this operation. 00208 // 00209 00210 irpSp = IoGetNextIrpStackLocation( irp ); 00211 irpSp->MajorFunction = IRP_MJ_LOCK_CONTROL; 00212 irpSp->MinorFunction = IRP_MN_UNLOCK_ALL; 00213 irpSp->FileObject = fileObject; 00214 00215 // 00216 // Reference the fileobject again for the IRP (cleared on completion) 00217 // 00218 00219 ObReferenceObject( fileObject ); 00220 00221 // 00222 // Insert the packet at the head of the IRP list for the thread. 00223 // 00224 00225 IopQueueThreadIrp( irp ); 00226 00227 // 00228 // Invoke the driver at its appropriate dispatch entry with the IRP. 00229 // 00230 00231 status = IoCallDriver( deviceObject, irp ); 00232 00233 // 00234 // If no error was incurred, wait for the I/O operation to complete. 00235 // 00236 00237 if (status == STATUS_PENDING) { 00238 (VOID) KeWaitForSingleObject( &event, 00239 UserRequest, 00240 KernelMode, 00241 FALSE, 00242 (PLARGE_INTEGER) NULL ); 00243 } 00244 } 00245 00246 // 00247 // If this operation was a synchronous I/O operation, release the 00248 // semaphore so that the file can be used by other threads. 00249 // 00250 00251 if (fileObject->Flags & FO_SYNCHRONOUS_IO) { 00252 IopReleaseFileObjectLock( fileObject ); 00253 } 00254 } 00255 00256 if (SystemHandleCount == 1) { 00257 00258 // 00259 // The last handle to this file object for all of the processes in the 00260 // system has just been closed, so invoke the driver's "cleanup" handler 00261 // for this file. This is the file system's opportunity to remove any 00262 // share access information for the file, to indicate that if the file 00263 // is opened for a caching operation and this is the last file object 00264 // to the file, then it can do whatever it needs with memory management 00265 // to cleanup any information. 00266 // 00267 // Begin by getting the address of the target device object. 00268 // 00269 00270 if (!(fileObject->Flags & FO_DIRECT_DEVICE_OPEN)) { 00271 deviceObject = IoGetRelatedDeviceObject( fileObject ); 00272 } else { 00273 deviceObject = IoGetAttachedDevice( fileObject->DeviceObject ); 00274 } 00275 00276 // 00277 // Ensure that the I/O system believes that this file has a handle 00278 // associated with it in case it doesn't actually get one from the 00279 // Object Manager. This is done because sometimes the Object Manager 00280 // actually creates a handle, but the I/O system never finds out 00281 // about it so it attempts to send two cleanups for the same file. 00282 // 00283 00284 fileObject->Flags |= FO_HANDLE_CREATED; 00285 00286 // 00287 // If this file is open for synchronous I/O, wait until this thread 00288 // owns it exclusively since there may still be a thread using it. 00289 // This occurs when a system service owns the file because it owns 00290 // the semaphore, but the I/O completion code has already dereferenced 00291 // the file object itself. Without waiting here for the same semaphore 00292 // there would be a race condition in the service who owns it now. The 00293 // service needs to be able to access the object w/o it going away after 00294 // its wait for the file event is satisfied. 00295 // 00296 00297 if (fileObject->Flags & FO_SYNCHRONOUS_IO) { 00298 00299 BOOLEAN interrupted; 00300 00301 if (!IopAcquireFastLock( fileObject )) { 00302 (VOID) IopAcquireFileObjectLock( fileObject, 00303 KernelMode, 00304 FALSE, 00305 &interrupted ); 00306 } 00307 } 00308 00309 // 00310 // Initialize the local event that will be used to synchronize access 00311 // to the driver completing this I/O operation. 00312 // 00313 00314 KeInitializeEvent( &event, SynchronizationEvent, FALSE ); 00315 00316 // 00317 // Reset the event in the file object. 00318 // 00319 00320 KeClearEvent( &fileObject->Event ); 00321 00322 // 00323 // Allocate and initialize the I/O Request Packet (IRP) for this 00324 // operation. 00325 // 00326 00327 irp = IopAllocateIrpMustSucceed( deviceObject->StackSize ); 00328 irp->Tail.Overlay.OriginalFileObject = fileObject; 00329 irp->Tail.Overlay.Thread = PsGetCurrentThread(); 00330 irp->RequestorMode = KernelMode; 00331 00332 // 00333 // Fill in the service independent parameters in the IRP. 00334 // 00335 00336 irp->UserEvent = &event; 00337 irp->UserIosb = &irp->IoStatus; 00338 irp->Overlay.AsynchronousParameters.UserApcRoutine = (PIO_APC_ROUTINE) NULL; 00339 irp->Flags = IRP_SYNCHRONOUS_API | IRP_CLOSE_OPERATION; 00340 00341 // 00342 // Get a pointer to the stack location for the first driver. This will 00343 // be used to pass the original function codes and parameters. No 00344 // function-specific parameters are required for this operation. 00345 // 00346 00347 irpSp = IoGetNextIrpStackLocation( irp ); 00348 irpSp->MajorFunction = IRP_MJ_CLEANUP; 00349 irpSp->FileObject = fileObject; 00350 00351 // 00352 // Insert the packet at the head of the IRP list for the thread. 00353 // 00354 00355 IopQueueThreadIrp( irp ); 00356 00357 // 00358 // Update the operation count statistic for the current process for 00359 // operations other than read and write. 00360 // 00361 00362 IopUpdateOtherOperationCount(); 00363 00364 // 00365 // Invoke the driver at its appropriate dispatch entry with the IRP. 00366 // 00367 00368 status = IoCallDriver( deviceObject, irp ); 00369 00370 // 00371 // If no error was incurred, wait for the I/O operation to complete. 00372 // 00373 00374 if (status == STATUS_PENDING) { 00375 (VOID) KeWaitForSingleObject( &event, 00376 UserRequest, 00377 KernelMode, 00378 FALSE, 00379 (PLARGE_INTEGER) NULL ); 00380 } 00381 00382 // 00383 // The following code tears down the IRP by hand since it may not 00384 // either be possible to it to be completed (because this code was 00385 // invoked as APC_LEVEL in the first place - or because the reference 00386 // count on the object cannot be incremented due to this routine 00387 // being invoked by the delete file procedure below). Cleanup IRPs 00388 // therefore use close sematics (the close operation flag is set 00389 // in the IRP) so that the I/O complete request routine itself sets 00390 // the event to the Signaled state. 00391 // 00392 00393 KeRaiseIrql( APC_LEVEL, &irql ); 00394 IopDequeueThreadIrp( irp ); 00395 KeLowerIrql( irql ); 00396 00397 // 00398 // Also, free the IRP. 00399 // 00400 00401 IoFreeIrp( irp ); 00402 00403 // 00404 // If this operation was a synchronous I/O operation, release the 00405 // semaphore so that the file can be used by other threads. 00406 // 00407 00408 if (fileObject->Flags & FO_SYNCHRONOUS_IO) { 00409 IopReleaseFileObjectLock( fileObject ); 00410 } 00411 } 00412 00413 return; 00414 } 00415 00416 VOID 00417 IopDeleteFile( 00418 IN PVOID Object 00419 ) 00420 00421 /*++ 00422 00423 Routine Description: 00424 00425 This routine is invoked when the last handle to a specific file handle is 00426 being closed and the file object is going away. It is the responsibility 00427 of this routine to perform the following functions: 00428 00429 o Notify the device driver that the file object is open on that the 00430 file is being closed. 00431 00432 o Dereference the user's error port for the file object, if there 00433 is one associated with the file object. 00434 00435 o Decrement the device object reference count. 00436 00437 Arguments: 00438 00439 Object - Pointer to the file object being deleted. 00440 00441 Return Value: 00442 00443 None. 00444 00445 --*/ 00446 00447 { 00448 PIRP irp; 00449 PIO_STACK_LOCATION irpSp; 00450 PDEVICE_OBJECT deviceObject; 00451 IO_STATUS_BLOCK ioStatusBlock; 00452 KIRQL irql; 00453 NTSTATUS status; 00454 PFILE_OBJECT fileObject; 00455 KEVENT event; 00456 PVPB vpb; 00457 BOOLEAN referenceCountDecremented; 00458 00459 // 00460 // Obtain a pointer to the file object. 00461 // 00462 00463 fileObject = (PFILE_OBJECT) Object; 00464 00465 // 00466 // Get a pointer to the first device driver which should be notified that 00467 // this file is going away. If the device driver field is NULL, then this 00468 // file is being shut down due to an error attempting to get it open in the 00469 // first place, so do not do any further processing. 00470 // 00471 00472 if (fileObject->DeviceObject) { 00473 if (!(fileObject->Flags & FO_DIRECT_DEVICE_OPEN)) { 00474 deviceObject = IoGetRelatedDeviceObject( fileObject ); 00475 } else { 00476 deviceObject = IoGetAttachedDevice( fileObject->DeviceObject ); 00477 } 00478 00479 // 00480 // If this file has never had a file handle created for it, and yet 00481 // it exists, invoke the close file procedure so that the file system 00482 // gets the cleanup IRP it is expecting before sending the close IRP. 00483 // 00484 00485 if (!(fileObject->Flags & FO_HANDLE_CREATED)) { 00486 IopCloseFile( (PEPROCESS) NULL, 00487 Object, 00488 0, 00489 1, 00490 1 ); 00491 } 00492 00493 // 00494 // If this file is open for synchronous I/O, wait until this thread 00495 // owns it exclusively since there may still be a thread using it. 00496 // This occurs when a system service owns the file because it owns 00497 // the semaphore, but the I/O completion code has already dereferenced 00498 // the file object itself. Without waiting here for the same semaphore 00499 // there would be a race condition in the service who owns it now. The 00500 // service needs to be able to access the object w/o it going away after 00501 // its wait for the file event is satisfied. 00502 // 00503 00504 if (fileObject->Flags & FO_SYNCHRONOUS_IO) { 00505 00506 BOOLEAN interrupted; 00507 00508 if (!IopAcquireFastLock( fileObject )) { 00509 (VOID) IopAcquireFileObjectLock( fileObject, 00510 KernelMode, 00511 FALSE, 00512 &interrupted ); 00513 } 00514 } 00515 00516 // 00517 // Reset a local event that can be used to wait for the device driver 00518 // to close the file. 00519 // 00520 00521 KeInitializeEvent( &event, SynchronizationEvent, FALSE ); 00522 00523 // 00524 // Reset the event in the file object. 00525 // 00526 00527 KeClearEvent( &fileObject->Event ); 00528 00529 // 00530 // Allocate an I/O Request Packet (IRP) to be used in communicating with 00531 // the appropriate device driver that the file is being closed. Notice 00532 // that the allocation of this packet is done without charging quota so 00533 // that the operation will not fail. This is done because there is no 00534 // way to return an error to the caller at this point. 00535 // 00536 00537 irp = IoAllocateIrp( deviceObject->StackSize, FALSE ); 00538 if (!irp) { 00539 irp = IopAllocateIrpMustSucceed( deviceObject->StackSize ); 00540 } 00541 00542 // 00543 // Get a pointer to the stack location for the first driver. This is 00544 // where the function codes and parameters are placed. 00545 // 00546 00547 irpSp = IoGetNextIrpStackLocation( irp ); 00548 00549 // 00550 // Fill in the IRP, indicating that this file object is being deleted. 00551 // 00552 00553 irpSp->MajorFunction = IRP_MJ_CLOSE; 00554 irpSp->FileObject = fileObject; 00555 irp->UserIosb = &ioStatusBlock; 00556 irp->UserEvent = &event; 00557 irp->Tail.Overlay.OriginalFileObject = fileObject; 00558 irp->Tail.Overlay.Thread = PsGetCurrentThread(); 00559 irp->AssociatedIrp.SystemBuffer = (PVOID) NULL; 00560 irp->Flags = IRP_CLOSE_OPERATION | IRP_SYNCHRONOUS_API; 00561 00562 // 00563 // Place this packet in the thread's I/O pending queue. 00564 // 00565 00566 IopQueueThreadIrp( irp ); 00567 00568 // 00569 // Decrement the reference count on the VPB, if necessary. We 00570 // have to do this BEFORE handing the Irp to the file system 00571 // because of a trick the file systems play with close, and 00572 // believe me, you really don't want to know what it is. 00573 // 00574 // Since there is not a error path here (close cannot fail), 00575 // and the file system is the only ome who can actually synchronize 00576 // with the actual completion of close processing, the file system 00577 // is the one responsible for Vpb deletion. 00578 // 00579 00580 vpb = fileObject->Vpb; 00581 00582 if (vpb && !(fileObject->Flags & FO_DIRECT_DEVICE_OPEN)) { 00583 ExInterlockedAddUlong( &vpb->ReferenceCount, 00584 0xffffffff, 00585 &IopVpbSpinLock ); 00586 } 00587 00588 // 00589 // If this device object has stated for a fact that it knows it will 00590 // never have the final non-zero reference count among the other 00591 // device objects associated with our driver object, then decrement 00592 // our reference count here BEFORE calling the file system. This 00593 // is required because for a special class of device objects, the 00594 // file system may delete them. 00595 // 00596 00597 if (fileObject->DeviceObject->Flags & DO_NEVER_LAST_DEVICE) { 00598 ExInterlockedAddUlong( &fileObject->DeviceObject->ReferenceCount, 00599 0xffffffff, 00600 &IopDatabaseLock ); 00601 00602 referenceCountDecremented = TRUE; 00603 } else { 00604 referenceCountDecremented = FALSE; 00605 } 00606 00607 // 00608 // Give the device driver the packet. If this request does not work, 00609 // there is nothing that can be done about it. This is unfortunate 00610 // because the driver may have had problems that it was about to 00611 // report about other operations (e.g., write behind failures, etc.) 00612 // that it can no longer report. The reason is that this routine 00613 // is really initially invoked by NtClose, which has already closed 00614 // the caller's handle, and that's what the return status from close 00615 // indicates: the handle has successfully been closed. 00616 // 00617 00618 status = IoCallDriver( deviceObject, irp ); 00619 00620 if (status == STATUS_PENDING) { 00621 (VOID) KeWaitForSingleObject( &event, 00622 Executive, 00623 KernelMode, 00624 FALSE, 00625 (PLARGE_INTEGER) NULL ); 00626 } 00627 00628 // 00629 // Perform any completion operations that need to be performed on 00630 // the IRP that was used for this request. This is done here as 00631 // as opposed to in normal completion code because there is a race 00632 // condition between when this routine executes if it was invoked 00633 // from a special kernel APC (e.g., some IRP was just completed and 00634 // dereferenced this file object for the last time), and when the 00635 // special kernel APC because of this packet's completion executing. 00636 // 00637 // This problem is solved by not having to queue a special kernel 00638 // APC routine for completion of this packet. Rather, it is treated 00639 // much like a synchronous paging I/O operation, except that the 00640 // packet is not even freed during I/O completion. This is because 00641 // the packet is still in this thread's queue, and there is no way 00642 // to get it out except at APC_LEVEL. Unfortunately, the part of 00643 // I/O completion that needs to dequeue the packet is running at 00644 // DISPATCH_LEVEL. 00645 // 00646 // Hence, the packet must be removed from the queue (synchronized, 00647 // of course), and then it must be freed. 00648 // 00649 00650 KeRaiseIrql( APC_LEVEL, &irql ); 00651 IopDequeueThreadIrp( irp ); 00652 KeLowerIrql( irql ); 00653 00654 IoFreeIrp( irp ); 00655 00656 // 00657 // Free the file name string buffer if there was one. 00658 // 00659 00660 if (fileObject->FileName.Length != 0) { 00661 ExFreePool( fileObject->FileName.Buffer ); 00662 } 00663 00664 // 00665 // If there was an completion port associated w/this file object, dereference 00666 // it now, and deallocate the completion context pool. 00667 // 00668 00669 if (fileObject->CompletionContext) { 00670 ObDereferenceObject( fileObject->CompletionContext->Port ); 00671 ExFreePool( fileObject->CompletionContext ); 00672 } 00673 00674 // 00675 // Get a pointer to the real device object so its reference count 00676 // can be decremented. 00677 // 00678 00679 deviceObject = fileObject->DeviceObject; 00680 00681 // 00682 // Decrement the reference count on the device object. Note that 00683 // if the driver has been marked for an unload operation, and the 00684 // reference count goes to zero, then the driver may need to be 00685 // unloaded at this point. 00686 // 00687 // Note: only do this if the reference count was not already done 00688 // above. The device object may be gone in this case. 00689 // 00690 00691 if (!referenceCountDecremented) { 00692 IopDecrementDeviceObjectRef( deviceObject, FALSE ); 00693 } 00694 } 00695 } 00696 00697 VOID 00698 IopDeleteDriver( 00699 IN PVOID Object 00700 ) 00701 00702 /*++ 00703 00704 Routine Description: 00705 00706 This routine is invoked when the reference count for a driver object 00707 becomes zero. That is, the last reference for the driver has gone away. 00708 This routine ensures that the object is cleaned up and the driver 00709 unloaded. 00710 00711 Arguments: 00712 00713 Object - Pointer to the driver object whose reference count has gone 00714 to zero. 00715 00716 Return value: 00717 00718 None. 00719 00720 --*/ 00721 00722 { 00723 PDRIVER_OBJECT driverObject = (PDRIVER_OBJECT) Object; 00724 PIO_CLIENT_EXTENSION extension; 00725 PIO_CLIENT_EXTENSION nextExtension; 00726 00727 PAGED_CODE(); 00728 00729 ASSERT( !driverObject->DeviceObject ); 00730 00731 // 00732 // Free any client driver object extensions. 00733 // 00734 00735 extension = driverObject->DriverExtension->ClientDriverExtension; 00736 while (extension != NULL) { 00737 00738 nextExtension = extension->NextExtension; 00739 ExFreePool( extension ); 00740 extension = nextExtension; 00741 } 00742 00743 // 00744 // If there is a driver section then unload the driver. 00745 // 00746 00747 if (driverObject->DriverSection != NULL) { 00748 MmUnloadSystemImage( driverObject->DriverSection ); 00749 } 00750 00751 // 00752 // Free the pool associated with the name of the driver. 00753 // 00754 00755 if (driverObject->DriverName.Buffer) { 00756 ExFreePool( driverObject->DriverName.Buffer ); 00757 } 00758 00759 // 00760 // Free the pool associated with the service key name of the driver. 00761 // 00762 00763 if (driverObject->DriverExtension->ServiceKeyName.Buffer) { 00764 ExFreePool( driverObject->DriverExtension->ServiceKeyName.Buffer ); 00765 } 00766 } 00767 00768 VOID 00769 IopDeleteDevice( 00770 IN PVOID Object 00771 ) 00772 00773 /*++ 00774 00775 Routine Description: 00776 00777 This routine is invoked when the reference count for a device object 00778 becomes zero. That is, the last reference for the device has gone away. 00779 This routine ensures that the object is cleaned up and the driver object 00780 is dereferenced. 00781 00782 Arguments: 00783 00784 Object - Pointer to the driver object whose reference count has gone 00785 to zero. 00786 00787 Return value: 00788 00789 None. 00790 00791 --*/ 00792 00793 { 00794 PDEVICE_OBJECT deviceObject = (PDEVICE_OBJECT) Object; 00795 PVPB vpb = NULL; 00796 00797 PAGED_CODE(); 00798 00799 IopDestroyDeviceNode(deviceObject->DeviceObjectExtension->DeviceNode); 00800 00801 #if DBG 00802 IopCheckDeviceNodeTree (deviceObject, NULL); 00803 #endif 00804 00805 // 00806 // If there's still a VPB attached then free it. 00807 // 00808 00809 vpb = InterlockedExchangePointer(&(deviceObject->Vpb), vpb); 00810 00811 if(vpb != NULL) { 00812 00813 ASSERTMSG("Unreferenced device object to be deleted is still in use", 00814 ((vpb->Flags & (VPB_MOUNTED | VPB_LOCKED)) == 0)); 00815 00816 ASSERT(vpb->ReferenceCount == 0); 00817 ExFreePool(vpb); 00818 } 00819 if (deviceObject->DriverObject != NULL) { 00820 ObDereferenceObject( deviceObject->DriverObject ); 00821 } 00822 } 00823 00824 00825 PDEVICE_OBJECT 00826 IopGetDevicePDO( 00827 IN PDEVICE_OBJECT DeviceObject 00828 ) 00829 /*++ 00830 00831 Routine Description: 00832 00833 Call this routine to obtain the Base PDO for a device object 00834 00835 Arguments: 00836 00837 DeviceObject - pointer to device object to get PDO for 00838 00839 ReturnValue: 00840 00841 PDO if DeviceObject is attached to a PDO, otherwise NULL 00842 The returned PDO is reference-counted 00843 00844 --*/ 00845 { 00846 PDEVICE_OBJECT deviceBaseObject; 00847 KIRQL irql; 00848 00849 ASSERT(DeviceObject); 00850 00851 IopAcquireEnumerationLock(NULL); // ensure we have acquired P&P locks 00852 00853 ExAcquireSpinLock(&IopDatabaseLock,&irql); 00854 deviceBaseObject = IopGetDeviceAttachmentBase(DeviceObject); 00855 if ((deviceBaseObject->Flags & DO_BUS_ENUMERATED_DEVICE) != 0) { 00856 // 00857 // we have determined that this is attached to a PDO 00858 // 00859 ObReferenceObject( deviceBaseObject ); 00860 00861 } else { 00862 // 00863 // not a PDO 00864 // 00865 deviceBaseObject = NULL; 00866 } 00867 ExReleaseSpinLock(&IopDatabaseLock,irql); 00868 00869 IopReleaseEnumerationLock(NULL); 00870 00871 return deviceBaseObject; 00872 } 00873 00874 00875 00876 NTSTATUS 00877 IopSetDeviceSecurityDescriptors( 00878 IN PDEVICE_OBJECT DeviceObject, 00879 IN PSECURITY_INFORMATION SecurityInformation, 00880 IN PSECURITY_DESCRIPTOR SecurityDescriptor, 00881 IN POOL_TYPE PoolType, 00882 IN PGENERIC_MAPPING GenericMapping, 00883 IN BOOLEAN DoAttachedDevices 00884 ) 00885 /*++ 00886 00887 Routine Description: 00888 00889 Call this routine to set device security descriptor 00890 00891 Arguments: 00892 00893 DeviceObject - pointer to base device object (first one to set) 00894 SecurityInformation )_ passed directly from IopGetSetSecurityObject 00895 SecurityDescriptor ) 00896 PoolType ) 00897 GenericMapping ) 00898 DoAttachedDevices - if true, iterate the AttachedDevice list 00899 00900 ReturnValue: 00901 00902 success, or error from first failure 00903 00904 --*/ 00905 { 00906 PDEVICE_OBJECT NewDeviceObject = NULL; 00907 PSECURITY_DESCRIPTOR OldSecurityDescriptor; 00908 KIRQL irql; 00909 NTSTATUS status; 00910 NTSTATUS firsterr = STATUS_SUCCESS; 00911 BOOLEAN first = TRUE; 00912 00913 ASSERT(DeviceObject); 00914 00915 IopAcquireEnumerationLock(NULL); // ensure we have acquired P&P locks 00916 // 00917 // pre-reference this object to match the dereference later 00918 // 00919 ObReferenceObject( DeviceObject ); 00920 00921 do { 00922 KeEnterCriticalRegion(); 00923 ExAcquireResourceExclusive( &IopSecurityResource, TRUE ); 00924 00925 OldSecurityDescriptor = DeviceObject->SecurityDescriptor; 00926 00927 if (OldSecurityDescriptor || first) { 00928 // 00929 // always call this on the first object, only do it for others that have a security descriptor 00930 // 00931 status = SeSetSecurityDescriptorInfo( NULL, 00932 SecurityInformation, 00933 SecurityDescriptor, 00934 &DeviceObject->SecurityDescriptor, 00935 PoolType, 00936 GenericMapping ); 00937 00938 if (NT_SUCCESS(firsterr)) { 00939 firsterr = status; 00940 } 00941 if (NT_SUCCESS( status )) { 00942 ASSERT(OldSecurityDescriptor); 00943 ExFreePool( OldSecurityDescriptor ); 00944 } 00945 first = FALSE; 00946 } 00947 00948 ExReleaseResource( &IopSecurityResource ); 00949 KeLeaveCriticalRegion(); 00950 00951 // 00952 // get next device on attachment chain 00953 // 00954 ExAcquireSpinLock(&IopDatabaseLock,&irql); 00955 NewDeviceObject = DeviceObject->AttachedDevice; 00956 if ( NewDeviceObject != NULL ) { 00957 ObReferenceObject( NewDeviceObject ); 00958 } else { 00959 DoAttachedDevices = FALSE; 00960 } 00961 ExReleaseSpinLock(&IopDatabaseLock,irql); 00962 00963 ObDereferenceObject( DeviceObject ); 00964 DeviceObject = NewDeviceObject; 00965 00966 } while(DoAttachedDevices); 00967 00968 IopReleaseEnumerationLock(NULL); 00969 00970 return firsterr; // of the PDO / single object 00971 } 00972 00973 00974 NTSTATUS 00975 IopGetSetSecurityObject( 00976 IN PVOID Object, 00977 IN SECURITY_OPERATION_CODE OperationCode, 00978 IN PSECURITY_INFORMATION SecurityInformation, 00979 IN OUT PSECURITY_DESCRIPTOR SecurityDescriptor, 00980 IN OUT PULONG CapturedLength, 00981 IN OUT PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor, 00982 IN POOL_TYPE PoolType, 00983 IN PGENERIC_MAPPING GenericMapping 00984 ) 00985 00986 /*++ 00987 00988 Routine Description: 00989 00990 This routine is invoked to either query or set the security descriptor 00991 for a file, directory, volume, or device. It implements these functions 00992 by either performing an in-line check if the file is a device or a 00993 volume, or an I/O Request Packet (IRP) is generated and given to the 00994 driver to perform the operation. 00995 00996 Arguments: 00997 00998 Object - Pointer to the file or device object representing the open object. 00999 01000 SecurityInformation - Information about what is being done to or obtained 01001 from the object's security descriptor. 01002 01003 SecurityDescriptor - Supplies the base security descriptor and returns 01004 the final security descriptor. Note that if this buffer is coming 01005 from user space, it has already been probed by the object manager 01006 to length "CapturedLength", otherwise it points to kernel space and 01007 should not be probed. It must, however, be referenced in a try 01008 clause. 01009 01010 CapturedLength - For a query operation this specifies the size, in 01011 bytes, of the output security descriptor buffer and on return 01012 contains the number of bytes needed to store the complete security 01013 descriptor. If the length needed is greater than the length 01014 supplied the operation will fail. This parameter is ignored for 01015 the set and delete operations. It is expected to point into 01016 system space, ie, it need not be probed and it will not change. 01017 01018 ObjectsSecurityDescriptor - Supplies and returns the object's security 01019 descriptor. 01020 01021 PoolType - Specifies from which type of pool memory is to be allocated. 01022 01023 GenericMapping - Supplies the generic mapping for the object type. 01024 01025 Return Value: 01026 01027 The final status of the operation is returned as the function value. 01028 01029 --*/ 01030 01031 { 01032 NTSTATUS status; 01033 PFILE_OBJECT fileObject; 01034 PDEVICE_OBJECT deviceObject; 01035 PDEVICE_OBJECT devicePDO = NULL; 01036 BOOLEAN synchronousIo; 01037 01038 UNREFERENCED_PARAMETER( ObjectsSecurityDescriptor ); 01039 UNREFERENCED_PARAMETER( PoolType ); 01040 01041 PAGED_CODE(); 01042 01043 01044 // 01045 // Begin by determining whether the security operation is to be performed 01046 // in this routine or by the driver. This is based upon whether the 01047 // object represents a device object, or it represents a file object 01048 // to a device, or a file on the device. If the open is a direct device 01049 // open then use the device object. 01050 // 01051 01052 if (((PDEVICE_OBJECT) (Object))->Type == IO_TYPE_DEVICE) { 01053 deviceObject = (PDEVICE_OBJECT) Object; 01054 fileObject = (PFILE_OBJECT) NULL; 01055 } else { 01056 fileObject = (PFILE_OBJECT) Object; 01057 if (fileObject->Flags & FO_DIRECT_DEVICE_OPEN) { 01058 deviceObject = IoGetAttachedDevice( fileObject->DeviceObject ); 01059 } 01060 else { 01061 deviceObject = fileObject->DeviceObject; 01062 } 01063 } 01064 01065 if (!fileObject || 01066 (!fileObject->FileName.Length && !fileObject->RelatedFileObject) || 01067 (fileObject->Flags & FO_DIRECT_DEVICE_OPEN)) { 01068 01069 // 01070 // This security operation is for the device itself, either through 01071 // a file object, or directly to the device object. For the latter 01072 // case, assignment operations are also possible. Also note that 01073 // this may be a stream file object, which do not have security. 01074 // The security for a stream file is actually represented by the 01075 // security descriptor on the file itself, or the volume, or the 01076 // device. 01077 // 01078 01079 if (OperationCode == AssignSecurityDescriptor) { 01080 01081 // 01082 // Simply assign the security descriptor to the device object, 01083 // if this is a device object. 01084 // 01085 01086 if (fileObject == NULL || !(fileObject->Flags & FO_STREAM_FILE)) { 01087 KeEnterCriticalRegion(); 01088 ExAcquireResourceExclusive( &IopSecurityResource, TRUE ); 01089 deviceObject->SecurityDescriptor = SecurityDescriptor; 01090 ExReleaseResource( &IopSecurityResource ); 01091 KeLeaveCriticalRegion(); 01092 } 01093 status = STATUS_SUCCESS; 01094 01095 } else if (OperationCode == SetSecurityDescriptor) { 01096 01097 // 01098 // This is a set operation. The SecurityInformation parameter 01099 // determines what part of the SecurityDescriptor is going to 01100 // be applied to the ObjectsSecurityDescriptor. 01101 // 01102 01103 // 01104 // if this deviceObject is attached to a PDO then we want 01105 // to modify the security on the PDO and apply it up the 01106 // device chain 01107 // 01108 if (fileObject == NULL || !(fileObject->Flags & FO_DIRECT_DEVICE_OPEN)) { 01109 // 01110 // see if there is a PDO for this object, and obtain it 01111 // 01112 devicePDO = IopGetDevicePDO(deviceObject); 01113 } else { 01114 devicePDO = NULL; 01115 } 01116 if (devicePDO) { 01117 // 01118 // set PDO and all attached device objects 01119 // 01120 status = IopSetDeviceSecurityDescriptors(devicePDO,SecurityInformation,SecurityDescriptor,PoolType,GenericMapping,TRUE); 01121 ObDereferenceObject( devicePDO ); 01122 } else { 01123 // 01124 // set this device object only 01125 // 01126 status = IopSetDeviceSecurityDescriptors(deviceObject,SecurityInformation,SecurityDescriptor,PoolType,GenericMapping,FALSE); 01127 } 01128 01129 } else if (OperationCode == QuerySecurityDescriptor) { 01130 01131 // 01132 // This is a get operation. The SecurityInformation parameter 01133 // determines what part of the SecurityDescriptor is going to 01134 // be returned from the ObjectsSecurityDescriptor. 01135 // 01136 01137 KeEnterCriticalRegion(); 01138 ExAcquireResourceShared( &IopSecurityResource, TRUE ); 01139 status = SeQuerySecurityDescriptorInfo( SecurityInformation, 01140 SecurityDescriptor, 01141 CapturedLength, 01142 &deviceObject->SecurityDescriptor ); 01143 ExReleaseResource( &IopSecurityResource ); 01144 KeLeaveCriticalRegion(); 01145 01146 } else { 01147 01148 // 01149 // This is a delete operation. Simply indicate that everything 01150 // worked just fine. 01151 // 01152 01153 status = STATUS_SUCCESS; 01154 01155 } 01156 01157 } else if (OperationCode == DeleteSecurityDescriptor) { 01158 01159 // 01160 // This is a delete operation for the security descriptor on a file 01161 // object. This function will be performed by the file system once 01162 // the FCB itself is deleted. Simply indicate that the operation 01163 // was successful. 01164 // 01165 01166 status = STATUS_SUCCESS; 01167 01168 } else { 01169 01170 PIRP irp; 01171 IO_STATUS_BLOCK localIoStatus; 01172 KEVENT event; 01173 PIO_STACK_LOCATION irpSp; 01174 KPROCESSOR_MODE requestorMode; 01175 01176 // 01177 // This file object does not refer to the device itself. Rather, it 01178 // refers to either a file or a directory on the device. This means 01179 // that the request must be passed to the file system for processing. 01180 // Note that the only requests that are passed through in this manner 01181 // are SET or QUERY security operations. DELETE operations have 01182 // already been taken care of above since the file system which just 01183 // drop the storage on the floor when it really needs to, and ASSIGN 01184 // operations are irrelevant to file systems since they never 01185 // generate one because they never assign the security descriptor 01186 // to the object in the first place, they just assign it to the FCB. 01187 // 01188 01189 requestorMode = KeGetPreviousMode(); 01190 01191 // 01192 // Begin by referencing the object by pointer. Note that the object 01193 // handle has already been checked for the appropriate access by the 01194 // object system caller. This reference must be performed because 01195 // standard I/O completion will dereference the object. 01196 // 01197 01198 ObReferenceObject( fileObject ); 01199 01200 // 01201 // Make a special check here to determine whether this is a synchronous 01202 // I/O operation. If it is, then wait here until the file is owned by 01203 // the current thread. If this is not a (serialized) synchronous I/O 01204 // operation, then initialize the local event. 01205 // 01206 01207 if (fileObject->Flags & FO_SYNCHRONOUS_IO) { 01208 01209 BOOLEAN interrupted; 01210 01211 if (!IopAcquireFastLock( fileObject )) { 01212 status = IopAcquireFileObjectLock( fileObject, 01213 requestorMode, 01214 (BOOLEAN) ((fileObject->Flags & FO_ALERTABLE_IO) != 0), 01215 &interrupted ); 01216 if (interrupted) { 01217 ObDereferenceObject( fileObject ); 01218 return status; 01219 } 01220 } 01221 synchronousIo = TRUE; 01222 } else { 01223 KeInitializeEvent( &event, SynchronizationEvent, FALSE ); 01224 synchronousIo = FALSE; 01225 } 01226 01227 // 01228 // Set the file object to the Not-Signaled state. 01229 // 01230 01231 KeClearEvent( &fileObject->Event ); 01232 01233 // 01234 // Get the address of the target device object. 01235 // 01236 01237 deviceObject = IoGetRelatedDeviceObject( fileObject ); 01238 01239 // 01240 // Allocate and initialize the I/O Request Packet (IRP) for this 01241 // operation. The allocation is performed with an exception handler 01242 // in case the caller does not have enough quota to allocate the packet. 01243 01244 irp = IoAllocateIrp( deviceObject->StackSize, TRUE ); 01245 if (!irp) { 01246 01247 // 01248 // An IRP could not be allocated. Cleanup and return an 01249 // appropriate error status code. 01250 // 01251 01252 IopAllocateIrpCleanup( fileObject, (PKEVENT) NULL ); 01253 01254 return STATUS_INSUFFICIENT_RESOURCES; 01255 } 01256 irp->Tail.Overlay.OriginalFileObject = fileObject; 01257 irp->Tail.Overlay.Thread = PsGetCurrentThread(); 01258 irp->RequestorMode = requestorMode; 01259 01260 // 01261 // Fill in the service independent parameters in the IRP. 01262 // 01263 01264 if (fileObject->Flags & FO_SYNCHRONOUS_IO) { 01265 irp->UserEvent = (PKEVENT) NULL; 01266 } else { 01267 irp->UserEvent = &event; 01268 irp->Flags = IRP_SYNCHRONOUS_API; 01269 } 01270 irp->UserIosb = &localIoStatus; 01271 irp->Overlay.AsynchronousParameters.UserApcRoutine = (PIO_APC_ROUTINE) NULL; 01272 01273 // 01274 // Get a pointer to the stack location for the first driver. This will 01275 // be used to pass the original function codes and parameters. 01276 // 01277 01278 irpSp = IoGetNextIrpStackLocation( irp ); 01279 01280 // 01281 // Now determine whether this is a set or a query operation. 01282 // 01283 01284 if (OperationCode == QuerySecurityDescriptor) { 01285 01286 // 01287 // This is a query operation. Fill in the appropriate fields in 01288 // the stack location for the packet, as well as the fixed part 01289 // of the packet. Note that each of these parameters has been 01290 // captured as well, so there is no need to perform any probing. 01291 // The only exception is the UserBuffer memory may change, but 01292 // that is the file system's responsibility to check. Note that 01293 // it has already been probed, so the pointer is at least not 01294 // in an address space that the caller should not be accessing 01295 // because of mode. 01296 // 01297 01298 irpSp->MajorFunction = IRP_MJ_QUERY_SECURITY; 01299 irpSp->Parameters.QuerySecurity.SecurityInformation = *SecurityInformation; 01300 irpSp->Parameters.QuerySecurity.Length = *CapturedLength; 01301 irp->UserBuffer = SecurityDescriptor; 01302 01303 } else { 01304 01305 // 01306 // This is a set operation. Fill in the appropriate fields in 01307 // the stack location for the packet. Note that access to the 01308 // SecurityInformation parameter is safe, as the parameter was 01309 // captured by the caller. Likewise, the SecurityDescriptor 01310 // refers to a captured copy of the descriptor. 01311 // 01312 01313 irpSp->MajorFunction = IRP_MJ_SET_SECURITY; 01314 irpSp->Parameters.SetSecurity.SecurityInformation = *SecurityInformation; 01315 irpSp->Parameters.SetSecurity.SecurityDescriptor = SecurityDescriptor; 01316 01317 } 01318 01319 irpSp->FileObject = fileObject; 01320 01321 // 01322 // Insert the packet at the head of the IRP list for the thread. 01323 // 01324 01325 IopQueueThreadIrp( irp ); 01326 01327 // 01328 // Update the operation count statistic for the current process for 01329 // operations other than read and write. 01330 // 01331 01332 IopUpdateOtherOperationCount(); 01333 01334 // 01335 // Everything has been properly set up, so simply invoke the driver. 01336 // 01337 01338 status = IoCallDriver( deviceObject, irp ); 01339 01340 // 01341 // If this operation was a synchronous I/O operation, check the return 01342 // status to determine whether or not to wait on the file object. If 01343 // the file object is to be waited on, wait for the operation to be 01344 // completed and obtain the final status from the file object itself. 01345 // 01346 01347 if (synchronousIo) { 01348 if (status == STATUS_PENDING) { 01349 (VOID) KeWaitForSingleObject( &fileObject->Event, 01350 Executive, 01351 KernelMode, 01352 FALSE, 01353 (PLARGE_INTEGER) NULL ); 01354 status = fileObject->FinalStatus; 01355 } 01356 IopReleaseFileObjectLock( fileObject ); 01357 01358 } else { 01359 01360 // 01361 // This is a normal synchronous I/O operation, as opposed to a 01362 // serialized synchronous I/O operation. For this case, wait 01363 // for the local event and return the final status information 01364 // back to the caller. 01365 // 01366 01367 if (status == STATUS_PENDING) { 01368 (VOID) KeWaitForSingleObject( &event, 01369 Executive, 01370 KernelMode, 01371 FALSE, 01372 (PLARGE_INTEGER) NULL ); 01373 status = localIoStatus.Status; 01374 } 01375 } 01376 01377 // 01378 // If this operation was just attempted on a file system or a device 01379 // driver of some kind that does not implement security, then return 01380 // a normal null security descriptor. 01381 // 01382 01383 if (status == STATUS_INVALID_DEVICE_REQUEST) { 01384 01385 // 01386 // The file system does not implement a security policy. Determine 01387 // what type of operation this was and implement the correct 01388 // semantics for the file system. 01389 // 01390 01391 if (OperationCode == QuerySecurityDescriptor) { 01392 01393 // 01394 // The operation is a query. If the caller's buffer is too 01395 // small, then indicate that this is the case and let him know 01396 // what size buffer is required. Otherwise, attempt to return 01397 // a null security descriptor. 01398 // 01399 01400 try { 01401 status = SeAssignWorldSecurityDescriptor( 01402 SecurityDescriptor, 01403 CapturedLength, 01404 SecurityInformation 01405 ); 01406 01407 } except( EXCEPTION_EXECUTE_HANDLER ) { 01408 01409 // 01410 // An exception was incurred while attempting to 01411 // access the caller's buffer. Clean everything 01412 // up and return an appropriate status code. 01413 // 01414 01415 status = GetExceptionCode(); 01416 } 01417 01418 } else { 01419 01420 // 01421 // This was an operation other than a query. Simply indicate 01422 // that the operation was successful. 01423 // 01424 01425 status = STATUS_SUCCESS; 01426 } 01427 01428 } else if (OperationCode == QuerySecurityDescriptor) { 01429 01430 // 01431 // The final return status from the file system was something 01432 // other than invalid device request. This means that the file 01433 // system actually implemented the query. Copy the size of the 01434 // returned data, or the size of the buffer required in order 01435 // to query the security descriptor. Note that once again the 01436 // assignment is performed inside of an exception handler in case 01437 // the caller's buffer is inaccessible. Also note that in order 01438 // for the Information field of the I/O status block to be set, 01439 // the file system must return a warning status. Return the 01440 // status that the caller expects if the buffer really is too 01441 // small. 01442 // 01443 01444 if (status == STATUS_BUFFER_OVERFLOW) { 01445 status = STATUS_BUFFER_TOO_SMALL; 01446 } 01447 01448 try { 01449 01450 *CapturedLength = (ULONG) localIoStatus.Information; 01451 01452 } except( EXCEPTION_EXECUTE_HANDLER ) { 01453 status = GetExceptionCode(); 01454 } 01455 } 01456 } 01457 01458 return status; 01459 }

Generated on Sat May 15 19:41:05 2004 for test by doxygen 1.3.7