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.

435 lines
14 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. hivechek.c
  5. Abstract:
  6. This module implements consistency checking for hives.
  7. Author:
  8. Bryan M. Willman (bryanwi) 09-Dec-91
  9. Environment:
  10. Revision History:
  11. --*/
  12. #include "cmp.h"
  13. #ifdef ALLOC_PRAGMA
  14. #pragma alloc_text(PAGE,HvCheckHive)
  15. #pragma alloc_text(PAGE,HvCheckBin)
  16. #endif
  17. //
  18. // debug structures
  19. //
  20. extern struct {
  21. PHHIVE Hive;
  22. ULONG Status;
  23. ULONG Space;
  24. HCELL_INDEX MapPoint;
  25. PHBIN BinPoint;
  26. } HvCheckHiveDebug;
  27. extern struct {
  28. PHBIN Bin;
  29. ULONG Status;
  30. PHCELL CellPoint;
  31. } HvCheckBinDebug;
  32. #if DBG
  33. ULONG HvHiveChecking=0;
  34. #endif
  35. ULONG
  36. HvCheckHive(
  37. PHHIVE Hive,
  38. PULONG Storage OPTIONAL
  39. )
  40. /*++
  41. Routine Description:
  42. Check the consistency of a hive. Apply CheckBin to bins, make sure
  43. all pointers in the cell map point to correct places.
  44. Arguments:
  45. Hive - supplies a pointer to the hive control structure for the
  46. hive of interest.
  47. Storage - supplies adddress of ULONG to receive size of allocated user data
  48. Return Value:
  49. 0 if Hive is OK. Error return indicator if not. Error value
  50. comes from one of the check procedures.
  51. RANGE: 2000 - 2999
  52. --*/
  53. {
  54. HCELL_INDEX p;
  55. ULONG Length;
  56. ULONG localstorage = 0;
  57. PHMAP_ENTRY t;
  58. PHBIN Bin = NULL;
  59. ULONG i;
  60. ULONG rc;
  61. PFREE_HBIN FreeBin;
  62. HvCheckHiveDebug.Hive = Hive;
  63. HvCheckHiveDebug.Status = 0;
  64. HvCheckHiveDebug.Space = (ULONG)-1;
  65. HvCheckHiveDebug.MapPoint = HCELL_NIL;
  66. HvCheckHiveDebug.BinPoint = 0;
  67. p = 0;
  68. #ifdef CM_MAP_NO_READ
  69. #ifndef _CM_LDR_
  70. //
  71. // we need to make sure all the cell's data is faulted in inside a
  72. // try/except block, as the IO to fault the data in can throw exceptions
  73. // STATUS_INSUFFICIENT_RESOURCES, in particular
  74. //
  75. try {
  76. #endif //_CM_LDR_
  77. #endif //CM_MAP_NO_READ
  78. //
  79. // one pass for Stable space, one pass for Volatile
  80. //
  81. for (i = 0; i <= Volatile; i++) {
  82. Length = Hive->Storage[i].Length;
  83. //
  84. // for each bin in the space
  85. //
  86. while (p < Length) {
  87. t = HvpGetCellMap(Hive, p);
  88. if (t == NULL) {
  89. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"HvCheckHive:"));
  90. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"\tBin@:%p invalid\n", Bin));
  91. HvCheckHiveDebug.Status = 2005;
  92. HvCheckHiveDebug.Space = i;
  93. HvCheckHiveDebug.MapPoint = p;
  94. return 2005;
  95. }
  96. if( (t->BinAddress & (HMAP_INPAGEDPOOL|HMAP_INVIEW)) == 0) {
  97. //
  98. // view is not mapped, neither in paged pool
  99. // try to map it.
  100. //
  101. // volatile info is always in paged pool
  102. ASSERT( i == Stable );
  103. if( !NT_SUCCESS(CmpMapThisBin((PCMHIVE)Hive,p,FALSE)) ) {
  104. //
  105. // we cannot map this bin due to insufficient resources.
  106. //
  107. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"HvCheckHive:"));
  108. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"\tinsufficient resources while mapping Bin@:%p\n", Bin));
  109. HvCheckHiveDebug.Status = 2006;
  110. HvCheckHiveDebug.Space = i;
  111. HvCheckHiveDebug.MapPoint = p;
  112. return 2010;
  113. }
  114. }
  115. if ((t->BinAddress & HMAP_DISCARDABLE) == 0) {
  116. Bin = (PHBIN)HBIN_BASE(t->BinAddress);
  117. //
  118. // bin header valid?
  119. //
  120. if ( (Bin->Size > Length) ||
  121. (Bin->Signature != HBIN_SIGNATURE) ||
  122. (Bin->FileOffset != p)
  123. )
  124. {
  125. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"HvCheckHive:"));
  126. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"\tBin@:%p invalid\n", Bin));
  127. HvCheckHiveDebug.Status = 2010;
  128. HvCheckHiveDebug.Space = i;
  129. HvCheckHiveDebug.MapPoint = p;
  130. HvCheckHiveDebug.BinPoint = Bin;
  131. return 2010;
  132. }
  133. //
  134. // structure inside the bin valid?
  135. //
  136. rc = HvCheckBin(Hive, Bin, &localstorage);
  137. if (rc != 0) {
  138. HvCheckHiveDebug.Status = rc;
  139. HvCheckHiveDebug.Space = i;
  140. HvCheckHiveDebug.MapPoint = p;
  141. HvCheckHiveDebug.BinPoint = Bin;
  142. return rc;
  143. }
  144. p = (ULONG)p + Bin->Size;
  145. } else {
  146. //
  147. // Bin is not present, skip it and advance to the next one.
  148. //
  149. FreeBin = (PFREE_HBIN)t->BlockAddress;
  150. p+=FreeBin->Size;
  151. }
  152. }
  153. p = 0x80000000; // Beginning of Volatile space
  154. }
  155. #ifdef CM_MAP_NO_READ
  156. #ifndef _CM_LDR_
  157. } except (EXCEPTION_EXECUTE_HANDLER) {
  158. HvCheckHiveDebug.Status = 2015;
  159. HvCheckHiveDebug.Space = GetExceptionCode();
  160. return HvCheckHiveDebug.Status;
  161. }
  162. #endif //_CM_LDR_
  163. #endif //CM_MAP_NO_READ
  164. if (ARGUMENT_PRESENT(Storage)) {
  165. *Storage = localstorage;
  166. }
  167. return 0;
  168. }
  169. ULONG
  170. HvCheckBin(
  171. PHHIVE Hive,
  172. PHBIN Bin,
  173. PULONG Storage
  174. )
  175. /*++
  176. Routine Description:
  177. Step through all of the cells in the bin. Make sure that
  178. they are consistent with each other, and with the bin header.
  179. Arguments:
  180. Hive - pointer to the hive control structure
  181. Bin - pointer to bin to check
  182. Storage - pointer to a ulong to get allocated user data size
  183. Return Value:
  184. 0 if Bin is OK. Number of test in procedure that failed if not.
  185. RANGE: 1 - 1999
  186. --*/
  187. {
  188. PHCELL p;
  189. PHCELL np;
  190. PHCELL lp;
  191. ULONG freespace = 0L;
  192. ULONG allocated = 0L;
  193. ULONG userallocated = 0L;
  194. HvCheckBinDebug.Bin = Bin;
  195. HvCheckBinDebug.Status = 0;
  196. HvCheckBinDebug.CellPoint = 0;
  197. //
  198. // Scan all the cells in the bin, total free and allocated, check
  199. // for impossible pointers.
  200. //
  201. p = (PHCELL)((PUCHAR)Bin + sizeof(HBIN));
  202. lp = p;
  203. // DRAGOS:
  204. // The way allocated and freespace are computed implies the following invariants:
  205. // 1. allocated + freespace = p + p->Size - (Bin + sizeof(HBIN)). This is because p->Size is added either to allocated or to freespace.
  206. // So, assuming that allocated > Bin->Size , then
  207. // ==> p + p->Size - (Bin + sizeof(HBIN)) > Bin->Size.
  208. // ==> p + p->Size > Bin + Bin->Size + sizeof(HBIN)
  209. // ==> p + p->Size > Bin + Bin->Size
  210. // This proves that the test "NeverFail 1" (see below) will never fail, because when something is wrong, the test above it (namely "Fail 1") will fail
  211. // and the function will exit.
  212. //
  213. // The same logic applies to the test "NeverFail 2", so it can be removed also.
  214. //
  215. // 2. The new value of p is always calculated as p = p + p->Size. By the time this is done, the new value of p (ie. p + p->Size) is already checked against
  216. // Bin + Bin->Size (see tests "Fail 1" and "Fail 2"). So, if p > Bin + Bin->Size, either "Fail 1" or "Fail 2" will fail before asigning the new bogus value
  217. // to p. Therefore, the only possible path to exit the while loop (except a return 20 or return 40), is when p == Bin + Bin->Size.
  218. // ==> test "NeverFail 3" can be removed as it will never fail !
  219. //
  220. // 3. Considering 1 (where p + p->Size became p)
  221. // ==> allocated + freespace = p - (Bin + sizeof(HBIN))
  222. // But, Considering 2 (above), when the while loop exits, p = Bin + Bin->Size
  223. // ==> allocated + freespace = Bin + Bin->Size - (Bin + sizeof(HBIN))
  224. // ==> allocated + freespace + sizeof(HBIN) = Bin->Size
  225. // This proves that test "NeverFail 4" (see below) will never fail as the expresion tested is always true (if the flow of execution reaches the test point).
  226. //
  227. while (p < (PHCELL)((PUCHAR)Bin + Bin->Size)) {
  228. //
  229. // Check last pointer
  230. //
  231. if (USE_OLD_CELL(Hive)) {
  232. if (lp == p) {
  233. if (p->u.OldCell.Last != HBIN_NIL) {
  234. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"HvCheckBin 20: First cell has wrong last pointer\n"));
  235. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"Bin = %p\n", Bin));
  236. HvCheckBinDebug.Status = 20;
  237. HvCheckBinDebug.CellPoint = p;
  238. return 20;
  239. }
  240. } else {
  241. if ((PHCELL)(p->u.OldCell.Last + (PUCHAR)Bin) != lp) {
  242. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"HvCheckBin 30: incorrect last pointer\n"));
  243. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"Bin = %p\n", Bin));
  244. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"p = %p\n", (ULONG_PTR)p));
  245. HvCheckBinDebug.Status = 30;
  246. HvCheckBinDebug.CellPoint = p;
  247. return 30;
  248. }
  249. }
  250. }
  251. //
  252. // Check size
  253. //
  254. if (p->Size < 0) {
  255. //
  256. // allocated cell
  257. //
  258. // DRAGOS: Fail 1
  259. // This test will always fail prior to the failure of the below test
  260. //
  261. if ( ((ULONG)(p->Size * -1) > Bin->Size) ||
  262. ( (PHCELL)((p->Size * -1) + (PUCHAR)p) >
  263. (PHCELL)((PUCHAR)Bin + Bin->Size) )
  264. )
  265. {
  266. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"HvCheckBin 40: impossible allocation\n"));
  267. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"Bin = %p\n", Bin));
  268. HvCheckBinDebug.Status = 40;
  269. HvCheckBinDebug.CellPoint = p;
  270. return 40;
  271. }
  272. allocated += (p->Size * -1);
  273. if (USE_OLD_CELL(Hive)) {
  274. userallocated += (p->Size * -1) - FIELD_OFFSET(HCELL, u.OldCell.u.UserData);
  275. } else {
  276. userallocated += (p->Size * -1) - FIELD_OFFSET(HCELL, u.NewCell.u.UserData);
  277. }
  278. //
  279. // DRAGOS: NeverFail 1
  280. // This test will never fail. If a size is wrong the above test (Fail 1)will fail. We can remove this test (it's useless).
  281. //
  282. if (allocated > Bin->Size) {
  283. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"HvCheckBin 50: allocated exceeds available\n"));
  284. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"Bin = %p\n", Bin));
  285. HvCheckBinDebug.Status = 50;
  286. HvCheckBinDebug.CellPoint = p;
  287. return 50;
  288. }
  289. np = (PHCELL)((PUCHAR)p + (p->Size * -1));
  290. } else {
  291. //
  292. // free cell
  293. //
  294. // DRAGOS: Fail 2
  295. // This test will always fail prior to the failure of the below test
  296. //
  297. if ( ((ULONG)p->Size > Bin->Size) ||
  298. ( (PHCELL)(p->Size + (PUCHAR)p) >
  299. (PHCELL)((PUCHAR)Bin + Bin->Size) ) ||
  300. (p->Size == 0) )
  301. {
  302. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"HvCheckBin 60: impossible free block\n"));
  303. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"Bin = %p\n", Bin));
  304. HvCheckBinDebug.Status = 60;
  305. HvCheckBinDebug.CellPoint = p;
  306. return 60;
  307. }
  308. freespace = freespace + p->Size;
  309. //
  310. // DRAGOS: NeverFail 2
  311. // This test will never fail. If a size is wrong the above test (Fail 2) will fail. We can remove this test (it's useless).
  312. //
  313. if (freespace > Bin->Size) {
  314. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"HvCheckBin 70: free exceeds available\n"));
  315. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"Bin = %p\n", Bin));
  316. HvCheckBinDebug.Status = 70;
  317. HvCheckBinDebug.CellPoint = p;
  318. return 70;
  319. }
  320. np = (PHCELL)((PUCHAR)p + p->Size);
  321. }
  322. lp = p;
  323. p = np;
  324. }
  325. // DRAGOS: NeverFail 4
  326. // This test never fails. If the while loop exits, the condition tested here is always true!!!
  327. // We can remove this test (it's useless)
  328. //
  329. if ((freespace + allocated + sizeof(HBIN)) != Bin->Size) {
  330. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"HvCheckBin 995: sizes do not add up\n"));
  331. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"Bin = %p\n", Bin));
  332. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"freespace = %08lx ", freespace));
  333. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"allocated = %08lx ", allocated));
  334. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"size = %08lx\n", Bin->Size));
  335. HvCheckBinDebug.Status = 995;
  336. return 995;
  337. }
  338. // DRAGOS: NeverFail 3
  339. // This test never fails. The only way out of the while loop is when p == Bin + Bin->Size !!!!!!!
  340. // We can remove this test (it's useless)
  341. //
  342. if (p != (PHCELL)((PUCHAR)Bin + Bin->Size)) {
  343. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"HvCheckBin 1000: last cell points off the end\n"));
  344. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"Bin = %p\n", Bin));
  345. HvCheckBinDebug.Status = 1000;
  346. return 1000;
  347. }
  348. if (ARGUMENT_PRESENT(Storage)) {
  349. *Storage += userallocated;
  350. }
  351. return 0;
  352. }