1 /*
2 * PROJECT: ReactOS API Tests
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Tests for UEFI Firmware functions
5 * COPYRIGHT: Copyright 2023 Ratin Gao <ratin@knsoft.org>
6 */
7
8 #include "precomp.h"
9
10 #include <ndk/psfuncs.h>
11 #include <ndk/setypes.h>
12 #include <ndk/sefuncs.h>
13 #include <ndk/obfuncs.h>
14
15 #define _A2W(quote) __A2W(quote)
16 #define __A2W(quote) L##quote
17
18 #define EFI_TEST_GUID_STRING "{8768B7AC-F82F-4120-B093-30DFA27DA3B5}"
19 #define EFI_TEST_VARIABLE_NAME "RosUefiVarTest"
20
21 #define EFI_DUMMY_NAMESPACE_GUID_STRING "{00000000-0000-0000-0000-000000000000}"
22 #define EFI_DUMMY_VARIABLE_NAME ""
23
24 typedef enum _FIRMWARE_TYPE
25 {
26 FirmwareTypeUnknown,
27 FirmwareTypeBios,
28 FirmwareTypeUefi,
29 FirmwareTypeMax
30 } FIRMWARE_TYPE, *PFIRMWARE_TYPE;
31
32 typedef
33 _Success_(return)
34 BOOL
35 WINAPI
36 FN_GetFirmwareType(_Out_ PFIRMWARE_TYPE FirmwareType);
37
38 static ULONG RandomSeed;
39 static DWORD EfiVariableValue;
40
test_GetFirmwareType(BOOL bIsUEFI)41 static VOID test_GetFirmwareType(BOOL bIsUEFI)
42 {
43 BOOL bResult;
44 HMODULE hKernel32;
45 FN_GetFirmwareType* pfnGetFirmwareType;
46 FIRMWARE_TYPE FirmwareType = FirmwareTypeUnknown, FirmwareExpect;
47
48 /* Load functions */
49 hKernel32 = GetModuleHandleW(L"kernel32.dll");
50 if (hKernel32 == NULL)
51 {
52 skip("Module kernel32 not found\n");
53 return;
54 }
55 pfnGetFirmwareType = (FN_GetFirmwareType*)GetProcAddress(hKernel32, "GetFirmwareType");
56 if (pfnGetFirmwareType == NULL)
57 {
58 skip("GetFirmwareType (NT6.2+ API) not found\n");
59 return;
60 }
61
62 /* Test GetFirmwareType, should return FirmwareTypeBios or FirmwareTypeUefi */
63 bResult = pfnGetFirmwareType(&FirmwareType);
64 ok(bResult,
65 "GetFirmwareType failed with error: 0x%08lX\n",
66 GetLastError());
67
68 if (!bResult)
69 return;
70
71 FirmwareExpect = (bIsUEFI ? FirmwareTypeUefi : FirmwareTypeBios);
72 ok(FirmwareType == FirmwareExpect,
73 "FirmwareType is %d, but %d is expected.\n",
74 FirmwareType, FirmwareExpect);
75 }
76
START_TEST(UEFIFirmware)77 START_TEST(UEFIFirmware)
78 {
79 BOOL bResult, bResultTemp, bIsUEFI;
80 DWORD dwError, dwErrorTemp, dwLength, dwLengthTemp, dwValue;
81 HANDLE hToken;
82 TOKEN_PRIVILEGES Privilege;
83 NTSTATUS Status;
84 ULONG ReturnLength;
85
86 /*
87 * Check whether this test runs on legacy BIOS-based or UEFI system
88 * by calling GetFirmwareEnvironmentVariable with dummy name and GUID.
89 * It should fail with ERROR_INVALID_FUNCTION on the former and
90 * fail with another error on the latter.
91 */
92 dwLength = GetFirmwareEnvironmentVariableW(_A2W(EFI_DUMMY_VARIABLE_NAME),
93 _A2W(EFI_DUMMY_NAMESPACE_GUID_STRING),
94 NULL,
95 0);
96 dwError = GetLastError();
97 ok(dwLength == 0, "dwLength = %lu, expected 0\n", dwLength);
98
99 bIsUEFI = (dwLength == 0 && dwError != ERROR_INVALID_FUNCTION);
100 test_GetFirmwareType(bIsUEFI);
101 if (!bIsUEFI)
102 {
103 skip("Skipping tests that require UEFI environment.\n");
104 return;
105 }
106
107 /* Test ANSI function too */
108 dwLengthTemp = GetFirmwareEnvironmentVariableA(EFI_DUMMY_VARIABLE_NAME,
109 EFI_DUMMY_NAMESPACE_GUID_STRING,
110 NULL,
111 0);
112 dwErrorTemp = GetLastError();
113 ok(dwLengthTemp == dwLength && dwErrorTemp == dwError,
114 "dwLength = %lu, LastError = %lu, expected bResult = %lu, LastError = %lu\n",
115 dwLengthTemp,
116 dwErrorTemp,
117 dwLength,
118 dwError);
119
120 /* Generate a random variable value to be used in this test */
121 RandomSeed = GetTickCount();
122 EfiVariableValue = RtlRandom(&RandomSeed);
123
124 /* Try to set firmware variable, should fail with ERROR_PRIVILEGE_NOT_HELD,
125 * because no SE_SYSTEM_ENVIRONMENT_NAME privilege enabled by default. */
126 bResult = SetFirmwareEnvironmentVariableW(_A2W(EFI_TEST_VARIABLE_NAME),
127 _A2W(EFI_TEST_GUID_STRING),
128 &EfiVariableValue,
129 sizeof(EfiVariableValue));
130 dwError = GetLastError();
131 ok(!bResult && dwError == ERROR_PRIVILEGE_NOT_HELD,
132 "bResult = %d, LastError = %lu, expected bResult = 0, LastError = ERROR_PRIVILEGE_NOT_HELD\n",
133 bResult,
134 dwError);
135
136 /* Test ANSI function too */
137 bResultTemp = SetFirmwareEnvironmentVariableA(EFI_TEST_VARIABLE_NAME,
138 EFI_TEST_GUID_STRING,
139 &EfiVariableValue,
140 sizeof(EfiVariableValue));
141 dwErrorTemp = GetLastError();
142 ok(bResultTemp == bResult && dwErrorTemp == dwError,
143 "bResult = %d, LastError = %lu, expected bResult = %d, LastError = %lu\n",
144 bResultTemp,
145 dwErrorTemp,
146 bResult,
147 dwError);
148
149 /* Enable SE_SYSTEM_ENVIRONMENT_NAME privilege required by the following tests */
150 bResult = OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken);
151 if (!bResult)
152 {
153 skip("OpenProcessToken failed with error: 0x%08lX, aborting.\n", GetLastError());
154 return;
155 }
156 Privilege.PrivilegeCount = 1;
157 Privilege.Privileges[0].Luid = RtlConvertUlongToLuid(SE_SYSTEM_ENVIRONMENT_PRIVILEGE);
158 Privilege.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
159 Status = NtAdjustPrivilegesToken(hToken, FALSE, &Privilege, sizeof(Privilege), NULL, &ReturnLength);
160 if (Status != STATUS_SUCCESS)
161 {
162 skip("NtAdjustPrivilegesToken failed with status: 0x%08lX, aborting.\n", Status);
163 NtClose(hToken);
164 return;
165 }
166
167 /* Set our test variable to UEFI firmware */
168 bResult = SetFirmwareEnvironmentVariableW(_A2W(EFI_TEST_VARIABLE_NAME),
169 _A2W(EFI_TEST_GUID_STRING),
170 &EfiVariableValue,
171 sizeof(EfiVariableValue));
172 ok(bResult,
173 "SetFirmwareEnvironmentVariableW failed with error: 0x%08lX\n",
174 GetLastError());
175 if (bResult)
176 {
177 /* Get the variable back and verify */
178 dwLength = GetFirmwareEnvironmentVariableW(_A2W(EFI_TEST_VARIABLE_NAME),
179 _A2W(EFI_TEST_GUID_STRING),
180 &dwValue,
181 sizeof(dwValue));
182 ok(dwLength,
183 "GetFirmwareEnvironmentVariableW failed with error: 0x%08lX\n",
184 GetLastError());
185 if (dwLength)
186 {
187 ok(dwLength == sizeof(EfiVariableValue) && dwValue == EfiVariableValue,
188 "Retrieved variable different from what we set, "
189 "dwLength = %lu, dwValue = %lu, expected dwLength = %u, dwValue = %lu",
190 dwLength,
191 dwValue,
192 sizeof(EfiVariableValue),
193 EfiVariableValue);
194 }
195 }
196
197 /* Change variable value and test ANSI function */
198 EfiVariableValue = RtlRandom(&RandomSeed);
199 bResult = SetFirmwareEnvironmentVariableA(EFI_TEST_VARIABLE_NAME,
200 EFI_TEST_GUID_STRING,
201 &EfiVariableValue,
202 sizeof(EfiVariableValue));
203 ok(bResult,
204 "SetFirmwareEnvironmentVariableA failed with error: 0x%08lX\n",
205 GetLastError());
206 if (bResult)
207 {
208 /* Get the variable back and verify */
209 dwLength = GetFirmwareEnvironmentVariableA(EFI_TEST_VARIABLE_NAME,
210 EFI_TEST_GUID_STRING,
211 &dwValue,
212 sizeof(dwValue));
213 ok(dwLength,
214 "GetFirmwareEnvironmentVariableA failed with error: 0x%08lX\n",
215 GetLastError());
216 if (dwLength)
217 {
218 ok(dwLength == sizeof(EfiVariableValue) && dwValue == EfiVariableValue,
219 "Retrieved variable different from what we set, "
220 "dwLength = %lu, dwValue = %lu, expected dwLength = %u, dwValue = %lu",
221 dwLength,
222 dwValue,
223 sizeof(EfiVariableValue),
224 EfiVariableValue);
225 }
226 }
227
228 /* Delete the variable */
229 bResult = SetFirmwareEnvironmentVariableW(_A2W(EFI_TEST_VARIABLE_NAME),
230 _A2W(EFI_TEST_GUID_STRING),
231 NULL,
232 0);
233 ok(bResult,
234 "SetFirmwareEnvironmentVariableW failed with error: 0x%08lX\n",
235 GetLastError());
236 if (bResult)
237 {
238 dwLength = GetFirmwareEnvironmentVariableW(_A2W(EFI_TEST_VARIABLE_NAME),
239 _A2W(EFI_TEST_GUID_STRING),
240 &dwValue,
241 sizeof(dwValue));
242 ok(dwLength == 0, "SetFirmwareEnvironmentVariableW didn't delete the variable!\n");
243 }
244
245 /* Restore variable and test ANSI function */
246 bResult = SetFirmwareEnvironmentVariableW(_A2W(EFI_TEST_VARIABLE_NAME),
247 _A2W(EFI_TEST_GUID_STRING),
248 &EfiVariableValue,
249 sizeof(EfiVariableValue));
250 if (!bResult)
251 {
252 skip("SetFirmwareEnvironmentVariableW failed to restore variable with error: 0x%08lX\n",
253 GetLastError());
254 goto _exit;
255 }
256 bResult = SetFirmwareEnvironmentVariableA(EFI_TEST_VARIABLE_NAME,
257 EFI_TEST_GUID_STRING,
258 NULL,
259 0);
260 ok(bResult,
261 "SetFirmwareEnvironmentVariableA failed with error: 0x%08lX\n",
262 GetLastError());
263 if (bResult)
264 {
265 dwLength = GetFirmwareEnvironmentVariableA(EFI_TEST_VARIABLE_NAME,
266 EFI_TEST_GUID_STRING,
267 &dwValue,
268 sizeof(dwValue));
269 ok(dwLength == 0, "SetFirmwareEnvironmentVariableA didn't delete the variable!\n");
270 }
271
272 _exit:
273 /* Restore the privilege */
274 Privilege.Privileges[0].Attributes = 0;
275 Status = NtAdjustPrivilegesToken(hToken, FALSE, &Privilege, sizeof(Privilege), NULL, &ReturnLength);
276 ok(Status == STATUS_SUCCESS, "NtAdjustPrivilegesToken failed with status: 0x%08lX\n", Status);
277 NtClose(hToken);
278 }
279