ReactOS  0.4.13-dev-961-g238ea69
ldt.c File Reference
#include <ntoskrnl.h>
#include <debug.h>
Include dependency graph for ldt.c:

Go to the source code of this file.

Macros

#define NDEBUG
 

Functions

NTSTATUS NTAPI Ke386GetGdtEntryThread (IN PKTHREAD Thread, IN ULONG Offset, IN PKGDTENTRY Descriptor)
 
VOID KeSetBaseGdtSelector (ULONG Entry, PVOID Base)
 
VOID KeSetGdtSelector (ULONG Entry, ULONG Value1, ULONG Value2)
 
BOOLEAN PspIsDescriptorValid (PLDT_ENTRY ldt_entry)
 
NTSTATUS NTAPI NtSetLdtEntries (ULONG Selector1, LDT_ENTRY LdtEntry1, ULONG Selector2, LDT_ENTRY LdtEntry2)
 

Variables

static KSPIN_LOCK LdtLock
 
static KSPIN_LOCK GdtLock
 

Macro Definition Documentation

◆ NDEBUG

#define NDEBUG

Definition at line 14 of file ldt.c.

Function Documentation

◆ Ke386GetGdtEntryThread()

NTSTATUS NTAPI Ke386GetGdtEntryThread ( IN PKTHREAD  Thread,
IN ULONG  Offset,
IN PKGDTENTRY  Descriptor 
)

Definition at line 26 of file ldt.c.

29 {
30  /* Make sure the offset isn't outside the allowed range */
31  if (Offset >= (KGDT_NUMBER * sizeof(KGDTENTRY)))
32  {
33  /* It is, fail */
35  }
36 
37  /* Check if this is the LDT selector */
38  if (Offset == KGDT_LDT)
39  {
40  /* Get it from the thread's process */
42  &Thread->Process->LdtDescriptor,
43  sizeof(KGDTENTRY));
44  }
45  else
46  {
47  /* Get the descriptor entry from the GDT */
49  (PVOID)(((ULONG_PTR)KeGetPcr()->GDT) + Offset),
50  sizeof(KGDTENTRY));
51 
52  /* Check if this is the TEB selector */
53  if (Offset == KGDT_R3_TEB)
54  {
55  /*
56  * Make sure we set the correct base for this thread. This is per
57  * process and is set in the GDT on context switch, so it might not
58  * be correct for the thread specified.
59  */
60  Descriptor->BaseLow =
61  (USHORT)((ULONG_PTR)(Thread->Teb) & 0xFFFF);
62  Descriptor->HighWord.Bytes.BaseMid =
63  (UCHAR)((ULONG_PTR)(Thread->Teb) >> 16);
64  Descriptor->HighWord.Bytes.BaseHi =
65  (UCHAR)((ULONG_PTR)(Thread->Teb) >> 24);
66  }
67  }
68 
69  /* Success */
70  return STATUS_SUCCESS;
71 }
NTSYSAPI VOID NTAPI RtlCopyMemory(VOID UNALIGNED *Destination, CONST VOID UNALIGNED *Source, ULONG Length)
#define KeGetPcr()
Definition: ke.h:25
uint32_t ULONG_PTR
Definition: typedefs.h:63
#define KGDT_LDT
Definition: ketypes.h:81
_In_ ULONG _In_ ULONG Offset
Definition: ntddpcm.h:101
Definition: utils.h:160
#define KGDT_R3_TEB
Definition: ketypes.h:80
_In_opt_ PFILE_OBJECT _In_opt_ PETHREAD Thread
Definition: fltkernel.h:2653
#define KGDT_NUMBER
Definition: ketypes.h:88
unsigned char UCHAR
Definition: xmlstorage.h:181
#define STATUS_ACCESS_VIOLATION
Definition: ntstatus.h:228
unsigned short USHORT
Definition: pedump.c:61
return STATUS_SUCCESS
Definition: btrfs.c:2777
_In_ PSTORAGE_PROPERTY_ID _Outptr_ PSTORAGE_DESCRIPTOR_HEADER * Descriptor
Definition: classpnp.h:966

Referenced by PspQueryDescriptorThread().

◆ KeSetBaseGdtSelector()

VOID KeSetBaseGdtSelector ( ULONG  Entry,
PVOID  Base 
)

Definition at line 74 of file ldt.c.

76 {
77  KIRQL oldIrql;
78  PUSHORT Gdt;
79 
80  DPRINT("KeSetBaseGdtSelector(Entry %x, Base %p)\n", Entry, Base);
81 
82  KeAcquireSpinLock(&GdtLock, &oldIrql);
83 
84  Gdt = (PUSHORT)KeGetPcr()->GDT;
85  Entry = (Entry & (~0x3)) / 2;
86 
87  Gdt[Entry + 1] = (USHORT)(((ULONG)Base) & 0xffff);
88 
89  Gdt[Entry + 2] = Gdt[Entry + 2] & ~(0xff);
90  Gdt[Entry + 2] = (USHORT)(Gdt[Entry + 2] |
91  ((((ULONG)Base) & 0xff0000) >> 16));
92 
93  Gdt[Entry + 3] = Gdt[Entry + 3] & ~(0xff00);
94  Gdt[Entry + 3] = (USHORT)(Gdt[Entry + 3] |
95  ((((ULONG)Base) & 0xff000000) >> 16));
96 
97  DPRINT("%x %x %x %x\n",
98  Gdt[Entry + 0],
99  Gdt[Entry + 1],
100  Gdt[Entry + 2],
101  Gdt[Entry + 3]);
102 
103  KeReleaseSpinLock(&GdtLock, oldIrql);
104 }
_In_opt_ ULONG Base
Definition: rtlfuncs.h:2343
#define KeGetPcr()
Definition: ke.h:25
UCHAR KIRQL
Definition: env_spec_w32.h:591
void DPRINT(...)
Definition: polytest.cpp:61
#define KeAcquireSpinLock(sl, irql)
Definition: env_spec_w32.h:609
unsigned short USHORT
Definition: pedump.c:61
#define KeReleaseSpinLock(sl, irql)
Definition: env_spec_w32.h:627
unsigned int ULONG
Definition: retypes.h:1
static KSPIN_LOCK GdtLock
Definition: ldt.c:20
unsigned short * PUSHORT
Definition: retypes.h:2
base of all file and directory entries
Definition: entries.h:82

◆ KeSetGdtSelector()

VOID KeSetGdtSelector ( ULONG  Entry,
ULONG  Value1,
ULONG  Value2 
)

Definition at line 107 of file ldt.c.

110 {
111  KIRQL oldIrql;
112  PULONG Gdt;
113 
114  DPRINT("KeSetGdtSelector(Entry %x, Value1 %x, Value2 %x)\n",
115  Entry, Value1, Value2);
116 
117  KeAcquireSpinLock(&GdtLock, &oldIrql);
118 
119  Gdt = (PULONG) KeGetPcr()->GDT;
120  Entry = (Entry & (~0x3)) / 4;
121 
122  Gdt[Entry] = Value1;
123  Gdt[Entry + 1] = Value2;
124 
125  DPRINT("%x %x\n",
126  Gdt[Entry + 0],
127  Gdt[Entry + 1]);
128 
129  KeReleaseSpinLock(&GdtLock, oldIrql);
130 }
struct _Entry Entry
Definition: kefuncs.h:640
#define KeGetPcr()
Definition: ke.h:25
UCHAR KIRQL
Definition: env_spec_w32.h:591
void DPRINT(...)
Definition: polytest.cpp:61
#define KeAcquireSpinLock(sl, irql)
Definition: env_spec_w32.h:609
unsigned int * PULONG
Definition: retypes.h:1
#define KeReleaseSpinLock(sl, irql)
Definition: env_spec_w32.h:627
static KSPIN_LOCK GdtLock
Definition: ldt.c:20
base of all file and directory entries
Definition: entries.h:82

Referenced by KiSwapContextExit(), KiSwapProcess(), and NtSetLdtEntries().

◆ NtSetLdtEntries()

NTSTATUS NTAPI NtSetLdtEntries ( ULONG  Selector1,
LDT_ENTRY  LdtEntry1,
ULONG  Selector2,
LDT_ENTRY  LdtEntry2 
)

Definition at line 184 of file ldt.c.

188 {
189  KIRQL oldIrql;
190  ULONG NewLdtSize = sizeof(LDT_ENTRY);
191  PUSHORT LdtDescriptor;
192  ULONG LdtBase;
193  ULONG LdtLimit;
194 
195  if((Selector1 & ~0xffff) || (Selector2 & ~0xffff)) return STATUS_INVALID_LDT_DESCRIPTOR;
196 
197  Selector1 &= ~0x7;
198  Selector2 &= ~0x7;
199 
200  if((Selector1 && !PspIsDescriptorValid(&LdtEntry1)) ||
201  (Selector2 && !PspIsDescriptorValid(&LdtEntry2))) return STATUS_INVALID_LDT_DESCRIPTOR;
202  if(!(Selector1 || Selector2)) return STATUS_SUCCESS;
203 
204  NewLdtSize += (Selector1 >= Selector2) ? Selector1 : Selector2;
205 
206  KeAcquireSpinLock(&LdtLock, &oldIrql);
207 
208  LdtDescriptor = (PUSHORT) &PsGetCurrentProcess()->Pcb.LdtDescriptor;
209  LdtBase = LdtDescriptor[1] |
210  ((LdtDescriptor[2] & 0xff) << 16) |
211  ((LdtDescriptor[3] & ~0xff) << 16);
212  LdtLimit = LdtDescriptor[0] |
213  ((LdtDescriptor[3] & 0xf) << 16);
214 
215  if(LdtLimit < (NewLdtSize - 1))
216  {
217  /* allocate new ldt, copy old one there, set gdt ldt entry to new
218  values and load ldtr register and free old ldt */
219 
220  ULONG NewLdtBase = (ULONG) ExAllocatePool(NonPagedPool,
221  NewLdtSize);
222 
223  if(!NewLdtBase)
224  {
225  KeReleaseSpinLock(&LdtLock, oldIrql);
227  }
228 
229  if(LdtBase)
230  {
231  memcpy((PVOID) NewLdtBase, (PVOID) LdtBase, LdtLimit+1);
232  }
233 
234  LdtDescriptor[0] = (USHORT)((--NewLdtSize) & 0xffff);
235  LdtDescriptor[1] = (USHORT)(NewLdtBase & 0xffff);
236  LdtDescriptor[2] = (USHORT)(((NewLdtBase & 0xff0000) >> 16) | 0x8200);
237  LdtDescriptor[3] = (USHORT)(((NewLdtSize & 0xf0000) >> 16) |
238  ((NewLdtBase & 0xff000000) >> 16));
239 
241  ((PULONG) LdtDescriptor)[0],
242  ((PULONG) LdtDescriptor)[1]);
243 
244  Ke386SetLocalDescriptorTable(KGDT_LDT);
245 
246  if(LdtBase)
247  {
248  ExFreePool((PVOID) LdtBase);
249  }
250 
251  LdtBase = NewLdtBase;
252  }
253 
254  if(Selector1)
255  {
256  memcpy((char*)LdtBase + Selector1,
257  &LdtEntry1,
258  sizeof(LDT_ENTRY));
259  }
260 
261  if(Selector2)
262  {
263  memcpy((char*)LdtBase + Selector2,
264  &LdtEntry2,
265  sizeof(LDT_ENTRY));
266  }
267 
268  KeReleaseSpinLock(&LdtLock, oldIrql);
269  return STATUS_SUCCESS;
270 }
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
#define LDT_ENTRY
Definition: ketypes.h:282
UCHAR KIRQL
Definition: env_spec_w32.h:591
#define KGDT_LDT
Definition: ketypes.h:81
VOID KeSetGdtSelector(ULONG Entry, ULONG Value1, ULONG Value2)
Definition: ldt.c:107
#define PsGetCurrentProcess
Definition: psfuncs.h:17
BOOLEAN PspIsDescriptorValid(PLDT_ENTRY ldt_entry)
Definition: ldt.c:132
#define KeAcquireSpinLock(sl, irql)
Definition: env_spec_w32.h:609
static KSPIN_LOCK LdtLock
Definition: ldt.c:19
#define ExAllocatePool(type, size)
Definition: fbtusb.h:44
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
Definition: compat.h:428
unsigned short USHORT
Definition: pedump.c:61
unsigned int * PULONG
Definition: retypes.h:1
#define KeReleaseSpinLock(sl, irql)
Definition: env_spec_w32.h:627
#define STATUS_INVALID_LDT_DESCRIPTOR
Definition: ntstatus.h:504
unsigned int ULONG
Definition: retypes.h:1
return STATUS_SUCCESS
Definition: btrfs.c:2777
unsigned short * PUSHORT
Definition: retypes.h:2
#define ExFreePool(addr)
Definition: env_spec_w32.h:352

◆ PspIsDescriptorValid()

BOOLEAN PspIsDescriptorValid ( PLDT_ENTRY  ldt_entry)

Definition at line 132 of file ldt.c.

133 {
134  ULONG Base, SegLimit;
135  /*
136  Allow invalid descriptors.
137  */
138  if(!ldt_entry->HighWord.Bits.Type &&
139  !ldt_entry->HighWord.Bits.Dpl)
140  return TRUE;
141 
142  /* eliminate system descriptors and code segments other than
143  execute and execute/read and DPL<3 descriptors */
144  if(!(ldt_entry->HighWord.Bits.Type & 0x10) ||
145  (ldt_entry->HighWord.Bits.Type & 0x8 &&
146  ldt_entry->HighWord.Bits.Type & 0x4) ||
147  ldt_entry->HighWord.Bits.Dpl != 3 ||
148  ldt_entry->HighWord.Bits.Reserved_0) return FALSE;
149 
150  if(!ldt_entry->HighWord.Bits.Pres) return TRUE;
151 
152  Base=ldt_entry->BaseLow | (ldt_entry->HighWord.Bytes.BaseMid << 16) |
153  (ldt_entry->HighWord.Bytes.BaseHi << 24);
154 
155  SegLimit=ldt_entry->LimitLow |
156  (ldt_entry->HighWord.Bits.LimitHi << 16);
157 
158  if(ldt_entry->HighWord.Bits.Type & 0x4)
159  {
160  SegLimit=(ldt_entry->HighWord.Bits.Default_Big) ? -1 : (USHORT)-1;
161 
162  } else if(ldt_entry->HighWord.Bits.Granularity)
163  {
164  SegLimit=(SegLimit << 12) | 0xfff;
165  }
166 
167  if ((Base + SegLimit > (ULONG_PTR) MmHighestUserAddress) ||
168  (Base > Base+SegLimit))
169  {
170  DPRINT1("WARNING: Windows would mark this descriptor invalid!\n");
171  }
172 
173  /*
174  Certain "DOS32" programs expect to be able to create DPMI selectors
175  that wrap the address space. Windows NT does not allow user-created
176  selectors to reach into kernel memory. However, there is no security
177  risk in allowing it; the page table will prevent access anyway.
178  */
179  return (/*(Base + SegLimit > (ULONG_PTR) MmHighestUserAddress) ||
180  (Base > Base+SegLimit) ? FALSE : TRUE*/ TRUE);
181 }
WORD LimitLow
Definition: compat.h:429
#define TRUE
Definition: types.h:120
_In_opt_ ULONG Base
Definition: rtlfuncs.h:2343
WORD BaseLow
Definition: compat.h:430
uint32_t ULONG_PTR
Definition: typedefs.h:63
struct _LDT_ENTRY::@340::@341 Bytes
unsigned short USHORT
Definition: pedump.c:61
PVOID MmHighestUserAddress
Definition: rtlcompat.c:29
#define DPRINT1
Definition: precomp.h:8
union _LDT_ENTRY::@340 HighWord
unsigned int ULONG
Definition: retypes.h:1
struct _LDT_ENTRY::@340::@342 Bits

Referenced by NtSetLdtEntries().

Variable Documentation

◆ GdtLock

KSPIN_LOCK GdtLock
static

Definition at line 20 of file ldt.c.

Referenced by KeSetBaseGdtSelector(), and KeSetGdtSelector().

◆ LdtLock

KSPIN_LOCK LdtLock
static

Definition at line 19 of file ldt.c.

Referenced by NtSetLdtEntries().