1 /*
2  * PROJECT:         ReactOS API tests
3  * LICENSE:         LGPLv2.1+ - See COPYING.LIB in the top level directory
4  * PURPOSE:         Test for RtlFirstFreeAce
5  * PROGRAMMERS:     Thomas Faber <thomas.faber@reactos.org>
6  */
7 
8 #include "precomp.h"
9 
10 static
11 PVOID
12 AllocateGuarded(
13     _In_ SIZE_T SizeRequested)
14 {
15     NTSTATUS Status;
16     SIZE_T Size = PAGE_ROUND_UP(SizeRequested + PAGE_SIZE);
17     PVOID VirtualMemory = NULL;
18     PCHAR StartOfBuffer;
19 
20     Status = NtAllocateVirtualMemory(NtCurrentProcess(), &VirtualMemory, 0, &Size, MEM_RESERVE, PAGE_NOACCESS);
21 
22     if (!NT_SUCCESS(Status))
23         return NULL;
24 
25     Size -= PAGE_SIZE;
26     if (Size)
27     {
28         Status = NtAllocateVirtualMemory(NtCurrentProcess(), &VirtualMemory, 0, &Size, MEM_COMMIT, PAGE_READWRITE);
29         if (!NT_SUCCESS(Status))
30         {
31             Size = 0;
32             Status = NtFreeVirtualMemory(NtCurrentProcess(), &VirtualMemory, &Size, MEM_RELEASE);
33             ok(Status == STATUS_SUCCESS, "Status = %lx\n", Status);
34             return NULL;
35         }
36     }
37 
38     StartOfBuffer = VirtualMemory;
39     StartOfBuffer += Size - SizeRequested;
40 
41     return StartOfBuffer;
42 }
43 
44 static
45 VOID
46 FreeGuarded(
47     _In_ PVOID Pointer)
48 {
49     NTSTATUS Status;
50     PVOID VirtualMemory = (PVOID)PAGE_ROUND_DOWN((SIZE_T)Pointer);
51     SIZE_T Size = 0;
52 
53     Status = NtFreeVirtualMemory(NtCurrentProcess(), &VirtualMemory, &Size, MEM_RELEASE);
54     ok(Status == STATUS_SUCCESS, "Status = %lx\n", Status);
55 }
56 
57 static
58 PACL
59 MakeAcl(
60     _In_ ULONG AceCount,
61     ...)
62 {
63     PACL Acl;
64     PACE_HEADER AceHeader;
65     ULONG AclSize;
66     ULONG AceSizes[10];
67     ULONG i;
68     va_list Args;
69 
70     ASSERT(AceCount <= RTL_NUMBER_OF(AceSizes));
71     AclSize = sizeof(ACL);
72     va_start(Args, AceCount);
73     for (i = 0; i < AceCount; i++)
74     {
75         AceSizes[i] = va_arg(Args, int);
76         AclSize += AceSizes[i];
77     }
78     va_end(Args);
79 
80     Acl = AllocateGuarded(AclSize);
81     if (!Acl)
82     {
83         skip("Failed to allocate %lu bytes\n", AclSize);
84         return NULL;
85     }
86 
87     Acl->AclRevision = ACL_REVISION;
88     Acl->Sbz1 = 0;
89     Acl->AclSize = AclSize;
90     Acl->AceCount = AceCount;
91     Acl->Sbz2 = 0;
92 
93     AceHeader = (PACE_HEADER)(Acl + 1);
94     for (i = 0; i < AceCount; i++)
95     {
96         AceHeader->AceType = 0;
97         AceHeader->AceFlags = 0;
98         AceHeader->AceSize = AceSizes[i];
99         AceHeader = (PACE_HEADER)((PCHAR)AceHeader + AceHeader->AceSize);
100     }
101 
102     return Acl;
103 }
104 
105 START_TEST(RtlFirstFreeAce)
106 {
107     PACL Acl;
108     PACE FirstAce;
109     BOOLEAN Found;
110 
111     Acl = MakeAcl(0);
112     if (Acl)
113     {
114         /* Simple empty ACL */
115         FirstAce = InvalidPointer;
116         Found = RtlFirstFreeAce(Acl, &FirstAce);
117         ok(Found == TRUE, "Found = %u\n", Found);
118         ok(FirstAce == (PACE)(Acl + 1), "FirstAce = %p (Acl was %p)\n", FirstAce, Acl);
119 
120         /* Not enough space */
121         Acl->AclSize = sizeof(ACL) - 1;
122         FirstAce = InvalidPointer;
123         Found = RtlFirstFreeAce(Acl, &FirstAce);
124         ok(Found == TRUE, "Found = %u\n", Found);
125         ok(FirstAce == NULL, "FirstAce = %p (Acl was %p)\n", FirstAce, Acl);
126 
127         /* Invalid values for all the other fields */
128         Acl->AclRevision = 76;
129         Acl->Sbz1 = 0x55;
130         Acl->AclSize = sizeof(ACL);
131         Acl->Sbz2 = 0x55;
132         FirstAce = InvalidPointer;
133         Found = RtlFirstFreeAce(Acl, &FirstAce);
134         ok(Found == TRUE, "Found = %u\n", Found);
135         ok(FirstAce == (PACE)(Acl + 1), "FirstAce = %p (Acl was %p)\n", FirstAce, Acl);
136 
137         FreeGuarded(Acl);
138     }
139 
140     Acl = MakeAcl(1, (int)sizeof(ACE_HEADER));
141     if (Acl)
142     {
143         /* ACL with one ACE */
144         FirstAce = InvalidPointer;
145         Found = RtlFirstFreeAce(Acl, &FirstAce);
146         ok(Found == TRUE, "Found = %u\n", Found);
147         ok(FirstAce == (PACE)((PACE_HEADER)(Acl + 1) + 1), "FirstAce = %p (Acl was %p)\n", FirstAce, Acl);
148 
149         /* The one ACE doesn't actually fit */
150         Acl->AclSize = sizeof(ACL);
151         FirstAce = InvalidPointer;
152         Found = RtlFirstFreeAce(Acl, &FirstAce);
153         ok(Found == FALSE, "Found = %u\n", Found);
154         ok(FirstAce == NULL, "FirstAce = %p (Acl was %p)\n", FirstAce, Acl);
155 
156         /* Only the first byte fits */
157         Acl->AclSize = sizeof(ACL) + 1;
158         FirstAce = InvalidPointer;
159         Found = RtlFirstFreeAce(Acl, &FirstAce);
160         ok(Found == TRUE, "Found = %u\n", Found);
161         ok(FirstAce == NULL, "FirstAce = %p (Acl was %p)\n", FirstAce, Acl);
162 
163         /* Until we cover the whole size we get NULL */
164         Acl->AclSize = sizeof(ACL) + sizeof(ACE_HEADER) - 1;
165         FirstAce = InvalidPointer;
166         Found = RtlFirstFreeAce(Acl, &FirstAce);
167         ok(Found == TRUE, "Found = %u\n", Found);
168         ok(FirstAce == NULL, "FirstAce = %p (Acl was %p)\n", FirstAce, Acl);
169 
170         FreeGuarded(Acl);
171     }
172 
173     /* Same but bigger */
174     Acl = MakeAcl(1, (int)sizeof(ACE_HEADER) + 4);
175     if (Acl)
176     {
177         /* ACL with one ACE */
178         FirstAce = InvalidPointer;
179         Found = RtlFirstFreeAce(Acl, &FirstAce);
180         ok(Found == TRUE, "Found = %u\n", Found);
181         ok(FirstAce == (PACE)((PCHAR)(Acl + 1) + sizeof(ACE_HEADER) + 4), "FirstAce = %p (Acl was %p)\n", FirstAce, Acl);
182 
183         /* The one ACE doesn't actually fit */
184         Acl->AclSize = sizeof(ACL);
185         FirstAce = InvalidPointer;
186         Found = RtlFirstFreeAce(Acl, &FirstAce);
187         ok(Found == FALSE, "Found = %u\n", Found);
188         ok(FirstAce == NULL, "FirstAce = %p (Acl was %p)\n", FirstAce, Acl);
189 
190         /* Only the first byte fits */
191         Acl->AclSize = sizeof(ACL) + 1;
192         FirstAce = InvalidPointer;
193         Found = RtlFirstFreeAce(Acl, &FirstAce);
194         ok(Found == TRUE, "Found = %u\n", Found);
195         ok(FirstAce == NULL, "FirstAce = %p (Acl was %p)\n", FirstAce, Acl);
196 
197         /* Until we cover the whole size we get NULL */
198         Acl->AclSize = sizeof(ACL) + sizeof(ACE_HEADER) - 3;
199         FirstAce = InvalidPointer;
200         Found = RtlFirstFreeAce(Acl, &FirstAce);
201         ok(Found == TRUE, "Found = %u\n", Found);
202         ok(FirstAce == NULL, "FirstAce = %p (Acl was %p)\n", FirstAce, Acl);
203 
204         FreeGuarded(Acl);
205     }
206 
207     Acl = MakeAcl(4, (int)sizeof(ACE_HEADER), (int)sizeof(ACE_HEADER), (int)sizeof(ACCESS_ALLOWED_ACE), (int)sizeof(ACCESS_ALLOWED_ACE));
208     if (Acl)
209     {
210         /* ACL with one ACE */
211         FirstAce = InvalidPointer;
212         Found = RtlFirstFreeAce(Acl, &FirstAce);
213         ok(Found == TRUE, "Found = %u\n", Found);
214         ok(FirstAce == (PACE)((PCHAR)(Acl + 1) + 2 * sizeof(ACE_HEADER) + 2 * sizeof(ACCESS_ALLOWED_ACE)), "FirstAce = %p (Acl was %p)\n", FirstAce, Acl);
215 
216         /* One less gives us NULL */
217         Acl->AclSize = sizeof(ACL) + 2 * sizeof(ACE_HEADER) + 2 * sizeof(ACCESS_ALLOWED_ACE) - 1;
218         FirstAce = InvalidPointer;
219         Found = RtlFirstFreeAce(Acl, &FirstAce);
220         ok(Found == TRUE, "Found = %u\n", Found);
221         ok(FirstAce == NULL, "FirstAce = %p (Acl was %p)\n", FirstAce, Acl);
222 
223         /* One ACE less also gives us FALSE */
224         Acl->AclSize = sizeof(ACL) + 2 * sizeof(ACE_HEADER) + sizeof(ACCESS_ALLOWED_ACE);
225         FirstAce = InvalidPointer;
226         Found = RtlFirstFreeAce(Acl, &FirstAce);
227         ok(Found == FALSE, "Found = %u\n", Found);
228         ok(FirstAce == NULL, "FirstAce = %p (Acl was %p)\n", FirstAce, Acl);
229 
230         FreeGuarded(Acl);
231     }
232 }
233