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.

3364 lines
86 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. obhandle.c
  5. Abstract:
  6. Object handle routines
  7. Author:
  8. Steve Wood (stevewo) 31-Mar-1989
  9. Revision History:
  10. --*/
  11. #include "obp.h"
  12. //
  13. // Define logical sum of all generic accesses.
  14. //
  15. #define GENERIC_ACCESS (GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL)
  16. //
  17. // Define the mask for the trace index. The last bit is used for
  18. // OBJ_PROTECT_CLOSE bit
  19. //
  20. #define OBP_CREATOR_BACKTRACE_LIMIT 0x7fff
  21. #define OBP_CREATOR_BACKTRACE_INDEX_MASK OBP_CREATOR_BACKTRACE_LIMIT
  22. //
  23. // Define local prototypes
  24. //
  25. NTSTATUS
  26. ObpIncrementHandleDataBase (
  27. IN POBJECT_HEADER ObjectHeader,
  28. IN PEPROCESS Process,
  29. OUT PULONG NewProcessHandleCount
  30. );
  31. NTSTATUS
  32. ObpCaptureHandleInformation (
  33. IN OUT PSYSTEM_HANDLE_TABLE_ENTRY_INFO *HandleEntryInfo,
  34. IN HANDLE UniqueProcessId,
  35. IN PVOID HandleTableEntry,
  36. IN HANDLE HandleIndex,
  37. IN ULONG Length,
  38. IN OUT PULONG RequiredLength
  39. );
  40. NTSTATUS
  41. ObpCaptureHandleInformationEx (
  42. IN OUT PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX *HandleEntryInfo,
  43. IN HANDLE UniqueProcessId,
  44. IN PHANDLE_TABLE_ENTRY ObjectTableEntry,
  45. IN HANDLE HandleIndex,
  46. IN ULONG Length,
  47. IN OUT PULONG RequiredLength
  48. );
  49. USHORT
  50. ObpComputeGrantedAccessIndex (
  51. ACCESS_MASK GrantedAccess
  52. );
  53. ACCESS_MASK
  54. ObpTranslateGrantedAccessIndex (
  55. USHORT GrantedAccessIndex
  56. );
  57. USHORT
  58. RtlLogUmodeStackBackTrace(
  59. VOID
  60. );
  61. #ifdef ALLOC_PRAGMA
  62. #pragma alloc_text(PAGE,NtDuplicateObject)
  63. #pragma alloc_text(PAGE,ObGetHandleInformation)
  64. #pragma alloc_text(PAGE,ObGetHandleInformationEx)
  65. #pragma alloc_text(PAGE,ObpCaptureHandleInformation)
  66. #pragma alloc_text(PAGE,ObpCaptureHandleInformationEx)
  67. #pragma alloc_text(PAGE,ObpIncrementHandleDataBase)
  68. #pragma alloc_text(PAGE,ObpInsertHandleCount)
  69. #pragma alloc_text(PAGE,ObpIncrementHandleCount)
  70. #pragma alloc_text(PAGE,ObpIncrementUnnamedHandleCount)
  71. #pragma alloc_text(PAGE,ObpChargeQuotaForObject)
  72. #pragma alloc_text(PAGE,ObpDecrementHandleCount)
  73. #pragma alloc_text(PAGE,ObpCreateHandle)
  74. #pragma alloc_text(PAGE,ObpCreateUnnamedHandle)
  75. #pragma alloc_text(PAGE,ObpValidateDesiredAccess)
  76. #pragma alloc_text(PAGE,ObDuplicateObject)
  77. #pragma alloc_text(PAGE,ObReferenceProcessHandleTable)
  78. #pragma alloc_text(PAGE,ObDereferenceProcessHandleTable)
  79. #pragma alloc_text(PAGE,ObpComputeGrantedAccessIndex)
  80. #pragma alloc_text(PAGE,ObpTranslateGrantedAccessIndex)
  81. #pragma alloc_text(PAGE,ObGetProcessHandleCount)
  82. #endif
  83. PHANDLE_TABLE
  84. ObReferenceProcessHandleTable (
  85. PEPROCESS SourceProcess
  86. )
  87. /*++
  88. Routine Description:
  89. This function allows safe cross process handle table references. Table deletion
  90. at process exit waits for all outstanding references to finish. Once the table
  91. is marked deleted further references are denied byt this funtion.
  92. Arguments:
  93. SourceProcesss - Process whose handle table is to be referenced
  94. Return Value:
  95. Referenced handle table or NULL if the processes handle table has been or is in the
  96. process of being deleted.
  97. --*/
  98. {
  99. PHANDLE_TABLE ObjectTable;
  100. ObjectTable = NULL;
  101. if (ExAcquireRundownProtection (&SourceProcess->RundownProtect)) {
  102. ObjectTable = SourceProcess->ObjectTable;
  103. if (ObjectTable == NULL) {
  104. ExReleaseRundownProtection (&SourceProcess->RundownProtect);
  105. }
  106. }
  107. return ObjectTable;
  108. }
  109. VOID
  110. ObDereferenceProcessHandleTable (
  111. PEPROCESS SourceProcess
  112. )
  113. /*++
  114. Routine Description:
  115. This function removes the outstanding reference obtained via ObReferenceProcessHandleTable.
  116. Arguments:
  117. ObjectTable - Handle table to dereference
  118. Return Value:
  119. None.
  120. --*/
  121. {
  122. ExReleaseRundownProtection (&SourceProcess->RundownProtect);
  123. }
  124. ULONG
  125. ObGetProcessHandleCount (
  126. PEPROCESS Process
  127. )
  128. /*++
  129. Routine Description:
  130. This function returns the total number of open handles for a process.
  131. Arguments:
  132. Process - Process whose handle table is to be queried.
  133. Return Value:
  134. Count of open handles.
  135. --*/
  136. {
  137. PHANDLE_TABLE HandleTable;
  138. ULONG HandleCount;
  139. HandleTable = ObReferenceProcessHandleTable (Process);
  140. if ( HandleTable ) {
  141. HandleCount = HandleTable->HandleCount;
  142. ObDereferenceProcessHandleTable (Process);
  143. } else {
  144. HandleCount = 0;
  145. }
  146. return HandleCount;
  147. }
  148. NTSTATUS
  149. ObDuplicateObject (
  150. IN PEPROCESS SourceProcess,
  151. IN HANDLE SourceHandle,
  152. IN PEPROCESS TargetProcess OPTIONAL,
  153. OUT PHANDLE TargetHandle OPTIONAL,
  154. IN ACCESS_MASK DesiredAccess,
  155. IN ULONG HandleAttributes,
  156. IN ULONG Options,
  157. IN KPROCESSOR_MODE PreviousMode
  158. )
  159. /*++
  160. Routine Description:
  161. This function creates a handle that is a duplicate of the specified
  162. source handle. The source handle is evaluated in the context of the
  163. specified source process. The calling process must have
  164. PROCESS_DUP_HANDLE access to the source process. The duplicate
  165. handle is created with the specified attributes and desired access.
  166. The duplicate handle is created in the handle table of the specified
  167. target process. The calling process must have PROCESS_DUP_HANDLE
  168. access to the target process.
  169. Arguments:
  170. SourceProcess - Supplies a pointer to the source process for the
  171. handle being duplicated
  172. SourceHandle - Supplies the handle being duplicated
  173. TargetProcess - Optionally supplies a pointer to the target process
  174. that is to receive the new handle
  175. TargetHandle - Optionally returns a the new duplicated handle
  176. DesiredAccess - Desired access for the new handle
  177. HandleAttributes - Desired attributes for the new handle
  178. Options - Duplication options that control things like close source,
  179. same access, and same attributes.
  180. PreviousMode - Mode of caller
  181. Return Value:
  182. NTSTATUS - Status pf call
  183. --*/
  184. {
  185. NTSTATUS Status;
  186. PVOID SourceObject;
  187. POBJECT_HEADER ObjectHeader;
  188. POBJECT_TYPE ObjectType;
  189. BOOLEAN Attached;
  190. PHANDLE_TABLE SourceObjectTable, TargetObjectTable;
  191. HANDLE_TABLE_ENTRY ObjectTableEntry;
  192. PHANDLE_TABLE_ENTRY SourceObjectTableEntry;
  193. OBJECT_HANDLE_INFORMATION HandleInformation;
  194. HANDLE NewHandle;
  195. ACCESS_STATE AccessState;
  196. AUX_ACCESS_DATA AuxData;
  197. ACCESS_MASK SourceAccess;
  198. ACCESS_MASK TargetAccess;
  199. ACCESS_MASK AuditMask = (ACCESS_MASK)0;
  200. PACCESS_STATE PassedAccessState = NULL;
  201. HANDLE_TABLE_ENTRY_INFO ObjectInfo;
  202. KAPC_STATE ApcState;
  203. if (ARGUMENT_PRESENT (TargetHandle)) {
  204. *TargetHandle = NULL;
  205. }
  206. //
  207. // If the caller is not asking for the same access then
  208. // validate the access they are requesting doesn't contain
  209. // any bad bits
  210. //
  211. if (!(Options & DUPLICATE_SAME_ACCESS)) {
  212. Status = ObpValidateDesiredAccess( DesiredAccess );
  213. if (!NT_SUCCESS( Status )) {
  214. return( Status );
  215. }
  216. }
  217. //
  218. // The Attached variable indicates if we needed to
  219. // attach to the source process because it was not the
  220. // current process.
  221. //
  222. Attached = FALSE;
  223. //
  224. // Lock down access to the process object tables
  225. //
  226. SourceObjectTable = ObReferenceProcessHandleTable (SourceProcess);
  227. //
  228. // Make sure the source process has an object table still
  229. //
  230. if ( SourceObjectTable == NULL ) {
  231. return STATUS_PROCESS_IS_TERMINATING;
  232. }
  233. //
  234. // If the specified source process is not the current process, attach
  235. // to the specified source process. Then after we reference the object
  236. // we can detach from the process.
  237. //
  238. if (PsGetCurrentProcess() != SourceProcess) {
  239. KeStackAttachProcess( &SourceProcess->Pcb, &ApcState );
  240. Attached = TRUE;
  241. }
  242. //
  243. // The the input source handle get a pointer to the
  244. // source object itself, then detach from the process
  245. // if necessary and check if we were given a good
  246. // source handle.
  247. //
  248. Status = ObReferenceObjectByHandle( SourceHandle,
  249. 0,
  250. (POBJECT_TYPE)NULL,
  251. PreviousMode,
  252. &SourceObject,
  253. &HandleInformation );
  254. //
  255. // Unfortunately, the OBJECT_HANDLE_INFORMATION structure is public,
  256. // so it can't be extended to include the AuditMask field in the
  257. // HANDLE_TABLE_ENTRY structure. So we have to map the handle and
  258. // grab it by hand. Fortunately, we only have to do this if
  259. // the source handle was audited when it was opened.
  260. //
  261. // We need to do this up here while we're still attached to the
  262. // source process.
  263. //
  264. if (NT_SUCCESS( Status )) {
  265. if (HandleInformation.HandleAttributes & OBJ_AUDIT_OBJECT_CLOSE) {
  266. SourceObjectTableEntry = ExMapHandleToPointer (
  267. SourceProcess->ObjectTable,
  268. SourceHandle
  269. );
  270. //
  271. // ExMapHandleToPointer will fail if the handle has been freed.
  272. //
  273. if (SourceObjectTableEntry != NULL) {
  274. PHANDLE_TABLE_ENTRY_INFO EntryInfo = ExGetHandleInfo( SourceProcess->ObjectTable,
  275. SourceHandle,
  276. TRUE
  277. );
  278. if (EntryInfo) {
  279. AuditMask = EntryInfo->AuditMask;
  280. }
  281. ExUnlockHandleTableEntry( SourceProcess->ObjectTable, SourceObjectTableEntry );
  282. }
  283. }
  284. }
  285. if (Attached) {
  286. KeUnstackDetachProcess(&ApcState);
  287. Attached = FALSE;
  288. }
  289. if (!NT_SUCCESS( Status )) {
  290. ObDereferenceProcessHandleTable (SourceProcess);
  291. return( Status );
  292. }
  293. //
  294. // We are all done if no target process handle was specified.
  295. // This is practially a noop because the only really end result
  296. // could be that we've closed the source handle.
  297. //
  298. if (!ARGUMENT_PRESENT( TargetProcess )) {
  299. //
  300. // If no TargetProcessHandle, then only possible option is to close
  301. // the source handle in the context of the source process.
  302. //
  303. if (!(Options & DUPLICATE_CLOSE_SOURCE)) {
  304. Status = STATUS_INVALID_PARAMETER;
  305. }
  306. if (Options & DUPLICATE_CLOSE_SOURCE) {
  307. KeStackAttachProcess( &SourceProcess->Pcb, &ApcState );
  308. NtClose( SourceHandle );
  309. KeUnstackDetachProcess (&ApcState);
  310. }
  311. ObDereferenceProcessHandleTable (SourceProcess);
  312. ObDereferenceObject( SourceObject );
  313. return( Status );
  314. }
  315. SourceAccess = HandleInformation.GrantedAccess;
  316. //
  317. // Make sure the target process has not exited
  318. //
  319. TargetObjectTable = ObReferenceProcessHandleTable (TargetProcess);
  320. if ( TargetObjectTable == NULL ) {
  321. if (Options & DUPLICATE_CLOSE_SOURCE) {
  322. KeStackAttachProcess( &SourceProcess->Pcb, &ApcState );
  323. NtClose( SourceHandle );
  324. KeUnstackDetachProcess (&ApcState);
  325. }
  326. ObDereferenceProcessHandleTable (SourceProcess);
  327. ObDereferenceObject( SourceObject );
  328. return STATUS_PROCESS_IS_TERMINATING;
  329. }
  330. //
  331. // If the specified target process is not the current process, attach
  332. // to the specified target process.
  333. //
  334. if (PsGetCurrentProcess() != TargetProcess) {
  335. KeStackAttachProcess( &TargetProcess->Pcb, &ApcState );
  336. Attached = TRUE;
  337. }
  338. //
  339. // Construct the proper desired access and attributes for the new handle
  340. //
  341. if (Options & DUPLICATE_SAME_ACCESS) {
  342. DesiredAccess = SourceAccess;
  343. }
  344. if (Options & DUPLICATE_SAME_ATTRIBUTES) {
  345. HandleAttributes = HandleInformation.HandleAttributes;
  346. } else {
  347. //
  348. // Always propogate auditing information.
  349. //
  350. HandleAttributes |= HandleInformation.HandleAttributes & OBJ_AUDIT_OBJECT_CLOSE;
  351. }
  352. //
  353. // Get the object header for the source object
  354. //
  355. ObjectHeader = OBJECT_TO_OBJECT_HEADER( SourceObject );
  356. ObjectType = ObjectHeader->Type;
  357. RtlZeroMemory( &ObjectTableEntry, sizeof( HANDLE_TABLE_ENTRY ) );
  358. ObjectTableEntry.Object = ObjectHeader;
  359. ObjectTableEntry.ObAttributes |= (HandleAttributes & OBJ_HANDLE_ATTRIBUTES);
  360. //
  361. // The following will be reset below if AVR is performed.
  362. //
  363. ObjectInfo.AuditMask = AuditMask;
  364. //
  365. // If any of the generic access bits are specified then map those to more
  366. // specific access bits
  367. //
  368. if ((DesiredAccess & GENERIC_ACCESS) != 0) {
  369. RtlMapGenericMask( &DesiredAccess,
  370. &ObjectType->TypeInfo.GenericMapping );
  371. }
  372. //
  373. // Make sure to preserve ACCESS_SYSTEM_SECURITY, which most likely is not
  374. // found in the ValidAccessMask
  375. //
  376. TargetAccess = DesiredAccess &
  377. (ObjectType->TypeInfo.ValidAccessMask | ACCESS_SYSTEM_SECURITY);
  378. //
  379. // If the access requested for the target is a superset of the
  380. // access allowed in the source, perform full AVR. If it is a
  381. // subset or equal, do not perform any access validation.
  382. //
  383. // Do not allow superset access if object type has a private security
  384. // method, as there is no means to call them in this case to do the
  385. // access check.
  386. //
  387. // If the AccessState is not passed to ObpIncrementHandleCount
  388. // there will be no AVR.
  389. //
  390. if (TargetAccess & ~SourceAccess) {
  391. if (ObjectType->TypeInfo.SecurityProcedure == SeDefaultObjectMethod) {
  392. Status = SeCreateAccessState( &AccessState,
  393. &AuxData,
  394. TargetAccess, // DesiredAccess
  395. &ObjectType->TypeInfo.GenericMapping );
  396. PassedAccessState = &AccessState;
  397. } else {
  398. Status = STATUS_ACCESS_DENIED;
  399. }
  400. } else {
  401. //
  402. // Do not perform AVR
  403. //
  404. PassedAccessState = NULL;
  405. Status = STATUS_SUCCESS;
  406. }
  407. //
  408. // Increment the new handle count and get a pointer to
  409. // the target processes object table
  410. //
  411. if ( NT_SUCCESS( Status )) {
  412. Status = ObpIncrementHandleCount( ObDuplicateHandle,
  413. PsGetCurrentProcess(), // this is already the target process
  414. SourceObject,
  415. ObjectType,
  416. PassedAccessState,
  417. PreviousMode,
  418. HandleAttributes );
  419. }
  420. if (Attached) {
  421. KeUnstackDetachProcess (&ApcState);
  422. Attached = FALSE;
  423. }
  424. if (Options & DUPLICATE_CLOSE_SOURCE) {
  425. KeStackAttachProcess( &SourceProcess->Pcb, &ApcState );
  426. NtClose( SourceHandle );
  427. KeUnstackDetachProcess(&ApcState);
  428. }
  429. if (!NT_SUCCESS( Status )) {
  430. if (PassedAccessState != NULL) {
  431. SeDeleteAccessState( PassedAccessState );
  432. }
  433. ObDereferenceProcessHandleTable (SourceProcess);
  434. ObDereferenceProcessHandleTable (TargetProcess);
  435. ObDereferenceObject( SourceObject );
  436. return( Status );
  437. }
  438. if ((PassedAccessState != NULL) && (PassedAccessState->GenerateOnClose == TRUE)) {
  439. //
  440. // If we performed AVR opening the handle, then mark the handle as needing
  441. // auditing when it's closed. Also save away the maximum audit mask
  442. // if one was created.
  443. //
  444. ObjectTableEntry.ObAttributes |= OBJ_AUDIT_OBJECT_CLOSE;
  445. ObjectInfo.AuditMask = ((PAUX_ACCESS_DATA)PassedAccessState->AuxData)->MaximumAuditMask;
  446. }
  447. #if i386
  448. if (NtGlobalFlag & FLG_KERNEL_STACK_TRACE_DB) {
  449. LONG StackTraceIndex;
  450. ObjectTableEntry.GrantedAccessIndex = ObpComputeGrantedAccessIndex( TargetAccess );
  451. if (PreviousMode == KernelMode) {
  452. StackTraceIndex = RtlLogStackBackTrace();
  453. } else {
  454. StackTraceIndex = RtlLogUmodeStackBackTrace();
  455. }
  456. //
  457. // Save the stack trace only if the index fits the CreatorBackTraceIndex
  458. // minus the ProtectOnClose bit
  459. //
  460. if (StackTraceIndex < OBP_CREATOR_BACKTRACE_LIMIT) {
  461. ObjectTableEntry.CreatorBackTraceIndex = (USHORT)StackTraceIndex;
  462. } else {
  463. ObjectTableEntry.CreatorBackTraceIndex = 0;
  464. }
  465. } else {
  466. ObjectTableEntry.GrantedAccess = TargetAccess;
  467. }
  468. #else
  469. ObjectTableEntry.GrantedAccess = TargetAccess;
  470. #endif // i386
  471. //
  472. // Now that we've constructed a new object table entry for the duplicated handle
  473. // we need to add it to the object table of the target process
  474. //
  475. ObpEncodeProtectClose(ObjectTableEntry);
  476. NewHandle = ExCreateHandle( TargetObjectTable, &ObjectTableEntry );
  477. if (NewHandle) {
  478. if ( ObjectInfo.AuditMask != 0 ) {
  479. //
  480. // Make sure it's the same object before setting the handle information.
  481. // The user may have closed it immediately after the ExCreateHandle call,
  482. // so at this time it may either be invalid or a completely different object.
  483. //
  484. PHANDLE_TABLE_ENTRY HandleTableEntry;
  485. HandleTableEntry = ExMapHandleToPointer ( TargetObjectTable, NewHandle );
  486. if (HandleTableEntry != NULL) {
  487. if (((ULONG_PTR)(HandleTableEntry->Object) & ~OBJ_HANDLE_ATTRIBUTES) == (ULONG_PTR)ObjectHeader) {
  488. ExSetHandleInfo(TargetObjectTable, NewHandle, &ObjectInfo, TRUE);
  489. }
  490. ExUnlockHandleTableEntry( TargetObjectTable, HandleTableEntry );
  491. }
  492. }
  493. //
  494. // We have a new handle to audit the creation of the new handle if
  495. // AVR was done. And set the optional output handle variable. Note
  496. // that if we reach here the status variable is already a success
  497. //
  498. if (PassedAccessState != NULL) {
  499. SeAuditHandleCreation( PassedAccessState, NewHandle );
  500. }
  501. if (SeDetailedAuditing && (ObjectTableEntry.ObAttributes & OBJ_AUDIT_OBJECT_CLOSE)) {
  502. SeAuditHandleDuplication( SourceHandle,
  503. NewHandle,
  504. SourceProcess,
  505. TargetProcess );
  506. }
  507. } else {
  508. //
  509. // We didn't get a new handle to decrement the handle count dereference
  510. // the necessary objects, set the optional output variable and indicate
  511. // why we're failing
  512. //
  513. ObpDecrementHandleCount( TargetProcess,
  514. ObjectHeader,
  515. ObjectType,
  516. TargetAccess );
  517. ObDereferenceObject( SourceObject );
  518. Status = STATUS_INSUFFICIENT_RESOURCES;
  519. }
  520. if (ARGUMENT_PRESENT( TargetHandle )) {
  521. *TargetHandle = NewHandle;
  522. }
  523. //
  524. // Cleanup from our selfs and then return to our caller
  525. //
  526. if (PassedAccessState != NULL) {
  527. SeDeleteAccessState( PassedAccessState );
  528. }
  529. ObDereferenceProcessHandleTable (SourceProcess);
  530. ObDereferenceProcessHandleTable (TargetProcess);
  531. return( Status );
  532. }
  533. NTSTATUS
  534. NtDuplicateObject (
  535. IN HANDLE SourceProcessHandle,
  536. IN HANDLE SourceHandle,
  537. IN HANDLE TargetProcessHandle OPTIONAL,
  538. OUT PHANDLE TargetHandle OPTIONAL,
  539. IN ACCESS_MASK DesiredAccess,
  540. IN ULONG HandleAttributes,
  541. IN ULONG Options
  542. )
  543. /*++
  544. Routine Description:
  545. This function creates a handle that is a duplicate of the specified
  546. source handle. The source handle is evaluated in the context of the
  547. specified source process. The calling process must have
  548. PROCESS_DUP_HANDLE access to the source process. The duplicate
  549. handle is created with the specified attributes and desired access.
  550. The duplicate handle is created in the handle table of the specified
  551. target process. The calling process must have PROCESS_DUP_HANDLE
  552. access to the target process.
  553. Arguments:
  554. SourceProcessHandle - Supplies a handle to the source process for the
  555. handle being duplicated
  556. SourceHandle - Supplies the handle being duplicated
  557. TargetProcessHandle - Optionally supplies a handle to the target process
  558. that is to receive the new handle
  559. TargetHandle - Optionally returns a the new duplicated handle
  560. DesiredAccess - Desired access for the new handle
  561. HandleAttributes - Desired attributes for the new handle
  562. Options - Duplication options that control things like close source,
  563. same access, and same attributes.
  564. Return Value:
  565. TBS
  566. --*/
  567. {
  568. KPROCESSOR_MODE PreviousMode;
  569. NTSTATUS Status, Status1;
  570. PEPROCESS SourceProcess;
  571. PEPROCESS TargetProcess;
  572. HANDLE NewHandle = NULL;
  573. //
  574. // Get previous processor mode and probe output arguments if necessary.
  575. //
  576. PreviousMode = KeGetPreviousMode();
  577. if (ARGUMENT_PRESENT( TargetHandle ) && (PreviousMode != KernelMode)) {
  578. try {
  579. ProbeForWriteHandle( TargetHandle );
  580. *TargetHandle = NULL;
  581. } except( EXCEPTION_EXECUTE_HANDLER ) {
  582. return( GetExceptionCode() );
  583. }
  584. }
  585. //
  586. // Given the input source process handle get a pointer
  587. // to the source process object
  588. //
  589. Status = ObReferenceObjectByHandle( SourceProcessHandle,
  590. PROCESS_DUP_HANDLE,
  591. PsProcessType,
  592. PreviousMode,
  593. (PVOID *)&SourceProcess,
  594. NULL );
  595. if (!NT_SUCCESS( Status )) {
  596. return Status;
  597. }
  598. //
  599. // We are all done if no target process handle was specified.
  600. // This is practially a noop because the only really end result
  601. // could be that we've closed the source handle.
  602. //
  603. if (!ARGUMENT_PRESENT( TargetProcessHandle )) {
  604. //
  605. // If no TargetProcessHandle, then only possible option is to close
  606. // the source handle in the context of the source process.
  607. //
  608. TargetProcess = NULL;
  609. Status1 = STATUS_SUCCESS;
  610. } else {
  611. //
  612. // At this point the caller did specify for a target process
  613. // So from the target process handle get a pointer to the
  614. // target process object.
  615. //
  616. Status1 = ObReferenceObjectByHandle( TargetProcessHandle,
  617. PROCESS_DUP_HANDLE,
  618. PsProcessType,
  619. PreviousMode,
  620. (PVOID *)&TargetProcess,
  621. NULL );
  622. //
  623. // The original structure of Duplicate cased us to still close the input handle if the output process handle
  624. // was bad. We preserve that functionality.
  625. //
  626. if (!NT_SUCCESS (Status1)) {
  627. TargetProcess = NULL;
  628. }
  629. }
  630. Status = ObDuplicateObject (SourceProcess,
  631. SourceHandle,
  632. TargetProcess,
  633. &NewHandle,
  634. DesiredAccess,
  635. HandleAttributes,
  636. Options,
  637. PreviousMode );
  638. if (ARGUMENT_PRESENT( TargetHandle )) {
  639. try {
  640. *TargetHandle = NewHandle;
  641. } except( EXCEPTION_EXECUTE_HANDLER ) {
  642. //
  643. // Fall through, since we cannot undo what we have done.
  644. //
  645. }
  646. }
  647. ObDereferenceObject( SourceProcess );
  648. if ( TargetProcess != NULL) {
  649. ObDereferenceObject( TargetProcess );
  650. }
  651. if (!NT_SUCCESS (Status1)) {
  652. Status = Status1;
  653. }
  654. return( Status );
  655. }
  656. NTSTATUS
  657. ObGetHandleInformation (
  658. OUT PSYSTEM_HANDLE_INFORMATION HandleInformation,
  659. IN ULONG Length,
  660. OUT PULONG ReturnLength OPTIONAL
  661. )
  662. /*++
  663. Routine Description:
  664. This routine returns information about the specified handle.
  665. Arguments:
  666. HandleInformation - Supplies an array of handle information
  667. structures to fill in
  668. Length - Supplies the length the handle information array in bytes
  669. ReturnLength - Receives the number of bytes used by this call
  670. Return Value:
  671. An appropriate status value
  672. --*/
  673. {
  674. NTSTATUS Status;
  675. ULONG RequiredLength;
  676. PAGED_CODE();
  677. RequiredLength = FIELD_OFFSET( SYSTEM_HANDLE_INFORMATION, Handles );
  678. if (Length < RequiredLength) {
  679. return( STATUS_INFO_LENGTH_MISMATCH );
  680. }
  681. HandleInformation->NumberOfHandles = 0;
  682. //
  683. // For every handle in every handle table we'll be calling
  684. // our callback routine
  685. //
  686. Status = ExSnapShotHandleTables( ObpCaptureHandleInformation,
  687. HandleInformation,
  688. Length,
  689. &RequiredLength );
  690. if (ARGUMENT_PRESENT( ReturnLength )) {
  691. *ReturnLength = RequiredLength;
  692. }
  693. return( Status );
  694. }
  695. NTSTATUS
  696. ObGetHandleInformationEx (
  697. OUT PSYSTEM_HANDLE_INFORMATION_EX HandleInformation,
  698. IN ULONG Length,
  699. OUT PULONG ReturnLength OPTIONAL
  700. )
  701. /*++
  702. Routine Description:
  703. This routine returns information about the specified handle.
  704. Arguments:
  705. HandleInformation - Supplies an array of handle information
  706. structures to fill in
  707. Length - Supplies the length the handle information array in bytes
  708. ReturnLength - Receives the number of bytes used by this call
  709. Return Value:
  710. An appropriate status value
  711. --*/
  712. {
  713. NTSTATUS Status;
  714. ULONG RequiredLength;
  715. PAGED_CODE();
  716. RequiredLength = FIELD_OFFSET( SYSTEM_HANDLE_INFORMATION_EX, Handles );
  717. if (Length < RequiredLength) {
  718. return( STATUS_INFO_LENGTH_MISMATCH );
  719. }
  720. HandleInformation->NumberOfHandles = 0;
  721. //
  722. // For every handle in every handle table we'll be calling
  723. // our callback routine
  724. //
  725. Status = ExSnapShotHandleTablesEx( ObpCaptureHandleInformationEx,
  726. HandleInformation,
  727. Length,
  728. &RequiredLength );
  729. if (ARGUMENT_PRESENT( ReturnLength )) {
  730. *ReturnLength = RequiredLength;
  731. }
  732. return( Status );
  733. }
  734. NTSTATUS
  735. ObpCaptureHandleInformation (
  736. IN OUT PSYSTEM_HANDLE_TABLE_ENTRY_INFO *HandleEntryInfo,
  737. IN HANDLE UniqueProcessId,
  738. IN PHANDLE_TABLE_ENTRY ObjectTableEntry,
  739. IN HANDLE HandleIndex,
  740. IN ULONG Length,
  741. IN OUT PULONG RequiredLength
  742. )
  743. /*++
  744. Routine Description:
  745. This is the callback routine of ObGetHandleInformation
  746. Arguments:
  747. HandleEntryInfo - Supplies a pointer to the output buffer to receive
  748. the handle information
  749. UniqueProcessId - Supplies the process id of the caller
  750. ObjectTableEntry - Supplies the handle table entry that is being
  751. captured
  752. HandleIndex - Supplies the index for the preceding handle table entry
  753. Length - Specifies the length, in bytes, of the original user buffer
  754. RequiredLength - Specifies the length, in bytes, that has already been
  755. used in the buffer to store information. On return this receives
  756. the updated number of bytes being used.
  757. Note that the HandleEntryInfo does not necessarily point to the
  758. start of the original user buffer. It will have been offset by
  759. the feed-in RequiredLength value.
  760. Return Value:
  761. An appropriate status value
  762. --*/
  763. {
  764. NTSTATUS Status;
  765. POBJECT_HEADER ObjectHeader;
  766. //
  767. // Figure out who much size we really need to contain this extra record
  768. // and then check that it fits.
  769. //
  770. *RequiredLength += sizeof( SYSTEM_HANDLE_TABLE_ENTRY_INFO );
  771. if (Length < *RequiredLength) {
  772. Status = STATUS_INFO_LENGTH_MISMATCH;
  773. } else {
  774. //
  775. // Get the object header from the table entry and then copy over the information
  776. //
  777. ObjectHeader = (POBJECT_HEADER)(((ULONG_PTR)(ObjectTableEntry->Object)) & ~OBJ_HANDLE_ATTRIBUTES);
  778. (*HandleEntryInfo)->UniqueProcessId = (USHORT)((ULONG_PTR)UniqueProcessId);
  779. (*HandleEntryInfo)->HandleAttributes = (UCHAR)ObpGetHandleAttributes(ObjectTableEntry);
  780. (*HandleEntryInfo)->ObjectTypeIndex = (UCHAR)(ObjectHeader->Type->Index);
  781. (*HandleEntryInfo)->HandleValue = (USHORT)((ULONG_PTR)(HandleIndex));
  782. (*HandleEntryInfo)->Object = &ObjectHeader->Body;
  783. (*HandleEntryInfo)->CreatorBackTraceIndex = 0;
  784. #if i386
  785. if (NtGlobalFlag & FLG_KERNEL_STACK_TRACE_DB) {
  786. (*HandleEntryInfo)->CreatorBackTraceIndex = ObjectTableEntry->CreatorBackTraceIndex & OBP_CREATOR_BACKTRACE_INDEX_MASK;
  787. (*HandleEntryInfo)->GrantedAccess = ObpTranslateGrantedAccessIndex( ObjectTableEntry->GrantedAccessIndex );
  788. } else {
  789. (*HandleEntryInfo)->GrantedAccess = ObpDecodeGrantedAccess(ObjectTableEntry->GrantedAccess);
  790. }
  791. #else
  792. (*HandleEntryInfo)->GrantedAccess = ObpDecodeGrantedAccess(ObjectTableEntry->GrantedAccess);
  793. #endif // i386
  794. (*HandleEntryInfo)++;
  795. Status = STATUS_SUCCESS;
  796. }
  797. return( Status );
  798. }
  799. NTSTATUS
  800. ObpCaptureHandleInformationEx (
  801. IN OUT PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX *HandleEntryInfo,
  802. IN HANDLE UniqueProcessId,
  803. IN PHANDLE_TABLE_ENTRY ObjectTableEntry,
  804. IN HANDLE HandleIndex,
  805. IN ULONG Length,
  806. IN OUT PULONG RequiredLength
  807. )
  808. /*++
  809. Routine Description:
  810. This is the callback routine of ObGetHandleInformation
  811. Arguments:
  812. HandleEntryInfo - Supplies a pointer to the output buffer to receive
  813. the handle information
  814. UniqueProcessId - Supplies the process id of the caller
  815. ObjectTableEntry - Supplies the handle table entry that is being
  816. captured
  817. HandleIndex - Supplies the index for the preceding handle table entry
  818. Length - Specifies the length, in bytes, of the original user buffer
  819. RequiredLength - Specifies the length, in bytes, that has already been
  820. used in the buffer to store information. On return this receives
  821. the updated number of bytes being used.
  822. Note that the HandleEntryInfo does not necessarily point to the
  823. start of the original user buffer. It will have been offset by
  824. the feed-in RequiredLength value.
  825. Return Value:
  826. An appropriate status value
  827. --*/
  828. {
  829. NTSTATUS Status;
  830. POBJECT_HEADER ObjectHeader;
  831. //
  832. // Figure out who much size we really need to contain this extra record
  833. // and then check that it fits.
  834. //
  835. *RequiredLength += sizeof( SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX );
  836. if (Length < *RequiredLength) {
  837. Status = STATUS_INFO_LENGTH_MISMATCH;
  838. } else {
  839. //
  840. // Get the object header from the table entry and then copy over the information
  841. //
  842. ObjectHeader = (POBJECT_HEADER)(((ULONG_PTR)(ObjectTableEntry->Object)) & ~OBJ_HANDLE_ATTRIBUTES);
  843. (*HandleEntryInfo)->UniqueProcessId = (ULONG_PTR)UniqueProcessId;
  844. (*HandleEntryInfo)->HandleAttributes = (UCHAR)ObpGetHandleAttributes(ObjectTableEntry);
  845. (*HandleEntryInfo)->ObjectTypeIndex = (USHORT)(ObjectHeader->Type->Index);
  846. (*HandleEntryInfo)->HandleValue = (ULONG_PTR)(HandleIndex);
  847. (*HandleEntryInfo)->Object = &ObjectHeader->Body;
  848. (*HandleEntryInfo)->CreatorBackTraceIndex = 0;
  849. #if i386
  850. if (NtGlobalFlag & FLG_KERNEL_STACK_TRACE_DB) {
  851. (*HandleEntryInfo)->CreatorBackTraceIndex = ObjectTableEntry->CreatorBackTraceIndex & OBP_CREATOR_BACKTRACE_INDEX_MASK;
  852. (*HandleEntryInfo)->GrantedAccess = ObpTranslateGrantedAccessIndex( ObjectTableEntry->GrantedAccessIndex );
  853. } else {
  854. (*HandleEntryInfo)->GrantedAccess = ObpDecodeGrantedAccess(ObjectTableEntry->GrantedAccess);
  855. }
  856. #else
  857. (*HandleEntryInfo)->GrantedAccess = ObpDecodeGrantedAccess(ObjectTableEntry->GrantedAccess);
  858. #endif // i386
  859. (*HandleEntryInfo)++;
  860. Status = STATUS_SUCCESS;
  861. }
  862. return( Status );
  863. }
  864. POBJECT_HANDLE_COUNT_ENTRY
  865. ObpInsertHandleCount (
  866. POBJECT_HEADER ObjectHeader
  867. )
  868. /*++
  869. Routine Description:
  870. This function will increase the size of the handle database
  871. stored in the handle information of an object header. If
  872. necessary it will allocate new and free old handle databases.
  873. This routine should not be called if there is already free
  874. space in the handle table.
  875. Arguments:
  876. ObjectHeader - The object whose handle count is being incremented
  877. Return Value:
  878. The pointer to the next free handle count entry within the
  879. handle database.
  880. --*/
  881. {
  882. POBJECT_HEADER_HANDLE_INFO HandleInfo;
  883. POBJECT_HANDLE_COUNT_DATABASE OldHandleCountDataBase;
  884. POBJECT_HANDLE_COUNT_DATABASE NewHandleCountDataBase;
  885. POBJECT_HANDLE_COUNT_ENTRY FreeHandleCountEntry;
  886. ULONG CountEntries;
  887. ULONG OldSize;
  888. ULONG NewSize;
  889. OBJECT_HANDLE_COUNT_DATABASE SingleEntryDataBase;
  890. PAGED_CODE();
  891. //
  892. // Check if the object has any handle information
  893. //
  894. HandleInfo = OBJECT_HEADER_TO_HANDLE_INFO(ObjectHeader);
  895. if (HandleInfo == NULL) {
  896. return NULL;
  897. }
  898. //
  899. // The object does have some handle information. If it has
  900. // a single handle entry then we'll construct a local dummy
  901. // handle count database and come up with a new data base for
  902. // storing two entries.
  903. //
  904. if (ObjectHeader->Flags & OB_FLAG_SINGLE_HANDLE_ENTRY) {
  905. SingleEntryDataBase.CountEntries = 1;
  906. SingleEntryDataBase.HandleCountEntries[0] = HandleInfo->SingleEntry;
  907. OldHandleCountDataBase = &SingleEntryDataBase;
  908. OldSize = sizeof( SingleEntryDataBase );
  909. CountEntries = 2;
  910. NewSize = sizeof(OBJECT_HANDLE_COUNT_DATABASE) +
  911. ((CountEntries - 1) * sizeof( OBJECT_HANDLE_COUNT_ENTRY ));
  912. } else {
  913. //
  914. // The object already has multiple handles so we reference the
  915. // current handle database, and compute a new size bumped by four
  916. //
  917. OldHandleCountDataBase = HandleInfo->HandleCountDataBase;
  918. CountEntries = OldHandleCountDataBase->CountEntries;
  919. OldSize = sizeof(OBJECT_HANDLE_COUNT_DATABASE) +
  920. ((CountEntries - 1) * sizeof( OBJECT_HANDLE_COUNT_ENTRY));
  921. CountEntries += 4;
  922. NewSize = sizeof(OBJECT_HANDLE_COUNT_DATABASE) +
  923. ((CountEntries - 1) * sizeof( OBJECT_HANDLE_COUNT_ENTRY));
  924. }
  925. //
  926. // Now allocate pool for the new handle database.
  927. //
  928. NewHandleCountDataBase = ExAllocatePoolWithTag(PagedPool, NewSize,'dHbO');
  929. if (NewHandleCountDataBase == NULL) {
  930. return NULL;
  931. }
  932. //
  933. // Copy over the old database. Note that this might just copy our
  934. // local dummy entry for the single entry case
  935. //
  936. RtlCopyMemory(NewHandleCountDataBase, OldHandleCountDataBase, OldSize);
  937. //
  938. // If the previous mode was a single entry then remove that
  939. // indication otherwise free up with previous handle database
  940. //
  941. if (ObjectHeader->Flags & OB_FLAG_SINGLE_HANDLE_ENTRY) {
  942. ObjectHeader->Flags &= ~OB_FLAG_SINGLE_HANDLE_ENTRY;
  943. } else {
  944. ExFreePool( OldHandleCountDataBase );
  945. }
  946. //
  947. // Find the end of the new database that is used and zero out
  948. // the memory
  949. //
  950. FreeHandleCountEntry =
  951. (POBJECT_HANDLE_COUNT_ENTRY)((PCHAR)NewHandleCountDataBase + OldSize);
  952. RtlZeroMemory(FreeHandleCountEntry, NewSize - OldSize);
  953. //
  954. // Set the new database to the proper entry count and put it
  955. // all in the object
  956. //
  957. NewHandleCountDataBase->CountEntries = CountEntries;
  958. HandleInfo->HandleCountDataBase = NewHandleCountDataBase;
  959. //
  960. // And return to our caller
  961. //
  962. return FreeHandleCountEntry;
  963. }
  964. NTSTATUS
  965. ObpIncrementHandleDataBase (
  966. IN POBJECT_HEADER ObjectHeader,
  967. IN PEPROCESS Process,
  968. OUT PULONG NewProcessHandleCount
  969. )
  970. /*++
  971. Routine Description:
  972. This function increments the handle count database associated with the
  973. specified object for a specified process. This function is assuming that
  974. is called only for MaintainHandleCount == TRUE.
  975. Arguments:
  976. ObjectHeader - Supplies a pointer to the object.
  977. Process - Supplies a pointer to the process whose handle count is to be
  978. updated.
  979. NewProcessHandleCount - Supplies a pointer to a variable that receives
  980. the new handle count for the process.
  981. Return Value:
  982. An appropriate status value
  983. --*/
  984. {
  985. POBJECT_HEADER_HANDLE_INFO HandleInfo;
  986. POBJECT_HANDLE_COUNT_DATABASE HandleCountDataBase;
  987. POBJECT_HANDLE_COUNT_ENTRY HandleCountEntry;
  988. POBJECT_HANDLE_COUNT_ENTRY FreeHandleCountEntry;
  989. ULONG CountEntries;
  990. ULONG ProcessHandleCount;
  991. PAGED_CODE();
  992. //
  993. // Translate the object header to the handle information.
  994. // The HandleInfo can't be null because this function should be
  995. // called only if MaintainHandleCount == TRUE
  996. //
  997. HandleInfo = OBJECT_HEADER_TO_HANDLE_INFO(ObjectHeader);
  998. //
  999. // Check if the object has space for only a single handle
  1000. //
  1001. if (ObjectHeader->Flags & OB_FLAG_SINGLE_HANDLE_ENTRY) {
  1002. //
  1003. // If the single handle isn't in use then set the entry
  1004. // and tell the caller there is only one handle
  1005. //
  1006. if (HandleInfo->SingleEntry.HandleCount == 0) {
  1007. *NewProcessHandleCount = 1;
  1008. HandleInfo->SingleEntry.HandleCount = 1;
  1009. HandleInfo->SingleEntry.Process = Process;
  1010. return STATUS_SUCCESS;
  1011. //
  1012. // If the single entry is for the same process as specified
  1013. // then increment the count and we're done
  1014. //
  1015. } else if (HandleInfo->SingleEntry.Process == Process) {
  1016. *NewProcessHandleCount = ++HandleInfo->SingleEntry.HandleCount;
  1017. return STATUS_SUCCESS;
  1018. //
  1019. // Finally we have a object with a single handle entry already
  1020. // in use, so we need to grow the handle database before
  1021. // we can set this new value
  1022. //
  1023. } else {
  1024. FreeHandleCountEntry = ObpInsertHandleCount( ObjectHeader );
  1025. if (FreeHandleCountEntry == NULL) {
  1026. return STATUS_INSUFFICIENT_RESOURCES;
  1027. }
  1028. FreeHandleCountEntry->Process = Process;
  1029. FreeHandleCountEntry->HandleCount = 1;
  1030. *NewProcessHandleCount = 1;
  1031. return STATUS_SUCCESS;
  1032. }
  1033. }
  1034. //
  1035. // The object does not contain a single entry, therefore we're
  1036. // assuming it already has a handle count database
  1037. //
  1038. HandleCountDataBase = HandleInfo->HandleCountDataBase;
  1039. FreeHandleCountEntry = NULL;
  1040. if (HandleCountDataBase != NULL) {
  1041. //
  1042. // Get the number of entries and a pointer to the first one
  1043. // in the handle database
  1044. //
  1045. CountEntries = HandleCountDataBase->CountEntries;
  1046. HandleCountEntry = &HandleCountDataBase->HandleCountEntries[ 0 ];
  1047. //
  1048. // For each entry in the handle database check for a process
  1049. // match and if so then increment the handle count and return
  1050. // to our caller. Otherwise if the entry is free then remember
  1051. // it so we can store to it later
  1052. //
  1053. while (CountEntries) {
  1054. if (HandleCountEntry->Process == Process) {
  1055. *NewProcessHandleCount = ++HandleCountEntry->HandleCount;
  1056. return STATUS_SUCCESS;
  1057. } else if (HandleCountEntry->HandleCount == 0) {
  1058. FreeHandleCountEntry = HandleCountEntry;
  1059. }
  1060. ++HandleCountEntry;
  1061. --CountEntries;
  1062. }
  1063. //
  1064. // If we did not find a free handle entry then we have to grow the
  1065. // handle database before we can set this new value
  1066. //
  1067. if (FreeHandleCountEntry == NULL) {
  1068. FreeHandleCountEntry = ObpInsertHandleCount( ObjectHeader );
  1069. if (FreeHandleCountEntry == NULL) {
  1070. return(STATUS_INSUFFICIENT_RESOURCES);
  1071. }
  1072. }
  1073. FreeHandleCountEntry->Process = Process;
  1074. FreeHandleCountEntry->HandleCount = 1;
  1075. *NewProcessHandleCount = 1;
  1076. }
  1077. return STATUS_SUCCESS;
  1078. }
  1079. NTSTATUS
  1080. ObpIncrementHandleCount (
  1081. OB_OPEN_REASON OpenReason,
  1082. PEPROCESS Process,
  1083. PVOID Object,
  1084. POBJECT_TYPE ObjectType,
  1085. PACCESS_STATE AccessState OPTIONAL,
  1086. KPROCESSOR_MODE AccessMode,
  1087. ULONG Attributes
  1088. )
  1089. /*++
  1090. Routine Description:
  1091. Increments the count of number of handles to the given object.
  1092. If the object is being opened or created, access validation and
  1093. auditing will be performed as appropriate.
  1094. Arguments:
  1095. OpenReason - Supplies the reason the handle count is being incremented.
  1096. Process - Pointer to the process in which the new handle will reside.
  1097. Object - Supplies a pointer to the body of the object.
  1098. ObjectType - Supplies the type of the object.
  1099. AccessState - Optional parameter supplying the current accumulated
  1100. security information describing the attempt to access the object.
  1101. AccessMode - Supplies the mode of the requestor.
  1102. Attributes - Desired attributes for the handle
  1103. Return Value:
  1104. An appropriate status value
  1105. --*/
  1106. {
  1107. NTSTATUS Status;
  1108. ULONG ProcessHandleCount;
  1109. BOOLEAN ExclusiveHandle;
  1110. POBJECT_HEADER_CREATOR_INFO CreatorInfo;
  1111. POBJECT_HEADER_QUOTA_INFO QuotaInfo;
  1112. POBJECT_HEADER ObjectHeader;
  1113. BOOLEAN HasPrivilege = FALSE;
  1114. PRIVILEGE_SET Privileges;
  1115. BOOLEAN NewObject;
  1116. BOOLEAN HoldObjectTypeMutex = FALSE;
  1117. KPROCESSOR_MODE AccessCheckMode;
  1118. ULONG NewTotal;
  1119. PAGED_CODE();
  1120. ObpValidateIrql( "ObpIncrementHandleCount" );
  1121. //
  1122. // Get a pointer to the object header
  1123. //
  1124. ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object );
  1125. //
  1126. // If the caller asked us to always do an access check then use user mode for previous mode
  1127. //
  1128. if (Attributes & OBJ_FORCE_ACCESS_CHECK) {
  1129. AccessCheckMode = UserMode;
  1130. } else {
  1131. AccessCheckMode = AccessMode;
  1132. }
  1133. ExclusiveHandle = FALSE;
  1134. HoldObjectTypeMutex = TRUE;
  1135. ObpLockObject( ObjectHeader );
  1136. try {
  1137. //
  1138. // Charge the user quota for the object
  1139. //
  1140. Status = ObpChargeQuotaForObject( ObjectHeader, ObjectType, &NewObject );
  1141. if (!NT_SUCCESS( Status )) {
  1142. leave;
  1143. }
  1144. //
  1145. // Check if the caller wants exlusive access and if so then
  1146. // make sure the attributes and header flags match up correctly
  1147. //
  1148. if (Attributes & OBJ_EXCLUSIVE) {
  1149. if ((Attributes & OBJ_INHERIT) ||
  1150. ((ObjectHeader->Flags & OB_FLAG_EXCLUSIVE_OBJECT) == 0)) {
  1151. Status = STATUS_INVALID_PARAMETER;
  1152. leave;
  1153. }
  1154. if (((OBJECT_HEADER_TO_EXCLUSIVE_PROCESS(ObjectHeader) == NULL) &&
  1155. (ObjectHeader->HandleCount != 0))
  1156. ||
  1157. ((OBJECT_HEADER_TO_EXCLUSIVE_PROCESS(ObjectHeader) != NULL) &&
  1158. (OBJECT_HEADER_TO_EXCLUSIVE_PROCESS(ObjectHeader) != PsGetCurrentProcess()))) {
  1159. Status = STATUS_ACCESS_DENIED;
  1160. leave;
  1161. }
  1162. ExclusiveHandle = TRUE;
  1163. //
  1164. // The user doesn't want exclusive access so now check to make sure
  1165. // the attriutes and header flags match up correctly
  1166. //
  1167. } else if ((ObjectHeader->Flags & OB_FLAG_EXCLUSIVE_OBJECT) &&
  1168. (OBJECT_HEADER_TO_EXCLUSIVE_PROCESS(ObjectHeader) != NULL)) {
  1169. Status = STATUS_ACCESS_DENIED;
  1170. leave;
  1171. }
  1172. //
  1173. // If handle count going from zero to one for an existing object that
  1174. // maintains a handle count database, but does not have an open procedure
  1175. // just a close procedure, then fail the call as they are trying to
  1176. // reopen an object by pointer and the close procedure will not know
  1177. // that the object has been 'recreated'
  1178. //
  1179. if ((ObjectHeader->HandleCount == 0) &&
  1180. (!NewObject) &&
  1181. (ObjectType->TypeInfo.MaintainHandleCount) &&
  1182. (ObjectType->TypeInfo.OpenProcedure == NULL) &&
  1183. (ObjectType->TypeInfo.CloseProcedure != NULL)) {
  1184. Status = STATUS_UNSUCCESSFUL;
  1185. leave;
  1186. }
  1187. if ((OpenReason == ObOpenHandle) ||
  1188. ((OpenReason == ObDuplicateHandle) && ARGUMENT_PRESENT(AccessState))) {
  1189. //
  1190. // Perform Access Validation to see if we can open this
  1191. // (already existing) object.
  1192. //
  1193. if (!ObCheckObjectAccess( Object,
  1194. AccessState,
  1195. TRUE,
  1196. AccessCheckMode,
  1197. &Status )) {
  1198. leave;
  1199. }
  1200. } else if ((OpenReason == ObCreateHandle)) {
  1201. //
  1202. // We are creating a new instance of this object type.
  1203. // A total of three audit messages may be generated:
  1204. //
  1205. // 1 - Audit the attempt to create an instance of this
  1206. // object type.
  1207. //
  1208. // 2 - Audit the successful creation.
  1209. //
  1210. // 3 - Audit the allocation of the handle.
  1211. //
  1212. //
  1213. // At this point, the RemainingDesiredAccess field in
  1214. // the AccessState may still contain either Generic access
  1215. // types, or MAXIMUM_ALLOWED. We will map the generics
  1216. // and substitute GenericAll for MAXIMUM_ALLOWED.
  1217. //
  1218. if ( AccessState->RemainingDesiredAccess & MAXIMUM_ALLOWED ) {
  1219. AccessState->RemainingDesiredAccess &= ~MAXIMUM_ALLOWED;
  1220. AccessState->RemainingDesiredAccess |= GENERIC_ALL;
  1221. }
  1222. if ((GENERIC_ACCESS & AccessState->RemainingDesiredAccess) != 0) {
  1223. RtlMapGenericMask( &AccessState->RemainingDesiredAccess,
  1224. &ObjectType->TypeInfo.GenericMapping );
  1225. }
  1226. //
  1227. // Since we are creating the object, we can give any access the caller
  1228. // wants. The only exception is ACCESS_SYSTEM_SECURITY, which requires
  1229. // a privilege.
  1230. //
  1231. if ( AccessState->RemainingDesiredAccess & ACCESS_SYSTEM_SECURITY ) {
  1232. //
  1233. // We could use SeSinglePrivilegeCheck here, but it
  1234. // captures the subject context again, and we don't
  1235. // want to do that in this path for performance reasons.
  1236. //
  1237. Privileges.PrivilegeCount = 1;
  1238. Privileges.Control = PRIVILEGE_SET_ALL_NECESSARY;
  1239. Privileges.Privilege[0].Luid = SeSecurityPrivilege;
  1240. Privileges.Privilege[0].Attributes = 0;
  1241. HasPrivilege = SePrivilegeCheck( &Privileges,
  1242. &AccessState->SubjectSecurityContext,
  1243. AccessCheckMode );
  1244. if (!HasPrivilege) {
  1245. SePrivilegedServiceAuditAlarm ( NULL,
  1246. &AccessState->SubjectSecurityContext,
  1247. &Privileges,
  1248. FALSE );
  1249. Status = STATUS_PRIVILEGE_NOT_HELD;
  1250. leave;
  1251. }
  1252. AccessState->RemainingDesiredAccess &= ~ACCESS_SYSTEM_SECURITY;
  1253. AccessState->PreviouslyGrantedAccess |= ACCESS_SYSTEM_SECURITY;
  1254. (VOID) SeAppendPrivileges( AccessState,
  1255. &Privileges );
  1256. }
  1257. }
  1258. if (ExclusiveHandle) {
  1259. OBJECT_HEADER_TO_QUOTA_INFO(ObjectHeader)->ExclusiveProcess = Process;
  1260. }
  1261. ObpIncrHandleCount( ObjectHeader );
  1262. ProcessHandleCount = 0;
  1263. //
  1264. // If the object type wants us to keep try of the handle counts
  1265. // then call our routine to do the work
  1266. //
  1267. if (ObjectType->TypeInfo.MaintainHandleCount) {
  1268. Status = ObpIncrementHandleDataBase( ObjectHeader,
  1269. Process,
  1270. &ProcessHandleCount );
  1271. if (!NT_SUCCESS(Status)) {
  1272. //
  1273. // The only thing we need to do is to remove the
  1274. // reference added before. The quota charge will be
  1275. // returned at object deletion
  1276. //
  1277. ObpDecrHandleCount( ObjectHeader );
  1278. leave;
  1279. }
  1280. }
  1281. ObpUnlockObject( ObjectHeader );
  1282. HoldObjectTypeMutex = FALSE;
  1283. //
  1284. // Set our preliminary status now to success because
  1285. // the call to the open procedure might change this
  1286. //
  1287. Status = STATUS_SUCCESS;
  1288. //
  1289. // If the object type has an open procedure
  1290. // then invoke that procedure
  1291. //
  1292. if (ObjectType->TypeInfo.OpenProcedure != NULL) {
  1293. KIRQL SaveIrql;
  1294. //
  1295. // Leave the object type mutex when call the OpenProcedure. If an exception
  1296. // while OpenProcedure the HoldObjectTypeMutex disable leaving the mutex
  1297. // on finally block
  1298. //
  1299. ObpBeginTypeSpecificCallOut( SaveIrql );
  1300. Status = (*ObjectType->TypeInfo.OpenProcedure)( OpenReason,
  1301. Process,
  1302. Object,
  1303. AccessState ?
  1304. AccessState->PreviouslyGrantedAccess :
  1305. 0,
  1306. ProcessHandleCount );
  1307. ObpEndTypeSpecificCallOut( SaveIrql, "Open", ObjectType, Object );
  1308. //
  1309. // Hold back the object type mutex and set the HoldObjectTypeMutex variable
  1310. // to allow releasing the mutex while leaving this procedure
  1311. //
  1312. if (!NT_SUCCESS(Status)) {
  1313. ObpLockObject( ObjectHeader );
  1314. HoldObjectTypeMutex = TRUE;
  1315. (VOID)ObpDecrHandleCount( ObjectHeader );
  1316. leave;
  1317. }
  1318. }
  1319. //
  1320. // Get the objects creator info block and insert it on the
  1321. // global list of objects for that type
  1322. //
  1323. if (OpenReason == ObCreateHandle) {
  1324. CreatorInfo = OBJECT_HEADER_TO_CREATOR_INFO( ObjectHeader );
  1325. if (CreatorInfo != NULL) {
  1326. ObpEnterObjectTypeMutex( ObjectType );
  1327. InsertTailList( &ObjectType->TypeList, &CreatorInfo->TypeList );
  1328. ObpLeaveObjectTypeMutex( ObjectType );
  1329. }
  1330. }
  1331. //
  1332. // Do some simple bookkeeping for the handle counts
  1333. // and then return to our caller
  1334. //
  1335. NewTotal = (ULONG) InterlockedIncrement((PLONG)&ObjectType->TotalNumberOfHandles);
  1336. //
  1337. // Note: The hightwather is only for bookeeping. We can do this w/o
  1338. // lock. In the worst case next time will be updated
  1339. //
  1340. if (NewTotal > ObjectType->HighWaterNumberOfHandles) {
  1341. ObjectType->HighWaterNumberOfHandles = NewTotal;
  1342. }
  1343. } finally {
  1344. if ( HoldObjectTypeMutex ) {
  1345. ObpUnlockObject( ObjectHeader );
  1346. }
  1347. }
  1348. return( Status );
  1349. }
  1350. NTSTATUS
  1351. ObpIncrementUnnamedHandleCount (
  1352. PACCESS_MASK DesiredAccess,
  1353. PEPROCESS Process,
  1354. PVOID Object,
  1355. POBJECT_TYPE ObjectType,
  1356. KPROCESSOR_MODE AccessMode,
  1357. ULONG Attributes
  1358. )
  1359. /*++
  1360. Routine Description:
  1361. Increments the count of number of handles to the given object.
  1362. Arguments:
  1363. Desired Access - Supplies the desired access to the object and receives
  1364. the assign access mask
  1365. Process - Pointer to the process in which the new handle will reside.
  1366. Object - Supplies a pointer to the body of the object.
  1367. ObjectType - Supplies the type of the object.
  1368. AccessMode - Supplies the mode of the requestor.
  1369. Attributes - Desired attributes for the handle
  1370. Return Value:
  1371. An appropriate status value
  1372. --*/
  1373. {
  1374. NTSTATUS Status;
  1375. BOOLEAN ExclusiveHandle;
  1376. POBJECT_HEADER_CREATOR_INFO CreatorInfo;
  1377. POBJECT_HEADER_QUOTA_INFO QuotaInfo;
  1378. POBJECT_HEADER ObjectHeader;
  1379. BOOLEAN NewObject;
  1380. ULONG ProcessHandleCount;
  1381. BOOLEAN HoldObjectTypeMutex = FALSE;
  1382. ULONG NewTotal;
  1383. PAGED_CODE();
  1384. ObpValidateIrql( "ObpIncrementUnnamedHandleCount" );
  1385. //
  1386. // Get a pointer to the object header
  1387. //
  1388. ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object );
  1389. ExclusiveHandle = FALSE;
  1390. HoldObjectTypeMutex = TRUE;
  1391. ObpLockObject( ObjectHeader );
  1392. try {
  1393. //
  1394. // Charge the user quota for the object
  1395. //
  1396. Status = ObpChargeQuotaForObject( ObjectHeader, ObjectType, &NewObject );
  1397. if (!NT_SUCCESS( Status )) {
  1398. leave;
  1399. }
  1400. //
  1401. // Check if the caller wants exlusive access and if so then
  1402. // make sure the attributes and header flags match up correctly
  1403. //
  1404. if (Attributes & OBJ_EXCLUSIVE) {
  1405. if ((Attributes & OBJ_INHERIT) ||
  1406. ((ObjectHeader->Flags & OB_FLAG_EXCLUSIVE_OBJECT) == 0)) {
  1407. Status = STATUS_INVALID_PARAMETER;
  1408. leave;
  1409. }
  1410. if (((OBJECT_HEADER_TO_EXCLUSIVE_PROCESS(ObjectHeader) == NULL) &&
  1411. (ObjectHeader->HandleCount != 0))
  1412. ||
  1413. ((OBJECT_HEADER_TO_EXCLUSIVE_PROCESS(ObjectHeader) != NULL) &&
  1414. (OBJECT_HEADER_TO_EXCLUSIVE_PROCESS(ObjectHeader) != PsGetCurrentProcess()))) {
  1415. Status = STATUS_ACCESS_DENIED;
  1416. leave;
  1417. }
  1418. ExclusiveHandle = TRUE;
  1419. //
  1420. // The user doesn't want exclusive access so now check to make sure
  1421. // the attriutes and header flags match up correctly
  1422. //
  1423. } else if ((ObjectHeader->Flags & OB_FLAG_EXCLUSIVE_OBJECT) &&
  1424. (OBJECT_HEADER_TO_EXCLUSIVE_PROCESS(ObjectHeader) != NULL)) {
  1425. Status = STATUS_ACCESS_DENIED;
  1426. leave;
  1427. }
  1428. //
  1429. // If handle count going from zero to one for an existing object that
  1430. // maintains a handle count database, but does not have an open procedure
  1431. // just a close procedure, then fail the call as they are trying to
  1432. // reopen an object by pointer and the close procedure will not know
  1433. // that the object has been 'recreated'
  1434. //
  1435. if ((ObjectHeader->HandleCount == 0) &&
  1436. (!NewObject) &&
  1437. (ObjectType->TypeInfo.MaintainHandleCount) &&
  1438. (ObjectType->TypeInfo.OpenProcedure == NULL) &&
  1439. (ObjectType->TypeInfo.CloseProcedure != NULL)) {
  1440. Status = STATUS_UNSUCCESSFUL;
  1441. leave;
  1442. }
  1443. //
  1444. // If the user asked for the maximum allowed then remove the bit and
  1445. // or in generic all access
  1446. //
  1447. if ( *DesiredAccess & MAXIMUM_ALLOWED ) {
  1448. *DesiredAccess &= ~MAXIMUM_ALLOWED;
  1449. *DesiredAccess |= GENERIC_ALL;
  1450. }
  1451. // If the user asked for any generic bit then translate it to
  1452. // someone more appropriate for the object type
  1453. //
  1454. if ((GENERIC_ACCESS & *DesiredAccess) != 0) {
  1455. RtlMapGenericMask( DesiredAccess,
  1456. &ObjectType->TypeInfo.GenericMapping );
  1457. }
  1458. if (ExclusiveHandle) {
  1459. OBJECT_HEADER_TO_QUOTA_INFO(ObjectHeader)->ExclusiveProcess = Process;
  1460. }
  1461. ObpIncrHandleCount( ObjectHeader );
  1462. ProcessHandleCount = 0;
  1463. //
  1464. // If the object type wants us to keep try of the handle counts
  1465. // then call our routine to do the work
  1466. //
  1467. if (ObjectType->TypeInfo.MaintainHandleCount) {
  1468. Status = ObpIncrementHandleDataBase( ObjectHeader,
  1469. Process,
  1470. &ProcessHandleCount );
  1471. if (!NT_SUCCESS(Status)) {
  1472. //
  1473. // The only thing we need to do is to remove the
  1474. // reference added before. The quota charge will be
  1475. // returned at object deletion.
  1476. //
  1477. ObpDecrHandleCount( ObjectHeader );
  1478. leave;
  1479. }
  1480. }
  1481. ObpUnlockObject( ObjectHeader );
  1482. HoldObjectTypeMutex = FALSE;
  1483. //
  1484. // Set our preliminary status now to success because
  1485. // the call to the open procedure might change this
  1486. //
  1487. Status = STATUS_SUCCESS;
  1488. //
  1489. // If the object type has an open procedure
  1490. // then invoke that procedure
  1491. //
  1492. if (ObjectType->TypeInfo.OpenProcedure != NULL) {
  1493. KIRQL SaveIrql;
  1494. //
  1495. // Call the OpenProcedure. If an exception
  1496. // while OpenProcedure the HoldObjectTypeMutex disable leaving the mutex
  1497. // on finally block
  1498. //
  1499. ObpBeginTypeSpecificCallOut( SaveIrql );
  1500. Status = (*ObjectType->TypeInfo.OpenProcedure)( ObCreateHandle,
  1501. Process,
  1502. Object,
  1503. *DesiredAccess,
  1504. ProcessHandleCount );
  1505. ObpEndTypeSpecificCallOut( SaveIrql, "Open", ObjectType, Object );
  1506. //
  1507. // Hold back the object type mutex and set the HoldObjectTypeMutex variable
  1508. // to allow releasing the mutex while leaving this procedure
  1509. //
  1510. if (!NT_SUCCESS(Status)) {
  1511. ObpLockObject( ObjectHeader );
  1512. HoldObjectTypeMutex = TRUE;
  1513. (VOID)ObpDecrHandleCount( ObjectHeader );
  1514. leave;
  1515. }
  1516. }
  1517. //
  1518. // Get a pointer to the creator info block for the object and insert
  1519. // it on the global list of object for that type
  1520. //
  1521. CreatorInfo = OBJECT_HEADER_TO_CREATOR_INFO( ObjectHeader );
  1522. if (CreatorInfo != NULL) {
  1523. ObpEnterObjectTypeMutex( ObjectType );
  1524. InsertTailList( &ObjectType->TypeList, &CreatorInfo->TypeList );
  1525. ObpLeaveObjectTypeMutex( ObjectType );
  1526. }
  1527. //
  1528. // Do some simple bookkeeping for the handle counts
  1529. // and then return to our caller
  1530. //
  1531. NewTotal = (ULONG) InterlockedIncrement((PLONG)&ObjectType->TotalNumberOfHandles);
  1532. if (NewTotal > ObjectType->HighWaterNumberOfHandles) {
  1533. ObjectType->HighWaterNumberOfHandles = NewTotal;
  1534. }
  1535. } finally {
  1536. if ( HoldObjectTypeMutex ) {
  1537. ObpUnlockObject( ObjectHeader );
  1538. }
  1539. }
  1540. return( Status );
  1541. }
  1542. NTSTATUS
  1543. ObpChargeQuotaForObject (
  1544. IN POBJECT_HEADER ObjectHeader,
  1545. IN POBJECT_TYPE ObjectType,
  1546. OUT PBOOLEAN NewObject
  1547. )
  1548. /*++
  1549. Routine Description:
  1550. This routine charges quota against the current process for the new
  1551. object
  1552. Arguments:
  1553. ObjectHeader - Supplies a pointer to the new object being charged for
  1554. ObjectType - Supplies the type of the new object
  1555. NewObject - Returns true if the object is really new and false otherwise
  1556. Return Value:
  1557. An appropriate status value
  1558. --*/
  1559. {
  1560. POBJECT_HEADER_QUOTA_INFO QuotaInfo;
  1561. ULONG NonPagedPoolCharge;
  1562. ULONG PagedPoolCharge;
  1563. //
  1564. // Get a pointer to the quota block for this object
  1565. //
  1566. QuotaInfo = OBJECT_HEADER_TO_QUOTA_INFO( ObjectHeader );
  1567. *NewObject = FALSE;
  1568. //
  1569. // If the object is new then we have work to do otherwise
  1570. // we'll return with NewObject set to false
  1571. //
  1572. if (ObjectHeader->Flags & OB_FLAG_NEW_OBJECT) {
  1573. //
  1574. // Say the object now isn't new
  1575. //
  1576. ObjectHeader->Flags &= ~OB_FLAG_NEW_OBJECT;
  1577. //
  1578. // If there does exist a quota info structure for this
  1579. // object then calculate what our charge should be from
  1580. // the information stored in that structure
  1581. //
  1582. if (QuotaInfo != NULL) {
  1583. PagedPoolCharge = QuotaInfo->PagedPoolCharge +
  1584. QuotaInfo->SecurityDescriptorCharge;
  1585. NonPagedPoolCharge = QuotaInfo->NonPagedPoolCharge;
  1586. } else {
  1587. //
  1588. // There isn't any quota information so we're on our own
  1589. // Paged pool charge is the default for the object plus
  1590. // the security descriptor if present. Nonpaged pool charge
  1591. // is the default for the object.
  1592. //
  1593. PagedPoolCharge = ObjectType->TypeInfo.DefaultPagedPoolCharge;
  1594. if (ObjectHeader->SecurityDescriptor != NULL) {
  1595. ObjectHeader->Flags |= OB_FLAG_DEFAULT_SECURITY_QUOTA;
  1596. PagedPoolCharge += SE_DEFAULT_SECURITY_QUOTA;
  1597. }
  1598. NonPagedPoolCharge = ObjectType->TypeInfo.DefaultNonPagedPoolCharge;
  1599. }
  1600. //
  1601. // Now charge for the quota and make sure it succeeds
  1602. //
  1603. ObjectHeader->QuotaBlockCharged = (PVOID)PsChargeSharedPoolQuota( PsGetCurrentProcess(),
  1604. PagedPoolCharge,
  1605. NonPagedPoolCharge );
  1606. if (ObjectHeader->QuotaBlockCharged == NULL) {
  1607. return STATUS_QUOTA_EXCEEDED;
  1608. }
  1609. *NewObject = TRUE;
  1610. }
  1611. return STATUS_SUCCESS;
  1612. }
  1613. VOID
  1614. ObpDecrementHandleCount (
  1615. PEPROCESS Process,
  1616. POBJECT_HEADER ObjectHeader,
  1617. POBJECT_TYPE ObjectType,
  1618. ACCESS_MASK GrantedAccess
  1619. )
  1620. /*++
  1621. Routine Description:
  1622. This procedure decrements the handle count for the specified object
  1623. Arguments:
  1624. Process - Supplies the process where the handle existed
  1625. ObjectHeader - Supplies a pointer to the object header for the object
  1626. ObjectType - Supplies a type of the object
  1627. GrantedAccess - Supplies the current access mask to the object
  1628. Return Value:
  1629. None.
  1630. --*/
  1631. {
  1632. POBJECT_HEADER_HANDLE_INFO HandleInfo;
  1633. POBJECT_HANDLE_COUNT_DATABASE HandleCountDataBase;
  1634. POBJECT_HANDLE_COUNT_ENTRY HandleCountEntry;
  1635. POBJECT_HEADER_CREATOR_INFO CreatorInfo;
  1636. PVOID Object;
  1637. ULONG CountEntries;
  1638. ULONG ProcessHandleCount;
  1639. ULONG SystemHandleCount;
  1640. BOOLEAN HandleCountIsZero;
  1641. PAGED_CODE();
  1642. Object = (PVOID)&ObjectHeader->Body;
  1643. ProcessHandleCount = 0;
  1644. ObpLockObject( ObjectHeader );
  1645. SystemHandleCount = ObjectHeader->HandleCount;
  1646. //
  1647. // Decrement the handle count and it was one and it
  1648. // was an exclusive object then zero out the exclusive
  1649. // process
  1650. //
  1651. HandleCountIsZero = ObpDecrHandleCount( ObjectHeader );
  1652. if ( HandleCountIsZero &&
  1653. (ObjectHeader->Flags & OB_FLAG_EXCLUSIVE_OBJECT)) {
  1654. OBJECT_HEADER_TO_QUOTA_INFO( ObjectHeader )->ExclusiveProcess = NULL;
  1655. }
  1656. //
  1657. // If the object maintains a handle count database then
  1658. // search through the handle database and decrement
  1659. // the necessary information
  1660. //
  1661. if (ObjectType->TypeInfo.MaintainHandleCount) {
  1662. HandleInfo = OBJECT_HEADER_TO_HANDLE_INFO( ObjectHeader );
  1663. //
  1664. // Check if there is a single handle entry, then it better
  1665. // be ours
  1666. //
  1667. if (ObjectHeader->Flags & OB_FLAG_SINGLE_HANDLE_ENTRY) {
  1668. ASSERT(HandleInfo->SingleEntry.Process == Process);
  1669. ASSERT(HandleInfo->SingleEntry.HandleCount > 0);
  1670. ProcessHandleCount = HandleInfo->SingleEntry.HandleCount--;
  1671. HandleCountEntry = &HandleInfo->SingleEntry;
  1672. } else {
  1673. //
  1674. // Otherwise search the database for a process match
  1675. //
  1676. HandleCountDataBase = HandleInfo->HandleCountDataBase;
  1677. if (HandleCountDataBase != NULL) {
  1678. CountEntries = HandleCountDataBase->CountEntries;
  1679. HandleCountEntry = &HandleCountDataBase->HandleCountEntries[ 0 ];
  1680. while (CountEntries) {
  1681. if ((HandleCountEntry->HandleCount != 0) &&
  1682. (HandleCountEntry->Process == Process)) {
  1683. ProcessHandleCount = HandleCountEntry->HandleCount--;
  1684. break;
  1685. }
  1686. HandleCountEntry++;
  1687. CountEntries--;
  1688. }
  1689. }
  1690. }
  1691. //
  1692. // Now if the process is giving up all handles to the object
  1693. // then zero out the handle count entry. For a single handle
  1694. // entry this is just the single entry in the header handle info
  1695. // structure
  1696. //
  1697. if (ProcessHandleCount == 1) {
  1698. HandleCountEntry->Process = NULL;
  1699. HandleCountEntry->HandleCount = 0;
  1700. }
  1701. }
  1702. ObpUnlockObject( ObjectHeader );
  1703. //
  1704. // If the Object Type has a Close Procedure, then release the type
  1705. // mutex before calling it, and then call ObpDeleteNameCheck without
  1706. // the mutex held.
  1707. //
  1708. if (ObjectType->TypeInfo.CloseProcedure) {
  1709. KIRQL SaveIrql;
  1710. ObpBeginTypeSpecificCallOut( SaveIrql );
  1711. (*ObjectType->TypeInfo.CloseProcedure)( Process,
  1712. Object,
  1713. GrantedAccess,
  1714. ProcessHandleCount,
  1715. SystemHandleCount );
  1716. ObpEndTypeSpecificCallOut( SaveIrql, "Close", ObjectType, Object );
  1717. }
  1718. ObpDeleteNameCheck( Object );
  1719. InterlockedDecrement((PLONG)&ObjectType->TotalNumberOfHandles);
  1720. return;
  1721. }
  1722. NTSTATUS
  1723. ObpCreateHandle (
  1724. IN OB_OPEN_REASON OpenReason,
  1725. IN PVOID Object,
  1726. IN POBJECT_TYPE ExpectedObjectType OPTIONAL,
  1727. IN PACCESS_STATE AccessState,
  1728. IN ULONG ObjectPointerBias OPTIONAL,
  1729. IN ULONG Attributes,
  1730. IN POBP_LOOKUP_CONTEXT LookupContext,
  1731. IN KPROCESSOR_MODE AccessMode,
  1732. OUT PVOID *ReferencedNewObject OPTIONAL,
  1733. OUT PHANDLE Handle
  1734. )
  1735. /*++
  1736. Routine Description:
  1737. This function creates a new handle to an existing object
  1738. Arguments:
  1739. OpenReason - The reason why we are doing this work
  1740. Object - A pointer to the body of the new object
  1741. ExpectedObjectType - Optionally Supplies the object type that
  1742. the caller is expecting
  1743. AccessState - Supplies the access state for the handle requested
  1744. by the caller
  1745. ObjectPointerBias - Optionally supplies a count of addition
  1746. increments we do to the pointer count for the object
  1747. Attributes - Desired attributes for the handle
  1748. DirectoryLocked - Indicates if the root directory mutex is already held
  1749. AccessMode - Supplies the mode of the requestor.
  1750. ReferencedNewObject - Optionally receives a pointer to the body
  1751. of the new object
  1752. Handle - Receives the new handle value
  1753. Return Value:
  1754. An appropriate status value
  1755. --*/
  1756. {
  1757. NTSTATUS Status;
  1758. POBJECT_HEADER ObjectHeader;
  1759. POBJECT_TYPE ObjectType;
  1760. PVOID ObjectTable;
  1761. HANDLE_TABLE_ENTRY ObjectTableEntry;
  1762. HANDLE NewHandle;
  1763. ACCESS_MASK DesiredAccess;
  1764. ACCESS_MASK GrantedAccess;
  1765. ACCESS_MASK AuditMask;
  1766. BOOLEAN AttachedToProcess = FALSE;
  1767. BOOLEAN KernelHandle = FALSE;
  1768. KAPC_STATE ApcState;
  1769. HANDLE_TABLE_ENTRY_INFO ObjectInfo;
  1770. PAGED_CODE();
  1771. ObpValidateIrql( "ObpCreateHandle" );
  1772. //
  1773. // Get a pointer to the object header and object type
  1774. //
  1775. ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object );
  1776. ObjectType = ObjectHeader->Type;
  1777. //
  1778. // If the object type isn't what was expected then
  1779. // return an error to our caller, but first see if
  1780. // we should release the directory mutex
  1781. //
  1782. if ((ARGUMENT_PRESENT( ExpectedObjectType )) &&
  1783. (ObjectType != ExpectedObjectType )) {
  1784. if (LookupContext) {
  1785. ObpReleaseLookupContext( LookupContext );
  1786. }
  1787. return( STATUS_OBJECT_TYPE_MISMATCH );
  1788. }
  1789. //
  1790. // Set the first ulong of the object table entry to point
  1791. // back to the object header
  1792. //
  1793. ObjectTableEntry.Object = ObjectHeader;
  1794. //
  1795. // Now get a pointer to the object table for either the current process
  1796. // of the kernel handle table. OBJ_KERNEL_HANDLE dropped for user mode on capture.
  1797. //
  1798. if ((Attributes & OBJ_KERNEL_HANDLE) /* && (AccessMode == KernelMode) */) {
  1799. ObjectTable = ObpKernelHandleTable;
  1800. KernelHandle = TRUE;
  1801. //
  1802. // Go to the system process if we have to
  1803. //
  1804. if (PsGetCurrentProcess() != PsInitialSystemProcess) {
  1805. KeStackAttachProcess (&PsInitialSystemProcess->Pcb, &ApcState);
  1806. AttachedToProcess = TRUE;
  1807. }
  1808. } else {
  1809. ObjectTable = ObpGetObjectTable();
  1810. }
  1811. //
  1812. // ObpIncrementHandleCount will perform access checking on the
  1813. // object being opened as appropriate.
  1814. //
  1815. Status = ObpIncrementHandleCount( OpenReason,
  1816. PsGetCurrentProcess(),
  1817. Object,
  1818. ObjectType,
  1819. AccessState,
  1820. AccessMode,
  1821. Attributes );
  1822. if (AccessState->GenerateOnClose) {
  1823. Attributes |= OBJ_AUDIT_OBJECT_CLOSE;
  1824. }
  1825. //
  1826. // Or in some low order bits into the first ulong of the object
  1827. // table entry
  1828. //
  1829. ObjectTableEntry.ObAttributes |= (Attributes & OBJ_HANDLE_ATTRIBUTES);
  1830. //
  1831. // Merge both the remaining desired access and the currently
  1832. // granted access states into one mask and then compute
  1833. // the granted access
  1834. //
  1835. DesiredAccess = AccessState->RemainingDesiredAccess |
  1836. AccessState->PreviouslyGrantedAccess;
  1837. GrantedAccess = DesiredAccess &
  1838. (ObjectType->TypeInfo.ValidAccessMask | ACCESS_SYSTEM_SECURITY );
  1839. //
  1840. // AccessState->PreviouslyGrantedAccess is used for success audits in SeAuditHandleCreation() which uses it in calls
  1841. // to SepAdtPrivilegeObjectAuditAlarm() and SepAdtOpenObjectAuditAlarm(). Sanitize any bad bits from it.
  1842. //
  1843. AccessState->PreviouslyGrantedAccess = GrantedAccess;
  1844. //
  1845. // Compute and save away the audit mask for this object
  1846. // (if one exists). Note we only do this if the GenerateOnClose
  1847. // flag comes back in the access state, because this tells us
  1848. // that the audit is a result of what is in the SACL.
  1849. //
  1850. ObjectInfo.AuditMask = ((PAUX_ACCESS_DATA)AccessState->AuxData)->MaximumAuditMask;
  1851. //
  1852. // Unlock the directory if it is locked and make sure
  1853. // we've been successful so far
  1854. //
  1855. if (LookupContext) {
  1856. ObpReleaseLookupContext( LookupContext );
  1857. }
  1858. if (!NT_SUCCESS( Status )) {
  1859. //
  1860. // If we are attached to the system process then return
  1861. // back to our caller
  1862. //
  1863. if (AttachedToProcess) {
  1864. KeUnstackDetachProcess(&ApcState);
  1865. AttachedToProcess = FALSE;
  1866. }
  1867. return( Status );
  1868. }
  1869. //
  1870. // Bias the pointer count if that is what the caller wanted
  1871. //
  1872. if (ARGUMENT_PRESENT( (PVOID)(ULONG_PTR)ObjectPointerBias )) {
  1873. ObpIncrPointerCountEx (ObjectHeader, ObjectPointerBias);
  1874. }
  1875. //
  1876. // Set the granted access mask in the object table entry (second ulong)
  1877. //
  1878. #if i386
  1879. if (NtGlobalFlag & FLG_KERNEL_STACK_TRACE_DB) {
  1880. LONG StackTraceIndex;
  1881. ObjectTableEntry.GrantedAccessIndex = ObpComputeGrantedAccessIndex( GrantedAccess );
  1882. if (AccessMode == KernelMode) {
  1883. StackTraceIndex = RtlLogStackBackTrace();
  1884. } else {
  1885. StackTraceIndex = RtlLogUmodeStackBackTrace();
  1886. }
  1887. //
  1888. // Save the stack trace only if the index fits the CreatorBackTraceIndex
  1889. // minus the ProtectOnClose bit
  1890. //
  1891. if (StackTraceIndex < OBP_CREATOR_BACKTRACE_LIMIT) {
  1892. ObjectTableEntry.CreatorBackTraceIndex = (USHORT)StackTraceIndex;
  1893. } else {
  1894. ObjectTableEntry.CreatorBackTraceIndex = 0;
  1895. }
  1896. } else {
  1897. ObjectTableEntry.GrantedAccess = GrantedAccess;
  1898. }
  1899. #else
  1900. ObjectTableEntry.GrantedAccess = GrantedAccess;
  1901. #endif // i386
  1902. //
  1903. // Add this new object table entry to the object table for the process
  1904. //
  1905. ObpEncodeProtectClose(ObjectTableEntry);
  1906. NewHandle = ExCreateHandle( ObjectTable, &ObjectTableEntry );
  1907. //
  1908. // If we didn't get a handle then cleanup after ourselves and return
  1909. // the error to our caller
  1910. //
  1911. if (NewHandle == NULL) {
  1912. if (ARGUMENT_PRESENT( (PVOID)(ULONG_PTR)ObjectPointerBias )) {
  1913. ObpDecrPointerCountEx (ObjectHeader, ObjectPointerBias);
  1914. }
  1915. ObpDecrementHandleCount( PsGetCurrentProcess(),
  1916. ObjectHeader,
  1917. ObjectType,
  1918. GrantedAccess );
  1919. //
  1920. // If we are attached to the system process then return
  1921. // back to our caller
  1922. //
  1923. if (AttachedToProcess) {
  1924. KeUnstackDetachProcess(&ApcState);
  1925. AttachedToProcess = FALSE;
  1926. }
  1927. return( STATUS_INSUFFICIENT_RESOURCES );
  1928. }
  1929. if ( ObjectInfo.AuditMask != 0 ) {
  1930. PHANDLE_TABLE_ENTRY HandleTableEntry;
  1931. PKTHREAD CurrentThread;
  1932. CurrentThread = KeGetCurrentThread();
  1933. KeEnterCriticalRegionThread( CurrentThread );
  1934. //
  1935. // Make sure it's the same object before setting the handle information.
  1936. // The user may have closed it immediately after the ExCreateHandle call,
  1937. // so at this time it may either be invalid or a completely different object.
  1938. //
  1939. HandleTableEntry = ExMapHandleToPointer ( ObjectTable, NewHandle );
  1940. if (HandleTableEntry != NULL) {
  1941. if (((ULONG_PTR)(HandleTableEntry->Object) & ~OBJ_HANDLE_ATTRIBUTES) == (ULONG_PTR)ObjectHeader) {
  1942. ExSetHandleInfo(ObjectTable, NewHandle, &ObjectInfo, TRUE);
  1943. }
  1944. ExUnlockHandleTableEntry( ObjectTable, HandleTableEntry );
  1945. }
  1946. KeLeaveCriticalRegionThread( CurrentThread );
  1947. }
  1948. //
  1949. // We have a new Ex style handle now make it an ob style handle and also
  1950. // adjust for the kernel handle by setting the sign bit in the handle
  1951. // value
  1952. //
  1953. if (KernelHandle) {
  1954. NewHandle = EncodeKernelHandle( NewHandle );
  1955. }
  1956. *Handle = NewHandle;
  1957. //
  1958. // If requested, generate audit messages to indicate that a new handle
  1959. // has been allocated.
  1960. //
  1961. // This is the final security operation in the creation/opening of the
  1962. // object.
  1963. //
  1964. if ( AccessState->GenerateAudit ) {
  1965. SeAuditHandleCreation( AccessState,
  1966. *Handle );
  1967. }
  1968. if (OpenReason == ObCreateHandle) {
  1969. PAUX_ACCESS_DATA AuxData = AccessState->AuxData;
  1970. if ( ( AuxData->PrivilegesUsed != NULL) && (AuxData->PrivilegesUsed->PrivilegeCount > 0) ) {
  1971. SePrivilegeObjectAuditAlarm( *Handle,
  1972. &AccessState->SubjectSecurityContext,
  1973. GrantedAccess,
  1974. AuxData->PrivilegesUsed,
  1975. TRUE,
  1976. KeGetPreviousMode() );
  1977. }
  1978. }
  1979. //
  1980. // If the caller had a pointer bias and wanted the new reference object
  1981. // then return that value
  1982. //
  1983. if ((ARGUMENT_PRESENT( (PVOID)(ULONG_PTR)ObjectPointerBias )) &&
  1984. (ARGUMENT_PRESENT( ReferencedNewObject ))) {
  1985. *ReferencedNewObject = Object;
  1986. }
  1987. //
  1988. // If we are attached to the system process then return
  1989. // back to our caller
  1990. //
  1991. if (AttachedToProcess) {
  1992. KeUnstackDetachProcess(&ApcState);
  1993. AttachedToProcess = FALSE;
  1994. }
  1995. //
  1996. // And return to our caller
  1997. //
  1998. return( STATUS_SUCCESS );
  1999. }
  2000. NTSTATUS
  2001. ObpCreateUnnamedHandle (
  2002. IN PVOID Object,
  2003. IN ACCESS_MASK DesiredAccess,
  2004. IN ULONG ObjectPointerBias OPTIONAL,
  2005. IN ULONG Attributes,
  2006. IN KPROCESSOR_MODE AccessMode,
  2007. OUT PVOID *ReferencedNewObject OPTIONAL,
  2008. OUT PHANDLE Handle
  2009. )
  2010. /*++
  2011. Routine Description:
  2012. This function creates a new unnamed handle for an existing object
  2013. Arguments:
  2014. Object - A pointer to the body of the new object
  2015. DesiredAccess - Supplies the access mask being requsted
  2016. ObjectPointerBias - Optionally supplies a count of addition
  2017. increments we do to the pointer count for the object
  2018. Attributes - Desired attributes for the handle
  2019. AccessMode - Supplies the mode of the requestor.
  2020. ReferencedNewObject - Optionally receives a pointer to the body
  2021. of the new object
  2022. Handle - Receives the new handle value
  2023. Return Value:
  2024. An appropriate status value
  2025. --*/
  2026. {
  2027. NTSTATUS Status;
  2028. POBJECT_HEADER ObjectHeader;
  2029. POBJECT_TYPE ObjectType;
  2030. PVOID ObjectTable;
  2031. HANDLE_TABLE_ENTRY ObjectTableEntry;
  2032. HANDLE NewHandle;
  2033. ULONG BiasCount;
  2034. ACCESS_MASK GrantedAccess;
  2035. BOOLEAN AttachedToProcess = FALSE;
  2036. BOOLEAN KernelHandle = FALSE;
  2037. KAPC_STATE ApcState;
  2038. PAGED_CODE();
  2039. ObpValidateIrql( "ObpCreateUnnamedHandle" );
  2040. //
  2041. // Get the object header and type for the new object
  2042. //
  2043. ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object );
  2044. ObjectType = ObjectHeader->Type;
  2045. //
  2046. // Set the first ulong of the object table entry to point
  2047. // to the object header and then or in the low order attribute
  2048. // bits
  2049. //
  2050. ObjectTableEntry.Object = ObjectHeader;
  2051. ObjectTableEntry.ObAttributes |= (Attributes & OBJ_HANDLE_ATTRIBUTES);
  2052. //
  2053. // Now get a pointer to the object table for either the current process
  2054. // of the kernel handle table
  2055. //
  2056. if ((Attributes & OBJ_KERNEL_HANDLE) /* && (AccessMode == KernelMode) */) {
  2057. ObjectTable = ObpKernelHandleTable;
  2058. KernelHandle = TRUE;
  2059. //
  2060. // Go to the system process if we have to
  2061. //
  2062. if (PsGetCurrentProcess() != PsInitialSystemProcess) {
  2063. KeStackAttachProcess (&PsInitialSystemProcess->Pcb, &ApcState);
  2064. AttachedToProcess = TRUE;
  2065. }
  2066. } else {
  2067. ObjectTable = ObpGetObjectTable();
  2068. }
  2069. //
  2070. // Increment the handle count, this routine also does the access
  2071. // check if necessary
  2072. //
  2073. Status = ObpIncrementUnnamedHandleCount( &DesiredAccess,
  2074. PsGetCurrentProcess(),
  2075. Object,
  2076. ObjectType,
  2077. AccessMode,
  2078. Attributes );
  2079. GrantedAccess = DesiredAccess &
  2080. (ObjectType->TypeInfo.ValidAccessMask | ACCESS_SYSTEM_SECURITY );
  2081. if (!NT_SUCCESS( Status )) {
  2082. //
  2083. // If we are attached to the system process then return
  2084. // back to our caller
  2085. //
  2086. if (AttachedToProcess) {
  2087. KeUnstackDetachProcess(&ApcState);
  2088. AttachedToProcess = FALSE;
  2089. }
  2090. return( Status );
  2091. }
  2092. //
  2093. // Bias the pointer count if that is what the caller wanted
  2094. //
  2095. if (ARGUMENT_PRESENT( (PVOID)(ULONG_PTR)ObjectPointerBias )) {
  2096. ObpIncrPointerCountEx (ObjectHeader, ObjectPointerBias);
  2097. }
  2098. //
  2099. // Set the granted access mask in the object table entry (second ulong)
  2100. //
  2101. #if i386
  2102. if (NtGlobalFlag & FLG_KERNEL_STACK_TRACE_DB) {
  2103. LONG StackTraceIndex;
  2104. ObjectTableEntry.GrantedAccessIndex = ObpComputeGrantedAccessIndex( GrantedAccess );
  2105. if (AccessMode == KernelMode) {
  2106. StackTraceIndex = RtlLogStackBackTrace();
  2107. } else {
  2108. StackTraceIndex = RtlLogUmodeStackBackTrace();
  2109. }
  2110. //
  2111. // Save the stack trace only if the index fits the CreatorBackTraceIndex
  2112. // minus the ProtectOnClose bit
  2113. //
  2114. if (StackTraceIndex < OBP_CREATOR_BACKTRACE_LIMIT) {
  2115. ObjectTableEntry.CreatorBackTraceIndex = (USHORT)StackTraceIndex;
  2116. } else {
  2117. ObjectTableEntry.CreatorBackTraceIndex = 0;
  2118. }
  2119. } else {
  2120. ObjectTableEntry.GrantedAccess = GrantedAccess;
  2121. }
  2122. #else
  2123. ObjectTableEntry.GrantedAccess = GrantedAccess;
  2124. #endif // i386
  2125. //
  2126. // Add this new object table entry to the object table for the process
  2127. //
  2128. ObpEncodeProtectClose(ObjectTableEntry);
  2129. NewHandle = ExCreateHandle( ObjectTable, &ObjectTableEntry );
  2130. //
  2131. // If we didn't get a handle then cleanup after ourselves and return
  2132. // the error to our caller
  2133. //
  2134. if (NewHandle == NULL) {
  2135. if (ARGUMENT_PRESENT( (PVOID)(ULONG_PTR)ObjectPointerBias )) {
  2136. ObpDecrPointerCountEx (ObjectHeader, ObjectPointerBias);
  2137. }
  2138. ObpDecrementHandleCount( PsGetCurrentProcess(),
  2139. ObjectHeader,
  2140. ObjectType,
  2141. GrantedAccess );
  2142. //
  2143. // If we are attached to the system process then return
  2144. // back to our caller
  2145. //
  2146. if (AttachedToProcess) {
  2147. KeUnstackDetachProcess(&ApcState);
  2148. AttachedToProcess = FALSE;
  2149. }
  2150. return( STATUS_INSUFFICIENT_RESOURCES );
  2151. }
  2152. //
  2153. // We have a new Ex style handle now make it an ob style handle and also
  2154. // adjust for the kernel handle by setting the sign bit in the handle
  2155. // value
  2156. //
  2157. if (KernelHandle) {
  2158. NewHandle = EncodeKernelHandle( NewHandle );
  2159. }
  2160. *Handle = NewHandle;
  2161. //
  2162. // If the caller had a pointer bias and wanted the new reference object
  2163. // then return that value
  2164. //
  2165. if ((ARGUMENT_PRESENT( (PVOID)(ULONG_PTR)ObjectPointerBias )) &&
  2166. (ARGUMENT_PRESENT( ReferencedNewObject ))) {
  2167. *ReferencedNewObject = Object;
  2168. }
  2169. //
  2170. // If we are attached to the system process then return
  2171. // back to our caller
  2172. //
  2173. if (AttachedToProcess) {
  2174. KeUnstackDetachProcess(&ApcState);
  2175. AttachedToProcess = FALSE;
  2176. }
  2177. return( STATUS_SUCCESS );
  2178. }
  2179. NTSTATUS
  2180. ObpValidateDesiredAccess (
  2181. IN ACCESS_MASK DesiredAccess
  2182. )
  2183. /*++
  2184. Routine Description:
  2185. This routine checks the input desired access mask to see that
  2186. some invalid bits are not set. The invalid bits are the top
  2187. two reserved bits and the top three standard rights bits.
  2188. See \nt\public\sdk\inc\ntseapi.h for more details.
  2189. Arguments:
  2190. DesiredAccess - Supplies the mask being checked
  2191. Return Value:
  2192. STATUS_ACCESS_DENIED if one or more of the wrongs bits are set and
  2193. STATUS_SUCCESS otherwise
  2194. --*/
  2195. {
  2196. if (DesiredAccess & 0x0CE00000) {
  2197. return( STATUS_ACCESS_DENIED );
  2198. } else {
  2199. return( STATUS_SUCCESS );
  2200. }
  2201. }
  2202. #if i386
  2203. //
  2204. // The following three variables are just performance counters
  2205. // for the following two routines
  2206. //
  2207. ULONG ObpXXX1;
  2208. ULONG ObpXXX2;
  2209. ULONG ObpXXX3;
  2210. USHORT
  2211. ObpComputeGrantedAccessIndex (
  2212. ACCESS_MASK GrantedAccess
  2213. )
  2214. /*++
  2215. Routine Description:
  2216. This routine takes a granted access and returns and index
  2217. back to our cache of granted access masks.
  2218. Arguments:
  2219. GrantedAccess - Supplies the access mask being added to the cache
  2220. Return Value:
  2221. USHORT - returns an index in the cache for the input granted access
  2222. --*/
  2223. {
  2224. ULONG GrantedAccessIndex, n;
  2225. PACCESS_MASK p;
  2226. PKTHREAD CurrentThread;
  2227. ObpXXX1 += 1;
  2228. //
  2229. // Lock the global data structure
  2230. //
  2231. CurrentThread = KeGetCurrentThread ();
  2232. KeEnterCriticalRegionThread (CurrentThread);
  2233. ExAcquirePushLockExclusive ( &ObpLock );
  2234. n = ObpCurCachedGrantedAccessIndex;
  2235. p = ObpCachedGrantedAccesses;
  2236. //
  2237. // For each index in our cache look for a match and if found
  2238. // then unlock the data structure and return that index
  2239. //
  2240. for (GrantedAccessIndex = 0; GrantedAccessIndex < n; GrantedAccessIndex++, p++ ) {
  2241. ObpXXX2 += 1;
  2242. if (*p == GrantedAccess) {
  2243. ExReleasePushLockExclusive ( &ObpLock );
  2244. KeLeaveCriticalRegionThread (CurrentThread);
  2245. return (USHORT)GrantedAccessIndex;
  2246. }
  2247. }
  2248. //
  2249. // We didn't find a match now see if we've maxed out the cache
  2250. //
  2251. if (ObpCurCachedGrantedAccessIndex == ObpMaxCachedGrantedAccessIndex) {
  2252. DbgPrint( "OB: GrantedAccess cache limit hit.\n" );
  2253. DbgBreakPoint();
  2254. }
  2255. //
  2256. // Set the granted access to the next free slot and increment the
  2257. // number used in the cache, release the lock, and return the
  2258. // new index to our caller
  2259. //
  2260. *p = GrantedAccess;
  2261. ObpCurCachedGrantedAccessIndex += 1;
  2262. ExReleasePushLockExclusive ( &ObpLock );
  2263. KeLeaveCriticalRegionThread (CurrentThread);
  2264. return (USHORT)GrantedAccessIndex;
  2265. }
  2266. ACCESS_MASK
  2267. ObpTranslateGrantedAccessIndex (
  2268. USHORT GrantedAccessIndex
  2269. )
  2270. /*++
  2271. Routine Description:
  2272. This routine takes as input a cache index and returns
  2273. the corresponding granted access mask
  2274. Arguments:
  2275. GrantedAccessIndex - Supplies the cache index to look up
  2276. Return Value:
  2277. ACCESS_MASK - Returns the corresponding desired access mask
  2278. --*/
  2279. {
  2280. KLOCK_QUEUE_HANDLE LockHandle;
  2281. ACCESS_MASK GrantedAccess = (ACCESS_MASK)0;
  2282. PKTHREAD CurrentThread;
  2283. ObpXXX3 += 1;
  2284. //
  2285. // Lock the global data structure
  2286. //
  2287. CurrentThread = KeGetCurrentThread ();
  2288. KeEnterCriticalRegionThread (CurrentThread);
  2289. ExAcquirePushLockExclusive ( &ObpLock );
  2290. //
  2291. // If the input index is within bounds then get the granted
  2292. // access
  2293. //
  2294. if (GrantedAccessIndex < ObpCurCachedGrantedAccessIndex) {
  2295. GrantedAccess = ObpCachedGrantedAccesses[ GrantedAccessIndex ];
  2296. }
  2297. //
  2298. // Release the lock and return the granted access to our caller
  2299. //
  2300. ExReleasePushLockExclusive ( &ObpLock );
  2301. KeLeaveCriticalRegionThread (CurrentThread);
  2302. return GrantedAccess;
  2303. }
  2304. #endif // i386