summaryrefslogtreecommitdiffstats
path: root/src/detection/bootmgr
diff options
context:
space:
mode:
authorsumuel <samuel@yakubos.org>2026-08-17 20:44:55 +0000
committersumuel <samuel@yakubos.org>2026-08-17 20:44:55 +0000
commit76424950e373d3b04ac3dd13019151bfba3e8423 (patch)
tree4c3cfdbda039e592b9186be3e28f8d7cfd439e8a /src/detection/bootmgr
Add the files
Diffstat (limited to 'src/detection/bootmgr')
-rw-r--r--src/detection/bootmgr/bootmgr.c44
-rw-r--r--src/detection/bootmgr/bootmgr.h13
-rw-r--r--src/detection/bootmgr/bootmgr_apple.c69
-rw-r--r--src/detection/bootmgr/bootmgr_bsd.c62
-rw-r--r--src/detection/bootmgr/bootmgr_haiku.cpp17
-rw-r--r--src/detection/bootmgr/bootmgr_linux.c32
-rw-r--r--src/detection/bootmgr/bootmgr_nosupport.c5
-rw-r--r--src/detection/bootmgr/bootmgr_windows.c74
-rw-r--r--src/detection/bootmgr/efi_helper.h22
9 files changed, 338 insertions, 0 deletions
diff --git a/src/detection/bootmgr/bootmgr.c b/src/detection/bootmgr/bootmgr.c
new file mode 100644
index 0000000..31838d4
--- /dev/null
+++ b/src/detection/bootmgr/bootmgr.c
@@ -0,0 +1,44 @@
+#include "efi_helper.h"
+
+static inline uint8_t evBits(uint16_t val, uint8_t mask, uint8_t shift) {
+ return (uint8_t) ((val & (mask << shift)) >> shift);
+}
+
+static void ffEfiUcs2ToUtf8(const uint16_t* const chars, FFstrbuf* result) {
+ for (uint32_t i = 0; chars[i]; i++) {
+ if (chars[i] <= 0x007f) {
+ ffStrbufAppendC(result, (char) chars[i]);
+ } else if (chars[i] > 0x007f && chars[i] <= 0x07ff) {
+ ffStrbufAppendC(result, (char) (0xc0 | evBits(chars[i], 0x1f, 6)));
+ ffStrbufAppendC(result, (char) (0x80 | evBits(chars[i], 0x3f, 0)));
+ } else {
+ ffStrbufAppendC(result, (char) (0xe0 | evBits(chars[i], 0xf, 12)));
+ ffStrbufAppendC(result, (char) (0x80 | evBits(chars[i], 0x3f, 6)));
+ ffStrbufAppendC(result, (char) (0x80 | evBits(chars[i], 0x3f, 0)));
+ }
+ }
+}
+
+bool ffEfiFillLoadOption(const FFEfiLoadOption* efiOption, FFBootmgrResult* result) {
+ uint32_t descLen = 0;
+ while (efiOption->Description[descLen]) {
+ ++descLen;
+ }
+
+ if (descLen) {
+ ffEfiUcs2ToUtf8(efiOption->Description, &result->name);
+ }
+
+ for (
+ ffEfiDevicePathProtocol* filePathList = (ffEfiDevicePathProtocol*) &efiOption->Description[descLen + 1];
+ filePathList->Type != 0x7F; // End of Hardware Device Path
+ filePathList = (ffEfiDevicePathProtocol*) ((uint8_t*) filePathList + filePathList->Length)) {
+ if (filePathList->Type == 4 && filePathList->SubType == 4) {
+ // https://uefi.org/specs/UEFI/2.10/10_Protocols_Device_Path_Protocol.html#file-path-media-device-path
+ ffEfiUcs2ToUtf8((uint16_t*) filePathList->SpecificDevicePathData, &result->firmware);
+ return true;
+ }
+ }
+
+ return false;
+}
diff --git a/src/detection/bootmgr/bootmgr.h b/src/detection/bootmgr/bootmgr.h
new file mode 100644
index 0000000..055b0ee
--- /dev/null
+++ b/src/detection/bootmgr/bootmgr.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include "fastfetch.h"
+#include "modules/bootmgr/option.h"
+
+typedef struct FFBootmgrResult {
+ FFstrbuf name;
+ FFstrbuf firmware;
+ uint16_t order;
+ bool secureBoot;
+} FFBootmgrResult;
+
+const char* ffDetectBootmgr(FFBootmgrResult* bios);
diff --git a/src/detection/bootmgr/bootmgr_apple.c b/src/detection/bootmgr/bootmgr_apple.c
new file mode 100644
index 0000000..d2b24e0
--- /dev/null
+++ b/src/detection/bootmgr/bootmgr_apple.c
@@ -0,0 +1,69 @@
+#include "bootmgr.h"
+#include "common/io.h"
+#include "common/apple/cf_helpers.h"
+
+#include <IOKit/IOKitLib.h>
+
+static const char* detectSecureBoot(bool* result) {
+#if __aarch64__
+ FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t entryDevice = IORegistryEntryFromPath(MACH_PORT_NULL, "IODeviceTree:/chosen");
+ if (!entryDevice) {
+ return "IORegistryEntryFromPath() failed";
+ }
+
+ FF_CFTYPE_AUTO_RELEASE CFTypeRef prop = IORegistryEntryCreateCFProperty(entryDevice, CFSTR("secure-boot"), kCFAllocatorDefault, kNilOptions);
+ if (!prop) {
+ return "IORegistryEntryCreateCFProperty() failed";
+ }
+
+ if (CFGetTypeID(prop) != CFDataGetTypeID() || CFDataGetLength((CFDataRef) prop) == 0) {
+ return "Invalid secure-boot property";
+ }
+
+ *result = (bool) *CFDataGetBytePtr((CFDataRef) prop);
+#else
+ FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t entryDevice = IORegistryEntryFromPath(MACH_PORT_NULL, "IODeviceTree:/options");
+ if (!entryDevice) {
+ return "IORegistryEntryFromPath() failed";
+ }
+
+ FF_CFTYPE_AUTO_RELEASE CFTypeRef prop = IORegistryEntryCreateCFProperty(entryDevice, CFSTR("94b73556-2197-4702-82a8-3e1337dafbfb:AppleSecureBootPolicy"), kCFAllocatorDefault, 0);
+ if (!prop) {
+ return "IORegistryEntryCreateCFProperty() failed";
+ }
+
+ if (CFGetTypeID(prop) != CFDataGetTypeID() || CFDataGetLength((CFDataRef) prop) == 0) {
+ return "Invalid secure-boot property";
+ }
+
+ *result = *CFDataGetBytePtr((CFDataRef) prop) != 0x02 /* Permissive Security */;
+#endif
+
+ return NULL;
+}
+
+const char* ffDetectBootmgr(FFBootmgrResult* result) {
+ if (ffPathExists("/System/Library/CoreServices/boot.efi", FF_PATHTYPE_FILE)) {
+ ffStrbufSetStatic(&result->firmware, "/System/Library/CoreServices/boot.efi");
+ }
+
+ #ifdef __aarch64__
+ FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t deviceChosen = IORegistryEntryFromPath(MACH_PORT_NULL, "IODeviceTree:/chosen");
+ if (deviceChosen) {
+ FF_CFTYPE_AUTO_RELEASE CFStringRef tag = IORegistryEntryCreateCFProperty(deviceChosen, CFSTR("iboot-stage-two-tag"), kCFAllocatorDefault, kNilOptions)
+ ?: IORegistryEntryCreateCFProperty(deviceChosen, CFSTR("system-firmware-version"), kCFAllocatorDefault, kNilOptions);
+ if (tag) {
+ ffCfStrGetString(tag, &result->name);
+ ffStrbufSubstrBeforeFirstC(&result->name, '-');
+ }
+ }
+ #endif
+
+ if (!result->name.length) {
+ ffStrbufSetStatic(&result->name, "iBoot");
+ }
+
+ detectSecureBoot(&result->secureBoot);
+
+ return NULL;
+}
diff --git a/src/detection/bootmgr/bootmgr_bsd.c b/src/detection/bootmgr/bootmgr_bsd.c
new file mode 100644
index 0000000..cfaa41d
--- /dev/null
+++ b/src/detection/bootmgr/bootmgr_bsd.c
@@ -0,0 +1,62 @@
+#include "bootmgr.h"
+#include "efi_helper.h"
+#include "common/io.h"
+
+#ifdef __OpenBSD__
+ #include <dev/efi/efiio.h>
+#else
+ #include <sys/efiio.h>
+#endif
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <stdalign.h>
+
+#ifdef __NetBSD__
+typedef uint16_t efi_char;
+#endif
+
+#ifndef EFI_GLOBAL_VARIABLE
+ #define EFI_GLOBAL_VARIABLE { 0x8be4df61, 0x93ca, 0x11d2, 0xaa, 0x0d, { 0x00, 0xe0, 0x98, 0x03, 0x2b, 0x8c } }
+#endif
+
+const char* ffDetectBootmgr(FFBootmgrResult* result) {
+ FF_AUTO_CLOSE_FD int efifd = open("/dev/efi", O_RDWR | O_CLOEXEC);
+ if (efifd < 0) {
+ return "open(/dev/efi) failed";
+ }
+
+ alignas(uint16_t) uint8_t buffer[2048];
+ struct efi_var_ioc ioc = {
+ .vendor = EFI_GLOBAL_VARIABLE,
+ .data = buffer,
+ };
+
+ ioc.datasize = sizeof(buffer);
+ ioc.name = (efi_char[]) { 'B', 'o', 'o', 't', 'C', 'u', 'r', 'r', 'e', 'n', 't', '\0' };
+ ioc.namesize = sizeof("BootCurrent") * 2;
+ if (ioctl(efifd, EFIIOC_VAR_GET, &ioc) < 0 || ioc.datasize != 2) {
+ return "ioctl(EFIIOC_VAR_GET, BootCurrent) failed";
+ }
+
+ result->order = *(uint16_t*) buffer;
+
+ unsigned char hex[5];
+ snprintf((char*) hex, sizeof(hex), "%04X", result->order);
+ ioc.datasize = sizeof(buffer);
+ ioc.name = (efi_char[]) { 'B', 'o', 'o', 't', hex[0], hex[1], hex[2], hex[3], '\0' };
+ ioc.namesize = sizeof("Boot####") * 2;
+ if (ioctl(efifd, EFIIOC_VAR_GET, &ioc) < 0 || ioc.datasize == sizeof(buffer)) {
+ return "ioctl(EFIIOC_VAR_GET, Boot####) failed";
+ }
+
+ ffEfiFillLoadOption((FFEfiLoadOption*) buffer, result);
+
+ ioc.name = (efi_char[]) { 'S', 'e', 'c', 'u', 'r', 'e', 'B', 'o', 'o', 't', '\0' };
+ ioc.namesize = sizeof("SecureBoot") * 2;
+ ioc.datasize = sizeof(buffer);
+ if (ioctl(efifd, EFIIOC_VAR_GET, &ioc) == 0 && ioc.datasize == 1) {
+ result->secureBoot = !!buffer[0];
+ }
+
+ return NULL;
+}
diff --git a/src/detection/bootmgr/bootmgr_haiku.cpp b/src/detection/bootmgr/bootmgr_haiku.cpp
new file mode 100644
index 0000000..72358fc
--- /dev/null
+++ b/src/detection/bootmgr/bootmgr_haiku.cpp
@@ -0,0 +1,17 @@
+extern "C" {
+ #include "bootmgr.h"
+ #include "common/io.h"
+}
+
+const char* ffDetectBootmgr(FFBootmgrResult* result) {
+ // TODO: glob haiku_loader.* + check EFI partition
+ if (ffPathExists("/system/haiku_loader.bios_ia32", FF_PATHTYPE_FILE)) {
+ ffStrbufSetStatic(&result->firmware, "/system/haiku_loader.bios_ia32");
+ }
+
+ ffStrbufSetStatic(&result->name, "haiku_loader");
+
+ // TODO: detectSecureBoot(&result->secureBoot);
+
+ return NULL;
+}
diff --git a/src/detection/bootmgr/bootmgr_linux.c b/src/detection/bootmgr/bootmgr_linux.c
new file mode 100644
index 0000000..0fd019a
--- /dev/null
+++ b/src/detection/bootmgr/bootmgr_linux.c
@@ -0,0 +1,32 @@
+#include "bootmgr.h"
+#include "common/io.h"
+#include "efi_helper.h"
+
+#include <stdalign.h>
+
+#define FF_EFIVARS_PATH_PREFIX "/sys/firmware/efi/efivars/"
+
+const char* ffDetectBootmgr(FFBootmgrResult* result) {
+ alignas(uint16_t) uint8_t buffer[2048];
+
+ if (ffReadFileData(FF_EFIVARS_PATH_PREFIX "BootCurrent-" FF_EFI_GLOBAL_GUID, sizeof(buffer), buffer) != 6) {
+ return "Failed to read efivar: BootCurrent";
+ }
+
+ result->order = *(uint16_t*) &buffer[4];
+
+ snprintf((char*) buffer, sizeof(buffer), FF_EFIVARS_PATH_PREFIX "Boot%04X-" FF_EFI_GLOBAL_GUID, result->order);
+
+ ssize_t size = ffReadFileData((const char*) buffer, sizeof(buffer), buffer);
+ if (size < 5 + (int) sizeof(FFEfiLoadOption) || size == (ssize_t) sizeof(buffer)) {
+ return "Failed to read efivar: Boot####";
+ }
+
+ ffEfiFillLoadOption((FFEfiLoadOption*) &buffer[4], result);
+
+ if (ffReadFileData(FF_EFIVARS_PATH_PREFIX "SecureBoot-" FF_EFI_GLOBAL_GUID, sizeof(buffer), buffer) >= 5) {
+ result->secureBoot = buffer[4] == 1;
+ }
+
+ return NULL;
+}
diff --git a/src/detection/bootmgr/bootmgr_nosupport.c b/src/detection/bootmgr/bootmgr_nosupport.c
new file mode 100644
index 0000000..bb01714
--- /dev/null
+++ b/src/detection/bootmgr/bootmgr_nosupport.c
@@ -0,0 +1,5 @@
+#include "bootmgr.h"
+
+const char* ffDetectBootmgr(FF_A_UNUSED FFBootmgrResult* result) {
+ return "Not supported on this platform";
+}
diff --git a/src/detection/bootmgr/bootmgr_windows.c b/src/detection/bootmgr/bootmgr_windows.c
new file mode 100644
index 0000000..e83e1e2
--- /dev/null
+++ b/src/detection/bootmgr/bootmgr_windows.c
@@ -0,0 +1,74 @@
+#include "bootmgr.h"
+#include "efi_helper.h"
+#include "common/io.h"
+#include "common/windows/nt.h"
+
+#include <ntstatus.h>
+#include <windows.h>
+
+const char* enablePrivilege(const wchar_t* privilege) {
+ FF_AUTO_CLOSE_FD HANDLE token = NULL;
+ if (!NT_SUCCESS(NtOpenProcessToken(NtCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &token))) {
+ return "NtOpenProcessToken() failed";
+ }
+
+ TOKEN_PRIVILEGES tp = {
+ .PrivilegeCount = 1,
+ .Privileges = {
+ (LUID_AND_ATTRIBUTES) { .Attributes = SE_PRIVILEGE_ENABLED } },
+ };
+ if (!LookupPrivilegeValueW(NULL, privilege, &tp.Privileges[0].Luid)) {
+ return "LookupPrivilegeValue() failed";
+ }
+
+ NTSTATUS status = NtAdjustPrivilegesToken(token, false, &tp, sizeof(tp), NULL, NULL);
+ if (!NT_SUCCESS(status)) {
+ return "NtAdjustPrivilegesToken() failed";
+ }
+
+ if (status == STATUS_NOT_ALL_ASSIGNED) {
+ return "The token does not have the specified privilege; try sudo please";
+ }
+
+ return NULL;
+}
+
+const char* ffDetectBootmgr(FFBootmgrResult* result) {
+ const char* err = enablePrivilege(L"SeSystemEnvironmentPrivilege");
+ if (err != NULL) {
+ return err;
+ }
+
+ GUID efiGlobalGuid;
+ if (!NT_SUCCESS(RtlGUIDFromString(&(UNICODE_STRING) RTL_CONSTANT_STRING(L"{" FF_EFI_GLOBAL_GUID L"}"), &efiGlobalGuid))) {
+ return "RtlGUIDFromString() failed";
+ }
+
+ ULONG size = sizeof(result->order);
+ if (!NT_SUCCESS(NtQuerySystemEnvironmentValueEx(&(UNICODE_STRING) RTL_CONSTANT_STRING(L"BootCurrent"), &efiGlobalGuid, &result->order, &size, NULL))) {
+ return "NtQuerySystemEnvironmentValueEx(BootCurrent) failed";
+ }
+ if (size != sizeof(result->order)) {
+ return "NtQuerySystemEnvironmentValueEx(BootCurrent) returned unexpected size";
+ }
+
+ uint8_t buffer[2048];
+ wchar_t key[9];
+ swprintf(key, ARRAY_SIZE(key), L"Boot%04X", result->order);
+ size = sizeof(buffer);
+ if (!NT_SUCCESS(NtQuerySystemEnvironmentValueEx(&(UNICODE_STRING) RTL_CONSTANT_STRING(key), &efiGlobalGuid, buffer, &size, NULL))) {
+ return "NtQuerySystemEnvironmentValueEx(Boot####) failed";
+ }
+ if (size < sizeof(FFEfiLoadOption) || size == ARRAY_SIZE(buffer)) {
+ return "NtQuerySystemEnvironmentValueEx(Boot####) returned unexpected size";
+ }
+
+ ffEfiFillLoadOption((FFEfiLoadOption*) buffer, result);
+
+ SYSTEM_SECUREBOOT_INFORMATION ssi;
+ if (NT_SUCCESS(NtQuerySystemInformation(SystemSecureBootInformation, &ssi, sizeof(ssi), NULL))) {
+ result->secureBoot = ssi.SecureBootEnabled;
+ }
+
+ return NULL;
+}
diff --git a/src/detection/bootmgr/efi_helper.h b/src/detection/bootmgr/efi_helper.h
new file mode 100644
index 0000000..b52ec8a
--- /dev/null
+++ b/src/detection/bootmgr/efi_helper.h
@@ -0,0 +1,22 @@
+#include "bootmgr.h"
+
+// https://uefi.org/specs/UEFI/2.10/10_Protocols_Device_Path_Protocol.html#generic-device-path-structures
+typedef struct ffEfiDevicePathProtocol {
+ uint8_t Type;
+ uint8_t SubType;
+ uint16_t Length;
+ uint8_t SpecificDevicePathData[];
+} ffEfiDevicePathProtocol;
+
+// https://uefi.org/specs/UEFI/2.10/03_Boot_Manager.html#load-options
+typedef struct FFEfiLoadOption {
+ uint32_t Attributes;
+ uint16_t FilePathListLength;
+ uint16_t Description[];
+ // ffEfiDevicePathProtocol FilePathList[];
+ // uint8_t OptionalData[];
+} FFEfiLoadOption;
+
+bool ffEfiFillLoadOption(const FFEfiLoadOption* efiOption, FFBootmgrResult* result);
+
+#define FF_EFI_GLOBAL_GUID "8be4df61-93ca-11d2-aa0d-00e098032b8c"