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 static ULONG RandomSeed;
25 static DWORD EfiVariableValue;
26 
27 static VOID test_GetFirmwareType(BOOL bIsUEFI)
28 {
29 #if (_WIN32_WINNT >= 0x0602)
30     BOOL bResult;
31     FIRMWARE_TYPE FirmwareType = FirmwareTypeUnknown, FirmwareExpect;
32 
33     /* Test GetFirmwareType, should return FirmwareTypeBios or FirmwareTypeUefi */
34     bResult = GetFirmwareType(&FirmwareType);
35 
36     ok(bResult,
37        "GetFirmwareType failed with error: 0x%08lX\n",
38        GetLastError());
39 
40     if (!bResult)
41         return;
42 
43     FirmwareExpect = (bIsUEFI ? FirmwareTypeUefi : FirmwareTypeBios);
44     ok(FirmwareType == FirmwareExpect,
45        "FirmwareType is %d, but %d is expected.\n",
46        FirmwareType, FirmwareExpect);
47 #else
48     skip("This test can be run only when compiled for NT >= 6.2.\n");
49 #endif
50 }
51 
52 START_TEST(UEFIFirmware)
53 {
54     BOOL bResult, bResultTemp, bIsUEFI;
55     DWORD dwError, dwErrorTemp, dwLength, dwLengthTemp, dwValue;
56     HANDLE hToken;
57     TOKEN_PRIVILEGES Privilege;
58     NTSTATUS Status;
59     ULONG ReturnLength;
60 
61     /*
62      * Check whether this test runs on legacy BIOS-based or UEFI system
63      * by calling GetFirmwareEnvironmentVariable with dummy name and GUID.
64      * It should fail with ERROR_INVALID_FUNCTION on the former and
65      * fail with another error on the latter.
66      */
67     dwLength = GetFirmwareEnvironmentVariableW(_A2W(EFI_DUMMY_VARIABLE_NAME),
68                                                _A2W(EFI_DUMMY_NAMESPACE_GUID_STRING),
69                                                NULL,
70                                                0);
71     dwError = GetLastError();
72     ok(dwLength == 0, "dwLength = %lu, expected 0\n", dwLength);
73 
74     bIsUEFI = (dwLength == 0 && dwError != ERROR_INVALID_FUNCTION);
75     test_GetFirmwareType(bIsUEFI);
76     if (!bIsUEFI)
77     {
78         skip("Skipping tests that require UEFI environment.\n");
79         return;
80     }
81 
82     /* Test ANSI function too */
83     dwLengthTemp = GetFirmwareEnvironmentVariableA(EFI_DUMMY_VARIABLE_NAME,
84                                                    EFI_DUMMY_NAMESPACE_GUID_STRING,
85                                                    NULL,
86                                                    0);
87     dwErrorTemp = GetLastError();
88     ok(dwLengthTemp == dwLength && dwErrorTemp == dwError,
89        "dwLength = %lu, LastError = %lu, expected bResult = %lu, LastError = %lu\n",
90        dwLengthTemp,
91        dwErrorTemp,
92        dwLength,
93        dwError);
94 
95     /* Generate a random variable value to be used in this test */
96     RandomSeed = GetTickCount();
97     EfiVariableValue = RtlRandom(&RandomSeed);
98 
99     /* Try to set firmware variable, should fail with ERROR_PRIVILEGE_NOT_HELD,
100      * because no SE_SYSTEM_ENVIRONMENT_NAME privilege enabled by default. */
101     bResult = SetFirmwareEnvironmentVariableW(_A2W(EFI_TEST_VARIABLE_NAME),
102                                               _A2W(EFI_TEST_GUID_STRING),
103                                               &EfiVariableValue,
104                                               sizeof(EfiVariableValue));
105     dwError = GetLastError();
106     ok(!bResult && dwError == ERROR_PRIVILEGE_NOT_HELD,
107        "bResult = %d, LastError = %lu, expected bResult = 0, LastError = ERROR_PRIVILEGE_NOT_HELD\n",
108        bResult,
109        dwError);
110 
111     /* Test ANSI function too */
112     bResultTemp = SetFirmwareEnvironmentVariableA(EFI_TEST_VARIABLE_NAME,
113                                                   EFI_TEST_GUID_STRING,
114                                                   &EfiVariableValue,
115                                                   sizeof(EfiVariableValue));
116     dwErrorTemp = GetLastError();
117     ok(bResultTemp == bResult && dwErrorTemp == dwError,
118        "bResult = %d, LastError = %lu, expected bResult = %d, LastError = %lu\n",
119        bResultTemp,
120        dwErrorTemp,
121        bResult,
122        dwError);
123 
124     /* Enable SE_SYSTEM_ENVIRONMENT_NAME privilege required by the following tests */
125     bResult = OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken);
126     if (!bResult)
127     {
128         skip("OpenProcessToken failed with error: 0x%08lX, aborting.\n", GetLastError());
129         return;
130     }
131     Privilege.PrivilegeCount = 1;
132     Privilege.Privileges[0].Luid = RtlConvertUlongToLuid(SE_SYSTEM_ENVIRONMENT_PRIVILEGE);
133     Privilege.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
134     Status = NtAdjustPrivilegesToken(hToken, FALSE, &Privilege, sizeof(Privilege), NULL, &ReturnLength);
135     if (Status != STATUS_SUCCESS)
136     {
137         skip("NtAdjustPrivilegesToken failed with status: 0x%08lX, aborting.\n", Status);
138         NtClose(hToken);
139         return;
140     }
141 
142     /* Set our test variable to UEFI firmware */
143     bResult = SetFirmwareEnvironmentVariableW(_A2W(EFI_TEST_VARIABLE_NAME),
144                                               _A2W(EFI_TEST_GUID_STRING),
145                                               &EfiVariableValue,
146                                               sizeof(EfiVariableValue));
147     ok(bResult,
148        "SetFirmwareEnvironmentVariableW failed with error: 0x%08lX\n",
149        GetLastError());
150     if (bResult)
151     {
152         /* Get the variable back and verify */
153         dwLength = GetFirmwareEnvironmentVariableW(_A2W(EFI_TEST_VARIABLE_NAME),
154                                                    _A2W(EFI_TEST_GUID_STRING),
155                                                    &dwValue,
156                                                    sizeof(dwValue));
157         ok(dwLength,
158            "GetFirmwareEnvironmentVariableW failed with error: 0x%08lX\n",
159            GetLastError());
160         if (dwLength)
161         {
162             ok(dwLength == sizeof(EfiVariableValue) && dwValue == EfiVariableValue,
163                "Retrieved variable different from what we set, "
164                "dwLength = %lu, dwValue = %lu, expected dwLength = %u, dwValue = %lu",
165                dwLength,
166                dwValue,
167                sizeof(EfiVariableValue),
168                EfiVariableValue);
169         }
170     }
171 
172     /* Change variable value and test ANSI function */
173     EfiVariableValue = RtlRandom(&RandomSeed);
174     bResult = SetFirmwareEnvironmentVariableA(EFI_TEST_VARIABLE_NAME,
175                                               EFI_TEST_GUID_STRING,
176                                               &EfiVariableValue,
177                                               sizeof(EfiVariableValue));
178     ok(bResult,
179        "SetFirmwareEnvironmentVariableA failed with error: 0x%08lX\n",
180        GetLastError());
181     if (bResult)
182     {
183         /* Get the variable back and verify */
184         dwLength = GetFirmwareEnvironmentVariableA(EFI_TEST_VARIABLE_NAME,
185                                                    EFI_TEST_GUID_STRING,
186                                                    &dwValue,
187                                                    sizeof(dwValue));
188         ok(dwLength,
189            "GetFirmwareEnvironmentVariableA failed with error: 0x%08lX\n",
190            GetLastError());
191         if (dwLength)
192         {
193             ok(dwLength == sizeof(EfiVariableValue) && dwValue == EfiVariableValue,
194                "Retrieved variable different from what we set, "
195                "dwLength = %lu, dwValue = %lu, expected dwLength = %u, dwValue = %lu",
196                dwLength,
197                dwValue,
198                sizeof(EfiVariableValue),
199                EfiVariableValue);
200         }
201     }
202 
203     /* Delete the variable */
204     bResult = SetFirmwareEnvironmentVariableW(_A2W(EFI_TEST_VARIABLE_NAME),
205                                               _A2W(EFI_TEST_GUID_STRING),
206                                               NULL,
207                                               0);
208     ok(bResult,
209        "SetFirmwareEnvironmentVariableW failed with error: 0x%08lX\n",
210        GetLastError());
211     if (bResult)
212     {
213         dwLength = GetFirmwareEnvironmentVariableW(_A2W(EFI_TEST_VARIABLE_NAME),
214                                                    _A2W(EFI_TEST_GUID_STRING),
215                                                    &dwValue,
216                                                    sizeof(dwValue));
217         ok(dwLength == 0, "SetFirmwareEnvironmentVariableW didn't delete the variable!\n");
218     }
219 
220     /* Restore variable and test ANSI function */
221     bResult = SetFirmwareEnvironmentVariableW(_A2W(EFI_TEST_VARIABLE_NAME),
222                                               _A2W(EFI_TEST_GUID_STRING),
223                                               &EfiVariableValue,
224                                               sizeof(EfiVariableValue));
225     if (!bResult)
226     {
227         skip("SetFirmwareEnvironmentVariableW failed to restore variable with error: 0x%08lX\n",
228              GetLastError());
229         goto _exit;
230     }
231     bResult = SetFirmwareEnvironmentVariableA(EFI_TEST_VARIABLE_NAME,
232                                               EFI_TEST_GUID_STRING,
233                                               NULL,
234                                               0);
235     ok(bResult,
236        "SetFirmwareEnvironmentVariableA failed with error: 0x%08lX\n",
237        GetLastError());
238     if (bResult)
239     {
240         dwLength = GetFirmwareEnvironmentVariableA(EFI_TEST_VARIABLE_NAME,
241                                                    EFI_TEST_GUID_STRING,
242                                                    &dwValue,
243                                                    sizeof(dwValue));
244         ok(dwLength == 0, "SetFirmwareEnvironmentVariableA didn't delete the variable!\n");
245     }
246 
247 _exit:
248     /* Restore the privilege */
249     Privilege.Privileges[0].Attributes = 0;
250     Status = NtAdjustPrivilegesToken(hToken, FALSE, &Privilege, sizeof(Privilege), NULL, &ReturnLength);
251     ok(Status == STATUS_SUCCESS, "NtAdjustPrivilegesToken failed with status: 0x%08lX\n", Status);
252     NtClose(hToken);
253 }
254