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.

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