Kernel32 Implement: - `GetFirmwareType` - `GetFirmwareEnvironmentVariableExA` - `GetFirmwareEnvironmentVariableExW` - `GetFirmwareEnvironmentVariableA` - `GetFirmwareEnvironmentVariableW`.
The code is needed to check SecureBoot status, security systems and for example to check the licenses of software that can use efi variables.
Example:
```C #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <windows.h> #include <winnt.h>
/* x86_64-w64-mingw32-gcc wuefi.c -o wuefi.exe -Wl,--subsystem,console */ int main(int argc, char **argv) { BOOLEAN secureboot = 0; char asus_license[2048]; FIRMWARE_TYPE type;
if(GetFirmwareType(&type)) printf("Firmware Type: %s\n", type == FirmwareTypeUefi ? "UEFI" : "BIOS");
if(GetFirmwareEnvironmentVariableA("SecureBoot", "{8be4df61-93ca-11d2-aa0d-00e098032b8c}", &secureboot, sizeof(BOOLEAN))) printf("SecureBoot: %s\n", secureboot ? "enabled" : "disabled");
if(GetFirmwareEnvironmentVariableW(L"SecureBoot", L"{8be4df61-93ca-11d2-aa0d-00e098032b8c}", &secureboot, sizeof(BOOLEAN))) printf("SecureBoot: %s\n", secureboot ? "enabled" : "disabled");
if(GetFirmwareEnvironmentVariableA("AsusOnboardToolLicense", "02076249-a52b-420e-bd53-aed044349379", asus_license, sizeof(asus_license))) printf("Asus License: \n%s\n\n", asus_license);
return 0; } ```
``` Firmware Type: UEFI SecureBoot: enabled SecureBoot: enabled Asus License: bigtext== [LicenseID]:FED7A1 [Model]:Dummy-BaseBoard-Id [Tools]:WAsusDmiS,LogoFlashS,ASUSFwConfigS,AsusEventLogS,AsusNvLockS [Customer]:DummyLic [Expire]:2022-11-24 ```
-- v2: kernel32: Implement GetFirmwareEnvironmentVariableExA, GetFirmwareEnvironmentVariableExW, GetFirmwareEnvironmentVariableA, GetFirmwareEnvironmentVariableW. kernel32: Implement GetFirmwareType.
From: Grigory Vasilyev h0tc0d3@gmail.com
--- dlls/kernel32/Makefile.in | 2 ++ dlls/kernel32/firmware.c | 59 +++++++++++++++++++++++++++++++++++++ dlls/kernel32/kernel_main.c | 2 ++ dlls/kernel32/process.c | 16 ++++++++-- dlls/kernel32/unixlib.h | 33 +++++++++++++++++++++ 5 files changed, 110 insertions(+), 2 deletions(-) create mode 100644 dlls/kernel32/firmware.c create mode 100644 dlls/kernel32/unixlib.h
diff --git a/dlls/kernel32/Makefile.in b/dlls/kernel32/Makefile.in index ca5bb437e24..feb02d23e39 100644 --- a/dlls/kernel32/Makefile.in +++ b/dlls/kernel32/Makefile.in @@ -1,5 +1,6 @@ EXTRADEFS = -D_KERNEL32_ -D_NORMALIZE_ MODULE = kernel32.dll +UNIXLIB = kernel32.so IMPORTLIB = kernel32 IMPORTS = kernelbase ntdll winecrt0
@@ -14,6 +15,7 @@ SOURCES = \ console.c \ debugger.c \ file.c \ + firmware.c \ heap.c \ kernel_main.c \ locale.c \ diff --git a/dlls/kernel32/firmware.c b/dlls/kernel32/firmware.c new file mode 100644 index 00000000000..b5064a624a4 --- /dev/null +++ b/dlls/kernel32/firmware.c @@ -0,0 +1,59 @@ +/* + * Kernel32 Firmware Interface + * + * Copyright (C) 2024 Grigory Vasilyev + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#if 0 +#pragma makedep unix +#endif + +#include <dirent.h> + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "unixlib.h" +#include "windef.h" + +/* Get Firmware Type */ +static NTSTATUS kernel32_unix_get_firmware_type(void *args) +{ + FIRMWARE_TYPE *type = args; + + DIR *efi_dir = opendir("/sys/firmware/efi"); + + if (efi_dir) { + closedir(efi_dir); + *type = FirmwareTypeUefi; + } else { + *type = FirmwareTypeBios; + } + + return STATUS_SUCCESS; +} + +const unixlib_entry_t __wine_unix_call_funcs[] = { + kernel32_unix_get_firmware_type, +}; + +#ifdef _WIN64 + +const unixlib_entry_t __wine_unix_call_wow64_funcs[] = { + kernel32_unix_get_firmware_type, +}; + +#endif /* _WIN64 */ diff --git a/dlls/kernel32/kernel_main.c b/dlls/kernel32/kernel_main.c index ae16195a550..70443cbce2a 100644 --- a/dlls/kernel32/kernel_main.c +++ b/dlls/kernel32/kernel_main.c @@ -31,6 +31,7 @@
#include "kernel_private.h" #include "wine/debug.h" +#include "wine/unixlib.h"
WINE_DEFAULT_DEBUG_CHANNEL(process);
@@ -161,6 +162,7 @@ BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved ) { case DLL_PROCESS_ATTACH: DisableThreadLibraryCalls( hinst ); + if (__wine_init_unix_call()) return FALSE; return process_attach( hinst ); case DLL_PROCESS_DETACH: WritePrivateProfileSectionW( NULL, NULL, NULL ); diff --git a/dlls/kernel32/process.c b/dlls/kernel32/process.c index 2a4ddc68f02..f96a66b78fc 100644 --- a/dlls/kernel32/process.c +++ b/dlls/kernel32/process.c @@ -37,6 +37,7 @@ #include "ddk/wdm.h" #include "wine/asm.h" #include "wine/debug.h" +#include "unixlib.h"
WINE_DEFAULT_DEBUG_CHANNEL(process);
@@ -763,10 +764,21 @@ BOOL WINAPI SetFirmwareEnvironmentVariableW(const WCHAR *name, const WCHAR *guid */ BOOL WINAPI GetFirmwareType(FIRMWARE_TYPE *type) { - if (!type) + static FIRMWARE_TYPE ftype = FirmwareTypeUnknown; + + if ( !type ) return FALSE;
- *type = FirmwareTypeUnknown; + if( ftype != FirmwareTypeUnknown ) + { + *type = ftype; + return TRUE; + } + + WINE_UNIX_CALL( kernel32_unix_func_get_firmware_type, &ftype ); + + *type = ftype; + return TRUE; }
diff --git a/dlls/kernel32/unixlib.h b/dlls/kernel32/unixlib.h new file mode 100644 index 00000000000..102f5645dc5 --- /dev/null +++ b/dlls/kernel32/unixlib.h @@ -0,0 +1,33 @@ +/* + * Kernel32 Unix interface + * + * Copyright (C) 2024 Grigory Vasilyev + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __WINE_KERNEL_UNIXLIB_H +#define __WINE_KERNEL_UNIXLIB_H + +#include "wine/unixlib.h" + +enum kernel32_unix_func +{ + kernel32_unix_func_get_firmware_type, +}; + +extern unixlib_handle_t __wine_unixlib_handle; + +#endif /* __WINE_KERNEL_UNIXLIB_H */
From: Grigory Vasilyev h0tc0d3@gmail.com
--- dlls/kernel32/firmware.c | 78 +++++++++++++++++++++++++++++++++++++ dlls/kernel32/kernel32.spec | 2 + dlls/kernel32/process.c | 57 ++++++++++++++++++++++++--- dlls/kernel32/unixlib.h | 11 ++++++ 4 files changed, 142 insertions(+), 6 deletions(-)
diff --git a/dlls/kernel32/firmware.c b/dlls/kernel32/firmware.c index b5064a624a4..aba4fb70382 100644 --- a/dlls/kernel32/firmware.c +++ b/dlls/kernel32/firmware.c @@ -22,7 +22,16 @@ #pragma makedep unix #endif
+#include <errno.h> #include <dirent.h> +#include <fcntl.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h>
#include "ntstatus.h" #define WIN32_NO_STATUS @@ -46,14 +55,83 @@ static NTSTATUS kernel32_unix_get_firmware_type(void *args) return STATUS_SUCCESS; }
+/* Get Firmware Variable */ +static NTSTATUS kernel32_unix_get_firmware_variable(void *args) +{ + int fd, rc; + size_t bytes, pos = 0; + ssize_t ssz; + char tguid[37]; + char filename[128]; + struct stat sb = {0}; + struct wine_get_firmware_variable_params *params = args; + + int gsize = strlen(params->guid); + + if (params->guid[0] == '{' && params->guid[(gsize - 1)] == '}') { + if (gsize - 2 < sizeof(tguid)) + bytes = gsize - 1; + else + bytes = sizeof(tguid); + memcpy(tguid, params->guid + 1, bytes); + tguid[bytes - 1] = '\0'; + snprintf(filename, sizeof(filename), "/sys/firmware/efi/efivars/%s-%s", params->name, tguid); + } else { + snprintf(filename, sizeof(filename), "/sys/firmware/efi/efivars/%s-%s", params->name, params->guid); + } + + fd = open(filename, O_RDONLY | O_NONBLOCK); + if (fd < 0) + goto done; + + rc = fstat(fd, &sb); + if (rc < 0 || sb.st_size == 0) + goto done; + + if (sb.st_size - 4 < params->size) + bytes = sb.st_size - 4; + else + bytes = params->size; + +try_read_attributes: + ssz = read(fd, params->attributes, 4); + if (ssz < 0) { + if (errno == EAGAIN || errno == EINTR) + goto try_read_attributes; + goto done; + } + + while (pos < bytes) { + ssz = read(fd, (char *) params->buffer + pos, bytes - pos); + if (ssz < 0) { + if (errno == EAGAIN || errno == EINTR) + continue; + goto done; + } + pos += ssz; + } + + close(fd); + params->status = ssz & 0xFFFFFFFF; + return STATUS_SUCCESS; + +done: + if (fd >= 0) + close(fd); + params->status = 0; + return STATUS_UNSUCCESSFUL; +} + const unixlib_entry_t __wine_unix_call_funcs[] = { kernel32_unix_get_firmware_type, + kernel32_unix_get_firmware_variable, };
#ifdef _WIN64
const unixlib_entry_t __wine_unix_call_wow64_funcs[] = { kernel32_unix_get_firmware_type, + kernel32_unix_get_firmware_variable, };
#endif /* _WIN64 */ diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec index 7ed8048f5d0..5d3556a2078 100644 --- a/dlls/kernel32/kernel32.spec +++ b/dlls/kernel32/kernel32.spec @@ -695,7 +695,9 @@ @ stdcall -import GetFileType(long) @ stdcall -import GetFinalPathNameByHandleA(long ptr long long) @ stdcall -import GetFinalPathNameByHandleW(long ptr long long) +@ stdcall GetFirmwareEnvironmentVariableExA(str str ptr long ptr) @ stdcall GetFirmwareEnvironmentVariableA(str str ptr long) +@ stdcall GetFirmwareEnvironmentVariableExW(wstr wstr ptr long ptr) @ stdcall GetFirmwareEnvironmentVariableW(wstr wstr ptr long) @ stdcall GetFirmwareType(ptr) @ stdcall -import GetFullPathNameA(str long ptr ptr) diff --git a/dlls/kernel32/process.c b/dlls/kernel32/process.c index f96a66b78fc..bccc5dbc5f2 100644 --- a/dlls/kernel32/process.c +++ b/dlls/kernel32/process.c @@ -719,14 +719,60 @@ WORD WINAPI GetMaximumProcessorGroupCount(void) return groups; }
+/*********************************************************************** + * GetFirmwareEnvironmentVariableExA (KERNEL32.@) + */ +DWORD WINAPI GetFirmwareEnvironmentVariableExA(LPCSTR name, LPCSTR guid, PVOID buffer, DWORD size, PDWORD attributes) +{ + struct wine_get_firmware_variable_params params = { 0 }; + params.name = name; + params.guid = guid; + params.buffer = buffer; + params.size = size; + params.attributes = attributes; + WINE_UNIX_CALL( kernel32_unix_func_get_firmware_variable, ¶ms ); + return params.status; +} + /*********************************************************************** * GetFirmwareEnvironmentVariableA (KERNEL32.@) */ DWORD WINAPI GetFirmwareEnvironmentVariableA(LPCSTR name, LPCSTR guid, PVOID buffer, DWORD size) { - FIXME("stub: %s %s %p %lu\n", debugstr_a(name), debugstr_a(guid), buffer, size); - SetLastError(ERROR_INVALID_FUNCTION); - return 0; + DWORD dwAttributes; + return GetFirmwareEnvironmentVariableExA( name, guid, buffer, size, &dwAttributes ); +} + +/*********************************************************************** + * GetFirmwareEnvironmentVariableExW (KERNEL32.@) + */ +DWORD WINAPI GetFirmwareEnvironmentVariableExW(LPCWSTR name, LPCWSTR guid, PVOID buffer, DWORD size, PDWORD attributes) +{ + DWORD ret; + INT len; + char *aname; + char *aguid; + + len = lstrlenW( name ) + 1; + ret = WideCharToMultiByte( GetOEMCP(), 0, name, len, NULL, 0, NULL, NULL ); + if ( !( aname = RtlAllocateHeap( GetProcessHeap(), 0, ret * sizeof(aname) ) ) ) + return 0; + WideCharToMultiByte( GetOEMCP(), 0, name, len, aname, ret, NULL, NULL ); + + len = lstrlenW( guid ) + 1; + ret = WideCharToMultiByte( GetOEMCP(), 0, guid, len, NULL, 0, NULL, NULL ); + if ( !( aguid = RtlAllocateHeap( GetProcessHeap(), 0, ret * sizeof(aguid) ) ) ) { + HeapFree( GetProcessHeap(), 0, aname ); + return 0; + } + WideCharToMultiByte( GetOEMCP(), 0, guid, len, aguid, ret, NULL, NULL ); + + ret = GetFirmwareEnvironmentVariableExA( aname, aguid, buffer, size, attributes ); + + HeapFree( GetProcessHeap(), 0, aname ); + HeapFree( GetProcessHeap(), 0, aguid ); + + return ret; }
/*********************************************************************** @@ -734,9 +780,8 @@ DWORD WINAPI GetFirmwareEnvironmentVariableA(LPCSTR name, LPCSTR guid, PVOID buf */ DWORD WINAPI GetFirmwareEnvironmentVariableW(LPCWSTR name, LPCWSTR guid, PVOID buffer, DWORD size) { - FIXME("stub: %s %s %p %lu\n", debugstr_w(name), debugstr_w(guid), buffer, size); - SetLastError(ERROR_INVALID_FUNCTION); - return 0; + DWORD dwAttributes; + return GetFirmwareEnvironmentVariableExW( name, guid, buffer, size, &dwAttributes ); }
/*********************************************************************** diff --git a/dlls/kernel32/unixlib.h b/dlls/kernel32/unixlib.h index 102f5645dc5..321c62194a6 100644 --- a/dlls/kernel32/unixlib.h +++ b/dlls/kernel32/unixlib.h @@ -23,9 +23,20 @@
#include "wine/unixlib.h"
+struct wine_get_firmware_variable_params +{ + LPCSTR name; + LPCSTR guid; + PVOID buffer; + DWORD size; + PDWORD attributes; + DWORD status; +}; + enum kernel32_unix_func { kernel32_unix_func_get_firmware_type, + kernel32_unix_func_get_firmware_variable, };
extern unixlib_handle_t __wine_unixlib_handle;
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=148139
Your paranoid android.
=== debian11 (build log) ===
/home/winetest/tools/testbot/var/wine-win32/../wine/dlls/winecrt0/unix_lib.c:52: undefined reference to `_imp__LdrGetDllHandle@16' /usr/bin/i686-w64-mingw32-ld: /home/winetest/tools/testbot/var/wine-win32/../wine/dlls/winecrt0/unix_lib.c:53: undefined reference to `_imp__RtlFindExportedRoutineByName@8' /home/winetest/tools/testbot/var/wine-win32/../wine/dlls/winecrt0/unix_lib.c:94: undefined reference to `_imp__NtQueryVirtualMemory@24' collect2: error: ld returned 1 exit status Task: The win32 Wine build failed
=== debian11b (build log) ===
/home/winetest/tools/testbot/var/wine-wow64/../wine/dlls/winecrt0/unix_lib.c:52: undefined reference to `__imp_LdrGetDllHandle' /usr/bin/x86_64-w64-mingw32-ld: /home/winetest/tools/testbot/var/wine-wow64/../wine/dlls/winecrt0/unix_lib.c:53: undefined reference to `__imp_RtlFindExportedRoutineByName' /home/winetest/tools/testbot/var/wine-wow64/../wine/dlls/winecrt0/unix_lib.c:94: undefined reference to `__imp_NtQueryVirtualMemory' collect2: error: ld returned 1 exit status Task: The wow64 Wine build failed
On Sun Sep 1 19:47:37 2024 +0000, Grigory Vasilyev wrote:
I think it's worth waiting for the reviewers' comments on this matter.
Done.