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.

1492 lines
37 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. psldt.c
  5. Abstract:
  6. This module contains code for the process and thread ldt support
  7. Author:
  8. Dave Hastings (daveh) 20 May 1991
  9. Notes:
  10. We return STATUS_SUCCESS for exceptions resulting from accessing the
  11. process info structures in user space. This is by design (so Markl
  12. tells me). By the time we reach these functions all of the parameters
  13. in user space have been probed, so if we get an exception it indicates
  14. that the user is altering portions of his address space that have been
  15. passed to the system.
  16. The nonpaged pool consumed by the Ldt is returned to the system at process
  17. deletion time. The process deletion handler calls PspDeleteLdt. We
  18. do not keep a reference to the process once the ldt is created.
  19. Note that the LDT must be kept in nonpaged memory because the EXIT_ALL
  20. macros that return from traps and interrupts pop ds (which may be an LDT
  21. selector) and then other registers. With interrupts disabled.
  22. We capture the user mode parameters into local parameters to prevent
  23. the possibility that the user will change them after we validate them.
  24. Revision History:
  25. --*/
  26. #include "psp.h"
  27. //
  28. // Internal constants
  29. //
  30. #define DESCRIPTOR_GRAN 0x00800000
  31. #define DESCRIPTOR_NP 0x00008000
  32. #define DESCRIPTOR_SYSTEM 0x00001000
  33. #define DESCRIPTOR_CONFORM 0x00001C00
  34. #define DESCRIPTOR_DPL 0x00006000
  35. #define DESCRIPTOR_TYPEDPL 0x00007F00
  36. KMUTEX LdtMutex;
  37. //
  38. // Internal subroutines
  39. //
  40. PLDT_ENTRY
  41. PspCreateLdt(
  42. IN PLDT_ENTRY Ldt,
  43. IN ULONG Offset,
  44. IN ULONG Size,
  45. IN ULONG AllocationSize
  46. );
  47. BOOLEAN
  48. PspIsDescriptorValid(
  49. IN PLDT_ENTRY Descriptor
  50. );
  51. #ifdef ALLOC_PRAGMA
  52. #pragma alloc_text(INIT, PspLdtInitialize)
  53. #pragma alloc_text(PAGE, NtSetLdtEntries)
  54. #pragma alloc_text(PAGE, PspDeleteLdt)
  55. #pragma alloc_text(PAGE, PspQueryLdtInformation)
  56. #pragma alloc_text(PAGE, PspSetLdtSize)
  57. #pragma alloc_text(PAGE, PspSetLdtInformation)
  58. #pragma alloc_text(PAGE, PspCreateLdt)
  59. #pragma alloc_text(PAGE, PspIsDescriptorValid)
  60. #pragma alloc_text(PAGE, PspQueryDescriptorThread)
  61. #endif
  62. NTSTATUS
  63. PspLdtInitialize(
  64. )
  65. /*++
  66. Routine Description:
  67. This routine initializes the Ldt support for the x86
  68. Arguments:
  69. None
  70. Return Value:
  71. TBS
  72. --*/
  73. {
  74. KeInitializeMutex( &LdtMutex, MUTEX_LEVEL_PS_LDT );
  75. return STATUS_SUCCESS;
  76. }
  77. NTSTATUS
  78. PspQueryLdtInformation(
  79. IN PEPROCESS Process,
  80. OUT PPROCESS_LDT_INFORMATION LdtInformation,
  81. IN ULONG LdtInformationLength,
  82. OUT PULONG ReturnLength
  83. )
  84. /*++
  85. Routine Description:
  86. This function performs the work for the Ldt portion of the query
  87. process information function. It copies the contents of the Ldt
  88. for the specified process into the user's buffer, up to the length
  89. of the buffer.
  90. Arguments:
  91. Process -- Supplies a pointer to the process to return LDT info for
  92. LdtInformation -- Supplies a pointer to the buffer
  93. ReturnLength -- Returns the number of bytes put into the buffer
  94. Return Value:
  95. TBS
  96. --*/
  97. {
  98. ULONG CopyLength, CopyEnd;
  99. NTSTATUS Status;
  100. ULONG HeaderLength;
  101. ULONG Length=0, Start=0;
  102. LONG MutexStatus;
  103. PLDTINFORMATION ProcessLdtInfo;
  104. PAGED_CODE();
  105. //
  106. // Verify the parameters
  107. //
  108. if (LdtInformationLength < sizeof(PROCESS_LDT_INFORMATION)) {
  109. return STATUS_INFO_LENGTH_MISMATCH;
  110. }
  111. //
  112. // This portion of the parameters may be in user space
  113. //
  114. try {
  115. //
  116. // Capture parameters
  117. //
  118. Length = LdtInformation->Length;
  119. Start = LdtInformation->Start;
  120. } except (EXCEPTION_EXECUTE_HANDLER) {
  121. return GetExceptionCode ();
  122. }
  123. //
  124. // The buffer containing the Ldt entries must be in the information
  125. // structure. We subtract one Ldt entry, because the structure is
  126. // declared to contain one.
  127. //
  128. if (LdtInformationLength - sizeof(PROCESS_LDT_INFORMATION) + sizeof(LDT_ENTRY) < Length) {
  129. return STATUS_INFO_LENGTH_MISMATCH;
  130. }
  131. // An Ldt entry is a processor structure, and must be 8 bytes long
  132. ASSERT((sizeof(LDT_ENTRY) == 8));
  133. //
  134. // The length of the structure must be an even number of Ldt entries
  135. //
  136. if (Length % sizeof(LDT_ENTRY)) {
  137. return STATUS_INVALID_LDT_SIZE;
  138. }
  139. //
  140. // The information to get from the Ldt must start on an Ldt entry
  141. // boundary.
  142. //
  143. if (Start % sizeof(LDT_ENTRY)) {
  144. return STATUS_INVALID_LDT_OFFSET;
  145. }
  146. //
  147. // Acquire the Ldt mutex
  148. //
  149. Status = KeWaitForSingleObject(
  150. &LdtMutex,
  151. Executive,
  152. KernelMode,
  153. FALSE,
  154. NULL
  155. );
  156. if ( !NT_SUCCESS(Status) ) {
  157. return Status;
  158. }
  159. ProcessLdtInfo = Process->LdtInformation;
  160. //
  161. // If the process has an Ldt
  162. //
  163. if (( ProcessLdtInfo) && (ProcessLdtInfo->Size )) {
  164. ASSERT ((ProcessLdtInfo->Ldt));
  165. //
  166. // Set the end of the copy to be the smaller of:
  167. // the end of the information the user requested or
  168. // the end of the information that is actually there
  169. //
  170. if (ProcessLdtInfo->Size < Start) {
  171. CopyEnd = Start;
  172. } else if (ProcessLdtInfo->Size - Start > Length) {
  173. CopyEnd = Length + Start;
  174. } else {
  175. CopyEnd = ProcessLdtInfo->Size;
  176. }
  177. CopyLength = CopyEnd - Start;
  178. try {
  179. //
  180. // Set the length field to the actual length of the Ldt
  181. //
  182. LdtInformation->Length = ProcessLdtInfo->Size;
  183. //
  184. // Copy the contents of the Ldt into the user's buffer
  185. //
  186. if (CopyLength) {
  187. RtlCopyMemory(
  188. &(LdtInformation->LdtEntries),
  189. (PCHAR)ProcessLdtInfo->Ldt + Start,
  190. CopyLength
  191. );
  192. }
  193. } except(EXCEPTION_EXECUTE_HANDLER) {
  194. MutexStatus = KeReleaseMutex( &LdtMutex, FALSE );
  195. ASSERT(( MutexStatus == 0 ));
  196. return GetExceptionCode ();
  197. }
  198. } else {
  199. //
  200. // There is no Ldt
  201. //
  202. CopyLength = 0;
  203. try {
  204. LdtInformation->Length = 0;
  205. } except(EXCEPTION_EXECUTE_HANDLER) {
  206. MutexStatus = KeReleaseMutex( &LdtMutex, FALSE );
  207. ASSERT(( MutexStatus == 0 ));
  208. return GetExceptionCode ();
  209. }
  210. }
  211. //
  212. // Set the length of the information returned
  213. //
  214. if ( ARGUMENT_PRESENT(ReturnLength) ) {
  215. try {
  216. HeaderLength = (PCHAR)(&(LdtInformation->LdtEntries)) -
  217. (PCHAR)(&(LdtInformation->Start));
  218. *ReturnLength = CopyLength + HeaderLength;
  219. } except(EXCEPTION_EXECUTE_HANDLER){
  220. MutexStatus = KeReleaseMutex( &LdtMutex, FALSE );
  221. ASSERT(( MutexStatus == 0 ));
  222. return GetExceptionCode ();
  223. }
  224. }
  225. MutexStatus = KeReleaseMutex( &LdtMutex, FALSE );
  226. ASSERT(( MutexStatus == 0 ));
  227. return STATUS_SUCCESS;
  228. }
  229. NTSTATUS
  230. PspSetLdtSize(
  231. IN PEPROCESS Process,
  232. IN PPROCESS_LDT_SIZE LdtSize,
  233. IN ULONG LdtSizeLength
  234. )
  235. /*++
  236. Routine Description:
  237. This routine changes the LDT size. It will shrink the LDT, but not
  238. grow it. If the LDT shrinks by 1 or more pages from its current allocation,
  239. the LDT will be reallocated for the new smaller size. If the allocated
  240. size of the LDT changes, the quota charge for the Ldt will be reduced.
  241. Arguments:
  242. Process -- Supplies a pointer to the process whose Ldt is to be sized
  243. LdtSize -- Supplies a pointer to the size information
  244. Return Value:
  245. TBS
  246. --*/
  247. {
  248. ULONG OldSize = 0, NewSize;
  249. LONG MutexState;
  250. ULONG Length=0;
  251. PLDT_ENTRY OldLdt = NULL;
  252. NTSTATUS Status;
  253. PLDTINFORMATION ProcessLdtInfo;
  254. PLDT_ENTRY Ldt;
  255. PAGED_CODE();
  256. //
  257. // Verify the parameters
  258. //
  259. if (LdtSizeLength != sizeof (PROCESS_LDT_SIZE)){
  260. return STATUS_INFO_LENGTH_MISMATCH;
  261. }
  262. //
  263. // The following parameters may be in user space
  264. //
  265. try {
  266. //
  267. // Capture the new Ldt length
  268. //
  269. Length = LdtSize->Length;
  270. } except(EXCEPTION_EXECUTE_HANDLER){
  271. return GetExceptionCode ();
  272. }
  273. ASSERT((sizeof(LDT_ENTRY) == 8));
  274. //
  275. // The Ldt must always be an integral number of LDT_ENTRIES
  276. //
  277. if (Length % sizeof(LDT_ENTRY)) {
  278. return STATUS_INVALID_LDT_SIZE;
  279. }
  280. //
  281. // Acquire the Ldt Mutex
  282. //
  283. Status = KeWaitForSingleObject(
  284. &LdtMutex,
  285. Executive,
  286. KernelMode,
  287. FALSE,
  288. NULL
  289. );
  290. if (!NT_SUCCESS (Status)) {
  291. return Status;
  292. }
  293. //
  294. // If there isn't an Ldt we can't set the size of the LDT
  295. //
  296. ProcessLdtInfo = Process->LdtInformation;
  297. if ((ProcessLdtInfo == NULL) || (ProcessLdtInfo->Size == 0)) {
  298. MutexState = KeReleaseMutex( &LdtMutex, FALSE );
  299. ASSERT((MutexState == 0));
  300. return STATUS_NO_LDT;
  301. }
  302. //
  303. // This function cannot be used to grow the Ldt
  304. //
  305. if (Length > ProcessLdtInfo->Size) {
  306. MutexState = KeReleaseMutex( &LdtMutex, FALSE );
  307. ASSERT((MutexState == 0));
  308. return STATUS_INVALID_LDT_SIZE;
  309. }
  310. //
  311. // Later, we will set ProcessLdtInfo->Ldt = Ldt. We may set the value
  312. // of Ldt in the if statement below, but there is one case where we
  313. // don't
  314. //
  315. Ldt = ProcessLdtInfo->Ldt;
  316. //
  317. // Adjust the size of the LDT
  318. //
  319. ProcessLdtInfo->Size = Length;
  320. //
  321. // Free some of the Ldt memory if conditions allow
  322. //
  323. if ( Length == 0 ) {
  324. OldSize = ProcessLdtInfo->AllocatedSize;
  325. OldLdt = ProcessLdtInfo->Ldt;
  326. ProcessLdtInfo->AllocatedSize = 0;
  327. Ldt = NULL;
  328. } else if ((ProcessLdtInfo->AllocatedSize - ProcessLdtInfo->Size) >= PAGE_SIZE) {
  329. OldSize = ProcessLdtInfo->AllocatedSize;
  330. OldLdt = ProcessLdtInfo->Ldt;
  331. //
  332. // Calculate new Ldt size (lowest integer number of pages
  333. // large enough)
  334. //
  335. ProcessLdtInfo->AllocatedSize = (ProcessLdtInfo->Size + PAGE_SIZE - 1)
  336. & ~(PAGE_SIZE - 1);
  337. //
  338. // Reallocate and copy the Ldt
  339. //
  340. Ldt = PspCreateLdt(
  341. ProcessLdtInfo->Ldt,
  342. 0,
  343. ProcessLdtInfo->Size,
  344. ProcessLdtInfo->AllocatedSize
  345. );
  346. if ( Ldt == NULL ) {
  347. // We cannot reduce the allocation, but we can reduce the
  348. // Ldt selector limit (done using Ke386SetLdtProcess)
  349. Ldt = OldLdt;
  350. ProcessLdtInfo->AllocatedSize = OldSize;
  351. OldLdt = NULL;
  352. }
  353. }
  354. ProcessLdtInfo->Ldt = Ldt;
  355. //
  356. // Change the limit on the Process Ldt
  357. //
  358. Ke386SetLdtProcess(
  359. &(Process->Pcb),
  360. ProcessLdtInfo->Ldt,
  361. ProcessLdtInfo->Size
  362. );
  363. NewSize = ProcessLdtInfo->AllocatedSize;
  364. MutexState = KeReleaseMutex( &LdtMutex, FALSE );
  365. ASSERT((MutexState == 0));
  366. //
  367. // If we resized the Ldt, free the old one and reduce the quota charge
  368. //
  369. if (OldLdt) {
  370. ExFreePool( OldLdt );
  371. PsReturnProcessNonPagedPoolQuota (Process,
  372. OldSize - NewSize);
  373. }
  374. return STATUS_SUCCESS;
  375. }
  376. NTSTATUS
  377. PspSetLdtInformation(
  378. IN PEPROCESS Process,
  379. IN PPROCESS_LDT_INFORMATION LdtInformation,
  380. IN ULONG LdtInformationLength
  381. )
  382. /*++
  383. Routine Description:
  384. This function alters the ldt for a specified process. It can alter
  385. portions of the LDT, or the whole LDT. If an Ldt is created or
  386. grown, the specified process will be charged the quota for the LDT.
  387. Each descriptor that is set will be verified.
  388. Arguments:
  389. Process -- Supplies a pointer to the process whose Ldt is to be modified
  390. LdtInformation -- Supplies a pointer to the information about the Ldt
  391. modifications
  392. LdtInformationLength -- Supplies the length of the LdtInformation
  393. structure.
  394. Return Value:
  395. TBS
  396. --*/
  397. {
  398. NTSTATUS Status;
  399. PLDT_ENTRY OldLdt = NULL;
  400. ULONG OldSize = 0;
  401. ULONG AllocatedSize;
  402. ULONG Size;
  403. ULONG MutexState;
  404. ULONG LdtOffset;
  405. PLDT_ENTRY CurrentDescriptor;
  406. PPROCESS_LDT_INFORMATION LdtInfo=NULL;
  407. PLDTINFORMATION ProcessLdtInfo;
  408. PLDT_ENTRY Ldt;
  409. PAGED_CODE();
  410. if (LdtInformationLength < sizeof (PROCESS_LDT_INFORMATION)) {
  411. return STATUS_INFO_LENGTH_MISMATCH;
  412. }
  413. Status = STATUS_SUCCESS;
  414. LdtInfo = ExAllocatePoolWithTag (NonPagedPool,
  415. LdtInformationLength,
  416. 'dLsP');
  417. if (LdtInfo == NULL) {
  418. return STATUS_INSUFFICIENT_RESOURCES;
  419. }
  420. //
  421. // alocate a local buffer to capture the ldt information to
  422. //
  423. try {
  424. //
  425. // Copy the information the user is supplying
  426. //
  427. RtlCopyMemory (LdtInfo,
  428. LdtInformation,
  429. LdtInformationLength);
  430. } except (EXCEPTION_EXECUTE_HANDLER) {
  431. ExFreePool (LdtInfo);
  432. Status = GetExceptionCode ();
  433. return Status;
  434. }
  435. //
  436. // Verify that the Start and Length are plausible
  437. //
  438. if (LdtInfo->Start & 0xFFFF0000) {
  439. ExFreePool (LdtInfo);
  440. return STATUS_INVALID_LDT_OFFSET;
  441. }
  442. if (LdtInfo->Length & 0xFFFF0000) {
  443. ExFreePool (LdtInfo);
  444. return STATUS_INVALID_LDT_SIZE;
  445. }
  446. //
  447. // Insure that the buffer it large enough to contain the specified number
  448. // of selectors.
  449. //
  450. if (LdtInformationLength - sizeof (PROCESS_LDT_INFORMATION) + sizeof (LDT_ENTRY) < LdtInfo->Length) {
  451. ExFreePool (LdtInfo);
  452. return STATUS_INFO_LENGTH_MISMATCH;
  453. }
  454. //
  455. // The info to set must be an integral number of selectors
  456. //
  457. if (LdtInfo->Length % sizeof (LDT_ENTRY)) {
  458. ExFreePool (LdtInfo);
  459. return STATUS_INVALID_LDT_SIZE;
  460. }
  461. //
  462. // The beginning of the info must be on a selector boundary
  463. //
  464. if (LdtInfo->Start % sizeof (LDT_ENTRY)) {
  465. ExFreePool (LdtInfo);
  466. return STATUS_INVALID_LDT_OFFSET;
  467. }
  468. //
  469. // Verify all of the descriptors.
  470. //
  471. for (CurrentDescriptor = LdtInfo->LdtEntries;
  472. (PCHAR)CurrentDescriptor < (PCHAR)LdtInfo->LdtEntries + LdtInfo->Length;
  473. CurrentDescriptor++) {
  474. if (!PspIsDescriptorValid (CurrentDescriptor)) {
  475. ExFreePool (LdtInfo);
  476. return STATUS_INVALID_LDT_DESCRIPTOR;
  477. }
  478. }
  479. //
  480. // Acquire the Ldt Mutex
  481. //
  482. Status = KeWaitForSingleObject (&LdtMutex,
  483. Executive,
  484. KernelMode,
  485. FALSE,
  486. NULL);
  487. if (!NT_SUCCESS (Status)) {
  488. ExFreePool (LdtInfo);
  489. return Status;
  490. }
  491. ProcessLdtInfo = Process->LdtInformation;
  492. //
  493. // If the process doen't have an Ldt information structure, allocate
  494. // one and attach it to the process
  495. //
  496. if (ProcessLdtInfo == NULL) {
  497. ProcessLdtInfo = ExAllocatePoolWithTag (NonPagedPool,
  498. sizeof(LDTINFORMATION),
  499. 'dLsP');
  500. if (ProcessLdtInfo == NULL) {
  501. goto SetInfoCleanup;
  502. }
  503. Process->LdtInformation = ProcessLdtInfo;
  504. RtlZeroMemory (ProcessLdtInfo, sizeof (LDTINFORMATION));
  505. }
  506. //
  507. // If we are supposed to remove the LDT
  508. //
  509. if (LdtInfo->Length == 0) {
  510. //
  511. // Remove the process' Ldt
  512. //
  513. if (ProcessLdtInfo->Ldt) {
  514. OldSize = ProcessLdtInfo->AllocatedSize;
  515. OldLdt = ProcessLdtInfo->Ldt;
  516. ProcessLdtInfo->AllocatedSize = 0;
  517. ProcessLdtInfo->Size = 0;
  518. ProcessLdtInfo->Ldt = NULL;
  519. Ke386SetLdtProcess (&Process->Pcb,
  520. NULL,
  521. 0);
  522. PsReturnProcessNonPagedPoolQuota (Process, OldSize);
  523. }
  524. } else if (ProcessLdtInfo->Ldt == NULL) {
  525. //
  526. // Create a new Ldt for the process
  527. //
  528. //
  529. // Allocate an integral number of pages for the LDT.
  530. //
  531. ASSERT(((PAGE_SIZE % 2) == 0));
  532. AllocatedSize = (LdtInfo->Start + LdtInfo->Length + PAGE_SIZE - 1) &
  533. ~(PAGE_SIZE - 1);
  534. Size = LdtInfo->Start + LdtInfo->Length;
  535. Ldt = PspCreateLdt (LdtInfo->LdtEntries,
  536. LdtInfo->Start,
  537. Size,
  538. AllocatedSize);
  539. if (Ldt == NULL) {
  540. Status = STATUS_INSUFFICIENT_RESOURCES;
  541. goto SetInfoCleanup;
  542. }
  543. Status = PsChargeProcessNonPagedPoolQuota (Process,
  544. AllocatedSize);
  545. if (!NT_SUCCESS (Status)) {
  546. ExFreePool (Ldt);
  547. Ldt = NULL;
  548. goto SetInfoCleanup;
  549. }
  550. ProcessLdtInfo->Ldt = Ldt;
  551. ProcessLdtInfo->Size = Size;
  552. ProcessLdtInfo->AllocatedSize = AllocatedSize;
  553. Ke386SetLdtProcess (&Process->Pcb,
  554. ProcessLdtInfo->Ldt,
  555. ProcessLdtInfo->Size);
  556. } else if (LdtInfo->Length + LdtInfo->Start > ProcessLdtInfo->Size) {
  557. //
  558. // Grow the process' Ldt
  559. //
  560. if (LdtInfo->Length + LdtInfo->Start > ProcessLdtInfo->AllocatedSize) {
  561. //
  562. // Current Ldt allocation is not large enough, so create a
  563. // new larger Ldt
  564. //
  565. OldSize = ProcessLdtInfo->AllocatedSize;
  566. Size = LdtInfo->Start + LdtInfo->Length;
  567. AllocatedSize = (Size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
  568. Ldt = PspCreateLdt (ProcessLdtInfo->Ldt,
  569. 0,
  570. OldSize,
  571. AllocatedSize);
  572. if (Ldt == NULL) {
  573. Status = STATUS_INSUFFICIENT_RESOURCES;
  574. goto SetInfoCleanup;
  575. }
  576. Status = PsChargeProcessNonPagedPoolQuota (Process,
  577. AllocatedSize);
  578. if (!NT_SUCCESS (Status)) {
  579. ExFreePool (Ldt);
  580. Ldt = NULL;
  581. goto SetInfoCleanup;
  582. }
  583. PsReturnProcessNonPagedPoolQuota (Process,
  584. OldSize);
  585. //
  586. // Swap Ldt information
  587. //
  588. OldLdt = ProcessLdtInfo->Ldt;
  589. ProcessLdtInfo->Ldt = Ldt;
  590. ProcessLdtInfo->Size = Size;
  591. ProcessLdtInfo->AllocatedSize = AllocatedSize;
  592. //
  593. // Put new selectors into the new ldt
  594. //
  595. RtlCopyMemory ((PCHAR)(ProcessLdtInfo->Ldt) + LdtInfo->Start,
  596. LdtInfo->LdtEntries,
  597. LdtInfo->Length);
  598. Ke386SetLdtProcess (&Process->Pcb,
  599. ProcessLdtInfo->Ldt,
  600. ProcessLdtInfo->Size);
  601. } else {
  602. //
  603. // Current Ldt allocation is large enough
  604. //
  605. ProcessLdtInfo->Size = LdtInfo->Length + LdtInfo->Start;
  606. Ke386SetLdtProcess (&Process->Pcb,
  607. ProcessLdtInfo->Ldt,
  608. ProcessLdtInfo->Size);
  609. //
  610. // Change the selectors in the table
  611. //
  612. for (LdtOffset = LdtInfo->Start, CurrentDescriptor = LdtInfo->LdtEntries;
  613. LdtOffset < LdtInfo->Start + LdtInfo->Length;
  614. LdtOffset += sizeof(LDT_ENTRY), CurrentDescriptor++) {
  615. Ke386SetDescriptorProcess (&Process->Pcb,
  616. LdtOffset,
  617. *CurrentDescriptor);
  618. }
  619. }
  620. } else {
  621. //
  622. // Simply changing some selectors
  623. //
  624. for (LdtOffset = LdtInfo->Start, CurrentDescriptor = LdtInfo->LdtEntries;
  625. LdtOffset < LdtInfo->Start + LdtInfo->Length;
  626. LdtOffset += sizeof(LDT_ENTRY), CurrentDescriptor++) {
  627. Ke386SetDescriptorProcess (&Process->Pcb,
  628. LdtOffset,
  629. *CurrentDescriptor);
  630. }
  631. Status = STATUS_SUCCESS;
  632. }
  633. SetInfoCleanup:
  634. MutexState = KeReleaseMutex (&LdtMutex, FALSE);
  635. ASSERT ((MutexState == 0));
  636. if (OldLdt != NULL) {
  637. ExFreePool (OldLdt);
  638. }
  639. if (LdtInfo != NULL) {
  640. ExFreePool (LdtInfo);
  641. }
  642. return Status;
  643. }
  644. PLDT_ENTRY
  645. PspCreateLdt (
  646. IN PLDT_ENTRY Ldt,
  647. IN ULONG Offset,
  648. IN ULONG Size,
  649. IN ULONG AllocationSize
  650. )
  651. /*++
  652. Routine Description:
  653. This routine allocates space in nonpaged pool for an LDT, and copies the
  654. specified selectors into it. IT DOES NOT VALIDATE THE SELECTORS.
  655. Selector validation must be done before calling this routine. IT
  656. DOES NOT CHARGE THE QUOTA FOR THE LDT.
  657. Arguments:
  658. Ldt -- Supplies a pointer to the descriptors to be put into the Ldt.
  659. Offset -- Supplies the offset in the LDT to copy the descriptors to.
  660. Size -- Supplies the actualsize of the new Ldt
  661. AllocationSize -- Supplies the size to allocate
  662. Return Value:
  663. Pointer to the new Ldt
  664. --*/
  665. {
  666. PLDT_ENTRY NewLdt;
  667. PAGED_CODE();
  668. ASSERT ((AllocationSize >= Size));
  669. ASSERT (((Size % sizeof(LDT_ENTRY)) == 0));
  670. NewLdt = ExAllocatePoolWithTag (NonPagedPool, AllocationSize, 'dLsP');
  671. if (NewLdt != NULL) {
  672. RtlZeroMemory (NewLdt, AllocationSize);
  673. RtlCopyMemory ((PCHAR)NewLdt + Offset, Ldt, Size - Offset);
  674. }
  675. return NewLdt;
  676. }
  677. BOOLEAN
  678. PspIsDescriptorValid(
  679. IN PLDT_ENTRY Descriptor
  680. )
  681. /*++
  682. Routine Description:
  683. This function determines if the supplied descriptor is valid to put
  684. into a process Ldt. For the descriptor to be valid it must have the
  685. following characteristics:
  686. Base < MM_HIGHEST_USER_ADDRESS
  687. Base + Limit < MM_HIGHEST_USER_ADDRESS
  688. Type must be
  689. ReadWrite, ReadOnly, ExecuteRead, ExecuteOnly, or Invalid
  690. big or small
  691. normal or grow down
  692. Not a system descriptor (system bit is 1 == application)
  693. This rules out all gates, etc
  694. Not conforming
  695. DPL must be 3
  696. Arguments:
  697. Descriptor -- Supplies a pointer to the descriptor to check
  698. Return Value:
  699. True if the descriptor is valid (note: valid to put into an LDT. This
  700. includes Invalid descriptors)
  701. False if not
  702. --*/
  703. {
  704. ULONG Base;
  705. ULONG Limit;
  706. PAGED_CODE();
  707. //
  708. // if descriptor is an invalid descriptor
  709. //
  710. if ((Descriptor->HighWord.Bits.Type == 0) &&
  711. (Descriptor->HighWord.Bits.Dpl == 0)) {
  712. return TRUE;
  713. }
  714. Base = Descriptor->BaseLow | (Descriptor->HighWord.Bytes.BaseMid << 16) |
  715. (Descriptor->HighWord.Bytes.BaseHi << 24);
  716. Limit = Descriptor->LimitLow | (Descriptor->HighWord.Bits.LimitHi << 16);
  717. //
  718. // Only have to check for present selectors
  719. //
  720. if (Descriptor->HighWord.Bits.Pres) {
  721. ULONG ActualLimit;
  722. if ((Descriptor->HighWord.Bits.Type&0x14) == 0x14) {
  723. if (Descriptor->HighWord.Bits.Default_Big == 1) {
  724. ActualLimit = 0xFFFFFFFF;
  725. } else {
  726. ActualLimit = 0xFFFF;
  727. }
  728. } else if (Descriptor->HighWord.Bits.Granularity == 0) {
  729. ActualLimit = Limit;
  730. } else {
  731. ActualLimit = (Limit<<12) + 0xFFF;
  732. }
  733. //
  734. // See if the segment extends into the kernel address space.
  735. //
  736. if (Base > Base + ActualLimit ||
  737. ((PVOID)(Base + ActualLimit) > MM_HIGHEST_USER_ADDRESS)) {
  738. return FALSE;
  739. }
  740. //
  741. // Don't let the reserved field be set.
  742. //
  743. if (Descriptor->HighWord.Bits.Reserved_0 != 0) {
  744. return FALSE;
  745. }
  746. }
  747. //
  748. // if descriptor is a system descriptor (which includes gates)
  749. // if bit 4 of the Type field is 0, then it's a system descriptor,
  750. // and we don't like it.
  751. //
  752. if (!(Descriptor->HighWord.Bits.Type & 0x10)) {
  753. return FALSE;
  754. }
  755. //
  756. // if descriptor is conforming code
  757. //
  758. if (((Descriptor->HighWord.Bits.Type & 0x18) == 0x18) &&
  759. (Descriptor->HighWord.Bits.Type & 0x4)) {
  760. return FALSE;
  761. }
  762. //
  763. // if Dpl is not 3
  764. //
  765. if (Descriptor->HighWord.Bits.Dpl != 3) {
  766. return FALSE;
  767. }
  768. return TRUE;
  769. }
  770. NTSTATUS
  771. PspQueryDescriptorThread (
  772. PETHREAD Thread,
  773. PVOID ThreadInformation,
  774. ULONG ThreadInformationLength,
  775. PULONG ReturnLength
  776. )
  777. /*++
  778. Routine Description:
  779. This function retrieves a descriptor table entry for the specified thread.
  780. This entry may be in either the Gdt or the Ldt, as specfied by the
  781. supplied selector
  782. Arguments:
  783. Thread -- Supplies a pointer to the thread.
  784. ThreadInformation -- Supplies information on the descriptor.
  785. ThreadInformationLength -- Supplies the length of the information.
  786. ReturnLength -- Returns the number of bytes returned.
  787. Return Value:
  788. TBS
  789. --*/
  790. {
  791. DESCRIPTOR_TABLE_ENTRY DescriptorEntry={0};
  792. PEPROCESS Process;
  793. LONG MutexState;
  794. NTSTATUS Status;
  795. PAGED_CODE();
  796. ASSERT( sizeof(KGDTENTRY) == sizeof(LDT_ENTRY) );
  797. //
  798. // Verify parameters
  799. //
  800. if ( ThreadInformationLength != sizeof(DESCRIPTOR_TABLE_ENTRY) ) {
  801. return STATUS_INFO_LENGTH_MISMATCH;
  802. }
  803. try {
  804. DescriptorEntry = *(PDESCRIPTOR_TABLE_ENTRY)ThreadInformation;
  805. } except(EXCEPTION_EXECUTE_HANDLER){
  806. return GetExceptionCode ();
  807. }
  808. Status = STATUS_SUCCESS;
  809. //
  810. // If its a Gdt entry, let the kernel find it for us
  811. //
  812. if ( !(DescriptorEntry.Selector & SELECTOR_TABLE_INDEX) ) {
  813. if ( (DescriptorEntry.Selector & 0xFFFFFFF8) >= KGDT_NUMBER * sizeof(KGDTENTRY) ) {
  814. return STATUS_ACCESS_VIOLATION;
  815. }
  816. try {
  817. Ke386GetGdtEntryThread (&Thread->Tcb,
  818. DescriptorEntry.Selector & 0xFFFFFFF8,
  819. (PKGDTENTRY) &(((PDESCRIPTOR_TABLE_ENTRY)ThreadInformation)->Descriptor));
  820. if (ARGUMENT_PRESENT(ReturnLength) ) {
  821. *ReturnLength = sizeof(LDT_ENTRY);
  822. }
  823. } except(EXCEPTION_EXECUTE_HANDLER) {
  824. return GetExceptionCode ();
  825. }
  826. } else {
  827. //
  828. // it's an Ldt entry, so copy it from the ldt
  829. //
  830. Process = THREAD_TO_PROCESS (Thread);
  831. //
  832. // Acquire the Ldt Mutex
  833. //
  834. Status = KeWaitForSingleObject (&LdtMutex,
  835. Executive,
  836. KernelMode,
  837. FALSE,
  838. NULL);
  839. if (!NT_SUCCESS (Status)) {
  840. return Status;
  841. }
  842. if ( Process->LdtInformation == NULL ) {
  843. // If there is no Ldt
  844. Status = STATUS_NO_LDT;
  845. } else if ( (DescriptorEntry.Selector & 0xFFFFFFF8) >=
  846. ((PLDTINFORMATION)(Process->LdtInformation))->Size ) {
  847. // Else If the selector is outside the table
  848. Status = STATUS_ACCESS_VIOLATION;
  849. } else try {
  850. // Else return the contents of the descriptor
  851. RtlCopyMemory (&(((PDESCRIPTOR_TABLE_ENTRY)ThreadInformation)->Descriptor),
  852. (PCHAR)(((PLDTINFORMATION)(Process->LdtInformation))->Ldt) +
  853. (DescriptorEntry.Selector & 0xFFFFFFF8),
  854. sizeof(LDT_ENTRY));
  855. if (ARGUMENT_PRESENT(ReturnLength)) {
  856. *ReturnLength = sizeof(LDT_ENTRY);
  857. }
  858. } except(EXCEPTION_EXECUTE_HANDLER) {
  859. Status = GetExceptionCode ();
  860. }
  861. MutexState = KeReleaseMutex (&LdtMutex, FALSE);
  862. ASSERT ((MutexState == 0));
  863. }
  864. return Status;
  865. }
  866. VOID
  867. PspDeleteLdt(
  868. IN PEPROCESS Process
  869. )
  870. /*++
  871. Routine Description:
  872. This routine frees the nonpaged pool associated with a process' Ldt, if
  873. it has one.
  874. Arguments:
  875. Process -- Supplies a pointer to the process
  876. Return Value:
  877. None
  878. --*/
  879. {
  880. PLDTINFORMATION LdtInformation;
  881. PAGED_CODE();
  882. LdtInformation = Process->LdtInformation;
  883. if (LdtInformation != NULL) {
  884. if (LdtInformation->Ldt != NULL) {
  885. PsReturnProcessNonPagedPoolQuota (Process, LdtInformation->AllocatedSize);
  886. ExFreePool (LdtInformation->Ldt);
  887. }
  888. ExFreePool( LdtInformation );
  889. }
  890. }
  891. NTSTATUS
  892. NtSetLdtEntries(
  893. IN ULONG Selector0,
  894. IN ULONG Entry0Low,
  895. IN ULONG Entry0Hi,
  896. IN ULONG Selector1,
  897. IN ULONG Entry1Low,
  898. IN ULONG Entry1Hi
  899. )
  900. /*++
  901. Routine Description:
  902. This routine sets up to two selectors in the current process's LDT.
  903. The LDT will be grown as necessary. A selector value of 0 indicates
  904. that the specified selector was not passed (allowing the setting of
  905. a single selector).
  906. Arguments:
  907. Selector0 -- Supplies the number of the first descriptor to set
  908. Entry0Low -- Supplies the low 32 bits of the descriptor
  909. Entry0Hi -- Supplies the high 32 bits of the descriptor
  910. Selector1 -- Supplies the number of the first descriptor to set
  911. Entry1Low -- Supplies the low 32 bits of the descriptor
  912. Entry1Hi -- Supplies the high 32 bits of the descriptor
  913. Return Value:
  914. TBS
  915. --*/
  916. {
  917. ULONG LdtSize, AllocatedSize;
  918. NTSTATUS Status;
  919. PEPROCESS Process;
  920. LDT_ENTRY Descriptor[2];
  921. PLDT_ENTRY Ldt, OldLdt;
  922. PLDTINFORMATION ProcessLdtInformation;
  923. LONG MutexState;
  924. ULONG Selector1Index;
  925. PAGED_CODE();
  926. //
  927. // Verify the selectors. We do not allow selectors that point into
  928. // Kernel space, system selectors, or conforming code selectors
  929. //
  930. //
  931. // Verify the selectors
  932. //
  933. if ((Selector0 & 0xFFFF0000) || (Selector1 & 0xFFFF0000)) {
  934. return STATUS_INVALID_LDT_DESCRIPTOR;
  935. }
  936. // Change the selector values to indexes into the LDT
  937. Selector0 = Selector0 & ~(RPL_MASK | SELECTOR_TABLE_INDEX);
  938. Selector1 = Selector1 & ~(RPL_MASK | SELECTOR_TABLE_INDEX);
  939. //
  940. // Verify descriptor 0
  941. //
  942. Selector1Index = 0;
  943. if (Selector0) {
  944. Selector1Index = 1;
  945. *((PULONG)(&Descriptor[0])) = Entry0Low;
  946. *(((PULONG)(&Descriptor[0])) + 1) = Entry0Hi;
  947. //
  948. // Validate the descriptor
  949. //
  950. if (!PspIsDescriptorValid (&Descriptor[0])) {
  951. return STATUS_INVALID_LDT_DESCRIPTOR;
  952. }
  953. }
  954. //
  955. // Verify descriptor 1
  956. //
  957. if (Selector1) {
  958. *((PULONG)(&Descriptor[Selector1Index])) = Entry1Low;
  959. *(((PULONG)(&Descriptor[Selector1Index])) + 1) = Entry1Hi;
  960. //
  961. // Validate the descriptor
  962. //
  963. if (!PspIsDescriptorValid (&Descriptor[Selector1Index])) {
  964. return STATUS_INVALID_LDT_DESCRIPTOR;
  965. }
  966. }
  967. //
  968. // Figure out how large the LDT needs to be
  969. //
  970. if (Selector0 > Selector1) {
  971. LdtSize = Selector0 + sizeof(LDT_ENTRY);
  972. } else {
  973. LdtSize = Selector1 + sizeof(LDT_ENTRY);
  974. }
  975. Process = PsGetCurrentProcess();
  976. //
  977. // Acquire the LDT mutex.
  978. //
  979. Status = KeWaitForSingleObject(
  980. &LdtMutex,
  981. Executive,
  982. KernelMode,
  983. FALSE,
  984. NULL
  985. );
  986. if (!NT_SUCCESS (Status)) {
  987. return Status;
  988. }
  989. ProcessLdtInformation = Process->LdtInformation;
  990. //
  991. // Most of the time, the process will already have an LDT, and it
  992. // will be large enough. for this, we just set the descriptors and
  993. // return
  994. //
  995. if (ProcessLdtInformation) {
  996. //
  997. // If the LDT descriptor does not have to be modified.
  998. //
  999. if (ProcessLdtInformation->Size >= LdtSize) {
  1000. if (Selector0) {
  1001. Ke386SetDescriptorProcess(
  1002. &(Process->Pcb),
  1003. Selector0,
  1004. Descriptor[0]
  1005. );
  1006. }
  1007. if (Selector1) {
  1008. Ke386SetDescriptorProcess(
  1009. &(Process->Pcb),
  1010. Selector1,
  1011. Descriptor[Selector1Index]
  1012. );
  1013. }
  1014. MutexState = KeReleaseMutex( &LdtMutex, FALSE );
  1015. ASSERT(( MutexState == 0 ));
  1016. return STATUS_SUCCESS;
  1017. //
  1018. // Else if the Ldt will fit in the memory currently allocated
  1019. //
  1020. } else if (ProcessLdtInformation->AllocatedSize >= LdtSize) {
  1021. //
  1022. // First remove the LDT. This will allow us to edit the memory.
  1023. // We will then put the LDT back. Since we have to change the
  1024. // limit anyway, it would take two calls to the kernel ldt
  1025. // management minimum to set the descriptors. Each of those calls
  1026. // would stall all of the processors in an MP system. If we
  1027. // didn't remove the ldt first, and we were setting two descriptors,
  1028. // we would have to call the LDT management 3 times (once per
  1029. // descriptor, and once to change the limit of the LDT).
  1030. //
  1031. Ke386SetLdtProcess(
  1032. &(Process->Pcb),
  1033. NULL,
  1034. 0L
  1035. );
  1036. //
  1037. // Set the Descriptors in the LDT
  1038. //
  1039. if (Selector0) {
  1040. *((PLDT_ENTRY) &ProcessLdtInformation->Ldt[Selector0/sizeof(LDT_ENTRY)]) = Descriptor[0];
  1041. }
  1042. if (Selector1) {
  1043. *((PLDT_ENTRY) &ProcessLdtInformation->Ldt[Selector1/sizeof(LDT_ENTRY)]) = Descriptor[Selector1Index];
  1044. }
  1045. //
  1046. // Set the LDT for the process
  1047. //
  1048. ProcessLdtInformation->Size = LdtSize;
  1049. Ke386SetLdtProcess(
  1050. &(Process->Pcb),
  1051. ProcessLdtInformation->Ldt,
  1052. ProcessLdtInformation->Size
  1053. );
  1054. MutexState = KeReleaseMutex (&LdtMutex, FALSE);
  1055. ASSERT ((MutexState == 0));
  1056. return STATUS_SUCCESS;
  1057. //
  1058. // Otherwise, we have to grow the LDT allocation
  1059. //
  1060. }
  1061. }
  1062. //
  1063. // If the process does not yet have an LDT information structure,
  1064. // allocate and attach one.
  1065. //
  1066. OldLdt = NULL;
  1067. if (!Process->LdtInformation) {
  1068. ProcessLdtInformation = ExAllocatePoolWithTag (NonPagedPool,
  1069. sizeof(LDTINFORMATION),
  1070. 'dLsP');
  1071. if (ProcessLdtInformation == NULL) {
  1072. goto SetLdtEntriesCleanup;
  1073. }
  1074. Process->LdtInformation = ProcessLdtInformation;
  1075. ProcessLdtInformation->Size = 0L;
  1076. ProcessLdtInformation->AllocatedSize = 0L;
  1077. ProcessLdtInformation->Ldt = NULL;
  1078. }
  1079. //
  1080. // Now, we either need to create or grow an LDT, so allocate some
  1081. // memory, and copy as necessary
  1082. //
  1083. AllocatedSize = (LdtSize + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
  1084. Ldt = ExAllocatePoolWithTag (NonPagedPool,
  1085. AllocatedSize,
  1086. 'dLsP');
  1087. if (Ldt) {
  1088. RtlZeroMemory (Ldt,
  1089. AllocatedSize);
  1090. } else {
  1091. goto SetLdtEntriesCleanup;
  1092. }
  1093. if (ProcessLdtInformation->Ldt) {
  1094. //
  1095. // copy the contents of the old ldt
  1096. //
  1097. RtlCopyMemory (Ldt,
  1098. ProcessLdtInformation->Ldt,
  1099. ProcessLdtInformation->Size);
  1100. Status = PsChargeProcessNonPagedPoolQuota (Process,
  1101. AllocatedSize);
  1102. if (!NT_SUCCESS (Status)) {
  1103. ExFreePool (Ldt);
  1104. Ldt = NULL;
  1105. } else {
  1106. PsReturnProcessNonPagedPoolQuota (Process,
  1107. ProcessLdtInformation->AllocatedSize);
  1108. }
  1109. if (Ldt == NULL) {
  1110. goto SetLdtEntriesCleanup;
  1111. }
  1112. } else {
  1113. Status = PsChargeProcessNonPagedPoolQuota (Process,
  1114. AllocatedSize);
  1115. if (!NT_SUCCESS (Status)) {
  1116. ExFreePool (Ldt);
  1117. Ldt = NULL;
  1118. }
  1119. if (Ldt == NULL) {
  1120. goto SetLdtEntriesCleanup;
  1121. }
  1122. }
  1123. OldLdt = ProcessLdtInformation->Ldt;
  1124. ProcessLdtInformation->Size = LdtSize;
  1125. ProcessLdtInformation->AllocatedSize = AllocatedSize;
  1126. ProcessLdtInformation->Ldt = Ldt;
  1127. //
  1128. // Set the descriptors in the LDT
  1129. //
  1130. if (Selector0) {
  1131. *((PLDT_ENTRY) &ProcessLdtInformation->Ldt[Selector0/sizeof(LDT_ENTRY)]) = Descriptor[0];
  1132. }
  1133. if (Selector1) {
  1134. *((PLDT_ENTRY) &ProcessLdtInformation->Ldt[Selector1/sizeof(LDT_ENTRY)]) = Descriptor[Selector1Index];
  1135. }
  1136. //
  1137. // Set the LDT for the process
  1138. //
  1139. Ke386SetLdtProcess (&Process->Pcb,
  1140. ProcessLdtInformation->Ldt,
  1141. ProcessLdtInformation->Size);
  1142. //
  1143. // Cleanup and exit
  1144. //
  1145. Status = STATUS_SUCCESS;
  1146. SetLdtEntriesCleanup:
  1147. if (OldLdt) {
  1148. ExFreePool(OldLdt);
  1149. }
  1150. MutexState = KeReleaseMutex (&LdtMutex, FALSE);
  1151. ASSERT (MutexState == 0);
  1152. return Status;
  1153. }