[NTOSKRNL] Rewrite IoCheckEaBufferValidity() so that it's less magic
[reactos.git] / ntoskrnl / io / iomgr / util.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/iomgr/util.c
5 * PURPOSE: I/O Utility Functions
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Aleksey Bragin (aleksey@reactos.org)
8 * Daniel Zimmerman (netzimme@aim.com)
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <debug.h>
16
17 VOID
18 NTAPI
19 RtlpGetStackLimits(PULONG_PTR StackBase,
20 PULONG_PTR StackLimit);
21
22 /* PRIVATE FUNCTIONS *********************************************************/
23
24 NTSTATUS
25 NTAPI
26 IoComputeDesiredAccessFileObject(IN PFILE_OBJECT FileObject,
27 IN PACCESS_MASK DesiredAccess)
28 {
29 /* Assume failure */
30 *DesiredAccess = 0;
31
32 /* First check we really have a FileObject */
33 if (OBJECT_TO_OBJECT_HEADER(FileObject)->Type != IoFileObjectType)
34 {
35 return STATUS_OBJECT_TYPE_MISMATCH;
36 }
37
38 /* Then compute desired access:
39 * Check if the handle has either FILE_WRITE_DATA or FILE_APPEND_DATA was
40 * granted. However, if this is a named pipe, make sure we don't ask for
41 * FILE_APPEND_DATA as it interferes with the FILE_CREATE_PIPE_INSTANCE
42 * access right!
43 */
44 *DesiredAccess = ((!(FileObject->Flags & FO_NAMED_PIPE) ? FILE_APPEND_DATA : 0) | FILE_WRITE_DATA);
45
46 return STATUS_SUCCESS;
47 }
48
49 /* FUNCTIONS *****************************************************************/
50
51 /*
52 * @implemented
53 */
54 VOID
55 NTAPI
56 IoAcquireCancelSpinLock(OUT PKIRQL Irql)
57 {
58 /* Just acquire the internal lock */
59 *Irql = KeAcquireQueuedSpinLock(LockQueueIoCancelLock);
60 }
61
62 /*
63 * @implemented
64 */
65 PVOID
66 NTAPI
67 IoGetInitialStack(VOID)
68 {
69 /* Return the initial stack from the TCB */
70 return PsGetCurrentThread()->Tcb.InitialStack;
71 }
72
73 /*
74 * @implemented
75 */
76 VOID
77 NTAPI
78 IoGetStackLimits(OUT PULONG_PTR LowLimit,
79 OUT PULONG_PTR HighLimit)
80 {
81 PKPRCB Prcb = KeGetCurrentPrcb();
82 ULONG_PTR DpcStack = (ULONG_PTR)(Prcb->DpcStack);
83 volatile ULONG_PTR StackAddress;
84
85 /* Save our stack address so we always know it's valid */
86 StackAddress = (ULONG_PTR)(&StackAddress);
87
88 /* Get stack values */
89 RtlpGetStackLimits(LowLimit, HighLimit);
90
91 /* Check if we're outside the stack */
92 if ((StackAddress < *LowLimit) || (StackAddress > *HighLimit))
93 {
94 /* Check if we may be in a DPC */
95 if (KeGetCurrentIrql() >= DISPATCH_LEVEL)
96 {
97 /* Check if we really are in a DPC */
98 if ((Prcb->DpcRoutineActive) &&
99 (StackAddress <= DpcStack) &&
100 (StackAddress >= DpcStack - KERNEL_STACK_SIZE))
101 {
102 /* Use the DPC stack limits */
103 *HighLimit = DpcStack;
104 *LowLimit = DpcStack - KERNEL_STACK_SIZE;
105 }
106 }
107 }
108 }
109
110 /*
111 * @implemented
112 */
113 BOOLEAN
114 NTAPI
115 IoIsSystemThread(IN PETHREAD Thread)
116 {
117 /* Call the Ps Function */
118 return PsIsSystemThread(Thread);
119 }
120
121 /*
122 * @implemented
123 */
124 BOOLEAN
125 NTAPI
126 IoIsWdmVersionAvailable(IN UCHAR MajorVersion,
127 IN UCHAR MinorVersion)
128 {
129 /* Return support for WDM 1.30 (Windows Server 2003) */
130 if (MajorVersion <= 1 && MinorVersion <= 0x30) return TRUE;
131 return FALSE;
132 }
133
134 /*
135 * @implemented
136 */
137 PEPROCESS
138 NTAPI
139 IoGetCurrentProcess(VOID)
140 {
141 /* Return the current thread's process */
142 return (PEPROCESS)PsGetCurrentThread()->Tcb.ApcState.Process;
143 }
144
145 /*
146 * @implemented
147 */
148 VOID
149 NTAPI
150 IoReleaseCancelSpinLock(IN KIRQL Irql)
151 {
152 /* Release the internal lock */
153 KeReleaseQueuedSpinLock(LockQueueIoCancelLock, Irql);
154 }
155
156 /*
157 * @implemented
158 */
159 PEPROCESS
160 NTAPI
161 IoThreadToProcess(IN PETHREAD Thread)
162 {
163 /* Return the thread's process */
164 return Thread->ThreadsProcess;
165 }
166
167 /*
168 * @implemented
169 */
170 NTSTATUS
171 NTAPI
172 IoCheckDesiredAccess(IN OUT PACCESS_MASK DesiredAccess,
173 IN ACCESS_MASK GrantedAccess)
174 {
175 PAGED_CODE();
176
177 /* Map the generic mask */
178 RtlMapGenericMask(DesiredAccess,
179 &IoFileObjectType->TypeInfo.GenericMapping);
180
181 /* Fail if the access masks don't grant full access */
182 if ((~(*DesiredAccess) & GrantedAccess)) return STATUS_ACCESS_DENIED;
183 return STATUS_SUCCESS;
184 }
185
186 /*
187 * @implemented
188 */
189 NTSTATUS
190 NTAPI
191 IoCheckEaBufferValidity(IN PFILE_FULL_EA_INFORMATION EaBuffer,
192 IN ULONG EaLength,
193 OUT PULONG ErrorOffset)
194 {
195 ULONG NextEntryOffset;
196 UCHAR EaNameLength;
197 ULONG ComputedLength;
198 PFILE_FULL_EA_INFORMATION Current;
199
200 PAGED_CODE();
201
202 /* We will browse all the entries */
203 for (Current = EaBuffer; ; Current = (PFILE_FULL_EA_INFORMATION)((ULONG_PTR)Current + NextEntryOffset))
204 {
205 /* Check that we have enough bits left for the current entry */
206 if (EaLength < FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName))
207 {
208 goto FailPath;
209 }
210
211 EaNameLength = Current->EaNameLength;
212 ComputedLength = Current->EaValueLength + EaNameLength + FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName) + 1;
213 /* Check that we have enough bits left for storing the name and its value */
214 if (EaLength < ComputedLength)
215 {
216 goto FailPath;
217 }
218
219 /* Make sure the name is null terminated */
220 if (Current->EaName[EaNameLength] != ANSI_NULL)
221 {
222 goto FailPath;
223 }
224
225 /* Get the next entry offset */
226 NextEntryOffset = Current->NextEntryOffset;
227 /* If it's 0, it's a termination case */
228 if (NextEntryOffset == 0)
229 {
230 /* If we don't overflow! */
231 if (EaLength - ComputedLength < 0)
232 {
233 goto FailPath;
234 }
235
236 break;
237 }
238
239 /* Compare the next offset we computed with the provided one, they must match */
240 if (ALIGN_UP_BY(ComputedLength, sizeof(ULONG)) != NextEntryOffset)
241 {
242 goto FailPath;
243 }
244
245 /* Check next entry offset value is positive */
246 if (NextEntryOffset < 0)
247 {
248 goto FailPath;
249 }
250
251 /* Compute the remaining bits */
252 EaLength -= NextEntryOffset;
253 /* We must have bits left */
254 if (EaLength < 0)
255 {
256 goto FailPath;
257 }
258
259 /* Move to the next entry */
260 }
261
262 /* If we end here, everything went OK */
263 return STATUS_SUCCESS;
264
265 FailPath:
266 /* If we end here, we failed, set failed offset */
267 *ErrorOffset = (ULONG_PTR)Current - (ULONG_PTR)EaBuffer;
268 return STATUS_EA_LIST_INCONSISTENT;
269 }
270
271 /*
272 * @unimplemented
273 */
274 NTSTATUS
275 NTAPI
276 IoCheckFunctionAccess(IN ACCESS_MASK GrantedAccess,
277 IN UCHAR MajorFunction,
278 IN UCHAR MinorFunction,
279 IN ULONG IoControlCode,
280 IN PVOID ExtraData OPTIONAL,
281 IN PVOID ExtraData2 OPTIONAL)
282 {
283 UNIMPLEMENTED;
284 return STATUS_NOT_IMPLEMENTED;
285 }
286
287 /*
288 * @unimplemented
289 */
290 NTSTATUS
291 NTAPI
292 IoValidateDeviceIoControlAccess(IN PIRP Irp,
293 IN ULONG RequiredAccess)
294 {
295 UNIMPLEMENTED;
296 return STATUS_NOT_IMPLEMENTED;
297 }
298
299 /*
300 * @implemented
301 */
302 VOID
303 NTAPI
304 IoSetDeviceToVerify(IN PETHREAD Thread,
305 IN PDEVICE_OBJECT DeviceObject)
306 {
307 /* Set the pointer in the thread */
308 Thread->DeviceToVerify = DeviceObject;
309 }
310
311 /*
312 * @implemented
313 */
314 VOID
315 NTAPI
316 IoSetHardErrorOrVerifyDevice(IN PIRP Irp,
317 IN PDEVICE_OBJECT DeviceObject)
318 {
319 /* Set the pointer in the IRP */
320 Irp->Tail.Overlay.Thread->DeviceToVerify = DeviceObject;
321 }
322
323 /*
324 * @implemented
325 */
326 PDEVICE_OBJECT
327 NTAPI
328 IoGetDeviceToVerify(IN PETHREAD Thread)
329 {
330 /* Return the pointer that was set with IoSetDeviceToVerify */
331 return Thread->DeviceToVerify;
332 }
333
334 /*
335 * @unimplemented
336 */
337 NTSTATUS
338 NTAPI
339 IoCheckQuerySetVolumeInformation(IN FS_INFORMATION_CLASS FsInformationClass,
340 IN ULONG Length,
341 IN BOOLEAN SetOperation)
342 {
343 UNIMPLEMENTED;
344 return STATUS_NOT_IMPLEMENTED;
345 }