Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

328 lines
9.2 KiB

  1. /*
  2. Copyright (c) 2001 Microsoft Corporation
  3. File name:
  4. hotpatch.c
  5. Author:
  6. Adrian Marinescu (adrmarin) Nov 20 2001
  7. Environment:
  8. Kernel mode only.
  9. Revision History:
  10. */
  11. #include "exp.h"
  12. #pragma hdrstop
  13. NTSTATUS
  14. ExpSyncRenameFiles(
  15. IN HANDLE FileHandle1,
  16. OUT PIO_STATUS_BLOCK IoStatusBlock1,
  17. IN PFILE_RENAME_INFORMATION RenameInformation1,
  18. IN ULONG RenameInformationLength1,
  19. IN HANDLE FileHandle2,
  20. OUT PIO_STATUS_BLOCK IoStatusBlock2,
  21. IN PFILE_RENAME_INFORMATION RenameInformation2,
  22. IN ULONG RenameInformationLength2
  23. );
  24. #ifdef ALLOC_PRAGMA
  25. #pragma alloc_text(PAGE,ExApplyCodePatch)
  26. #pragma alloc_text(PAGE,ExpSyncRenameFiles)
  27. #endif
  28. #define EXP_MAX_HOTPATCH_INFO_SIZE PAGE_SIZE
  29. //
  30. // Privileged flags define the operations where we require privilege check
  31. //
  32. #define FLG_HOTPATCH_PRIVILEGED_FLAGS (FLG_HOTPATCH_KERNEL | FLG_HOTPATCH_RELOAD_NTDLL | FLG_HOTPATCH_RENAME_INFO | FLG_HOTPATCH_MAP_ATOMIC_SWAP)
  33. //
  34. // Exclusive flags define the flags that cannot be used in combinations with other flags
  35. //
  36. #define FLG_HOTPATCH_EXCLUSIVE_FLAGS (FLG_HOTPATCH_RELOAD_NTDLL | FLG_HOTPATCH_RENAME_INFO | FLG_HOTPATCH_MAP_ATOMIC_SWAP)
  37. volatile LONG ExHotpSyncRenameSequence = 0;
  38. NTSTATUS
  39. ExpSyncRenameFiles(
  40. IN HANDLE FileHandle1,
  41. OUT PIO_STATUS_BLOCK IoStatusBlock1,
  42. IN PFILE_RENAME_INFORMATION RenameInformation1,
  43. IN ULONG RenameInformationLength1,
  44. IN HANDLE FileHandle2,
  45. OUT PIO_STATUS_BLOCK IoStatusBlock2,
  46. IN PFILE_RENAME_INFORMATION RenameInformation2,
  47. IN ULONG RenameInformationLength2
  48. )
  49. /*++
  50. Routine Description:
  51. This service changes the provided information about a specified file. The
  52. information that is changed is determined by the FileInformationClass that
  53. is specified. The new information is taken from the FileInformation buffer.
  54. Arguments:
  55. FileHandle1 - Supplies a first handle to the file to be renamed.
  56. IoStatusBlock1 - Address of the caller's I/O status block.
  57. FileInformation1 - Supplies the new name for the first file.
  58. RenameInformationLength1 - Supplies the lengtd of the rename information buffer
  59. FileHandle2 - Supplies a second handle to the file to be renamed.
  60. IoStatusBlock2 - Address of the second caller's I/O status block.
  61. FileInformation2 - Supplies the new name for the second file.
  62. RenameInformationLength2 - Supplies the lengtd of the rename information buffer
  63. Return Value:
  64. The status returned is the final completion status of the operation.
  65. --*/
  66. {
  67. NTSTATUS Status;
  68. LONG CapturedSeqNumber;
  69. PAGED_CODE();
  70. CapturedSeqNumber = ExHotpSyncRenameSequence;
  71. if ((CapturedSeqNumber & 1)
  72. ||
  73. InterlockedCompareExchange(&ExHotpSyncRenameSequence, CapturedSeqNumber + 1, CapturedSeqNumber) != CapturedSeqNumber) {
  74. return STATUS_UNSUCCESSFUL;
  75. }
  76. Status = NtSetInformationFile( FileHandle1,
  77. IoStatusBlock1,
  78. RenameInformation1,
  79. RenameInformationLength1,
  80. FileRenameInformation);
  81. if ( NT_SUCCESS(Status) ) {
  82. Status = NtSetInformationFile( FileHandle2,
  83. IoStatusBlock2,
  84. RenameInformation2,
  85. RenameInformationLength2,
  86. FileRenameInformation);
  87. }
  88. InterlockedIncrement(&ExHotpSyncRenameSequence);
  89. return Status;
  90. }
  91. NTSTATUS
  92. ExApplyCodePatch (
  93. IN PVOID PatchInfoPtr,
  94. IN SIZE_T PatchSize
  95. )
  96. /*++
  97. Routine Description:
  98. This routine is handling the common tasks to both user-mode
  99. and kernel-mode patching
  100. Arguments:
  101. PatchInfoPtr - Pointer to PSYSTEM_HOTPATCH_CODE_INFORMATION structure
  102. describing the patch. The pointer is user-mode.
  103. PatchSize - the size of the PatchInfoPtr buffer passed in
  104. Return Value:
  105. NTSTATUS.
  106. --*/
  107. {
  108. PSYSTEM_HOTPATCH_CODE_INFORMATION PatchInfo;
  109. NTSTATUS Status = STATUS_SUCCESS;
  110. KPROCESSOR_MODE PreviousMode;
  111. //
  112. // Allocate a temporary non-paged buffer to capture the used information
  113. // Restrict the size of the data to be patched to EXP_MAX_HOTPATCH_INFO_SIZE
  114. // The buffer must be non-paged because the information is accessed at DPC of higher level
  115. //
  116. if ( (PatchSize > (sizeof(SYSTEM_HOTPATCH_CODE_INFORMATION) + EXP_MAX_HOTPATCH_INFO_SIZE))
  117. ||
  118. (PatchSize < sizeof(SYSTEM_HOTPATCH_CODE_INFORMATION)) ) {
  119. return STATUS_INVALID_PARAMETER;
  120. }
  121. PatchInfo = ExAllocatePoolWithQuotaTag (NonPagedPool | POOL_QUOTA_FAIL_INSTEAD_OF_RAISE,
  122. PatchSize,
  123. 'PtoH');
  124. if (PatchInfo == NULL) {
  125. return STATUS_INSUFFICIENT_RESOURCES;
  126. }
  127. PreviousMode = KeGetPreviousMode ();
  128. try {
  129. //
  130. // Get previous processor mode and probe output argument if necessary.
  131. //
  132. if (PreviousMode != KernelMode) {
  133. ProbeForRead (PatchInfoPtr, PatchSize, sizeof(ULONG_PTR));
  134. }
  135. RtlCopyMemory (PatchInfo, PatchInfoPtr, PatchSize);
  136. } except (EXCEPTION_EXECUTE_HANDLER) {
  137. Status = GetExceptionCode ();
  138. }
  139. if (!NT_SUCCESS(Status)) {
  140. ExFreePool (PatchInfo);
  141. return Status;
  142. }
  143. if (PatchInfo->Flags & FLG_HOTPATCH_PRIVILEGED_FLAGS) {
  144. if (!SeSinglePrivilegeCheck (SeDebugPrivilege, PreviousMode)
  145. ||
  146. !SeSinglePrivilegeCheck (SeLoadDriverPrivilege, PreviousMode)) {
  147. ExFreePool (PatchInfo);
  148. return STATUS_ACCESS_DENIED;
  149. }
  150. }
  151. if (PatchInfo->Flags & FLG_HOTPATCH_EXCLUSIVE_FLAGS) {
  152. //
  153. // Special hotpatch operation
  154. //
  155. if (PatchInfo->Flags & FLG_HOTPATCH_RELOAD_NTDLL) {
  156. Status = PsLocateSystemDll( TRUE );
  157. } else if (PatchInfo->Flags & FLG_HOTPATCH_RENAME_INFO) {
  158. //
  159. // The io routine is expected to perform the parameter check
  160. //
  161. Status = ExpSyncRenameFiles( PatchInfo->RenameInfo.FileHandle1,
  162. PatchInfo->RenameInfo.IoStatusBlock1,
  163. PatchInfo->RenameInfo.RenameInformation1,
  164. PatchInfo->RenameInfo.RenameInformationLength1,
  165. PatchInfo->RenameInfo.FileHandle2,
  166. PatchInfo->RenameInfo.IoStatusBlock2,
  167. PatchInfo->RenameInfo.RenameInformation2,
  168. PatchInfo->RenameInfo.RenameInformationLength2);
  169. } else if (PatchInfo->Flags & FLG_HOTPATCH_MAP_ATOMIC_SWAP) {
  170. Status = ObSwapObjectNames( PatchInfo->AtomicSwap.ParentDirectory,
  171. PatchInfo->AtomicSwap.ObjectHandle1,
  172. PatchInfo->AtomicSwap.ObjectHandle2,
  173. 0);
  174. }
  175. } else {
  176. //
  177. // Regular patch operation which can be in either kernel mode or user mode
  178. //
  179. if (PatchInfo->Flags & FLG_HOTPATCH_KERNEL) {
  180. //
  181. // Kernel-mode patch
  182. //
  183. if ( (PatchInfo->InfoSize != PatchSize)
  184. ||
  185. !(PatchInfo->Flags & FLG_HOTPATCH_NAME_INFO)
  186. ||
  187. (PatchInfo->KernelInfo.NameOffset >= PatchSize)
  188. ||
  189. (PatchInfo->KernelInfo.NameLength >= PatchSize)
  190. ||
  191. ((ULONG)(PatchInfo->KernelInfo.NameOffset + PatchInfo->KernelInfo.NameLength) > PatchSize)) {
  192. Status = STATUS_INVALID_PARAMETER;
  193. } else {
  194. Status = MmHotPatchRoutine (PatchInfo);
  195. }
  196. } else {
  197. //
  198. // User-mode patch
  199. //
  200. // No privilege check is required for the user mode patching
  201. // as it can only be done to the current process
  202. //
  203. //
  204. // Lock the user buffer. This function also performs the
  205. // validation of the patch address to be USER
  206. //
  207. if ((PatchSize < sizeof(SYSTEM_HOTPATCH_CODE_INFORMATION))
  208. ||
  209. (PatchInfo->InfoSize != PatchSize)
  210. ||
  211. ((PatchInfo->CodeInfo.DescriptorsCount - 1) >
  212. (PatchSize - sizeof(SYSTEM_HOTPATCH_CODE_INFORMATION))/sizeof(HOTPATCH_HOOK_DESCRIPTOR))) {
  213. ExFreePool (PatchInfo);
  214. return STATUS_INVALID_PARAMETER;
  215. }
  216. Status = MmLockAndCopyMemory(PatchInfo, PreviousMode);
  217. }
  218. }
  219. ExFreePool (PatchInfo);
  220. return Status;
  221. }