From: Grigory Vasilyev h0tc0d3@gmail.com
--- dlls/ntdll/tests/info.c | 32 ++++++++++++++ dlls/ntdll/unix/system.c | 96 ++++++++++++++++++++++++++++++++++++++++ dlls/wow64/system.c | 3 ++ include/winternl.h | 22 +++++++++ 4 files changed, 153 insertions(+)
diff --git a/dlls/ntdll/tests/info.c b/dlls/ntdll/tests/info.c index ba19b248e43..62c17649808 100644 --- a/dlls/ntdll/tests/info.c +++ b/dlls/ntdll/tests/info.c @@ -322,6 +322,37 @@ static void test_query_basic(void) } }
+static void test_query_boot(void) +{ + NTSTATUS status; + ULONG ret_size; + SYSTEM_BOOT_ENVIRONMENT_INFORMATION bi = {0}; + + /* + * NtQuerySystemInformation - SystemBootEnvironmentInformation + */ + status = pNtQuerySystemInformation(SystemBootEnvironmentInformation, &bi, sizeof(bi), &ret_size); + if (status == STATUS_NOT_IMPLEMENTED) + { + skip("NtQuerySystemInformation - SystemBootEnvironmentInformation not implemented.\n"); + return; + } + ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS.\n"); + + ok(ret_size == sizeof(bi), "Expected ret_size == sizeof(SYSTEM_BOOT_ENVIRONMENT_INFORMATION).\n"); + + ok(bi.FirmwareType == FirmwareTypeBios || bi.FirmwareType == FirmwareTypeUefi, + "Expected FirmwareTypeBios or FirmwareTypeUefi, got %02x\n", bi.FirmwareType); + + ok(bi.BootIdentifier.Data1 != 0, "A non-zero BootIdentifier value is expected.\n"); + + status = pNtQuerySystemInformation(SystemBootEnvironmentInformation, NULL, sizeof(bi), NULL); + ok(status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION.\n"); + + status = pNtQuerySystemInformation(SystemBootEnvironmentInformation, NULL, 0, NULL); + ok(status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH.\n"); +} + static void test_query_cpu(void) { NTSTATUS status; @@ -4080,6 +4111,7 @@ START_TEST(info)
/* NtQuerySystemInformation */ test_query_basic(); + test_query_boot(); test_query_cpu(); test_query_performance(); test_query_timeofday(); diff --git a/dlls/ntdll/unix/system.c b/dlls/ntdll/unix/system.c index b015cfff923..b280b552ec7 100644 --- a/dlls/ntdll/unix/system.c +++ b/dlls/ntdll/unix/system.c @@ -30,6 +30,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <sys/stat.h> #include <sys/types.h> #include <unistd.h> #include <errno.h> @@ -2927,6 +2928,101 @@ NTSTATUS WINAPI NtQuerySystemInformation( SYSTEM_INFORMATION_CLASS class, break; }
+ case SystemBootEnvironmentInformation: /* 90 */ + { + static SYSTEM_BOOT_ENVIRONMENT_INFORMATION boot_info = {0}; + struct stat stat_info = {0}; + ssize_t ssz; +#if defined(__linux__) || defined(__gnu_linux__) + int fd; + char buffer[32]; +#endif + len = sizeof(boot_info); + if (size == len) + { +#if defined(__linux__) || defined(__gnu_linux__) + if (boot_info.FirmwareType == FirmwareTypeUnknown) + { + if (!stat("/sys/firmware/efi", &stat_info)) + boot_info.FirmwareType = FirmwareTypeUefi; + else + boot_info.FirmwareType = FirmwareTypeBios; + } +#elif defined(__APPLE__) + /* + * Since 2006, Mac computers use Extensible Firmware Interface (EFI). + * Reference: https://support.apple.com/guide/security/uefi-firmware-security-in-an-intel-... + */ + boot_info.FirmwareType = FirmwareTypeUefi; +#else + boot_info.FirmwareType = FirmwareTypeBios; +#endif + if (boot_info.BootIdentifier.Data1 == 0) + { +#if defined(__linux__) || defined(__gnu_linux__) + if (!stat("/etc/machine-id", &stat_info) && stat_info.st_size >= 32) + { + fd = open("/etc/machine-id", O_RDONLY); + if (fd == -1) + goto try_read_hostid; + ssz = read(fd, &buffer, 32); + if (ssz < 0) + { + close(fd); + goto try_read_hostid; + } + close(fd); + if (sscanf(buffer, + "%08X%04hX%04hX%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX", + (unsigned int *)&boot_info.BootIdentifier.Data1, &boot_info.BootIdentifier.Data2, + &boot_info.BootIdentifier.Data3, &boot_info.BootIdentifier.Data4[0], + &boot_info.BootIdentifier.Data4[1], &boot_info.BootIdentifier.Data4[2], + &boot_info.BootIdentifier.Data4[3], &boot_info.BootIdentifier.Data4[4], + &boot_info.BootIdentifier.Data4[5], &boot_info.BootIdentifier.Data4[6], + &boot_info.BootIdentifier.Data4[7]) != 11) + goto try_read_hostid; + } + else + { + try_read_hostid: +#endif +#ifdef __APPLE__ + if (!stat("/Users", &stat_info) || !stat("/System", &stat_info)) +#else + if (!stat("/home", &stat_info) || !stat("/usr", &stat_info)) +#endif + { + boot_info.BootIdentifier.Data1 = gethostid() & 0xFFFFFFFF; + boot_info.BootIdentifier.Data2 = stat_info.st_dev & 0xFFFF; + boot_info.BootIdentifier.Data3 = stat_info.st_ino & 0xFFFF; + boot_info.BootIdentifier.Data4[0] = 'W' ^ (boot_info.BootIdentifier.Data1 & 0xFF); + boot_info.BootIdentifier.Data4[1] = 'I' ^ ((boot_info.BootIdentifier.Data1 >> 4) & 0xFF); + boot_info.BootIdentifier.Data4[2] = 'N' ^ ((boot_info.BootIdentifier.Data1 >> 8) & 0xFF); + boot_info.BootIdentifier.Data4[3] = 'E' ^ ((boot_info.BootIdentifier.Data1 >> 12) & 0xFF); + boot_info.BootIdentifier.Data4[4] = 'B' ^ ((boot_info.BootIdentifier.Data1 >> 16) & 0xFF); + boot_info.BootIdentifier.Data4[5] = 'O' ^ ((boot_info.BootIdentifier.Data1 >> 20) & 0xFF); + boot_info.BootIdentifier.Data4[6] = 'O' ^ ((boot_info.BootIdentifier.Data1 >> 24) & 0xFF); + boot_info.BootIdentifier.Data4[7] = 'T' ^ ((boot_info.BootIdentifier.Data1 >> 28) & 0xFF); + } +#if defined(__linux__) || defined(__gnu_linux__) + } +#endif + boot_info.BootIdentifier.Data3 &= 0x0fff; + boot_info.BootIdentifier.Data3 |= (4 << 12); + /* Set the topmost bits of Data4 (clock_seq_hi_and_reserved) as + * specified in RFC 4122, section 4.4. + */ + boot_info.BootIdentifier.Data4[0] &= 0x3f; + boot_info.BootIdentifier.Data4[0] |= 0x80; + } + if (!info) ret = STATUS_ACCESS_VIOLATION; + else memcpy(info, &boot_info, len); + } + else ret = STATUS_INFO_LENGTH_MISMATCH; + if (ret_size) *ret_size = len; + break; + } + case SystemCpuInformation: /* 1 */ if (size >= (len = sizeof(cpu_info))) memcpy(info, &cpu_info, len); else ret = STATUS_INFO_LENGTH_MISMATCH; diff --git a/dlls/wow64/system.c b/dlls/wow64/system.c index 5f3056a4179..402b53e1eda 100644 --- a/dlls/wow64/system.c +++ b/dlls/wow64/system.c @@ -356,6 +356,9 @@ NTSTATUS WINAPI wow64_NtQuerySystemInformation( UINT *args ) if (retlen) *retlen = sizeof(SYSTEM_BASIC_INFORMATION32); return status;
+ case SystemBootEnvironmentInformation: /* SYSTEM_BOOT_ENVIRONMENT_INFORMATION */ + return NtQuerySystemInformation(class, ptr, len, retlen); + case SystemProcessInformation: /* SYSTEM_PROCESS_INFORMATION */ case SystemExtendedProcessInformation: /* SYSTEM_PROCESS_INFORMATION */ { diff --git a/include/winternl.h b/include/winternl.h index 828fbc6e915..510bba09042 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -2724,6 +2724,28 @@ typedef struct _SYSTEM_BASIC_INFORMATION { #endif } SYSTEM_BASIC_INFORMATION, *PSYSTEM_BASIC_INFORMATION;
+/* System Information Class 0x90 */ +typedef struct _SYSTEM_BOOT_ENVIRONMENT_INFORMATION +{ + GUID BootIdentifier; + FIRMWARE_TYPE FirmwareType; + union + { + ULONGLONG BootFlags; + struct + { + ULONGLONG DbgMenuOsSelection : 1; + ULONGLONG DbgHiberBoot : 1; + ULONGLONG DbgSoftBoot : 1; + ULONGLONG DbgMeasuredLaunch : 1; + ULONGLONG DbgMeasuredLaunchCapable : 1; + ULONGLONG DbgSystemHiveReplace : 1; + ULONGLONG DbgMeasuredLaunchSmmProtections : 1; + ULONGLONG DbgMeasuredLaunchSmmLevel : 7; + }; + }; +} SYSTEM_BOOT_ENVIRONMENT_INFORMATION, *PSYSTEM_BOOT_ENVIRONMENT_INFORMATION; + /* System Information Class 0x01 */
typedef struct _SYSTEM_CPU_INFORMATION {