[PATCH v2 0/2] MR6423: kernel32: Implement GetFirmwareType, GetFirmwareEnvironmentVariable*
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. https://gitlab.winehq.org/wine/wine/-/merge_requests/6423
From: Grigory Vasilyev <h0tc0d3(a)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 */ -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/6423
From: Grigory Vasilyev <h0tc0d3(a)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; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/6423
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(a)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(a)8' /home/winetest/tools/testbot/var/wine-win32/../wine/dlls/winecrt0/unix_lib.c:94: undefined reference to `_imp__NtQueryVirtualMemory(a)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.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/6423#note_80635
participants (3)
-
Grigory Vasilyev -
Grigory Vasilyev (@h0tc0d3) -
Marvin