You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在调用UEFI RT服务时阻止其他UEFI Runtime Services任务运行?

阻止其他UEFI Runtime服务调用的实现方案

以下从Linux侧和UEFI侧分别提供可落地的C语言实现方案,核心思路是通过钩子拦截+权限过滤,确保仅你的任务A能调用目标UEFI RT服务。

Linux侧实现

方案1:内核模块钩子(推荐,权限足够)

Linux内核维护着UEFI Runtime服务的函数表,通过内核模块可以直接替换目标服务的函数指针为自定义钩子,实现调用过滤。

示例代码(以拦截SetVariable服务为例):

#include <linux/module.h>
#include <linux/efi.h>
#include <linux/spinlock.h>

// 保存原始服务函数指针
static EFI_STATUS (*orig_set_var)(const efi_char16_t *, const efi_guid_t *, u32, unsigned long, const void *);
static DEFINE_SPINLOCK(efi_service_lock);
// 任务A的唯一标识(自定义GUID)
static const efi_guid_t my_task_a_guid = {0x12345678, 0x1234, 0x1234, {0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef}};

// 自定义钩子函数
static EFI_STATUS hook_set_var(const efi_char16_t *var_name, const efi_guid_t *vendor_guid,
                               u32 attrs, unsigned long data_size, const void *data)
{
    unsigned long flags;
    spin_lock_irqsave(&efi_service_lock, flags);

    // 仅允许任务A的调用通过(通过GUID判断)
    if (efi_guidcmp(vendor_guid, &my_task_a_guid) == 0) {
        EFI_STATUS ret = orig_set_var(var_name, vendor_guid, attrs, data_size, data);
        spin_unlock_irqrestore(&efi_service_lock, flags);
        return ret;
    } else {
        // 拒绝其他调用,返回权限错误
        spin_unlock_irqrestore(&efi_service_lock, flags);
        return EFI_ACCESS_DENIED;
    }
}

static int __init efi_hook_init(void)
{
    // 获取原始服务指针
    orig_set_var = efi.runtime->set_variable;
    // 替换为钩子函数
    efi.runtime->set_variable = hook_set_var;
    pr_info("UEFI SetVariable hooked successfully\n");
    return 0;
}

static void __exit efi_hook_exit(void)
{
    // 恢复原始服务指针
    efi.runtime->set_variable = orig_set_var;
    pr_info("UEFI SetVariable hook removed\n");
}

module_init(efi_hook_init);
module_exit(efi_hook_exit);
MODULE_LICENSE("GPL");

方案2:用户空间包装(需内核配合)

如果无法编写内核模块,可在用户空间通过包装efi_call_runtime_service宏,加入互斥锁和调用过滤,但需确保内核未限制对EFI服务表的修改(部分内核版本会保护该区域)。

示例代码:

#include <pthread.h>
#include <efi.h>
#include <efilib.h>

pthread_mutex_t efi_lock = PTHREAD_MUTEX_INITIALIZER;
// 任务A的GUID
static const EFI_GUID my_task_a_guid = {0x12345678, 0x1234, 0x1234, {0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef}};

// 包装SetVariable调用
EFI_STATUS my_set_variable(CHAR16 *var_name, EFI_GUID *vendor_guid, UINT32 attrs, UINTN data_size, VOID *data)
{
    pthread_mutex_lock(&efi_lock);

    if (!CompareGuid(vendor_guid, &my_task_a_guid)) {
        pthread_mutex_unlock(&efi_lock);
        return EFI_ACCESS_DENIED;
    }

    EFI_STATUS ret = efi_call_runtime_service(SetVariable, var_name, vendor_guid, attrs, data_size, data);
    pthread_mutex_unlock(&efi_lock);
    return ret;
}

// 任务A代码
void task_a()
{
    CHAR16 var_name[] = L"MyTaskAVar";
    UINT8 data = 0xAA;
    my_set_variable(var_name, (EFI_GUID*)&my_task_a_guid, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, 1, &data);
}

UEFI侧实现

从固件层面修改RT服务,是最彻底的拦截方案,需编写UEFI Runtime Driver并加载到固件中。

示例代码(拦截SetVariable服务):

#include <Uefi.h>
#include <Library/UefiRuntimeServicesTableLib.h>
#include <Library/UefiLib.h>

// 保存原始服务指针
static EFI_SET_VARIABLE OriginalSetVariable;
// EFI Runtime可用的锁(必须用EFI提供的锁,不能用普通互斥锁)
static EFI_LOCK ServiceLock = EFI_INITIALIZE_LOCK_VARIABLE;
// 任务A的唯一GUID
static CONST EFI_GUID MyTaskAGuid = {0x12345678, 0x1234, 0x1234, {0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef}};

// 自定义包装服务函数
EFI_STATUS EFIAPI WrappedSetVariable(
    IN CHAR16 *VariableName,
    IN EFI_GUID *VendorGuid,
    IN UINT32 Attributes,
    IN UINTN DataSize,
    IN VOID *Data
)
{
    EFI_STATUS Status;

    EfiAcquireLock(&ServiceLock);

    // 仅允许任务A的调用
    if (!CompareGuid(VendorGuid, &MyTaskAGuid)) {
        EfiReleaseLock(&ServiceLock);
        return EFI_ACCESS_DENIED;
    }

    // 调用原始服务
    Status = OriginalSetVariable(VariableName, VendorGuid, Attributes, DataSize, Data);

    EfiReleaseLock(&ServiceLock);
    return Status;
}

// Runtime Driver入口
EFI_STATUS EFIAPI MyRuntimeDriverEntry(
    IN EFI_HANDLE ImageHandle,
    IN EFI_SYSTEM_TABLE *SystemTable
)
{
    // 保存原始服务指针
    OriginalSetVariable = gRT->SetVariable;
    // 替换为包装函数
    gRT->SetVariable = WrappedSetVariable;

    return EFI_SUCCESS;
}

方案优缺点对比

方案优点缺点
Linux内核模块无需修改固件,权限足够内核版本兼容性需注意
Linux用户空间实现简单,无内核编译依赖可能受内核内存保护限制
UEFI侧修改拦截最彻底,无Linux依赖需要固件开发/修改权限,适配不同固件难度高

内容的提问来源于stack exchange,提问作者user8292736

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 21:15:40