[80708] | 1 | /* $Id: RTSystemFirmware-win.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
|
---|
| 2 | /** @file
|
---|
| 3 | * IPRT - System firmware information, Win32.
|
---|
| 4 | */
|
---|
| 5 |
|
---|
| 6 | /*
|
---|
[98103] | 7 | * Copyright (C) 2019-2023 Oracle and/or its affiliates.
|
---|
[80708] | 8 | *
|
---|
[96407] | 9 | * This file is part of VirtualBox base platform packages, as
|
---|
| 10 | * available from https://www.virtualbox.org.
|
---|
[80708] | 11 | *
|
---|
[96407] | 12 | * This program is free software; you can redistribute it and/or
|
---|
| 13 | * modify it under the terms of the GNU General Public License
|
---|
| 14 | * as published by the Free Software Foundation, in version 3 of the
|
---|
| 15 | * License.
|
---|
| 16 | *
|
---|
| 17 | * This program is distributed in the hope that it will be useful, but
|
---|
| 18 | * WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
| 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
---|
| 20 | * General Public License for more details.
|
---|
| 21 | *
|
---|
| 22 | * You should have received a copy of the GNU General Public License
|
---|
| 23 | * along with this program; if not, see <https://www.gnu.org/licenses>.
|
---|
| 24 | *
|
---|
[80708] | 25 | * The contents of this file may alternatively be used under the terms
|
---|
| 26 | * of the Common Development and Distribution License Version 1.0
|
---|
[96407] | 27 | * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
|
---|
| 28 | * in the VirtualBox distribution, in which case the provisions of the
|
---|
[80708] | 29 | * CDDL are applicable instead of those of the GPL.
|
---|
| 30 | *
|
---|
| 31 | * You may elect to license modified versions of this file under the
|
---|
| 32 | * terms and conditions of either the GPL or the CDDL or both.
|
---|
[96407] | 33 | *
|
---|
| 34 | * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
|
---|
[80708] | 35 | */
|
---|
| 36 |
|
---|
| 37 |
|
---|
| 38 | /*********************************************************************************************************************************
|
---|
| 39 | * Header Files *
|
---|
| 40 | *********************************************************************************************************************************/
|
---|
[81062] | 41 | #include "internal/iprt.h"
|
---|
| 42 | #include <iprt/system.h>
|
---|
[80708] | 43 |
|
---|
| 44 | #include <iprt/nt/nt-and-windows.h>
|
---|
[81062] | 45 | #include <WinSDKVer.h>
|
---|
[80708] | 46 |
|
---|
[81062] | 47 | #include <iprt/asm.h>
|
---|
[80708] | 48 | #include <iprt/assert.h>
|
---|
[81062] | 49 | #include <iprt/err.h>
|
---|
[80708] | 50 | #include <iprt/mem.h>
|
---|
| 51 | #include <iprt/ldr.h>
|
---|
| 52 | #include <iprt/string.h>
|
---|
| 53 | #include <iprt/utf16.h>
|
---|
| 54 |
|
---|
[81062] | 55 | #include "internal-r3-win.h"
|
---|
[80708] | 56 |
|
---|
[81062] | 57 |
|
---|
[80708] | 58 | /*********************************************************************************************************************************
|
---|
| 59 | * Structures and Typedefs *
|
---|
| 60 | *********************************************************************************************************************************/
|
---|
[81062] | 61 | #if _WIN32_MAXVER < 0x0602 /* Windows 7 or older, supply missing GetFirmwareType bits. */
|
---|
| 62 | typedef enum _FIRMWARE_TYPE
|
---|
[80708] | 63 | {
|
---|
[81062] | 64 | FirmwareTypeUnknown,
|
---|
| 65 | FirmwareTypeBios,
|
---|
| 66 | FirmwareTypeUefi,
|
---|
| 67 | FirmwareTypeMax
|
---|
| 68 | } FIRMWARE_TYPE;
|
---|
| 69 | typedef FIRMWARE_TYPE *PFIRMWARE_TYPE;
|
---|
| 70 | WINBASEAPI BOOL WINAPI GetFirmwareType(PFIRMWARE_TYPE);
|
---|
| 71 | #endif
|
---|
[80708] | 72 |
|
---|
| 73 |
|
---|
[81062] | 74 | /*********************************************************************************************************************************
|
---|
| 75 | * Defined Constants And Macros *
|
---|
| 76 | *********************************************************************************************************************************/
|
---|
[80708] | 77 | /** Defines the UEFI Globals UUID. */
|
---|
| 78 | #define VBOX_UEFI_UUID_GLOBALS L"{8BE4DF61-93CA-11D2-AA0D-00E098032B8C}"
|
---|
[81063] | 79 | /** Defines an UEFI dummy UUID, see MSDN docs of the API. */
|
---|
[80708] | 80 | #define VBOX_UEFI_UUID_DUMMY L"{00000000-0000-0000-0000-000000000000}"
|
---|
| 81 |
|
---|
| 82 |
|
---|
[81062] | 83 | /*********************************************************************************************************************************
|
---|
| 84 | * Global Variables *
|
---|
| 85 | *********************************************************************************************************************************/
|
---|
| 86 | static volatile bool g_fResolvedApis = false;
|
---|
| 87 | static decltype(GetFirmwareType) *g_pfnGetFirmwareType;
|
---|
| 88 | static decltype(GetFirmwareEnvironmentVariableW) *g_pfnGetFirmwareEnvironmentVariableW;
|
---|
| 89 |
|
---|
| 90 |
|
---|
| 91 | static void rtSystemFirmwareResolveApis(void)
|
---|
| 92 | {
|
---|
| 93 | FARPROC pfnTmp1 = GetProcAddress(g_hModKernel32, "GetFirmwareType");
|
---|
| 94 | FARPROC pfnTmp2 = GetProcAddress(g_hModKernel32, "GetFirmwareEnvironmentVariableW");
|
---|
| 95 | ASMCompilerBarrier(); /* paranoia^2 */
|
---|
| 96 |
|
---|
| 97 | g_pfnGetFirmwareType = (decltype(GetFirmwareType) *)pfnTmp1;
|
---|
| 98 | g_pfnGetFirmwareEnvironmentVariableW = (decltype(GetFirmwareEnvironmentVariableW) *)pfnTmp2;
|
---|
| 99 | ASMAtomicWriteBool(&g_fResolvedApis, true);
|
---|
| 100 | }
|
---|
| 101 |
|
---|
| 102 |
|
---|
[80708] | 103 | static int rtSystemFirmwareGetPrivileges(LPCTSTR pcszPrivilege)
|
---|
| 104 | {
|
---|
| 105 | HANDLE hToken;
|
---|
| 106 | BOOL fRc = OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);
|
---|
| 107 | if (!fRc)
|
---|
| 108 | return RTErrConvertFromWin32(GetLastError());
|
---|
| 109 |
|
---|
| 110 | int rc = VINF_SUCCESS;
|
---|
| 111 |
|
---|
| 112 | TOKEN_PRIVILEGES tokenPriv;
|
---|
| 113 | fRc = LookupPrivilegeValue(NULL, pcszPrivilege, &tokenPriv.Privileges[0].Luid);
|
---|
| 114 | if (fRc)
|
---|
| 115 | {
|
---|
| 116 | tokenPriv.PrivilegeCount = 1;
|
---|
| 117 | tokenPriv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
---|
| 118 | fRc = AdjustTokenPrivileges(hToken, FALSE, &tokenPriv, 0, (PTOKEN_PRIVILEGES)NULL, 0);
|
---|
| 119 | if (!fRc)
|
---|
| 120 | rc = RTErrConvertFromWin32(GetLastError());
|
---|
| 121 | }
|
---|
| 122 | else
|
---|
| 123 | rc = RTErrConvertFromWin32(GetLastError());
|
---|
| 124 |
|
---|
| 125 | CloseHandle(hToken);
|
---|
| 126 |
|
---|
| 127 | return rc;
|
---|
| 128 | }
|
---|
| 129 |
|
---|
| 130 |
|
---|
[81137] | 131 | RTDECL(int) RTSystemQueryFirmwareType(PRTSYSFWTYPE penmFirmwareType)
|
---|
[80708] | 132 | {
|
---|
[81062] | 133 | AssertPtrReturn(penmFirmwareType, VERR_INVALID_POINTER);
|
---|
[80708] | 134 |
|
---|
[81062] | 135 | if (!g_fResolvedApis)
|
---|
| 136 | rtSystemFirmwareResolveApis();
|
---|
[80708] | 137 |
|
---|
[81062] | 138 | *penmFirmwareType = RTSYSFWTYPE_INVALID;
|
---|
| 139 | int rc = VERR_NOT_SUPPORTED;
|
---|
| 140 |
|
---|
| 141 | /* GetFirmwareType is Windows 8 and later. */
|
---|
| 142 | if (g_pfnGetFirmwareType)
|
---|
[80708] | 143 | {
|
---|
[81062] | 144 | FIRMWARE_TYPE enmWinFwType;
|
---|
| 145 | if (g_pfnGetFirmwareType(&enmWinFwType))
|
---|
[80708] | 146 | {
|
---|
[81062] | 147 | switch (enmWinFwType)
|
---|
[80708] | 148 | {
|
---|
[81062] | 149 | case FirmwareTypeBios:
|
---|
| 150 | *penmFirmwareType = RTSYSFWTYPE_BIOS;
|
---|
| 151 | break;
|
---|
| 152 | case FirmwareTypeUefi:
|
---|
| 153 | *penmFirmwareType = RTSYSFWTYPE_UEFI;
|
---|
| 154 | break;
|
---|
| 155 | default:
|
---|
| 156 | *penmFirmwareType = RTSYSFWTYPE_UNKNOWN;
|
---|
| 157 | AssertMsgFailed(("%d\n", enmWinFwType));
|
---|
| 158 | break;
|
---|
[80708] | 159 | }
|
---|
[81062] | 160 | rc = VINF_SUCCESS;
|
---|
[80708] | 161 | }
|
---|
[81062] | 162 | else
|
---|
| 163 | rc = RTErrConvertFromWin32(GetLastError());
|
---|
| 164 | }
|
---|
| 165 | /* GetFirmwareEnvironmentVariableW is XP and later. */
|
---|
| 166 | else if (g_pfnGetFirmwareEnvironmentVariableW)
|
---|
| 167 | {
|
---|
| 168 | rtSystemFirmwareGetPrivileges(SE_SYSTEM_ENVIRONMENT_NAME);
|
---|
| 169 |
|
---|
[81063] | 170 | /* On a non-UEFI system (or such a system in legacy boot mode), we will get
|
---|
| 171 | back ERROR_INVALID_FUNCTION when querying any firmware variable. While on a
|
---|
| 172 | UEFI system we'll typically get ERROR_ACCESS_DENIED or similar as the dummy
|
---|
| 173 | is a non-exising dummy namespace. See the API docs. */
|
---|
| 174 | SetLastError(0);
|
---|
| 175 | uint8_t abWhatever[64];
|
---|
| 176 | DWORD cbRet = g_pfnGetFirmwareEnvironmentVariableW(L"", VBOX_UEFI_UUID_DUMMY, abWhatever, sizeof(abWhatever));
|
---|
| 177 | DWORD dwErr = GetLastError();
|
---|
| 178 | *penmFirmwareType = cbRet != 0 || dwErr != ERROR_INVALID_FUNCTION ? RTSYSFWTYPE_UEFI : RTSYSFWTYPE_BIOS;
|
---|
| 179 | rc = VINF_SUCCESS;
|
---|
[80708] | 180 | }
|
---|
| 181 | return rc;
|
---|
| 182 | }
|
---|
| 183 |
|
---|
| 184 |
|
---|
[81140] | 185 | RTDECL(int) RTSystemQueryFirmwareBoolean(RTSYSFWBOOL enmBoolean, bool *pfValue)
|
---|
[80708] | 186 | {
|
---|
[81137] | 187 | *pfValue = false;
|
---|
[80708] | 188 |
|
---|
[81062] | 189 | /*
|
---|
[81140] | 190 | * Translate the enmBoolean to a name:
|
---|
[81062] | 191 | */
|
---|
| 192 | const wchar_t *pwszName = NULL;
|
---|
[81140] | 193 | switch (enmBoolean)
|
---|
[80708] | 194 | {
|
---|
[81140] | 195 | case RTSYSFWBOOL_SECURE_BOOT:
|
---|
[81062] | 196 | pwszName = L"SecureBoot";
|
---|
[80708] | 197 | break;
|
---|
| 198 |
|
---|
| 199 | default:
|
---|
[81140] | 200 | AssertReturn(enmBoolean > RTSYSFWBOOL_INVALID && enmBoolean < RTSYSFWBOOL_END, VERR_INVALID_PARAMETER);
|
---|
[81062] | 201 | return VERR_SYS_UNSUPPORTED_FIRMWARE_PROPERTY;
|
---|
[80708] | 202 | }
|
---|
| 203 |
|
---|
[81063] | 204 | /*
|
---|
[81137] | 205 | * Do the query.
|
---|
[81500] | 206 | * Note! This will typically fail with access denied unless we're in an elevated process.
|
---|
[81063] | 207 | */
|
---|
[81062] | 208 | if (!g_pfnGetFirmwareEnvironmentVariableW)
|
---|
| 209 | return VERR_NOT_SUPPORTED;
|
---|
| 210 | rtSystemFirmwareGetPrivileges(SE_SYSTEM_ENVIRONMENT_NAME);
|
---|
| 211 |
|
---|
[81137] | 212 | uint8_t bValue = 0;
|
---|
| 213 | DWORD cbRet = g_pfnGetFirmwareEnvironmentVariableW(pwszName, VBOX_UEFI_UUID_GLOBALS, &bValue, sizeof(bValue));
|
---|
| 214 | *pfValue = cbRet != 0 && bValue != 0;
|
---|
[81499] | 215 | if (cbRet != 0)
|
---|
| 216 | return VINF_SUCCESS;
|
---|
| 217 | DWORD dwErr = GetLastError();
|
---|
| 218 | if ( dwErr == ERROR_INVALID_FUNCTION
|
---|
| 219 | || dwErr == ERROR_ENVVAR_NOT_FOUND)
|
---|
| 220 | return VINF_SUCCESS;
|
---|
| 221 | return RTErrConvertFromWin32(dwErr);
|
---|
[80708] | 222 | }
|
---|
| 223 |
|
---|