ReactOS  0.4.14-dev-358-gbef841c
ldt.c
Go to the documentation of this file.
1 /*
2  * COPYRIGHT: See COPYING in the top level directory
3  * PROJECT: ReactOS kernel
4  * FILE: ntoskrnl/ke/i386/ldt.c
5  * PURPOSE: LDT managment
6  *
7  * PROGRAMMERS: David Welch (welch@cwcom.net)
8  * Stefan Ginsberg (stefan.ginsberg@reactos.org)
9  */
10 
11 /* INCLUDES *****************************************************************/
12 
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <debug.h>
16 
17 /* GLOBALS *******************************************************************/
18 
21 
22 /* FUNCTIONS *****************************************************************/
23 
25 NTAPI
27  IN ULONG Offset,
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 }
72 
73 VOID
75  PVOID Base)
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 }
105 
106 VOID
108  ULONG Value1,
109  ULONG Value2)
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 }
131 
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 }
182 
185  LDT_ENTRY LdtEntry1,
186  ULONG Selector2,
187  LDT_ENTRY LdtEntry2)
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 }
271 
272 
WORD LimitLow
Definition: compat.h:437
NTSTATUS NTAPI Ke386GetGdtEntryThread(IN PKTHREAD Thread, IN ULONG Offset, IN PKGDTENTRY Descriptor)
Definition: ldt.c:26
#define IN
Definition: typedefs.h:38
VOID KeSetBaseGdtSelector(ULONG Entry, PVOID Base)
Definition: ldt.c:74
#define TRUE
Definition: types.h:120
NTSYSAPI VOID NTAPI RtlCopyMemory(VOID UNALIGNED *Destination, CONST VOID UNALIGNED *Source, ULONG Length)
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
struct _Entry Entry
Definition: kefuncs.h:640
#define LDT_ENTRY
Definition: ketypes.h:291
LONG NTSTATUS
Definition: precomp.h:26
_In_opt_ ULONG Base
Definition: rtlfuncs.h:2343
WORD BaseLow
Definition: compat.h:438
#define KeGetPcr()
Definition: ke.h:25
struct _LDT_ENTRY::@347::@348 Bytes
uint32_t ULONG_PTR
Definition: typedefs.h:63
UCHAR KIRQL
Definition: env_spec_w32.h:591
#define KGDT_LDT
Definition: ketypes.h:83
NTSTATUS NTAPI NtSetLdtEntries(ULONG Selector1, LDT_ENTRY LdtEntry1, ULONG Selector2, LDT_ENTRY LdtEntry2)
Definition: ldt.c:184
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
_In_ ULONG _In_ ULONG Offset
Definition: ntddpcm.h:101
VOID KeSetGdtSelector(ULONG Entry, ULONG Value1, ULONG Value2)
Definition: ldt.c:107
#define PsGetCurrentProcess
Definition: psfuncs.h:17
unsigned char BOOLEAN
void DPRINT(...)
Definition: polytest.cpp:61
Definition: utils.h:160
BOOLEAN PspIsDescriptorValid(PLDT_ENTRY ldt_entry)
Definition: ldt.c:132
union _LDT_ENTRY::@347 HighWord
#define KeAcquireSpinLock(sl, irql)
Definition: env_spec_w32.h:609
#define KGDT_R3_TEB
Definition: ketypes.h:81
_In_opt_ PFILE_OBJECT _In_opt_ PETHREAD Thread
Definition: fltkernel.h:2653
#define KGDT_NUMBER
Definition: ketypes.h:90
unsigned char UCHAR
Definition: xmlstorage.h:181
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
struct _LDT_ENTRY::@347::@349 Bits
Definition: compat.h:436
#define STATUS_ACCESS_VIOLATION
Definition: ntstatus.h:228
unsigned short USHORT
Definition: pedump.c:61
ULONG KSPIN_LOCK
Definition: env_spec_w32.h:72
unsigned int * PULONG
Definition: retypes.h:1
PVOID MmHighestUserAddress
Definition: rtlcompat.c:29
#define KeReleaseSpinLock(sl, irql)
Definition: env_spec_w32.h:627
#define STATUS_INVALID_LDT_DESCRIPTOR
Definition: ntstatus.h:504
#define DPRINT1
Definition: precomp.h:8
unsigned int ULONG
Definition: retypes.h:1
static KSPIN_LOCK GdtLock
Definition: ldt.c:20
return STATUS_SUCCESS
Definition: btrfs.c:2938
unsigned short * PUSHORT
Definition: retypes.h:2
base of all file and directory entries
Definition: entries.h:82
#define ExFreePool(addr)
Definition: env_spec_w32.h:352
_In_ PSTORAGE_PROPERTY_ID _Outptr_ PSTORAGE_DESCRIPTOR_HEADER * Descriptor
Definition: classpnp.h:966