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.

557 lines
13 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. obclose.c
  5. Abstract:
  6. Object close system service
  7. Author:
  8. Steve Wood (stevewo) 31-Mar-1989
  9. Revision History:
  10. --*/
  11. #include "obp.h"
  12. #ifdef ALLOC_PRAGMA
  13. #pragma alloc_text(PAGE,NtMakeTemporaryObject)
  14. #pragma alloc_text(PAGE,NtClose)
  15. #pragma alloc_text(PAGE,ObMakeTemporaryObject)
  16. #pragma alloc_text(PAGE,ObpCloseHandleTableEntry)
  17. #pragma alloc_text(PAGE,ObCloseHandle)
  18. #pragma alloc_text(PAGE,ObpCloseHandle)
  19. #endif
  20. //
  21. // Indicates if auditing is enabled so we have to close down the object
  22. // audit alarm
  23. //
  24. extern BOOLEAN SepAdtAuditingEnabled;
  25. ObpCloseHandleTableEntry (
  26. IN PHANDLE_TABLE ObjectTable,
  27. IN PHANDLE_TABLE_ENTRY ObjectTableEntry,
  28. IN HANDLE Handle,
  29. IN KPROCESSOR_MODE PreviousMode,
  30. IN BOOLEAN Rundown,
  31. IN BOOLEAN CanNotRaise
  32. )
  33. /*++
  34. Routine Description:
  35. This function is used to close a handle table entry
  36. Arguments:
  37. ObjectTableEntry - Supplies the entry being closed. It must be locked
  38. PreviousMode - Mode of caller
  39. Rundown - Called as part of process rundown, ignore protected handles in this mode
  40. CanNotRaise - Can not raise user exceptions
  41. Return Value:
  42. An appropriate status value
  43. --*/
  44. {
  45. POBJECT_HEADER ObjectHeader;
  46. POBJECT_TYPE ObjectType;
  47. PVOID Object;
  48. ULONG CapturedGrantedAccess;
  49. ULONG CapturedAttributes;
  50. #if DBG
  51. KIRQL SaveIrql;
  52. #endif // DBG
  53. //
  54. // From the object table entry we can grab a pointer to the object
  55. // header, get its type and its body
  56. //
  57. ObjectHeader = (POBJECT_HEADER)(((ULONG_PTR)(ObjectTableEntry->Object)) & ~OBJ_HANDLE_ATTRIBUTES);
  58. ObjectType = ObjectHeader->Type;
  59. Object = &ObjectHeader->Body;
  60. //
  61. // If the object type specifies an okay to close procedure then we
  62. // need to invoke that callback. If the callback doesn't want us to
  63. // close handle then unlock the object table and return the error
  64. // to our caller
  65. //
  66. if (ObjectType->TypeInfo.OkayToCloseProcedure != NULL) {
  67. ObpBeginTypeSpecificCallOut( SaveIrql );
  68. if (!(*ObjectType->TypeInfo.OkayToCloseProcedure)( PsGetCurrentProcess(),
  69. Object,
  70. Handle,
  71. PreviousMode )) {
  72. ObpEndTypeSpecificCallOut( SaveIrql, "NtClose", ObjectType, Object );
  73. ExUnlockHandleTableEntry( ObjectTable, ObjectTableEntry );
  74. return STATUS_HANDLE_NOT_CLOSABLE;
  75. }
  76. ObpEndTypeSpecificCallOut( SaveIrql, "NtClose", ObjectType, Object );
  77. }
  78. CapturedAttributes = ObpGetHandleAttributes(ObjectTableEntry);
  79. //
  80. // If the previous mode was user and the handle is protected from
  81. // being closed, then we'll either raise or return an error depending
  82. // on the global flags and debugger port situation.
  83. //
  84. if ((CapturedAttributes & OBJ_PROTECT_CLOSE) != 0 && Rundown == FALSE) {
  85. if (PreviousMode != KernelMode) {
  86. PETHREAD CurrentThread;
  87. ExUnlockHandleTableEntry( ObjectTable, ObjectTableEntry );
  88. CurrentThread = PsGetCurrentThread ();
  89. if (!CanNotRaise && !KeIsAttachedProcess() &&
  90. !PsIsThreadTerminating (CurrentThread) &&
  91. !CurrentThread->Tcb.ApcState.KernelApcInProgress &&
  92. ((NtGlobalFlag & FLG_ENABLE_CLOSE_EXCEPTIONS) ||
  93. (PsGetCurrentProcess()->DebugPort != NULL))) {
  94. //
  95. // Raise and exception in user mode
  96. //
  97. return KeRaiseUserException(STATUS_HANDLE_NOT_CLOSABLE);
  98. } else {
  99. return STATUS_HANDLE_NOT_CLOSABLE;
  100. }
  101. } else {
  102. KeBugCheckEx(INVALID_KERNEL_HANDLE, (ULONG_PTR)Handle, 0, 0, 0);
  103. }
  104. }
  105. //
  106. // Get the granted access for the handle
  107. //
  108. #if i386
  109. if (NtGlobalFlag & FLG_KERNEL_STACK_TRACE_DB) {
  110. CapturedGrantedAccess = ObpTranslateGrantedAccessIndex( ObjectTableEntry->GrantedAccessIndex );
  111. } else {
  112. CapturedGrantedAccess = ObpDecodeGrantedAccess(ObjectTableEntry->GrantedAccess);
  113. }
  114. #else
  115. CapturedGrantedAccess = ObpDecodeGrantedAccess(ObjectTableEntry->GrantedAccess);
  116. #endif // i386
  117. //
  118. // Now remove the handle from the handle table
  119. //
  120. ExDestroyHandle( ObjectTable,
  121. Handle,
  122. ObjectTableEntry );
  123. //
  124. // perform any auditing required
  125. //
  126. //
  127. // Extract the value of the GenerateOnClose bit stored
  128. // after object open auditing is performed. This value
  129. // was stored by a call to ObSetGenerateOnClosed.
  130. //
  131. if (CapturedAttributes & OBJ_AUDIT_OBJECT_CLOSE) {
  132. if ( SepAdtAuditingEnabled ) {
  133. SeCloseObjectAuditAlarm( Object,
  134. (HANDLE)((ULONG_PTR)Handle & ~OBJ_HANDLE_TAGBITS), // Mask off the tagbits defined for OB objects.
  135. TRUE );
  136. }
  137. }
  138. //
  139. // Since we took the handle away we need to decrement the objects
  140. // handle count, and remove a reference
  141. //
  142. ObpDecrementHandleCount( PsGetCurrentProcess(),
  143. ObjectHeader,
  144. ObjectType,
  145. CapturedGrantedAccess );
  146. ObDereferenceObject( Object );
  147. //
  148. // And return to our caller
  149. //
  150. return STATUS_SUCCESS;
  151. }
  152. NTSTATUS
  153. ObpCloseHandle (
  154. IN HANDLE Handle,
  155. IN KPROCESSOR_MODE PreviousMode,
  156. IN BOOLEAN CanNotRaise
  157. )
  158. /*++
  159. Routine Description:
  160. This function is used to close access to the specified handle with the given mode
  161. Arguments:
  162. Handle - Supplies the handle being closed
  163. PreviousMode - Processor mode to be used in the handle access checks.
  164. CanNotRaise - We are not allowed to do a user mode raise.
  165. Return Value:
  166. An appropriate status value
  167. --*/
  168. {
  169. PHANDLE_TABLE ObjectTable;
  170. PHANDLE_TABLE_ENTRY ObjectTableEntry;
  171. NTSTATUS Status;
  172. BOOLEAN AttachedToProcess = FALSE;
  173. KAPC_STATE ApcState;
  174. PETHREAD CurrentThread;
  175. PEPROCESS CurrentProcess;
  176. ObpValidateIrql( "NtClose" );
  177. CurrentThread = PsGetCurrentThread ();
  178. CurrentProcess = PsGetCurrentProcessByThread (CurrentThread);
  179. //
  180. // For the current process we will grab its handle/object table and
  181. // translate the handle to its corresponding table entry. If the
  182. // call is successful it also lock down the handle table. But first
  183. // check for a kernel handle and attach and use that table if so.
  184. //
  185. if (IsKernelHandle( Handle, PreviousMode )) {
  186. Handle = DecodeKernelHandle( Handle );
  187. ObjectTable = ObpKernelHandleTable;
  188. //
  189. // Go to the system process if we have to
  190. //
  191. if (CurrentProcess != PsInitialSystemProcess) {
  192. KeStackAttachProcess (&PsInitialSystemProcess->Pcb, &ApcState);
  193. AttachedToProcess = TRUE;
  194. }
  195. } else {
  196. ObjectTable = CurrentProcess->ObjectTable;
  197. }
  198. //
  199. // Protect ourselves from being interrupted while we hold a handle table
  200. // entry lock
  201. //
  202. KeEnterCriticalRegionThread(&CurrentThread->Tcb);
  203. ObjectTableEntry = ExMapHandleToPointer( ObjectTable,
  204. Handle );
  205. //
  206. // Check that the specified handle is legitimate otherwise we can
  207. // assume the caller just passed in some bogus handle value
  208. //
  209. if (ObjectTableEntry != NULL) {
  210. Status = ObpCloseHandleTableEntry (ObjectTable, ObjectTableEntry, Handle, PreviousMode, FALSE, CanNotRaise);
  211. KeLeaveCriticalRegionThread(&CurrentThread->Tcb);
  212. //
  213. // If we are attached to the system process then detach
  214. //
  215. if (AttachedToProcess) {
  216. KeUnstackDetachProcess(&ApcState);
  217. AttachedToProcess = FALSE;
  218. }
  219. } else {
  220. KeLeaveCriticalRegionThread(&CurrentThread->Tcb);
  221. //
  222. // At this point the input handle did not translate to a valid
  223. // object table entry
  224. //
  225. //
  226. // If we are attached to the system process then return
  227. // back to our caller
  228. //
  229. if (AttachedToProcess) {
  230. KeUnstackDetachProcess(&ApcState);
  231. AttachedToProcess = FALSE;
  232. }
  233. //
  234. // Now if the handle is not null and it does not represent the
  235. // current thread or process then if we're user mode we either raise
  236. // or return an error
  237. //
  238. if ((Handle != NULL) &&
  239. (Handle != NtCurrentThread()) &&
  240. (Handle != NtCurrentProcess())) {
  241. if (PreviousMode != KernelMode) {
  242. if ((NtGlobalFlag & FLG_ENABLE_CLOSE_EXCEPTIONS) ||
  243. (CurrentProcess->DebugPort != NULL)) {
  244. if (!CanNotRaise && !KeIsAttachedProcess() &&
  245. !PsIsThreadTerminating (CurrentThread) &&
  246. !CurrentThread->Tcb.ApcState.KernelApcInProgress) {
  247. return KeRaiseUserException (STATUS_INVALID_HANDLE);
  248. } else {
  249. return STATUS_INVALID_HANDLE;
  250. }
  251. }
  252. } else {
  253. //
  254. // bugcheck here if kernel debugger is enabled and if kernel mode code is
  255. // closing a bogus handle and process is not exiting. Ignore
  256. // if no PEB as this occurs if process is killed before
  257. // really starting.
  258. //
  259. if (( !PsIsThreadTerminating(CurrentThread)) &&
  260. (CurrentProcess->Peb != NULL)) {
  261. if (KdDebuggerEnabled) {
  262. KeBugCheckEx(INVALID_KERNEL_HANDLE, (ULONG_PTR)Handle, 1, 0, 0);
  263. }
  264. }
  265. }
  266. }
  267. Status = STATUS_INVALID_HANDLE;
  268. }
  269. return Status;
  270. }
  271. NTSTATUS
  272. ObCloseHandle (
  273. IN HANDLE Handle,
  274. IN KPROCESSOR_MODE PreviousMode
  275. )
  276. /*++
  277. Routine Description:
  278. This function is used to close access to the specified handle with the given mode
  279. Arguments:
  280. Handle - Supplies the handle being closed
  281. PreviousMode - Processor mode to be used in the handle access checks.
  282. Return Value:
  283. An appropriate status value
  284. --*/
  285. {
  286. return ObpCloseHandle (Handle,
  287. PreviousMode,
  288. TRUE);
  289. }
  290. NTSTATUS
  291. NtClose (
  292. IN HANDLE Handle
  293. )
  294. /*++
  295. Routine Description:
  296. This function is used to close access to the specified handle
  297. Arguments:
  298. Handle - Supplies the handle being closed
  299. Return Value:
  300. An appropriate status value
  301. --*/
  302. {
  303. return ObpCloseHandle (Handle,
  304. KeGetPreviousMode (),
  305. FALSE);
  306. }
  307. NTSTATUS
  308. NtMakeTemporaryObject (
  309. IN HANDLE Handle
  310. )
  311. /*++
  312. Routine Description:
  313. This routine makes the specified object non permanent.
  314. Arguments:
  315. Handle - Supplies a handle to the object being modified
  316. Return Value:
  317. An appropriate status value.
  318. --*/
  319. {
  320. KPROCESSOR_MODE PreviousMode;
  321. NTSTATUS Status;
  322. PVOID Object;
  323. OBJECT_HANDLE_INFORMATION HandleInformation;
  324. PAGED_CODE();
  325. //
  326. // Get previous processor mode and probe output argument if necessary.
  327. //
  328. PreviousMode = KeGetPreviousMode();
  329. Status = ObReferenceObjectByHandle( Handle,
  330. DELETE,
  331. (POBJECT_TYPE)NULL,
  332. PreviousMode,
  333. &Object,
  334. &HandleInformation );
  335. if (!NT_SUCCESS( Status )) {
  336. return( Status );
  337. }
  338. //
  339. // Make the object temporary. Note that the object should still
  340. // have a name and directory entry because its handle count is not
  341. // zero
  342. //
  343. ObMakeTemporaryObject( Object );
  344. //
  345. // Check if we need to generate a delete object audit/alarm
  346. //
  347. if (HandleInformation.HandleAttributes & OBJ_AUDIT_OBJECT_CLOSE) {
  348. SeDeleteObjectAuditAlarm( Object,
  349. Handle );
  350. }
  351. ObDereferenceObject( Object );
  352. return( Status );
  353. }
  354. VOID
  355. ObMakeTemporaryObject (
  356. IN PVOID Object
  357. )
  358. /*++
  359. Routine Description:
  360. This routine removes the name of the object from its parent
  361. directory. The object is only removed if it has a non zero
  362. handle count and a name. Otherwise the object is simply
  363. made non permanent
  364. Arguments:
  365. Object - Supplies the object being modified
  366. Return Value:
  367. None.
  368. --*/
  369. {
  370. POBJECT_HEADER ObjectHeader;
  371. POBJECT_TYPE ObjectType;
  372. PAGED_CODE();
  373. ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object );
  374. ObjectType = ObjectHeader->Type;
  375. //
  376. // Other bits are set in this flags field by the handle database code. Synchronise with that.
  377. //
  378. ObpLockObject( ObjectHeader );
  379. ObjectHeader->Flags &= ~OB_FLAG_PERMANENT_OBJECT;
  380. ObpUnlockObject( ObjectHeader );
  381. //
  382. // Now delete the object name if no more handles are present.
  383. //
  384. ObpDeleteNameCheck( Object );
  385. return;
  386. }