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.

874 lines
27 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation
  3. Module Name:
  4. rtlmmapio.c
  5. Abstract:
  6. Functions to aid in
  7. rigorously safe
  8. reasonably efficient
  9. reasonably easy to code
  10. memory mapped i/o that captures with "tight" __try/__excepts to
  11. catch status_in_page_errors, and captures only as much as is needed,
  12. like only individual struct fields, to keep stack usage low.
  13. Author:
  14. Jay Krell (JayKrell) January 2002
  15. Revision History:
  16. Environment:
  17. Pretty much anywhere memory mapped i/o is available.
  18. Initial client is win32k.sys font loading "rewrite".
  19. --*/
  20. #pragma warning(disable:4214) /* bit field types other than int */
  21. #pragma warning(disable:4201) /* nameless struct/union */
  22. #pragma warning(disable:4115) /* named type definition in parentheses */
  23. #pragma warning(disable:4127) /* condition expression is constant */
  24. #include "nt.h"
  25. #include "ntrtl.h"
  26. #include "nturtl.h"
  27. #include "ntrtlmmapio.h"
  28. #include "ntrtloverflow.h"
  29. #if defined(__cplusplus)
  30. extern "C" {
  31. #endif
  32. #define NOT_YET_USED 1
  33. #define RTLP_STRINGIZE_(x) #x
  34. #define RTLP_STRINGIZE(x) RTLP_STRINGIZE_(x)
  35. #define RTLP_LINE_AS_STRING() RTLP_STRINGIZE(__LINE__)
  36. #define RTLP_PREPEND_LINE_SPACE_TO_STRING(x) RTLP_LINE_AS_STRING() " " x
  37. #define RTLP_COPY_MAPPED_MEMORY_EX_FLAG_CATCH_INPAGE_ERRORS_IN_FROM_RANGE (0x00000001)
  38. #define RTLP_COPY_MAPPED_MEMORY_EX_FLAG_CATCH_INPAGE_ERRORS_IN_TO_RANGE (0x00000002)
  39. NTSTATUS
  40. RtlpAddWithOverflowCheckUlongPtr(
  41. ULONG_PTR *pc,
  42. ULONG_PTR a,
  43. ULONG_PTR b
  44. )
  45. {
  46. return RtlAddWithCarryOutUlongPtr(pc, a, b) ? STATUS_INTEGER_OVERFLOW : STATUS_SUCCESS;
  47. }
  48. NTSTATUS
  49. RtlpAddWithOverflowCheckSizet(
  50. SIZE_T *pc,
  51. SIZE_T a,
  52. SIZE_T b
  53. )
  54. {
  55. return RtlAddWithCarryOutSizet(pc, a, b) ? STATUS_INTEGER_OVERFLOW : STATUS_SUCCESS;
  56. }
  57. LONG
  58. RtlpCopyMappedMemoryEx_ExceptionFilter(
  59. ULONG Flags,
  60. PVOID ToAddress,
  61. PCVOID FromAddress,
  62. SIZE_T Size,
  63. OUT PSIZE_T BytesCopiedOut OPTIONAL,
  64. OUT PEXCEPTION_RECORD ExceptionRecordOut OPTIONAL,
  65. IN PEXCEPTION_POINTERS ExceptionPointers,
  66. OUT PNTSTATUS StatusOut OPTIONAL
  67. )
  68. /*++
  69. Routine Description:
  70. This routine serves as an exception filter and has the special job of
  71. extracting the "real" I/O error when Mm raises STATUS_IN_PAGE_ERROR
  72. beneath us. This is based on CcCopyReadExceptionFilter / MiGetExceptionInfo / RtlUnhandledExceptionFilter
  73. Arguments:
  74. ExceptionPointers - A pointer to the context and
  75. the exception record that contains the real Io Status.
  76. ExceptionCode - A pointer to an NTSTATUS that is to receive the real
  77. status.
  78. Return Value:
  79. EXCEPTION_EXECUTE_HANDLER for inpage errors in the "expected" range
  80. otherwise EXCEPTION_CONTINUE_SEARCH
  81. --*/
  82. {
  83. const PEXCEPTION_RECORD ExceptionRecord = ExceptionPointers->ExceptionRecord;
  84. NTSTATUS ExceptionCode = ExceptionRecord->ExceptionCode;
  85. LONG Disposition = EXCEPTION_CONTINUE_SEARCH;
  86. SIZE_T BytesCopied = 0;
  87. if (ExceptionCode == STATUS_IN_PAGE_ERROR) {
  88. const ULONG NumberParameters = ExceptionRecord->NumberParameters;
  89. if (RTL_IN_PAGE_ERROR_EXCEPTION_INFO_FAULTING_VA_INDEX < NumberParameters) {
  90. const ULONG_PTR ExceptionAddress = ExceptionRecord->ExceptionInformation[RTL_IN_PAGE_ERROR_EXCEPTION_INFO_FAULTING_VA_INDEX];
  91. if ((Flags & RTLP_COPY_MAPPED_MEMORY_EX_FLAG_CATCH_INPAGE_ERRORS_IN_FROM_RANGE) != 0
  92. && ExceptionAddress >= ((ULONG_PTR)FromAddress)
  93. && ExceptionAddress < (((ULONG_PTR)FromAddress) + Size)) {
  94. Disposition = EXCEPTION_EXECUTE_HANDLER;
  95. BytesCopied = (SIZE_T)(ExceptionAddress - (ULONG_PTR)FromAddress);
  96. } else if ((Flags & RTLP_COPY_MAPPED_MEMORY_EX_FLAG_CATCH_INPAGE_ERRORS_IN_TO_RANGE) != 0
  97. && ExceptionAddress >= ((ULONG_PTR)ToAddress)
  98. && ExceptionAddress < (((ULONG_PTR)ToAddress) + Size)) {
  99. Disposition = EXCEPTION_EXECUTE_HANDLER;
  100. BytesCopied = (SIZE_T)(ExceptionAddress - (ULONG_PTR)ToAddress);
  101. }
  102. } else {
  103. //
  104. // We don't have the information to do the range check. What to do?
  105. // We return continue_search.
  106. //
  107. // Comments in code indicate this can happen, that the iomgr reraises
  108. // inpage errors without the additional parameters.
  109. //
  110. }
  111. if (RTL_IN_PAGE_ERROR_EXCEPTION_INFO_UNDERLYING_STATUS_INDEX < NumberParameters) {
  112. ExceptionCode = (NTSTATUS) ExceptionRecord->ExceptionInformation[RTL_IN_PAGE_ERROR_EXCEPTION_INFO_UNDERLYING_STATUS_INDEX];
  113. }
  114. }
  115. if (ARGUMENT_PRESENT(ExceptionRecordOut)) {
  116. *ExceptionRecordOut = *ExceptionRecord;
  117. }
  118. if (ARGUMENT_PRESENT(StatusOut)) {
  119. *StatusOut = ExceptionCode;
  120. }
  121. if (ARGUMENT_PRESENT(BytesCopiedOut)) {
  122. *BytesCopiedOut = BytesCopied;
  123. }
  124. return Disposition;
  125. }
  126. NTSTATUS
  127. NTAPI
  128. RtlpCopyMappedMemoryEx(
  129. ULONG Flags,
  130. PVOID ToAddress,
  131. PCVOID FromAddress,
  132. SIZE_T Size,
  133. PSIZE_T BytesCopied OPTIONAL,
  134. PEXCEPTION_RECORD ExceptionRecordOut OPTIONAL
  135. )
  136. {
  137. NTSTATUS Status;
  138. if (ARGUMENT_PRESENT(BytesCopied)) {
  139. *BytesCopied = 0;
  140. }
  141. __try {
  142. RtlCopyMemory(ToAddress, FromAddress, Size);
  143. if (ARGUMENT_PRESENT(BytesCopied)) {
  144. *BytesCopied = Size;
  145. }
  146. Status = STATUS_SUCCESS;
  147. } __except(
  148. RtlpCopyMappedMemoryEx_ExceptionFilter(
  149. Flags,
  150. ToAddress,
  151. FromAddress,
  152. Size,
  153. BytesCopied,
  154. ExceptionRecordOut,
  155. GetExceptionInformation(),
  156. &Status)) {
  157. }
  158. return Status;
  159. }
  160. NTSTATUS
  161. NTAPI
  162. RtlCopyMappedMemory(
  163. PVOID ToAddress,
  164. PCVOID FromAddress,
  165. SIZE_T Size
  166. )
  167. {
  168. return
  169. RtlpCopyMappedMemoryEx(
  170. RTLP_COPY_MAPPED_MEMORY_EX_FLAG_CATCH_INPAGE_ERRORS_IN_FROM_RANGE
  171. | RTLP_COPY_MAPPED_MEMORY_EX_FLAG_CATCH_INPAGE_ERRORS_IN_TO_RANGE,
  172. ToAddress,
  173. FromAddress,
  174. Size,
  175. NULL, // BytesCopied OPTIONAL,
  176. NULL // ExceptionRecordOut OPTIONAL
  177. );
  178. }
  179. #if NOT_YET_USED
  180. NTSTATUS
  181. NTAPI
  182. RtlCopyMemoryFromMappedView(
  183. PCVOID ViewBase,
  184. SIZE_T ViewSize,
  185. PVOID ToAddress,
  186. PCVOID FromAddress,
  187. SIZE_T Size,
  188. PSIZE_T BytesCopied OPTIONAL,
  189. PEXCEPTION_RECORD ExceptionRecordOut OPTIONAL
  190. )
  191. /*++
  192. Routine Description:
  193. Arguments:
  194. ViewBase - the base of a memory mapped view
  195. ViewSize - the size of the memory mapped view mapped at ViewBase
  196. ToAddress - where to copy memory to, like the first parameter to RtlCopyMemory
  197. This assumed to point to memory for which inpage errors are "not possible"
  198. like backed by the pagefile or nonpaged pool
  199. If copying to mapped files or from and to mapped files, see RtlpCopyMappedMemoryEx.
  200. FromAddress - where to copy memory from, like the second parameter to RtlCopyMemory
  201. this must be within [ViewBase, ViewBase + ViewSize)
  202. Size - the number of bytes to copy, like the third parameter to RtlCopyMemory
  203. BytesCopied - optional out parameter that tells the number of bytes
  204. successfully copied; in this case of partial success, this
  205. is computed based in information in GetExceptionInformation
  206. ExceptionRecordOut - optional out parameter so the caller can pick apart
  207. the full details an exception, like to get the error
  208. underlying a status_inpage_error in the exception handler
  209. Return Value:
  210. STATUS_SUCCESS - everything is groovy
  211. STATUS_ACCESS_VIOLATION - the memory is not within the mapped view
  212. STATUS_IN_PAGE_ERROR - the memory could not be paged in
  213. the details as to why can be found via ExceptionRecordOut
  214. see RTL_IN_PAGE_ERROR_EXCEPTION_INFO_UNDERLYING_STATUS_INDEX
  215. STATUS_INVALID_PARAMETER
  216. --*/
  217. {
  218. NTSTATUS Status;
  219. if (ARGUMENT_PRESENT(BytesCopied)) {
  220. *BytesCopied = 0;
  221. }
  222. Status = RtlMappedViewRangeCheck(ViewBase, ViewSize, FromAddress, Size);
  223. if (!NT_SUCCESS(Status)) {
  224. //
  225. // Note that ExceptionRecordOut is not filled in in this case.
  226. //
  227. goto Exit;
  228. }
  229. Status =
  230. RtlpCopyMappedMemoryEx(
  231. RTLP_COPY_MAPPED_MEMORY_EX_FLAG_CATCH_INPAGE_ERRORS_IN_FROM_RANGE,
  232. ToAddress,
  233. FromAddress,
  234. Size,
  235. BytesCopied,
  236. ExceptionRecordOut
  237. );
  238. if (!NT_SUCCESS(Status)) {
  239. goto Exit;
  240. }
  241. Status = STATUS_SUCCESS;
  242. Exit:
  243. return Status;
  244. }
  245. #endif
  246. #if NOT_YET_USED
  247. NTSTATUS
  248. NTAPI
  249. RtlMemoryMappedIoCapturePartialStruct(
  250. PCVOID ViewBase,
  251. SIZE_T ViewSize,
  252. PCMEMORY_MAPPED_IO_CAPTURE_PARTIAL_STRUCT_DESCRIPTOR Descriptor,
  253. PCVOID VoidStructInViewBase,
  254. PVOID VoidSafeBuffer,
  255. SIZE_T SafeBufferSize
  256. )
  257. {
  258. NTSTATUS Status;
  259. PCMEMORY_MAPPED_IO_CAPTURE_PARTIAL_STRUCT_MEMBER_DESCRIPTOR Member;
  260. PCMEMORY_MAPPED_IO_CAPTURE_PARTIAL_STRUCT_MEMBER_DESCRIPTOR MemberEnd;
  261. PCBYTE StructInViewBase;
  262. PBYTE SafeBuffer;
  263. ULONG_PTR SafeBufferEnd;
  264. SIZE_T EntireStructFileSize;
  265. StructInViewBase = (PCBYTE)VoidStructInViewBase;
  266. SafeBuffer = (PBYTE)VoidSafeBuffer;
  267. Status = STATUS_INTERNAL_ERROR;
  268. Member = (PCMEMORY_MAPPED_IO_CAPTURE_PARTIAL_STRUCT_MEMBER_DESCRIPTOR)~(ULONG_PTR)0;
  269. MemberEnd = (PCMEMORY_MAPPED_IO_CAPTURE_PARTIAL_STRUCT_MEMBER_DESCRIPTOR)~(ULONG_PTR)0;
  270. if (!RTL_SOFT_VERIFY(
  271. ViewBase != NULL
  272. && ViewSize != 0
  273. && Descriptor != NULL
  274. && StructInViewBase != NULL
  275. && SafeBuffer != NULL
  276. && SafeBufferSize != 0
  277. && SafeBufferSize == Descriptor->PartialStructMemorySize
  278. )) {
  279. Status = STATUS_INVALID_PARAMETER;
  280. goto Exit;
  281. }
  282. if (!RTL_SOFT_VERIFY(NT_SUCCESS(Status =
  283. RtlpAddWithOverflowCheckUlongPtr(
  284. &SafeBufferEnd,
  285. (ULONG_PTR)SafeBuffer,
  286. SafeBufferSize
  287. )))) {
  288. goto Exit;
  289. }
  290. if (!RTL_SOFT_VERIFY(NT_SUCCESS(Status =
  291. RtlMappedViewRangeCheck(
  292. ViewBase,
  293. ViewSize,
  294. StructInViewBase,
  295. (EntireStructFileSize = Descriptor->EntireStructFileSize)
  296. )))) {
  297. goto Exit;
  298. }
  299. Member = Descriptor->MemberDescriptors;
  300. MemberEnd = Member + Descriptor->NumberOfMembers;
  301. __try {
  302. for ( ; Member != MemberEnd; ++Member ) {
  303. RtlCopyMemory(
  304. SafeBuffer + Member->MemberOffsetInMemory,
  305. StructInViewBase + Member->MemberOffsetInFile,
  306. Member->MemberSize
  307. );
  308. }
  309. Status = STATUS_SUCCESS;
  310. }
  311. __except(
  312. //
  313. // Note that we describe the entire frombuffer here.
  314. // We do not describe the tobuffer, and we don't describe just one field.
  315. // It is an optimization to not describe individual fields.
  316. // We cannot describe the tobuffer accurately because its size is different (smaller)
  317. // than the frombuffer.
  318. //
  319. RtlpCopyMappedMemoryEx_ExceptionFilter(
  320. RTLP_COPY_MAPPED_MEMORY_EX_FLAG_CATCH_INPAGE_ERRORS_IN_FROM_RANGE,
  321. NULL, // "to" isn't checked, and the tosize and fromsize are different
  322. VoidStructInViewBase,
  323. EntireStructFileSize,
  324. NULL, // BytesCopied
  325. NULL, // ExceptionRecordOut
  326. GetExceptionInformation(),
  327. &Status
  328. )) {
  329. }
  330. Exit:
  331. return Status;
  332. }
  333. #endif
  334. #if NOT_YET_USED
  335. NTSTATUS
  336. NTAPI
  337. RtlValidateMemoryMappedIoCapturePartialStructDescriptor(
  338. PCMEMORY_MAPPED_IO_CAPTURE_PARTIAL_STRUCT_DESCRIPTOR Struct,
  339. OUT PULONG Disposition,
  340. OUT PULONG_PTR Detail OPTIONAL,
  341. OUT PULONG_PTR Detail2 OPTIONAL
  342. )
  343. {
  344. NTSTATUS Status;
  345. NTSTATUS Status2;
  346. PCMEMORY_MAPPED_IO_CAPTURE_PARTIAL_STRUCT_MEMBER_DESCRIPTOR Member;
  347. PCMEMORY_MAPPED_IO_CAPTURE_PARTIAL_STRUCT_MEMBER_DESCRIPTOR MemberEnd;
  348. PCSTR LocalDetail;
  349. ULONG_PTR LocalDetail2;
  350. ULONG LocalDisposition;
  351. BOOLEAN SetDetail2;
  352. SIZE_T OffsetEnd;
  353. SetDetail2 = FALSE;
  354. LocalDetail = NULL;
  355. LocalDetail2 = 0;
  356. Status = STATUS_INTERNAL_ERROR;
  357. Status2 = STATUS_INTERNAL_ERROR;
  358. Member = NULL;
  359. MemberEnd = NULL;
  360. LocalDisposition = RTL_VALIDATE_MEMORY_MAPPED_IO_CAPTURE_PARTIAL_STRUCT_DESCRIPTOR_DISPOSITION_BAD;
  361. OffsetEnd = 0;
  362. if (ARGUMENT_PRESENT(Detail)) {
  363. *Detail = 0;
  364. }
  365. if (ARGUMENT_PRESENT(Detail2)) {
  366. *Detail2 = 0;
  367. }
  368. if (Disposition != NULL) {
  369. *Disposition = LocalDisposition;
  370. }
  371. Status = STATUS_INVALID_PARAMETER;
  372. if (!RTL_SOFT_VERIFY(Struct != NULL)) {
  373. goto Exit;
  374. }
  375. if (!RTL_SOFT_VERIFY(Disposition != NULL)) {
  376. goto Exit;
  377. }
  378. Status = STATUS_SUCCESS;
  379. if (!RTL_SOFT_VERIFY(Struct->PartialStructMemorySize <= Struct->EntireStructFileSize)) {
  380. LocalDetail = RTLP_PREPEND_LINE_SPACE_TO_STRING("memory > file");
  381. goto Exit;
  382. }
  383. //
  384. // Given that members cannot have zero size,
  385. // the number of members must be <= size.
  386. //
  387. if (!RTL_SOFT_VERIFY(Struct->NumberOfMembers <= Struct->EntireStructFileSize)) {
  388. LocalDetail = RTLP_PREPEND_LINE_SPACE_TO_STRING("nummemb <= filesize");
  389. goto Exit;
  390. }
  391. if (!RTL_SOFT_VERIFY(Struct->NumberOfMembers <= Struct->PartialStructMemorySize)) {
  392. LocalDetail = RTLP_PREPEND_LINE_SPACE_TO_STRING("nummemb <= memsize");
  393. goto Exit;
  394. }
  395. if (!RTL_SOFT_VERIFY(Struct->NumberOfMembers != 0)) {
  396. LocalDetail = RTLP_PREPEND_LINE_SPACE_TO_STRING("nummemb != 0");
  397. goto Exit;
  398. }
  399. if (!RTL_SOFT_VERIFY(Struct->EntireStructFileSize != 0)) {
  400. LocalDetail = RTLP_PREPEND_LINE_SPACE_TO_STRING("filesize != 0");
  401. goto Exit;
  402. }
  403. if (!RTL_SOFT_VERIFY(Struct->PartialStructMemorySize != 0)) {
  404. LocalDetail = RTLP_PREPEND_LINE_SPACE_TO_STRING("memsize != 0");
  405. goto Exit;
  406. }
  407. if (!RTL_SOFT_VERIFY(Struct->MemberDescriptors != NULL)) {
  408. LocalDetail = RTLP_PREPEND_LINE_SPACE_TO_STRING("members != NULL");
  409. goto Exit;
  410. }
  411. Member = Struct->MemberDescriptors;
  412. MemberEnd = Member + Struct->NumberOfMembers;
  413. SetDetail2 = TRUE;
  414. for ( ; Member != MemberEnd; ++Member )
  415. {
  416. if (!RTL_SOFT_VERIFY(Member->MemberSize != 0)) {
  417. LocalDetail = RTLP_PREPEND_LINE_SPACE_TO_STRING("membersize != NULL");
  418. goto Exit;
  419. }
  420. if (!RTL_SOFT_VERIFY(Member->MemberOffsetInFile < Struct->EntireStructFileSize)) {
  421. LocalDetail = RTLP_PREPEND_LINE_SPACE_TO_STRING("fileoffset < filesize");
  422. goto Exit;
  423. }
  424. if (!RTL_SOFT_VERIFY(NT_SUCCESS(Status2 = RtlpAddWithOverflowCheckSizet(&OffsetEnd, Member->MemberOffsetInFile, Member->MemberSize)))) {
  425. LocalDetail = RTLP_PREPEND_LINE_SPACE_TO_STRING("file overflow");
  426. goto Exit;
  427. }
  428. if (!RTL_SOFT_VERIFY(OffsetEnd <= Struct->EntireStructFileSize)) {
  429. LocalDetail = RTLP_PREPEND_LINE_SPACE_TO_STRING("file out of bounds");
  430. goto Exit;
  431. }
  432. if (!RTL_SOFT_VERIFY(Member->MemberOffsetInMemory < Struct->PartialStructMemorySize)) {
  433. LocalDetail = RTLP_PREPEND_LINE_SPACE_TO_STRING("memoffset < memsize");
  434. goto Exit;
  435. }
  436. if (!RTL_SOFT_VERIFY(NT_SUCCESS(Status2 = RtlpAddWithOverflowCheckSizet(&OffsetEnd, Member->MemberOffsetInMemory, Member->MemberSize)))) {
  437. LocalDetail = RTLP_PREPEND_LINE_SPACE_TO_STRING("mem overflow");
  438. goto Exit;
  439. }
  440. if (!RTL_SOFT_VERIFY(OffsetEnd <= Struct->PartialStructMemorySize)) {
  441. LocalDetail = RTLP_PREPEND_LINE_SPACE_TO_STRING("mem out of bounds");
  442. goto Exit;
  443. }
  444. }
  445. LocalDisposition = RTL_VALIDATE_MEMORY_MAPPED_IO_CAPTURE_PARTIAL_STRUCT_DESCRIPTOR_DISPOSITION_GOOD;
  446. Exit:
  447. if (LocalDisposition == RTL_VALIDATE_MEMORY_MAPPED_IO_CAPTURE_PARTIAL_STRUCT_DESCRIPTOR_DISPOSITION_BAD) {
  448. if (ARGUMENT_PRESENT(Detail)) {
  449. *Detail = (ULONG_PTR)LocalDetail;
  450. }
  451. if (ARGUMENT_PRESENT(Detail2) && SetDetail2) {
  452. *Detail2 = (MemberEnd - Member);
  453. }
  454. }
  455. if (Disposition != NULL) {
  456. *Disposition = LocalDisposition;
  457. }
  458. return Status;
  459. }
  460. #endif
  461. #if NOT_YET_USED
  462. NTSTATUS
  463. NTAPI
  464. RtlMappedViewStrlen(
  465. PCVOID VoidViewBase,
  466. SIZE_T ViewSize,
  467. PCVOID VoidString,
  468. OUT PSIZE_T OutLength OPTIONAL
  469. )
  470. /*++
  471. Routine Description:
  472. Given a mapped view and size and starting address, verify that the 8bit string
  473. starting at the address is nul terminated within the mapped view, optionally
  474. returning the length of the string.
  475. in_page_errors are caught
  476. Arguments:
  477. VoidViewBase -
  478. ViewSize -
  479. VoidString -
  480. OutLength -
  481. Return Value:
  482. STATUS_SUCCESS: the string is nul terminated within the view
  483. STATUS_ACCESS_VIOLATION: the string is not nul terminated within the view
  484. STATUS_IN_PAGE_ERROR
  485. --*/
  486. {
  487. NTSTATUS Status;
  488. PCBYTE ByteViewBase;
  489. PCBYTE ByteViewEnd;
  490. PCBYTE ByteString;
  491. PCBYTE ByteStringEnd;
  492. Status = STATUS_INTERNAL_ERROR;
  493. ByteViewBase = (PCBYTE)VoidViewBase;
  494. ByteViewEnd = ViewSize + ByteViewBase;
  495. ByteString = (PCBYTE)VoidString;
  496. ByteStringEnd = ByteString;
  497. if (ARGUMENT_PRESENT(OutLength)) {
  498. *OutLength = 0;
  499. }
  500. if (!(ByteString >= ByteViewBase && ByteString < ByteViewEnd)) {
  501. Status = STATUS_ACCESS_VIOLATION;
  502. goto Exit;
  503. }
  504. __try {
  505. //
  506. // This could be done more efficiently with page granularity, using memchr.
  507. //
  508. for ( ; ByteStringEnd != ByteViewEnd && *ByteStringEnd != 0 ; ++ByteStringEnd) {
  509. // nothing
  510. }
  511. if (ByteStringEnd == ByteViewEnd) {
  512. Status = STATUS_ACCESS_VIOLATION;
  513. } else {
  514. Status = STATUS_SUCCESS;
  515. }
  516. } __except(
  517. //
  518. // We describe the whole buffer instead of an individual byte so that
  519. // the loop variables can be enregistered.
  520. //
  521. // If we switch to page granularity, this optimization may be less important.
  522. //
  523. RtlpCopyMappedMemoryEx_ExceptionFilter(
  524. RTLP_COPY_MAPPED_MEMORY_EX_FLAG_CATCH_INPAGE_ERRORS_IN_FROM_RANGE, // flags
  525. NULL, // no to address
  526. VoidViewBase, // from address
  527. ViewSize, // size
  528. NULL, // BytesCopied
  529. NULL, // ExceptionRecord,
  530. GetExceptionInformation(),
  531. &Status
  532. )) {
  533. ASSERT(Status != STATUS_SUCCESS);
  534. }
  535. if (ARGUMENT_PRESENT(OutLength)) {
  536. *OutLength = (SIZE_T)(ByteStringEnd - ByteString);
  537. }
  538. Exit:
  539. return Status;
  540. }
  541. #endif
  542. #if NOT_YET_USED
  543. NTSTATUS
  544. NTAPI
  545. RtlMappedViewRangeCheck(
  546. PCVOID ViewBase,
  547. SIZE_T ViewSize,
  548. PCVOID DataAddress,
  549. SIZE_T DataSize
  550. )
  551. /*++
  552. Routine Description:
  553. Given a mapped view and size, range check a data address and size.
  554. Arguments:
  555. ViewBase -
  556. ViewSize -
  557. DataAddress -
  558. DataSize -
  559. Return Value:
  560. STATUS_SUCCESS: all of the data is within the view
  561. STATUS_ACCESS_VIOLATION: some of the data is outside the view
  562. --*/
  563. {
  564. ULONG_PTR UlongPtrViewBegin;
  565. ULONG_PTR UlongPtrViewEnd;
  566. ULONG_PTR UlongPtrDataBegin;
  567. ULONG_PTR UlongPtrDataEnd;
  568. BOOLEAN InBounds;
  569. //
  570. // UlongPtrDataBegin is a valid address.
  571. // UlongPtrDataEnd is one past a valid address.
  572. // We must not allow UlongPtrDataBegin == UlongPtrViewEnd.
  573. // We must allow UlongPtrDataEnd == UlongPtrViewEnd.
  574. // Therefore, we must not allow UlongPtrDataBegin == UlongPtrDataEnd.
  575. // This can be achieved by not allowing DataSize == 0.
  576. //
  577. if (DataSize == 0)
  578. {
  579. DataSize = 1;
  580. }
  581. UlongPtrViewBegin = (ULONG_PTR)ViewBase;
  582. UlongPtrViewEnd = UlongPtrViewBegin + ViewSize;
  583. UlongPtrDataBegin = (ULONG_PTR)DataAddress;
  584. UlongPtrDataEnd = UlongPtrDataBegin + DataSize;
  585. InBounds =
  586. ( UlongPtrDataBegin >= UlongPtrViewBegin
  587. && UlongPtrDataBegin < UlongPtrDataEnd
  588. && UlongPtrDataEnd <= UlongPtrViewEnd
  589. && DataSize <= ViewSize
  590. );
  591. return (InBounds ? STATUS_SUCCESS : STATUS_ACCESS_VIOLATION);
  592. }
  593. #endif
  594. #if NOT_YET_USED
  595. //
  596. // This code is not yet as robust as the "capture partial struct" functions,
  597. // which do overflow checking, including offering a "preflight" validation of
  598. // constant parameter blocks.
  599. //
  600. typedef struct _RTL_COPY_MEMORY_SCATTER_GATHER_LIST_ELEMENT {
  601. SIZE_T FromOffset;
  602. SIZE_T ToOffset;
  603. SIZE_T Size;
  604. } RTL_COPY_MEMORY_SCATTER_GATHER_LIST_ELEMENT, *PRTL_COPY_MEMORY_SCATTER_GATHER_LIST_ELEMENT;
  605. typedef CONST RTL_COPY_MEMORY_SCATTER_GATHER_LIST_ELEMENT *PCRTL_COPY_MEMORY_SCATTER_GATHER_LIST_ELEMENT;
  606. #define RTL_COPY_MEMORY_SCATTER_GATHER_FLAG_VALID (0x00000001)
  607. typedef struct _RTL_COPY_MEMORY_SCATTER_GATHER_PARAMETERS {
  608. ULONG Flags;
  609. PCVOID FromBase;
  610. SIZE_T FromSize;
  611. PVOID ToBase;
  612. SIZE_T ToSize;
  613. SIZE_T NumberOfScatterGatherListElements;
  614. PCRTL_COPY_MEMORY_SCATTER_GATHER_LIST_ELEMENT ScatterGatherListElements;
  615. struct {
  616. BOOLEAN Caught;
  617. NTSTATUS UnderlyingStatus;
  618. PEXCEPTION_RECORD ExceptionRecord OPTIONAL;
  619. SIZE_T BytesCopied;
  620. SIZE_T FailedElementIndex;
  621. } InpageError;
  622. } RTL_COPY_MEMORY_SCATTER_GATHER_PARAMETERS, *PRTL_COPY_MEMORY_SCATTER_GATHER_PARAMETERS;
  623. typedef CONST RTL_COPY_MEMORY_SCATTER_GATHER_PARAMETERS *PCRTL_COPY_MEMORY_SCATTER_GATHER_PARAMETERS;
  624. #endif
  625. #if NOT_YET_USED
  626. LONG
  627. RtlpCopyMemoryScatterGatherExceptionHandlerAssumeValid(
  628. PRTL_COPY_MEMORY_SCATTER_GATHER_PARAMETERS Parameters,
  629. PEXCEPTION_POINTERS ExceptionPointers
  630. )
  631. {
  632. PEXCEPTION_RECORD ExceptionRecord = 0;
  633. ULONG NumberParameters = 0;
  634. ULONG_PTR ExceptionAddress = 0;
  635. ULONG_PTR CaughtBase = 0;
  636. NTSTATUS ExceptionCode = 0;
  637. LONG Disposition = 0;
  638. Disposition = EXCEPTION_CONTINUE_SEARCH;
  639. ExceptionRecord = ExceptionPointers->ExceptionRecord;
  640. ExceptionCode = ExceptionRecord->ExceptionCode;
  641. if (ExceptionCode != STATUS_IN_PAGE_ERROR) {
  642. goto Exit;
  643. }
  644. NumberParameters = ExceptionRecord->NumberParameters;
  645. if (RTL_IN_PAGE_ERROR_EXCEPTION_INFO_FAULTING_VA_INDEX < NumberParameters) {
  646. //
  647. // We don't have the information to do the range check so give up and do
  648. // not catch the exception. This can happen apparently.
  649. //
  650. goto Exit;
  651. }
  652. ExceptionAddress = ExceptionRecord->ExceptionInformation[RTL_IN_PAGE_ERROR_EXCEPTION_INFO_FAULTING_VA_INDEX];
  653. if (ExceptionAddress >= (CaughtBase = (ULONG_PTR)Parameters->FromBase)
  654. && ExceptionAddress < (CaughtBase + Parameters->FromSize)) {
  655. // nothing
  656. } else if (ExceptionAddress >= (CaughtBase = (ULONG_PTR)Parameters->ToBase)
  657. && ExceptionAddress < (CaughtBase + Parameters->ToSize)) {
  658. // nothing
  659. }
  660. else {
  661. // not in range, don't catch it
  662. goto Exit;
  663. }
  664. Disposition = EXCEPTION_EXECUTE_HANDLER;
  665. Parameters->InpageError.Caught = TRUE;
  666. Parameters->InpageError.BytesCopied = (SIZE_T)(ExceptionAddress - CaughtBase);
  667. if (ARGUMENT_PRESENT(Parameters->InpageError.ExceptionRecord)) {
  668. *Parameters->InpageError.ExceptionRecord = *ExceptionRecord;
  669. }
  670. if (RTL_IN_PAGE_ERROR_EXCEPTION_INFO_UNDERLYING_STATUS_INDEX < NumberParameters) {
  671. ExceptionCode = (NTSTATUS) ExceptionRecord->ExceptionInformation[RTL_IN_PAGE_ERROR_EXCEPTION_INFO_UNDERLYING_STATUS_INDEX];
  672. } else {
  673. // else just leave it as status_in_page_error
  674. }
  675. Parameters->InpageError.UnderlyingStatus = ExceptionCode;
  676. // DbgPrint...
  677. Exit:
  678. return Disposition;
  679. }
  680. #endif
  681. #if NOT_YET_USED
  682. LONG
  683. NTAPI
  684. RtlCopyMemoryScatterGatherExceptionHandler(
  685. PRTL_COPY_MEMORY_SCATTER_GATHER_PARAMETERS Parameters,
  686. PEXCEPTION_POINTERS ExceptionPointers
  687. )
  688. {
  689. //
  690. // This bit lets people turn off "large try/excepts" when they only really want
  691. // catch inpage errors in a small part of the try body. The pattern is:
  692. //
  693. // __try {
  694. // Parameters.Flags &= ~RTL_COPY_MEMORY_SCATTER_GATHER_FLAG_VALID;
  695. // ...
  696. // ... lots of code ...
  697. // ...
  698. // Parameters.Flags |= RTL_COPY_MEMORY_SCATTER_GATHER_FLAG_VALID;
  699. // RtlCopyMemory(&Parameters);
  700. // Parameters.Flags &= ~RTL_COPY_MEMORY_SCATTER_GATHER_FLAG_VALID;
  701. // ...
  702. // ... lots of code ...
  703. // ...
  704. // __except(RtlCopyMemoryScatterGatherExceptionHandler())
  705. //
  706. if ((Parameters->Flags & RTL_COPY_MEMORY_SCATTER_GATHER_FLAG_VALID) == 0) {
  707. return EXCEPTION_CONTINUE_SEARCH;
  708. }
  709. return RtlpCopyMemoryScatterGatherExceptionHandlerAssumeValid(Parameters, ExceptionPointers);
  710. }
  711. #endif
  712. #if NOT_YET_USED
  713. NTSTATUS
  714. NTAPI
  715. RtlCopyMemoryScatterGather(
  716. PRTL_COPY_MEMORY_SCATTER_GATHER_PARAMETERS Parameters
  717. )
  718. {
  719. RTL_COPY_MEMORY_SCATTER_GATHER_PARAMETERS LocalParameters;
  720. SIZE_T i;
  721. NTSTATUS Status = 0;
  722. // capture in locals to avoid unncessary pointer derefs in the loop
  723. LocalParameters.FromBase = Parameters->FromBase;
  724. LocalParameters.ToBase = Parameters->ToBase;
  725. LocalParameters.NumberOfScatterGatherListElements = Parameters->NumberOfScatterGatherListElements;
  726. LocalParameters.ScatterGatherListElements = Parameters->ScatterGatherListElements;
  727. __try {
  728. for (i = 0 ; i != LocalParameters.NumberOfScatterGatherListElements ; ++i) {
  729. RtlCopyMemory(
  730. ((PBYTE)LocalParameters.ToBase) + LocalParameters.ScatterGatherListElements[i].ToOffset,
  731. ((PCBYTE)LocalParameters.FromBase) + LocalParameters.ScatterGatherListElements[i].FromOffset,
  732. LocalParameters.ScatterGatherListElements[i].Size
  733. );
  734. }
  735. Status = STATUS_SUCCESS;
  736. } __except(RtlpCopyMemoryScatterGatherExceptionHandlerAssumeValid(Parameters, GetExceptionInformation())) {
  737. Status = Parameters->InpageError.UnderlyingStatus;
  738. Parameters->InpageError.FailedElementIndex = i;
  739. }
  740. return Status;
  741. }
  742. #endif
  743. #if defined(__cplusplus)
  744. } /* extern "C" */
  745. #endif