From: Grigory Vasilyev h0tc0d3@gmail.com
--- dlls/ntdll/tests/info.c | 52 +++++++++++++++- dlls/ntdll/unix/system.c | 124 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 174 insertions(+), 2 deletions(-)
diff --git a/dlls/ntdll/tests/info.c b/dlls/ntdll/tests/info.c index 62c17649808..b1f5fd2fe1c 100644 --- a/dlls/ntdll/tests/info.c +++ b/dlls/ntdll/tests/info.c @@ -34,6 +34,7 @@ static NTSTATUS (WINAPI * pNtQuerySystemInformation)(SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG); static NTSTATUS (WINAPI * pNtSetSystemInformation)(SYSTEM_INFORMATION_CLASS, PVOID, ULONG); static NTSTATUS (WINAPI * pRtlGetNativeSystemInformation)(SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG); +static NTSTATUS (WINAPI * pNtQuerySystemEnvironmentValueEx)(PUNICODE_STRING, LPGUID, PVOID, PULONG, PULONG); static NTSTATUS (WINAPI * pNtQuerySystemInformationEx)(SYSTEM_INFORMATION_CLASS, void*, ULONG, void*, ULONG, ULONG*); static NTSTATUS (WINAPI * pNtPowerInformation)(POWER_INFORMATION_LEVEL, PVOID, ULONG, PVOID, ULONG); static NTSTATUS (WINAPI * pNtQueryInformationThread)(HANDLE, THREADINFOCLASS, PVOID, ULONG, PULONG); @@ -91,6 +92,7 @@ static void InitFunctionPtrs(void)
NTDLL_GET_PROC(NtQuerySystemInformation); NTDLL_GET_PROC(NtQuerySystemInformationEx); + NTDLL_GET_PROC(NtQuerySystemEnvironmentValueEx); NTDLL_GET_PROC(NtSetSystemInformation); NTDLL_GET_PROC(RtlGetNativeSystemInformation); NTDLL_GET_PROC(NtPowerInformation); @@ -322,10 +324,14 @@ static void test_query_basic(void) } }
-static void test_query_boot(void) +static void test_query_boot_and_system_env(void) { NTSTATUS status; ULONG ret_size; + BOOLEAN secureboot; + DWORD attributes; + UNICODE_STRING secureboot_name; + GUID secureboot_guid = {0x8be4df61, 0x93ca, 0x11d2, {0xaa, 0x0d, 0x00, 0xe0, 0x98, 0x03, 0x2b, 0x8c}}; SYSTEM_BOOT_ENVIRONMENT_INFORMATION bi = {0};
/* @@ -351,6 +357,48 @@ static void test_query_boot(void)
status = pNtQuerySystemInformation(SystemBootEnvironmentInformation, NULL, 0, NULL); ok(status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH.\n"); + + /* + * NtQuerySystemEnvironmentValueEx + */ + RtlInitUnicodeString(&secureboot_name, L"SecureBoot"); + ret_size = sizeof(secureboot); + + status = pNtQuerySystemEnvironmentValueEx(&secureboot_name, &secureboot_guid, &secureboot, &ret_size, &attributes); + if(bi.FirmwareType != FirmwareTypeUefi) + ok(status == STATUS_NOT_IMPLEMENTED, "Expected STATUS_NOT_IMPLEMENTED on non-UEFI boots.\n"); + + if (status == STATUS_NOT_IMPLEMENTED) + { + skip("NtQuerySystemEnvironmentValueEx not implemented.\n"); + return; + } + + ok(status == STATUS_SUCCESS || status == STATUS_VARIABLE_NOT_FOUND, "Expected STATUS_SUCCESS or STATUS_VARIABLE_NOT_FOUND.\n"); + + status = pNtQuerySystemEnvironmentValueEx(NULL, NULL, &secureboot, &ret_size, &attributes); + ok(status == STATUS_INVALID_PARAMETER, "Expected STATUS_INVALID_PARAMETER.\n"); + + status = pNtQuerySystemEnvironmentValueEx(NULL, &secureboot_guid, &secureboot, &ret_size, &attributes); + ok(status == STATUS_INVALID_PARAMETER, "Expected STATUS_INVALID_PARAMETER.\n"); + + status = pNtQuerySystemEnvironmentValueEx(&secureboot_name, NULL, &secureboot, &ret_size, &attributes); + ok(status == STATUS_INVALID_PARAMETER, "Expected STATUS_INVALID_PARAMETER.\n"); + + status = pNtQuerySystemEnvironmentValueEx(&secureboot_name, &secureboot_guid, NULL, NULL, NULL); + ok(status == STATUS_INVALID_PARAMETER, "Expected STATUS_INVALID_PARAMETER.\n"); + + status = pNtQuerySystemEnvironmentValueEx(&secureboot_name, &secureboot_guid, &secureboot, NULL, NULL); + ok(status == STATUS_INVALID_PARAMETER, "Expected STATUS_INVALID_PARAMETER.\n"); + + status = pNtQuerySystemEnvironmentValueEx(&secureboot_name, &secureboot_guid, &secureboot, NULL, &attributes); + ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS.\n"); + + status = pNtQuerySystemEnvironmentValueEx(&secureboot_name, &secureboot_guid, NULL, &ret_size, NULL); + ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS.\n"); + + status = pNtQuerySystemEnvironmentValueEx(&secureboot_name, &secureboot_guid, NULL, &ret_size, &attributes); + ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS.\n"); }
static void test_query_cpu(void) @@ -4111,7 +4159,7 @@ START_TEST(info)
/* NtQuerySystemInformation */ test_query_basic(); - test_query_boot(); + test_query_boot_and_system_env(); test_query_cpu(); test_query_performance(); test_query_timeofday(); diff --git a/dlls/ntdll/unix/system.c b/dlls/ntdll/unix/system.c index b280b552ec7..7e8794cfca5 100644 --- a/dlls/ntdll/unix/system.c +++ b/dlls/ntdll/unix/system.c @@ -3912,9 +3912,133 @@ NTSTATUS WINAPI NtQuerySystemEnvironmentValue( UNICODE_STRING *name, WCHAR *buff NTSTATUS WINAPI NtQuerySystemEnvironmentValueEx( UNICODE_STRING *name, GUID *vendor, void *buffer, ULONG *retlen, ULONG *attrib ) { +#if defined(__linux__) || defined(__gnu_linux__) + int fd, rc; + size_t bytes, pos = 0; + ssize_t ssz; + char buff[4]; + char *cname; + char filename[PATH_MAX + 1]; + NTSTATUS status; + struct stat stat_info = {0}; + static SYSTEM_BOOT_ENVIRONMENT_INFORMATION boot_info = {0}; + + if(boot_info.FirmwareType == FirmwareTypeUnknown) + { + status = NtQuerySystemInformation(SystemBootEnvironmentInformation, + &boot_info, sizeof(boot_info), NULL); + if(status != STATUS_SUCCESS) return status; + } + + if(boot_info.FirmwareType != FirmwareTypeUefi) + { + /* + * This behavior matches the behavior of Windows for non-UEFI boots, + * and older versions of Windows. + */ + return STATUS_NOT_IMPLEMENTED; + } + + if(!name || !vendor || (name && vendor && !retlen && !attrib)) + { + return STATUS_INVALID_PARAMETER; + } + + cname = (char *) malloc(wcslen(name->Buffer) * 3 + 1); + if(!cname) + return STATUS_MEMORY_NOT_ALLOCATED; + + rc = ntdll_wcstoumbs(name->Buffer, wcslen(name->Buffer) + 1, cname, wcslen(name->Buffer) * 3 + 1, TRUE); + if(rc <= 0) { + free(cname); + return STATUS_SOME_NOT_MAPPED; + } + + snprintf(filename, sizeof(filename), + "/sys/firmware/efi/efivars/%s-%08lx-%04hx-%04hx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx", + cname, (unsigned long)vendor->Data1, vendor->Data2, vendor->Data3, + vendor->Data4[0], vendor->Data4[1], vendor->Data4[2], vendor->Data4[3], + vendor->Data4[4], vendor->Data4[5], vendor->Data4[6], vendor->Data4[7]); + + fd = open(filename, O_RDONLY); + if (fd == -1) + { + free(cname); + return STATUS_VARIABLE_NOT_FOUND; + } + + rc = fstat(fd, &stat_info); + if (rc < 0 || stat_info.st_size == 0) + goto done; + + if(attrib) ssz = read(fd, attrib, 4); + else ssz = read(fd, buff, 4); // lseek not work in efifs. + if (ssz < 0) goto done; + + if(buffer && retlen) + { + if (stat_info.st_size - 4 < *retlen) + bytes = stat_info.st_size - 4; + else + bytes = *retlen; + while (pos < bytes) + { + ssz = read(fd, (char *) buffer + pos, bytes - pos); + if (ssz < 0) goto done; + pos += ssz; + } + *retlen = ssz & 0xFFFFFFFF; + } + else if(retlen) *retlen = (stat_info.st_size - 4) & 0xFFFFFFFF; + + close(fd); + return STATUS_SUCCESS; + +done: + free(cname); + if (fd >= 0) + close(fd); + return STATUS_UNSUCCESSFUL; +#elif defined(__APPLE__) + int rc; + char *cname; + GUID secureboot_guid = {0x8be4df61, 0x93ca, 0x11d2, {0xaa, 0x0d, 0x00, 0xe0, 0x98, 0x03, 0x2b, 0x8c}}; + if(!name || !vendor || (name && vendor && !retlen && !attrib)) + { + return STATUS_INVALID_PARAMETER; + } + + cname = (char *) malloc(wcslen(name->Buffer) * 3 + 1); + if(!cname) + return STATUS_MEMORY_NOT_ALLOCATED; + + rc = ntdll_wcstoumbs(name->Buffer, wcslen(name->Buffer) + 1, cname, wcslen(name->Buffer) * 3 + 1, TRUE); + if(rc <= 0) { + free(cname); + return STATUS_SOME_NOT_MAPPED; + } + /* + * Since 2006, Mac computers use Extensible Firmware Interface (EFI). + * Apple requires a developer account and mandatory code signing, + * and the entire system boot process is verified, we can return SecureBoot enabled. + * Reference: https://support.apple.com/guide/security/uefi-firmware-security-in-an-intel-... + */ + if(!memcmp(vendor, &secureboot_guid, sizeof(secureboot_guid)) && !strcmp(cname, "SecureBoot")) + { + if(attrib) *attrib = 0x06; + if(buffer && retlen && *retlen == sizeof(BOOLEAN)) *((BOOLEAN *)buffer) = 1; + else if(retlen) *retlen = sizeof(BOOLEAN) & 0xFFFFFFFF; + free(cname); + return STATUS_SUCCESS; + } + + free(cname); + return STATUS_VARIABLE_NOT_FOUND; +#else FIXME( "(%s, %s, %p, %p, %p), stub\n", debugstr_us(name), debugstr_guid(vendor), buffer, retlen, attrib ); return STATUS_NOT_IMPLEMENTED; +#endif }