* [PATCH] lkdtm: Add more EFI runtime tests
@ 2026-10-11 11:40 Ard Biesheuvel
2026-10-12 17:07 ` Kees Cook
0 siblings, 1 reply; 4+ messages in thread
From: Ard Biesheuvel @ 2026-10-11 11:40 UTC (permalink / raw)
To: linux-efi; +Cc: linux-kernel, kees, Ard Biesheuvel
Two bugs were found in the arm64 EFI runtime support that weren't caught
by LKDTM. The existing EFI_RUNTIME_CRASH test instructs the firmware to
write to kernel memory that is mapped read-only, which usually fails as
expected. However, this does not exercise the runtime mapping logic in
the kernel, nor the fault recovery logic when the faulting address is
inside the EFI runtime memory regions itself.
So add two more test cases:
- a write to R/O memory test that uses the firmware's own executable
memory as an output buffer
- a branch to memory that is occupied by the firmware's runtime services
function table, which is usually mapped non-execute.
This depends on the EFI memory attributes table having been exposed by
the firmware and having been taken into account by the runtime mapping
code, so this is used as a prerequisite by the new tests, otherwise it
produces an XFAIL.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
drivers/firmware/efi/runtime-wrappers.c | 55 ++++++++++++++++++++
drivers/misc/lkdtm/bugs.c | 23 ++++++++
include/linux/efi.h | 10 ++++
3 files changed, 88 insertions(+)
diff --git a/drivers/firmware/efi/runtime-wrappers.c b/drivers/firmware/efi/runtime-wrappers.c
index 33f256dd3d2c..7a43ea5f81b5 100644
--- a/drivers/firmware/efi/runtime-wrappers.c
+++ b/drivers/firmware/efi/runtime-wrappers.c
@@ -337,6 +337,29 @@ static void __nocfi efi_call_rts(struct work_struct *work)
* function identifier into efi_rts_work->efi_rts_id
*/
pr_err("Requested executing invalid EFI Runtime Service.\n");
+ break;
+
+#ifdef CONFIG_LKDTM
+ case EFI_LKDTM_RUNTIME_RO_TEST:
+ /*
+ * Call GetTime() with the output argument pointing to
+ * executable memory, which should be mapped read-only in the
+ * EFI page tables.
+ */
+ status = arch_efi_call_virt(efi.runtime, get_time,
+ (void *)efi.runtime->set_time,
+ NULL);
+ break;
+ case EFI_LKDTM_RUNTIME_NX_TEST:
+ /*
+ * Call efi.runtime, which points to a data object in a EFI
+ * runtime region, as if it were a function pointer.
+ */
+ struct { efi_status_t (__efiapi *fn)(int); } s = { (void *)efi.runtime };
+
+ status = arch_efi_call_virt((&s), fn, 0);
+ break;
+#endif
}
efi_call_virt_check_flags(flags, efi_rts_work.caller);
@@ -624,6 +647,34 @@ static efi_status_t virt_efi_query_capsule_caps(efi_capsule_header_t **capsules,
return status;
}
+#ifdef CONFIG_LKDTM
+static efi_status_t efi_lkdtm_rt_test(enum efi_rts_ids id)
+{
+ efi_status_t status;
+
+ switch (id) {
+ case EFI_LKDTM_RUNTIME_RO_TEST:
+ if (!efi.get_time ||
+ !efi_rt_services_supported(EFI_RT_SUPPORTED_GET_TIME))
+ return EFI_UNSUPPORTED;
+ fallthrough;
+ case EFI_LKDTM_RUNTIME_NX_TEST:
+ if (!efi_enabled(EFI_MEM_ATTR) ||
+ !efi_enabled(EFI_RUNTIME_SERVICES))
+ return EFI_UNSUPPORTED;
+ break;
+ default:
+ return EFI_UNSUPPORTED;
+ }
+
+ if (down_interruptible(&efi_runtime_lock))
+ return EFI_NOT_READY;
+ status = __efi_queue_work(id, NULL);
+ up(&efi_runtime_lock);
+ return status;
+}
+#endif
+
void __init efi_native_runtime_setup(void)
{
efi.get_time = virt_efi_get_time;
@@ -640,6 +691,10 @@ void __init efi_native_runtime_setup(void)
efi.query_variable_info_nonblocking = virt_efi_query_variable_info_nb;
efi.update_capsule = virt_efi_update_capsule;
efi.query_capsule_caps = virt_efi_query_capsule_caps;
+
+#ifdef CONFIG_LKDTM
+ efi.lkdtm_rt_test = efi_lkdtm_rt_test;
+#endif
}
#ifdef CONFIG_ACPI_PRMT
diff --git a/drivers/misc/lkdtm/bugs.c b/drivers/misc/lkdtm/bugs.c
index 3eca2ef64aff..7bcd88d05505 100644
--- a/drivers/misc/lkdtm/bugs.c
+++ b/drivers/misc/lkdtm/bugs.c
@@ -841,6 +841,27 @@ static void __maybe_unused lkdtm_EFI_RUNTIME_CRASH(void)
status);
}
+static void efi_rt_test(enum efi_rts_ids id, const char *desc)
+{
+ efi_status_t status = efi.lkdtm_rt_test(id);
+
+ if (status == EFI_UNSUPPORTED)
+ pr_err("XFAIL: Test not supported on this configuration\n");
+ else if (status != EFI_ABORTED || efi_enabled(EFI_RUNTIME_SERVICES))
+ pr_err("FAIL: EFI %s memory not caught (%#lx)\n",
+ desc, status);
+}
+
+static void __maybe_unused lkdtm_EFI_RUNTIME_WRITE_TO_RO(void)
+{
+ efi_rt_test(EFI_LKDTM_RUNTIME_RO_TEST, "write to RO");
+}
+
+static void __maybe_unused lkdtm_EFI_RUNTIME_BRANCH_TO_NX(void)
+{
+ efi_rt_test(EFI_LKDTM_RUNTIME_NX_TEST, "branch to NX");
+}
+
static struct crashtype crashtypes[] = {
CRASHTYPE(PANIC),
CRASHTYPE(PANIC_STOP_IRQOFF),
@@ -876,6 +897,8 @@ static struct crashtype crashtypes[] = {
CRASHTYPE(CORRUPT_PAC),
#ifdef CONFIG_EFI
CRASHTYPE(EFI_RUNTIME_CRASH),
+ CRASHTYPE(EFI_RUNTIME_WRITE_TO_RO),
+ CRASHTYPE(EFI_RUNTIME_BRANCH_TO_NX),
#endif
};
diff --git a/include/linux/efi.h b/include/linux/efi.h
index fda81d7c4850..dfdb3352ad9d 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -631,6 +631,8 @@ typedef struct {
extern unsigned long __ro_after_init efi_rng_seed; /* RNG Seed table */
+enum efi_rts_ids;
+
/*
* All runtime access to EFI goes through this structure:
*/
@@ -666,6 +668,10 @@ extern struct efi {
efi_get_next_high_mono_count_t *get_next_high_mono_count;
efi_reset_system_t *reset_system;
+#ifdef CONFIG_LKDTM
+ efi_status_t (*lkdtm_rt_test)(enum efi_rts_ids id);
+#endif
+
struct efi_memory_map memmap;
unsigned long flags;
} efi;
@@ -1253,6 +1259,10 @@ enum efi_rts_ids {
EFI_UPDATE_CAPSULE,
EFI_QUERY_CAPSULE_CAPS,
EFI_ACPI_PRM_HANDLER,
+#ifdef CONFIG_LKDTM
+ EFI_LKDTM_RUNTIME_RO_TEST,
+ EFI_LKDTM_RUNTIME_NX_TEST,
+#endif
};
union efi_rts_args;
--
2.56.0.385.gd3acb90ef8-goog
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH] lkdtm: Add more EFI runtime tests
@ 2026-10-11 14:48 MaeeFilho FL
2026-10-12 5:23 ` Ard Biesheuvel
0 siblings, 1 reply; 4+ messages in thread
From: MaeeFilho FL @ 2026-10-11 14:48 UTC (permalink / raw)
To: Ard Biesheuvel; +Cc: linux-efi, linux-kernel, Kees Cook
Hi Ard,
The Code is excellent. A few points worth highlighting:
> Two bugs were found in the arm64 EFI runtime support that weren't caught
> by LKDTM. The existing EFI_RUNTIME_CRASH test instructs the firmware to
> write to kernel memory that is mapped read-only, which usually fails as
> expected. However, this does not exercise the runtime mapping logic in
> the kernel, nor the fault recovery logic when the faulting address is
> inside the EFI runtime memory regions itself.
>
> So add two more test cases:
> - a write to R/O memory test that uses the firmware's own executable
> memory as an output buffer
> - a branch to memory that is occupied by the firmware's runtime services
> function table, which is usually mapped non-execute.
This is an excellent addition to the LKDTM suite. Forcing GetTime() to
target efi.runtime->set_time is a very clever way to ensure that the
firmware page tables are strictly enforcing permissions over its own
executable boundaries, rather than just testing general kernel mappings.
The execution tracking via the anonymous function pointer struct conversion
to trap NX faults on efi.runtime data object is also rock solid and properly
exercises the arm64 translation tables validation logic.
Reviewed-by: João Guilherme da Silva Freitas Lima <joaoanandalima@gmail.com>
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] lkdtm: Add more EFI runtime tests
2026-10-11 14:48 MaeeFilho FL
@ 2026-10-12 5:23 ` Ard Biesheuvel
0 siblings, 0 replies; 4+ messages in thread
From: Ard Biesheuvel @ 2026-10-12 5:23 UTC (permalink / raw)
To: MaeeFilho FL; +Cc: linux-efi, linux-kernel, Kees Cook
On Sun, 11 Oct 2026, at 16:48, MaeeFilho FL wrote:
> Hi Ard,
>
> The Code is excellent. A few points worth highlighting:
>
>> Two bugs were found in the arm64 EFI runtime support that weren't caught
>> by LKDTM. The existing EFI_RUNTIME_CRASH test instructs the firmware to
>> write to kernel memory that is mapped read-only, which usually fails as
>> expected. However, this does not exercise the runtime mapping logic in
>> the kernel, nor the fault recovery logic when the faulting address is
>> inside the EFI runtime memory regions itself.
>>
>> So add two more test cases:
>> - a write to R/O memory test that uses the firmware's own executable
>> memory as an output buffer
>> - a branch to memory that is occupied by the firmware's runtime services
>> function table, which is usually mapped non-execute.
>
> This is an excellent addition to the LKDTM suite. Forcing GetTime() to
> target efi.runtime->set_time is a very clever way to ensure that the
> firmware page tables are strictly enforcing permissions over its own
> executable boundaries, rather than just testing general kernel mappings.
>
> The execution tracking via the anonymous function pointer struct conversion
> to trap NX faults on efi.runtime data object is also rock solid and properly
> exercises the arm64 translation tables validation logic.
>
> Reviewed-by: João Guilherme da Silva Freitas Lima <joaoanandalima@gmail.com>
Thanks, but next time, please don't bother with the LLM generated reviews
unless there is actionable feedback.
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] lkdtm: Add more EFI runtime tests
2026-10-11 11:40 [PATCH] lkdtm: Add more EFI runtime tests Ard Biesheuvel
@ 2026-10-12 17:07 ` Kees Cook
0 siblings, 0 replies; 4+ messages in thread
From: Kees Cook @ 2026-10-12 17:07 UTC (permalink / raw)
To: Ard Biesheuvel, linux-efi; +Cc: linux-kernel
On October 11, 2026 4:40:14 AM PDT, Ard Biesheuvel <ardb@kernel.org> wrote:
>+static void efi_rt_test(enum efi_rts_ids id, const char *desc)
>+{
>+ efi_status_t status = efi.lkdtm_rt_test(id);
>+
>+ if (status == EFI_UNSUPPORTED)
>+ pr_err("XFAIL: Test not supported on this configuration\n");
I've tried to have more specific rationale for XFAIL reports. Like, I try to say what someone needs to do to make it not an XFAIL. Here that's running under EFI?
Otherwise looks good! If that message is made a little more "actionable", feel free to take via EFI:
Reviewed-by: Kees Cook <kees@kernel.org>
-Kees
--
Kees Cook
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-10-12 17:07 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-11 11:40 [PATCH] lkdtm: Add more EFI runtime tests Ard Biesheuvel
2026-10-12 17:07 ` Kees Cook
-- strict thread matches above, loose matches on Subject: below --
2026-10-11 14:48 MaeeFilho FL
2026-10-12 5:23 ` Ard Biesheuvel
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox