ReactOS 0.4.16-dev-112-g52265ae
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 management
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
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
73VOID
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
106VOID
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
unsigned char BOOLEAN
LONG NTSTATUS
Definition: precomp.h:26
#define DPRINT1
Definition: precomp.h:8
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
UCHAR KIRQL
Definition: env_spec_w32.h:591
ULONG KSPIN_LOCK
Definition: env_spec_w32.h:72
#define KeReleaseSpinLock(sl, irql)
Definition: env_spec_w32.h:627
#define KeAcquireSpinLock(sl, irql)
Definition: env_spec_w32.h:609
#define ExFreePool(addr)
Definition: env_spec_w32.h:352
#define NonPagedPool
Definition: env_spec_w32.h:307
#define ExAllocatePool(type, size)
Definition: fbtusb.h:44
_In_opt_ PFILE_OBJECT _In_opt_ PETHREAD Thread
Definition: fltkernel.h:2653
static KSPIN_LOCK LdtLock
Definition: ldt.c:19
static KSPIN_LOCK GdtLock
Definition: ldt.c:20
VOID KeSetGdtSelector(ULONG Entry, ULONG Value1, ULONG Value2)
Definition: ldt.c:107
BOOLEAN PspIsDescriptorValid(PLDT_ENTRY ldt_entry)
Definition: ldt.c:132
NTSTATUS NTAPI NtSetLdtEntries(ULONG Selector1, LDT_ENTRY LdtEntry1, ULONG Selector2, LDT_ENTRY LdtEntry2)
Definition: ldt.c:184
NTSTATUS NTAPI Ke386GetGdtEntryThread(IN PKTHREAD Thread, IN ULONG Offset, IN PKGDTENTRY Descriptor)
Definition: ldt.c:26
VOID KeSetBaseGdtSelector(ULONG Entry, PVOID Base)
Definition: ldt.c:74
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
#define LDT_ENTRY
Definition: ketypes.h:289
#define KGDT_R3_TEB
Definition: ketypes.h:129
#define KeGetPcr()
Definition: ketypes.h:81
#define KGDT_NUMBER
Definition: ketypes.h:138
#define KGDT_LDT
Definition: ketypes.h:131
_In_opt_ ULONG Base
Definition: rtlfuncs.h:2451
_In_ ULONG _In_ ULONG Offset
Definition: ntddpcm.h:101
#define STATUS_INVALID_LDT_DESCRIPTOR
Definition: ntstatus.h:518
#define STATUS_ACCESS_VIOLATION
Definition: ntstatus.h:242
unsigned short USHORT
Definition: pedump.c:61
PVOID MmHighestUserAddress
Definition: rtlcompat.c:29
#define STATUS_SUCCESS
Definition: shellext.h:65
#define DPRINT
Definition: sndvol32.h:73
base of all file and directory entries
Definition: entries.h:83
Definition: compat.h:777
union _LDT_ENTRY::@356 HighWord
WORD LimitLow
Definition: compat.h:778
struct _LDT_ENTRY::@356::@358 Bits
WORD BaseLow
Definition: compat.h:779
struct _LDT_ENTRY::@356::@357 Bytes
uint32_t * PULONG
Definition: typedefs.h:59
#define NTAPI
Definition: typedefs.h:36
uint16_t * PUSHORT
Definition: typedefs.h:56
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define IN
Definition: typedefs.h:39
uint32_t ULONG
Definition: typedefs.h:59
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
_Must_inspect_result_ _In_ WDFIORESLIST _In_ PIO_RESOURCE_DESCRIPTOR Descriptor
Definition: wdfresource.h:342
#define PsGetCurrentProcess
Definition: psfuncs.h:17
unsigned char UCHAR
Definition: xmlstorage.h:181