Devicetree
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Sven Peter" <sven@kernel.org>
Cc: conor+dt@kernel.org, robh@kernel.org, devicetree@vger.kernel.org
Subject: Re: [PATCH RFC 2/6] arm64/efi: Add and parse custom PSCI EFI configuration table
Date: Wed, 08 Jul 2026 07:39:02 +0000	[thread overview]
Message-ID: <20260708073902.E72301F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260708-efi-psci-v1-2-9efb3abf0e4c@kernel.org>

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] Unclamped `num_features` leads to out-of-bounds read of `efi_psci.features` array.
- [High] PSCI power-down calls (CPU_SUSPEND/CPU_OFF) bypass the `arm64_efi_psci_call` epilogue, causing a permanent `preempt_count` and `TTBR0` leak.
- [High] `arm64_efi_psci_call()` lacks validation of EFI runtime services state, leading to a translation fault and panic if booted with `efi=noruntime`.
--

--- Patch [2]: [PATCH RFC 2/6] arm64/efi: Add and parse custom PSCI EFI configuration table ---
commit fe3c6fc95ebeb940962943f65e4f442c468d4718
Author: Sven Peter <sven@kernel.org>

arm64/efi: Add and parse custom PSCI EFI configuration table

This commit adds a new custom EFI configuration table and extracts a
pointer to a PSCI handler. It invokes the handler under the EFI virtual
mapping as a plain call rather than through the runtime services dispatch.
This approach relies on the firmware to not use lazy state and to be
reentrant.

> diff --git a/arch/arm64/kernel/efi.c b/arch/arm64/kernel/efi.c
> index 30cd7f8043986..e40885567f9e9 100644
> --- a/arch/arm64/kernel/efi.c
> +++ b/arch/arm64/kernel/efi.c
[ ... ]
> @@ -242,6 +243,63 @@ bool efi_runtime_fixup_exception(struct pt_regs *regs, const char *msg)
>  /* EFI requires 8 KiB of stack space for runtime services */
>  static_assert(THREAD_SIZE >= SZ_8K);
>  
> +struct efi_psci_table efi_psci __ro_after_init;
> +static unsigned long efi_psci_handler_table __initdata = EFI_INVALID_TABLE_ADDR;
> +const efi_config_table_type_t efi_arch_tables[] __initconst = {
> +	{LINUX_EFI_ARM_PSCI_HANDLER_TABLE_GUID, &efi_psci_handler_table},
> +	{}
> +};
> +
> +static void __init arm64_efi_init_psci(void)
> +{
> +	struct efi_psci_table *psci;
> +
> +	if (efi_psci_handler_table == EFI_INVALID_TABLE_ADDR)
> +		return;
> +
> +	psci = early_memremap_ro(efi_psci_handler_table, sizeof(*psci));
> +	if (psci == NULL) {
> +		pr_warn("Unable to map PSCI table.\n");
> +		return;
> +	}
> +
> +	memcpy(&efi_psci, psci, sizeof(*psci));

[Severity: High]
Is it safe to copy the num_features field from untrusted firmware directly
into efi_psci without clamping it to EFI_PSCI_MAX_FN?

The destination structure defines features as a fixed-size array of size
EFI_PSCI_MAX_FN. If firmware provides a num_features value larger than
this, subsequent driver code relying on num_features to indicate the number
of valid entries could read past the end of the efi_psci object in .rodata.

Could we validate and clamp num_features here?

> +	early_memunmap(psci, sizeof(*psci));
> +}
> +
> +void __init arm64_efi_init(void)
> +{
> +	efi_init();
> +	arm64_efi_init_psci();
> +}
> +
> +unsigned long arm64_efi_psci_call(unsigned long function_id, unsigned long arg0,
> +				  unsigned long arg1, unsigned long arg2)
> +{
> +	unsigned long ret, flags;
> +
> +	/*
> +	 * Note that unlike for regular EFI runtime calls we don't have to save
> +	 * FP/SIMD state here because the handler ABI forbids using those.
> +	 * Likewise, we do not take any lock here because the handler has to be
> +	 * re-entrant. We couldn't take the sleeping efi_runtime_lock here
> +	 * anyway because we may be called from atomic context for cpuidle
> +	 * and CPU bring-up.
> +	 */
> +	local_irq_save(flags);
> +	efi_virtmap_load();
> +	uaccess_ttbr0_enable();
> +	post_ttbr_update_workaround();

[Severity: High]
What happens here if the system is booted with efi=noruntime?

If EFI runtime services are disabled, arm_enable_runtime_services() returns
early, and efi_mm.pgd is left as NULL. However, arm64_efi_init_psci()
parses the configuration table and registers the handler regardless of whether
efi_enabled(EFI_RUNTIME_SERVICES) is true.

When arm64_efi_psci_call() unconditionally invokes efi_virtmap_load(), it
would pass the NULL efi_mm.pgd to cpu_switch_mm(), programming a garbage
physical address into TTBR0_EL1. This could crash the system with a
translation fault when attempting to execute the unmapped EFI virtual address.

Should we check efi_enabled(EFI_RUNTIME_SERVICES) before registering the
handler or attempting to load the map?

> +
> +	ret = efi_psci.psci_handler(function_id, arg0, arg1, arg2);
> +
> +	uaccess_ttbr0_disable();
> +	efi_virtmap_unload();
> +	local_irq_restore(flags);

[Severity: High]
Can PSCI power-down calls (like CPU_SUSPEND or CPU_OFF) bypass this
epilogue?

efi_virtmap_load() calls preempt_disable(), and efi_virtmap_unload()
calls preempt_enable().

Successful CPU power-down calls do not return to the caller. For example, for
CPU_SUSPEND, execution resumes via the kernel's hardware reset vector
(cpu_resume), which bypasses this return path and jumps straight to the
caller of __cpu_suspend_enter.

As a result, the epilogue of arm64_efi_psci_call() is skipped entirely,
permanently leaking the +1 preempt_count and leaving TTBR0_EL1 incorrectly
mapped to efi_mm on the idle thread.

Is there a way to handle this bypass for suspend/off calls?

> +
> +	return ret;
> +}

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260708-efi-psci-v1-0-9efb3abf0e4c@kernel.org?part=2

  reply	other threads:[~2026-07-08  7:39 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-08  7:15 [PATCH RFC 0/6] PSCI-via-EFI to support firmware and kernel sharing EL2 for Apple Silicon Sven Peter
2026-07-08  7:15 ` [PATCH RFC 1/6] dt-bindings: arm: psci: Add EFI conduit Sven Peter
2026-07-08  7:15 ` [PATCH RFC 2/6] arm64/efi: Add and parse custom PSCI EFI configuration table Sven Peter
2026-07-08  7:39   ` sashiko-bot [this message]
2026-07-08  7:15 ` [PATCH RFC 3/6] efi: Add EFI_MEMORY_ISA_{MASK,VALID} Sven Peter
2026-07-08  7:25   ` sashiko-bot
2026-07-08  7:15 ` [PATCH RFC 4/6] arm64/efi: Honor EFI_MEMORY_ISA_MASK for Device-nGnRnE vs -nGnRE Sven Peter
2026-07-08  7:33   ` sashiko-bot
2026-07-08  7:15 ` [PATCH RFC 5/6] firmware/psci: Add EFI runtime conduit Sven Peter
2026-07-08  7:46   ` sashiko-bot
2026-07-08  7:15 ` [PATCH RFC 6/6] arm64: dts: apple: t8103: Add PSCI and CPU idle states Sven Peter
2026-07-08  7:48   ` sashiko-bot

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260708073902.E72301F000E9@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=conor+dt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=robh@kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    --cc=sven@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox