* [PATCH v9 1/7] KVM: arm64: Forward FFA_NOTIFICATION_BITMAP calls to Trustzone
2026-09-07 17:19 [PATCH v9 0/7] KVM: arm64: Forward FFA_NOTIFICATION* calls to TrustZone Sebastian Ene
@ 2026-09-07 17:19 ` Sebastian Ene
2026-09-07 17:19 ` [PATCH v9 2/7] KVM: arm64: Support FFA_NOTIFICATION_BIND in host handler Sebastian Ene
` (5 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Sebastian Ene @ 2026-09-07 17:19 UTC (permalink / raw)
To: catalin.marinas, maz, oupton, fuad.tabba, will
Cc: joey.gouly, korneld, kvmarm, linux-arm-kernel, linux-kernel,
android-kvm, mrigendra.chaubey, perlarsen, sebastianene,
suzuki.poulose, vdonnefort, yuzenghui
Allow FF-A notification bitmap messages to be forwarded to
Trustzone from the host kernel driver and enforce the host vmid
check.
Reviewed-by: Vincent Donnefort <vdonnefort@google.com>
Signed-off-by: Sebastian Ene <sebastianene@google.com>
---
arch/arm64/kvm/hyp/nvhe/ffa.c | 21 +++++++++++++++++++--
1 file changed, 19 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/kvm/hyp/nvhe/ffa.c b/arch/arm64/kvm/hyp/nvhe/ffa.c
index a327c2bbb6b6..aa82c58380a8 100644
--- a/arch/arm64/kvm/hyp/nvhe/ffa.c
+++ b/arch/arm64/kvm/hyp/nvhe/ffa.c
@@ -692,8 +692,6 @@ static bool ffa_call_supported(u64 func_id)
case FFA_MEM_DONATE:
case FFA_MEM_RETRIEVE_REQ:
/* Optional notification interfaces added in FF-A 1.1 */
- case FFA_NOTIFICATION_BITMAP_CREATE:
- case FFA_NOTIFICATION_BITMAP_DESTROY:
case FFA_NOTIFICATION_BIND:
case FFA_NOTIFICATION_UNBIND:
case FFA_NOTIFICATION_SET:
@@ -878,6 +876,21 @@ static void do_ffa_part_get(struct arm_smccc_1_2_regs *res,
hyp_spin_unlock(&host_buffers.lock);
}
+static void do_ffa_notif_bitmap(struct arm_smccc_1_2_regs *res,
+ struct kvm_cpu_context *ctxt)
+{
+ DECLARE_REG(u32, vmid, ctxt, 1);
+ struct arm_smccc_1_2_regs *args;
+
+ if (vmid != HOST_FFA_ID) {
+ ffa_to_smccc_res(res, FFA_RET_INVALID_PARAMETERS);
+ return;
+ }
+
+ args = (void *)&ctxt->regs.regs[0];
+ hyp_smccc_1_2_smc(args, res);
+}
+
bool kvm_host_ffa_handler(struct kvm_cpu_context *host_ctxt, u32 func_id)
{
struct arm_smccc_1_2_regs res = {0};
@@ -936,6 +949,10 @@ bool kvm_host_ffa_handler(struct kvm_cpu_context *host_ctxt, u32 func_id)
case FFA_PARTITION_INFO_GET:
do_ffa_part_get(&res, host_ctxt);
goto out_handled;
+ case FFA_NOTIFICATION_BITMAP_CREATE:
+ case FFA_NOTIFICATION_BITMAP_DESTROY:
+ do_ffa_notif_bitmap(&res, host_ctxt);
+ goto out_handled;
}
if (ffa_call_supported(func_id))
--
2.55.0.979.g7e5102b832-goog
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH v9 2/7] KVM: arm64: Support FFA_NOTIFICATION_BIND in host handler
2026-09-07 17:19 [PATCH v9 0/7] KVM: arm64: Forward FFA_NOTIFICATION* calls to TrustZone Sebastian Ene
2026-09-07 17:19 ` [PATCH v9 1/7] KVM: arm64: Forward FFA_NOTIFICATION_BITMAP calls to Trustzone Sebastian Ene
@ 2026-09-07 17:19 ` Sebastian Ene
2026-09-07 17:19 ` [PATCH v9 3/7] KVM: arm64: Support FFA_NOTIFICATION_UNBIND " Sebastian Ene
` (4 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Sebastian Ene @ 2026-09-07 17:19 UTC (permalink / raw)
To: catalin.marinas, maz, oupton, fuad.tabba, will
Cc: joey.gouly, korneld, kvmarm, linux-arm-kernel, linux-kernel,
android-kvm, mrigendra.chaubey, perlarsen, sebastianene,
suzuki.poulose, vdonnefort, yuzenghui
Verify the arguments of the FF-A notification bind call and forward the
message to Trustzone.
Reviewed-by: Vincent Donnefort <vdonnefort@google.com>
Signed-off-by: Sebastian Ene <sebastianene@google.com>
---
arch/arm64/kvm/hyp/nvhe/ffa.c | 27 ++++++++++++++++++++++++++-
1 file changed, 26 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/kvm/hyp/nvhe/ffa.c b/arch/arm64/kvm/hyp/nvhe/ffa.c
index aa82c58380a8..89872e12f9d4 100644
--- a/arch/arm64/kvm/hyp/nvhe/ffa.c
+++ b/arch/arm64/kvm/hyp/nvhe/ffa.c
@@ -42,6 +42,8 @@
*/
#define HOST_FFA_ID 0
+#define FFA_NOTIF_RECEIVER_ENDP_MASK GENMASK(15, 0)
+
/*
* A buffer to hold the maximum descriptor size we can see from the host,
* which is required when the SPMD returns a fragmented FFA_MEM_RETRIEVE_RESP
@@ -692,7 +694,6 @@ static bool ffa_call_supported(u64 func_id)
case FFA_MEM_DONATE:
case FFA_MEM_RETRIEVE_REQ:
/* Optional notification interfaces added in FF-A 1.1 */
- case FFA_NOTIFICATION_BIND:
case FFA_NOTIFICATION_UNBIND:
case FFA_NOTIFICATION_SET:
case FFA_NOTIFICATION_GET:
@@ -891,6 +892,27 @@ static void do_ffa_notif_bitmap(struct arm_smccc_1_2_regs *res,
hyp_smccc_1_2_smc(args, res);
}
+static void do_ffa_notif_bind(struct arm_smccc_1_2_regs *res,
+ struct kvm_cpu_context *ctxt)
+{
+ DECLARE_REG(u32, endp_id, ctxt, 1);
+ DECLARE_REG(u32, flags, ctxt, 2);
+ struct arm_smccc_1_2_regs *args;
+
+ if (FIELD_GET(FFA_NOTIF_RECEIVER_ENDP_MASK, endp_id) != HOST_FFA_ID) {
+ ffa_to_smccc_res(res, FFA_RET_INVALID_PARAMETERS);
+ return;
+ }
+
+ if (flags > 1) {
+ ffa_to_smccc_res(res, FFA_RET_INVALID_PARAMETERS);
+ return;
+ }
+
+ args = (void *)&ctxt->regs.regs[0];
+ hyp_smccc_1_2_smc(args, res);
+}
+
bool kvm_host_ffa_handler(struct kvm_cpu_context *host_ctxt, u32 func_id)
{
struct arm_smccc_1_2_regs res = {0};
@@ -953,6 +975,9 @@ bool kvm_host_ffa_handler(struct kvm_cpu_context *host_ctxt, u32 func_id)
case FFA_NOTIFICATION_BITMAP_DESTROY:
do_ffa_notif_bitmap(&res, host_ctxt);
goto out_handled;
+ case FFA_NOTIFICATION_BIND:
+ do_ffa_notif_bind(&res, host_ctxt);
+ goto out_handled;
}
if (ffa_call_supported(func_id))
--
2.55.0.979.g7e5102b832-goog
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH v9 3/7] KVM: arm64: Support FFA_NOTIFICATION_UNBIND in host handler
2026-09-07 17:19 [PATCH v9 0/7] KVM: arm64: Forward FFA_NOTIFICATION* calls to TrustZone Sebastian Ene
2026-09-07 17:19 ` [PATCH v9 1/7] KVM: arm64: Forward FFA_NOTIFICATION_BITMAP calls to Trustzone Sebastian Ene
2026-09-07 17:19 ` [PATCH v9 2/7] KVM: arm64: Support FFA_NOTIFICATION_BIND in host handler Sebastian Ene
@ 2026-09-07 17:19 ` Sebastian Ene
2026-09-07 17:32 ` sashiko-bot
2026-09-07 17:19 ` [PATCH v9 4/7] KVM: arm64: Support FFA_NOTIFICATION_SET " Sebastian Ene
` (3 subsequent siblings)
6 siblings, 1 reply; 10+ messages in thread
From: Sebastian Ene @ 2026-09-07 17:19 UTC (permalink / raw)
To: catalin.marinas, maz, oupton, fuad.tabba, will
Cc: joey.gouly, korneld, kvmarm, linux-arm-kernel, linux-kernel,
android-kvm, mrigendra.chaubey, perlarsen, sebastianene,
suzuki.poulose, vdonnefort, yuzenghui
Verify the arguments of the FF-A notification unbind call and forward
the message to Trustzone.
Reviewed-by: Vincent Donnefort <vdonnefort@google.com>
Signed-off-by: Sebastian Ene <sebastianene@google.com>
---
arch/arm64/kvm/hyp/nvhe/ffa.c | 25 ++++++++++++++++++++++++-
1 file changed, 24 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/kvm/hyp/nvhe/ffa.c b/arch/arm64/kvm/hyp/nvhe/ffa.c
index 89872e12f9d4..a1ba4463d1ef 100644
--- a/arch/arm64/kvm/hyp/nvhe/ffa.c
+++ b/arch/arm64/kvm/hyp/nvhe/ffa.c
@@ -694,7 +694,6 @@ static bool ffa_call_supported(u64 func_id)
case FFA_MEM_DONATE:
case FFA_MEM_RETRIEVE_REQ:
/* Optional notification interfaces added in FF-A 1.1 */
- case FFA_NOTIFICATION_UNBIND:
case FFA_NOTIFICATION_SET:
case FFA_NOTIFICATION_GET:
case FFA_NOTIFICATION_INFO_GET:
@@ -913,6 +912,27 @@ static void do_ffa_notif_bind(struct arm_smccc_1_2_regs *res,
hyp_smccc_1_2_smc(args, res);
}
+static void do_ffa_notif_unbind(struct arm_smccc_1_2_regs *res,
+ struct kvm_cpu_context *ctxt)
+{
+ DECLARE_REG(u32, endp_id, ctxt, 1);
+ DECLARE_REG(u32, reserved, ctxt, 2);
+ struct arm_smccc_1_2_regs *args;
+
+ if (reserved) {
+ ffa_to_smccc_res(res, FFA_RET_INVALID_PARAMETERS);
+ return;
+ }
+
+ if (FIELD_GET(FFA_NOTIF_RECEIVER_ENDP_MASK, endp_id) != HOST_FFA_ID) {
+ ffa_to_smccc_res(res, FFA_RET_INVALID_PARAMETERS);
+ return;
+ }
+
+ args = (void *)&ctxt->regs.regs[0];
+ hyp_smccc_1_2_smc(args, res);
+}
+
bool kvm_host_ffa_handler(struct kvm_cpu_context *host_ctxt, u32 func_id)
{
struct arm_smccc_1_2_regs res = {0};
@@ -978,6 +998,9 @@ bool kvm_host_ffa_handler(struct kvm_cpu_context *host_ctxt, u32 func_id)
case FFA_NOTIFICATION_BIND:
do_ffa_notif_bind(&res, host_ctxt);
goto out_handled;
+ case FFA_NOTIFICATION_UNBIND:
+ do_ffa_notif_unbind(&res, host_ctxt);
+ goto out_handled;
}
if (ffa_call_supported(func_id))
--
2.55.0.979.g7e5102b832-goog
^ permalink raw reply related [flat|nested] 10+ messages in thread* Re: [PATCH v9 3/7] KVM: arm64: Support FFA_NOTIFICATION_UNBIND in host handler
2026-09-07 17:19 ` [PATCH v9 3/7] KVM: arm64: Support FFA_NOTIFICATION_UNBIND " Sebastian Ene
@ 2026-09-07 17:32 ` sashiko-bot
0 siblings, 0 replies; 10+ messages in thread
From: sashiko-bot @ 2026-09-07 17:32 UTC (permalink / raw)
To: Sebastian Ene; +Cc: Oliver Upton, kvmarm, Marc Zyngier
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] do_ffa_notif_unbind improperly restricts the host to only unbind notifications where it is the receiver, preventing it from unbinding notifications it sent.
--
commit c6b253b0c883368d7d43d8e94ff20acf54cb8109
Author: Sebastian Ene <sebastianene@google.com>
KVM: arm64: Support FFA_NOTIFICATION_UNBIND in host handler
This commit adds support for the FFA_NOTIFICATION_UNBIND hypercall in the
host handler, verifying arguments and forwarding the message to Trustzone.
> diff --git a/arch/arm64/kvm/hyp/nvhe/ffa.c b/arch/arm64/kvm/hyp/nvhe/ffa.c
> index 89872e12f9d45..a1ba4463d1ef7 100644
> --- a/arch/arm64/kvm/hyp/nvhe/ffa.c
> +++ b/arch/arm64/kvm/hyp/nvhe/ffa.c
[ ... ]
> @@ -913,6 +912,27 @@ static void do_ffa_notif_bind(struct arm_smccc_1_2_regs *res,
> hyp_smccc_1_2_smc(args, res);
> }
>
> +static void do_ffa_notif_unbind(struct arm_smccc_1_2_regs *res,
> + struct kvm_cpu_context *ctxt)
> +{
> + DECLARE_REG(u32, endp_id, ctxt, 1);
> + DECLARE_REG(u32, reserved, ctxt, 2);
> + struct arm_smccc_1_2_regs *args;
> +
> + if (reserved) {
> + ffa_to_smccc_res(res, FFA_RET_INVALID_PARAMETERS);
> + return;
> + }
> +
> + if (FIELD_GET(FFA_NOTIF_RECEIVER_ENDP_MASK, endp_id) != HOST_FFA_ID) {
> + ffa_to_smccc_res(res, FFA_RET_INVALID_PARAMETERS);
> + return;
> + }
[Severity: Medium]
Does this check improperly restrict the host to only unbind notifications
where it is the receiver?
The FF-A 1.1 specification explicitly permits either the sender or receiver
to unbind a notification. By unconditionally rejecting the hypercall when
the receiver ID does not match HOST_FFA_ID, this prevents the host (acting
as a sender) from unbinding a notification it bound to an SP.
> +
> + args = (void *)&ctxt->regs.regs[0];
> + hyp_smccc_1_2_smc(args, res);
> +}
> +
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260907171930.4037166-1-sebastianene@google.com?part=3
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v9 4/7] KVM: arm64: Support FFA_NOTIFICATION_SET in host handler
2026-09-07 17:19 [PATCH v9 0/7] KVM: arm64: Forward FFA_NOTIFICATION* calls to TrustZone Sebastian Ene
` (2 preceding siblings ...)
2026-09-07 17:19 ` [PATCH v9 3/7] KVM: arm64: Support FFA_NOTIFICATION_UNBIND " Sebastian Ene
@ 2026-09-07 17:19 ` Sebastian Ene
2026-09-07 17:19 ` [PATCH v9 5/7] KVM: arm64: Support FFA_NOTIFICATION_GET " Sebastian Ene
` (2 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Sebastian Ene @ 2026-09-07 17:19 UTC (permalink / raw)
To: catalin.marinas, maz, oupton, fuad.tabba, will
Cc: joey.gouly, korneld, kvmarm, linux-arm-kernel, linux-kernel,
android-kvm, mrigendra.chaubey, perlarsen, sebastianene,
suzuki.poulose, vdonnefort, yuzenghui
Allow FF-A notification SET messages to be proxied from the pKVM
hypervisor to Trustzone and verify the arguments.
Reviewed-by: Vincent Donnefort <vdonnefort@google.com>
Signed-off-by: Sebastian Ene <sebastianene@google.com>
---
arch/arm64/kvm/hyp/nvhe/ffa.c | 26 +++++++++++++++++++++++++-
1 file changed, 25 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/kvm/hyp/nvhe/ffa.c b/arch/arm64/kvm/hyp/nvhe/ffa.c
index a1ba4463d1ef..923f32caa04b 100644
--- a/arch/arm64/kvm/hyp/nvhe/ffa.c
+++ b/arch/arm64/kvm/hyp/nvhe/ffa.c
@@ -43,6 +43,7 @@
#define HOST_FFA_ID 0
#define FFA_NOTIF_RECEIVER_ENDP_MASK GENMASK(15, 0)
+#define FFA_NOTIF_SENDER_ENDP_MASK GENMASK(31, 16)
/*
* A buffer to hold the maximum descriptor size we can see from the host,
@@ -694,7 +695,6 @@ static bool ffa_call_supported(u64 func_id)
case FFA_MEM_DONATE:
case FFA_MEM_RETRIEVE_REQ:
/* Optional notification interfaces added in FF-A 1.1 */
- case FFA_NOTIFICATION_SET:
case FFA_NOTIFICATION_GET:
case FFA_NOTIFICATION_INFO_GET:
/* Optional interfaces added in FF-A 1.2 */
@@ -933,6 +933,27 @@ static void do_ffa_notif_unbind(struct arm_smccc_1_2_regs *res,
hyp_smccc_1_2_smc(args, res);
}
+static void do_ffa_notif_set(struct arm_smccc_1_2_regs *res,
+ struct kvm_cpu_context *ctxt)
+{
+ DECLARE_REG(u32, endp_id, ctxt, 1);
+ DECLARE_REG(u32, flags, ctxt, 2);
+ struct arm_smccc_1_2_regs *args;
+
+ if (FIELD_GET(FFA_NOTIF_SENDER_ENDP_MASK, endp_id) != HOST_FFA_ID) {
+ ffa_to_smccc_res(res, FFA_RET_INVALID_PARAMETERS);
+ return;
+ }
+
+ if (flags & GENMASK(15, 2)) {
+ ffa_to_smccc_res(res, FFA_RET_INVALID_PARAMETERS);
+ return;
+ }
+
+ args = (void *)&ctxt->regs.regs[0];
+ hyp_smccc_1_2_smc(args, res);
+}
+
bool kvm_host_ffa_handler(struct kvm_cpu_context *host_ctxt, u32 func_id)
{
struct arm_smccc_1_2_regs res = {0};
@@ -1001,6 +1022,9 @@ bool kvm_host_ffa_handler(struct kvm_cpu_context *host_ctxt, u32 func_id)
case FFA_NOTIFICATION_UNBIND:
do_ffa_notif_unbind(&res, host_ctxt);
goto out_handled;
+ case FFA_NOTIFICATION_SET:
+ do_ffa_notif_set(&res, host_ctxt);
+ goto out_handled;
}
if (ffa_call_supported(func_id))
--
2.55.0.979.g7e5102b832-goog
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH v9 5/7] KVM: arm64: Support FFA_NOTIFICATION_GET in host handler
2026-09-07 17:19 [PATCH v9 0/7] KVM: arm64: Forward FFA_NOTIFICATION* calls to TrustZone Sebastian Ene
` (3 preceding siblings ...)
2026-09-07 17:19 ` [PATCH v9 4/7] KVM: arm64: Support FFA_NOTIFICATION_SET " Sebastian Ene
@ 2026-09-07 17:19 ` Sebastian Ene
2026-09-07 17:19 ` [PATCH v9 6/7] KVM: arm64: Support FFA_NOTIFICATION_INFO_GET " Sebastian Ene
2026-09-07 17:19 ` [PATCH v9 7/7] KVM: arm64: Enforce strict SBZ checks in the FF-A proxy Sebastian Ene
6 siblings, 0 replies; 10+ messages in thread
From: Sebastian Ene @ 2026-09-07 17:19 UTC (permalink / raw)
To: catalin.marinas, maz, oupton, fuad.tabba, will
Cc: joey.gouly, korneld, kvmarm, linux-arm-kernel, linux-kernel,
android-kvm, mrigendra.chaubey, perlarsen, sebastianene,
suzuki.poulose, vdonnefort, yuzenghui
Allow FF-A notification GET messages to be proxied from the pKVM
hypervisor to Trustzone and verify the arguments sent from the host
driver.
Reviewed-by: Vincent Donnefort <vdonnefort@google.com>
Signed-off-by: Sebastian Ene <sebastianene@google.com>
---
arch/arm64/kvm/hyp/nvhe/ffa.c | 25 ++++++++++++++++++++++++-
1 file changed, 24 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/kvm/hyp/nvhe/ffa.c b/arch/arm64/kvm/hyp/nvhe/ffa.c
index 923f32caa04b..e11fb06df63d 100644
--- a/arch/arm64/kvm/hyp/nvhe/ffa.c
+++ b/arch/arm64/kvm/hyp/nvhe/ffa.c
@@ -695,7 +695,6 @@ static bool ffa_call_supported(u64 func_id)
case FFA_MEM_DONATE:
case FFA_MEM_RETRIEVE_REQ:
/* Optional notification interfaces added in FF-A 1.1 */
- case FFA_NOTIFICATION_GET:
case FFA_NOTIFICATION_INFO_GET:
/* Optional interfaces added in FF-A 1.2 */
case FFA_MSG_SEND_DIRECT_REQ2: /* Optional per 7.5.1 */
@@ -954,6 +953,27 @@ static void do_ffa_notif_set(struct arm_smccc_1_2_regs *res,
hyp_smccc_1_2_smc(args, res);
}
+static void do_ffa_notif_get(struct arm_smccc_1_2_regs *res,
+ struct kvm_cpu_context *ctxt)
+{
+ DECLARE_REG(u32, endp_id, ctxt, 1);
+ DECLARE_REG(u32, flags, ctxt, 2);
+ struct arm_smccc_1_2_regs *args;
+
+ if (FIELD_GET(FFA_NOTIF_RECEIVER_ENDP_MASK, endp_id) != HOST_FFA_ID) {
+ ffa_to_smccc_res(res, FFA_RET_INVALID_PARAMETERS);
+ return;
+ }
+
+ if (flags & GENMASK(31, 4)) {
+ ffa_to_smccc_res(res, FFA_RET_INVALID_PARAMETERS);
+ return;
+ }
+
+ args = (void *)&ctxt->regs.regs[0];
+ hyp_smccc_1_2_smc(args, res);
+}
+
bool kvm_host_ffa_handler(struct kvm_cpu_context *host_ctxt, u32 func_id)
{
struct arm_smccc_1_2_regs res = {0};
@@ -1025,6 +1045,9 @@ bool kvm_host_ffa_handler(struct kvm_cpu_context *host_ctxt, u32 func_id)
case FFA_NOTIFICATION_SET:
do_ffa_notif_set(&res, host_ctxt);
goto out_handled;
+ case FFA_NOTIFICATION_GET:
+ do_ffa_notif_get(&res, host_ctxt);
+ goto out_handled;
}
if (ffa_call_supported(func_id))
--
2.55.0.979.g7e5102b832-goog
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH v9 6/7] KVM: arm64: Support FFA_NOTIFICATION_INFO_GET in host handler
2026-09-07 17:19 [PATCH v9 0/7] KVM: arm64: Forward FFA_NOTIFICATION* calls to TrustZone Sebastian Ene
` (4 preceding siblings ...)
2026-09-07 17:19 ` [PATCH v9 5/7] KVM: arm64: Support FFA_NOTIFICATION_GET " Sebastian Ene
@ 2026-09-07 17:19 ` Sebastian Ene
2026-09-07 17:19 ` [PATCH v9 7/7] KVM: arm64: Enforce strict SBZ checks in the FF-A proxy Sebastian Ene
6 siblings, 0 replies; 10+ messages in thread
From: Sebastian Ene @ 2026-09-07 17:19 UTC (permalink / raw)
To: catalin.marinas, maz, oupton, fuad.tabba, will
Cc: joey.gouly, korneld, kvmarm, linux-arm-kernel, linux-kernel,
android-kvm, mrigendra.chaubey, perlarsen, sebastianene,
suzuki.poulose, vdonnefort, yuzenghui
Allow the host to send FF-A notification queries to Trustzone and proxy
these messages from pKVM.
Reviewed-by: Vincent Donnefort <vdonnefort@google.com>
Signed-off-by: Sebastian Ene <sebastianene@google.com>
---
arch/arm64/kvm/hyp/nvhe/ffa.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/arch/arm64/kvm/hyp/nvhe/ffa.c b/arch/arm64/kvm/hyp/nvhe/ffa.c
index e11fb06df63d..2281ac2e42fc 100644
--- a/arch/arm64/kvm/hyp/nvhe/ffa.c
+++ b/arch/arm64/kvm/hyp/nvhe/ffa.c
@@ -694,8 +694,6 @@ static bool ffa_call_supported(u64 func_id)
case FFA_RXTX_MAP:
case FFA_MEM_DONATE:
case FFA_MEM_RETRIEVE_REQ:
- /* Optional notification interfaces added in FF-A 1.1 */
- case FFA_NOTIFICATION_INFO_GET:
/* Optional interfaces added in FF-A 1.2 */
case FFA_MSG_SEND_DIRECT_REQ2: /* Optional per 7.5.1 */
case FFA_MSG_SEND_DIRECT_RESP2: /* Optional per 7.5.1 */
--
2.55.0.979.g7e5102b832-goog
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH v9 7/7] KVM: arm64: Enforce strict SBZ checks in the FF-A proxy
2026-09-07 17:19 [PATCH v9 0/7] KVM: arm64: Forward FFA_NOTIFICATION* calls to TrustZone Sebastian Ene
` (5 preceding siblings ...)
2026-09-07 17:19 ` [PATCH v9 6/7] KVM: arm64: Support FFA_NOTIFICATION_INFO_GET " Sebastian Ene
@ 2026-09-07 17:19 ` Sebastian Ene
2026-09-07 17:33 ` sashiko-bot
6 siblings, 1 reply; 10+ messages in thread
From: Sebastian Ene @ 2026-09-07 17:19 UTC (permalink / raw)
To: catalin.marinas, maz, oupton, fuad.tabba, will
Cc: joey.gouly, korneld, kvmarm, linux-arm-kernel, linux-kernel,
android-kvm, mrigendra.chaubey, perlarsen, sebastianene,
suzuki.poulose, vdonnefort, yuzenghui
Introduce a helper method ffa_check_unused_args_sbz to enforce strict
arguments checking when the hypervisor acts as a relayer between the
host and Trustzone.
Reviewed-by: Vincent Donnefort <vdonnefort@google.com>
Acked-by: Will Deacon <will@kernel.org>
Signed-off-by: Sebastian Ene <sebastianene@google.com>
---
arch/arm64/kvm/hyp/nvhe/ffa.c | 96 ++++++++++++++++++++++++++++++++++-
1 file changed, 95 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/kvm/hyp/nvhe/ffa.c b/arch/arm64/kvm/hyp/nvhe/ffa.c
index 2281ac2e42fc..5ad74ab265b5 100644
--- a/arch/arm64/kvm/hyp/nvhe/ffa.c
+++ b/arch/arm64/kvm/hyp/nvhe/ffa.c
@@ -74,6 +74,21 @@ static u32 hyp_ffa_version;
static bool has_version_negotiated;
static hyp_spinlock_t version_lock;
+static bool ffa_check_unused_args_sbz(struct kvm_cpu_context *ctxt, int first_reg)
+{
+ DECLARE_REG(u32, func_id, ctxt, 0);
+ int reg, end_reg = 7;
+
+ if (hyp_ffa_version >= FFA_VERSION_1_2 && ARM_SMCCC_IS_64(func_id))
+ end_reg = 17;
+ for (reg = first_reg; reg <= end_reg; reg++) {
+ if (cpu_reg(ctxt, reg))
+ return true;
+ }
+
+ return false;
+}
+
static void ffa_to_smccc_error(struct arm_smccc_1_2_regs *res, u64 ffa_errno)
{
*res = (struct arm_smccc_1_2_regs) {
@@ -242,6 +257,11 @@ static void do_ffa_rxtx_map(struct arm_smccc_1_2_regs *res,
int ret = 0;
void *rx_virt, *tx_virt;
+ if (ffa_check_unused_args_sbz(ctxt, 4)) {
+ ret = FFA_RET_INVALID_PARAMETERS;
+ goto out;
+ }
+
if (npages != (KVM_FFA_MBOX_NR_PAGES * PAGE_SIZE) / FFA_PAGE_SIZE) {
ret = FFA_RET_INVALID_PARAMETERS;
goto out;
@@ -318,6 +338,11 @@ static void do_ffa_rxtx_unmap(struct arm_smccc_1_2_regs *res,
DECLARE_REG(u32, id, ctxt, 1);
int ret = 0;
+ if (ffa_check_unused_args_sbz(ctxt, 2)) {
+ ret = FFA_RET_INVALID_PARAMETERS;
+ goto out;
+ }
+
if (id != HOST_FFA_ID) {
ret = FFA_RET_INVALID_PARAMETERS;
goto out;
@@ -424,6 +449,11 @@ static void do_ffa_mem_frag_tx(struct arm_smccc_1_2_regs *res,
int ret = FFA_RET_INVALID_PARAMETERS;
u32 nr_ranges;
+ if (ffa_check_unused_args_sbz(ctxt, 5)) {
+ ffa_to_smccc_res(res, FFA_RET_INVALID_PARAMETERS);
+ return;
+ }
+
if (fraglen > KVM_FFA_MBOX_NR_PAGES * PAGE_SIZE)
goto out;
@@ -486,6 +516,11 @@ static void __do_ffa_mem_xfer(const u64 func_id,
int ret = 0;
size_t mem_region_len = FFA_MEM_REGION_SZ(hyp_ffa_version);
+ if (ffa_check_unused_args_sbz(ctxt, 5)) {
+ ret = FFA_RET_INVALID_PARAMETERS;
+ goto out;
+ }
+
if (addr_mbz || npages_mbz || fraglen > len ||
fraglen > KVM_FFA_MBOX_NR_PAGES * PAGE_SIZE) {
ret = FFA_RET_INVALID_PARAMETERS;
@@ -589,6 +624,11 @@ static void do_ffa_mem_reclaim(struct arm_smccc_1_2_regs *res,
int ret = 0;
u64 handle;
+ if (ffa_check_unused_args_sbz(ctxt, 4)) {
+ ffa_to_smccc_res(res, FFA_RET_INVALID_PARAMETERS);
+ return;
+ }
+
handle = PACK_HANDLE(handle_lo, handle_hi);
hyp_spin_lock(&host_buffers.lock);
@@ -780,6 +820,11 @@ static void do_ffa_version(struct arm_smccc_1_2_regs *res,
{
DECLARE_REG(u32, ffa_req_version, ctxt, 1);
+ if (ffa_check_unused_args_sbz(ctxt, 2)) {
+ res->a0 = FFA_RET_NOT_SUPPORTED;
+ return;
+ }
+
if (FFA_MAJOR_VERSION(ffa_req_version) != 1) {
res->a0 = FFA_RET_NOT_SUPPORTED;
return;
@@ -829,6 +874,11 @@ static void do_ffa_part_get(struct arm_smccc_1_2_regs *res,
DECLARE_REG(u32, flags, ctxt, 5);
u32 count, partition_sz, copy_sz;
+ if (ffa_check_unused_args_sbz(ctxt, 6)) {
+ ffa_to_smccc_res(res, FFA_RET_INVALID_PARAMETERS);
+ return;
+ }
+
hyp_spin_lock(&host_buffers.lock);
if (!host_buffers.rx) {
ffa_to_smccc_res(res, FFA_RET_BUSY);
@@ -876,9 +926,15 @@ static void do_ffa_part_get(struct arm_smccc_1_2_regs *res,
static void do_ffa_notif_bitmap(struct arm_smccc_1_2_regs *res,
struct kvm_cpu_context *ctxt)
{
+ DECLARE_REG(u32, func_id, ctxt, 0);
DECLARE_REG(u32, vmid, ctxt, 1);
struct arm_smccc_1_2_regs *args;
+ if (ffa_check_unused_args_sbz(ctxt, func_id == FFA_NOTIFICATION_BITMAP_CREATE ? 3 : 2)) {
+ ffa_to_smccc_res(res, FFA_RET_INVALID_PARAMETERS);
+ return;
+ }
+
if (vmid != HOST_FFA_ID) {
ffa_to_smccc_res(res, FFA_RET_INVALID_PARAMETERS);
return;
@@ -895,6 +951,11 @@ static void do_ffa_notif_bind(struct arm_smccc_1_2_regs *res,
DECLARE_REG(u32, flags, ctxt, 2);
struct arm_smccc_1_2_regs *args;
+ if (ffa_check_unused_args_sbz(ctxt, 5)) {
+ ffa_to_smccc_res(res, FFA_RET_INVALID_PARAMETERS);
+ return;
+ }
+
if (FIELD_GET(FFA_NOTIF_RECEIVER_ENDP_MASK, endp_id) != HOST_FFA_ID) {
ffa_to_smccc_res(res, FFA_RET_INVALID_PARAMETERS);
return;
@@ -916,7 +977,7 @@ static void do_ffa_notif_unbind(struct arm_smccc_1_2_regs *res,
DECLARE_REG(u32, reserved, ctxt, 2);
struct arm_smccc_1_2_regs *args;
- if (reserved) {
+ if (ffa_check_unused_args_sbz(ctxt, 5) || reserved) {
ffa_to_smccc_res(res, FFA_RET_INVALID_PARAMETERS);
return;
}
@@ -942,6 +1003,11 @@ static void do_ffa_notif_set(struct arm_smccc_1_2_regs *res,
return;
}
+ if (ffa_check_unused_args_sbz(ctxt, 5)) {
+ ffa_to_smccc_res(res, FFA_RET_INVALID_PARAMETERS);
+ return;
+ }
+
if (flags & GENMASK(15, 2)) {
ffa_to_smccc_res(res, FFA_RET_INVALID_PARAMETERS);
return;
@@ -963,6 +1029,11 @@ static void do_ffa_notif_get(struct arm_smccc_1_2_regs *res,
return;
}
+ if (ffa_check_unused_args_sbz(ctxt, 3)) {
+ ffa_to_smccc_res(res, FFA_RET_INVALID_PARAMETERS);
+ return;
+ }
+
if (flags & GENMASK(31, 4)) {
ffa_to_smccc_res(res, FFA_RET_INVALID_PARAMETERS);
return;
@@ -972,6 +1043,20 @@ static void do_ffa_notif_get(struct arm_smccc_1_2_regs *res,
hyp_smccc_1_2_smc(args, res);
}
+static void do_ffa_notif_info_get(struct arm_smccc_1_2_regs *res,
+ struct kvm_cpu_context *ctxt)
+{
+ struct arm_smccc_1_2_regs *args;
+
+ if (ffa_check_unused_args_sbz(ctxt, 1)) {
+ ffa_to_smccc_res(res, FFA_RET_INVALID_PARAMETERS);
+ return;
+ }
+
+ args = (void *)&ctxt->regs.regs[0];
+ hyp_smccc_1_2_smc(args, res);
+}
+
bool kvm_host_ffa_handler(struct kvm_cpu_context *host_ctxt, u32 func_id)
{
struct arm_smccc_1_2_regs res = {0};
@@ -1000,6 +1085,11 @@ bool kvm_host_ffa_handler(struct kvm_cpu_context *host_ctxt, u32 func_id)
switch (func_id) {
case FFA_FEATURES:
+ if (ffa_check_unused_args_sbz(host_ctxt, 3)) {
+ ffa_to_smccc_res(&res, FFA_RET_INVALID_PARAMETERS);
+ goto out_handled;
+ }
+
if (!do_ffa_features(&res, host_ctxt))
return false;
goto out_handled;
@@ -1046,6 +1136,10 @@ bool kvm_host_ffa_handler(struct kvm_cpu_context *host_ctxt, u32 func_id)
case FFA_NOTIFICATION_GET:
do_ffa_notif_get(&res, host_ctxt);
goto out_handled;
+ case FFA_NOTIFICATION_INFO_GET:
+ case FFA_FN64_NOTIFICATION_INFO_GET:
+ do_ffa_notif_info_get(&res, host_ctxt);
+ goto out_handled;
}
if (ffa_call_supported(func_id))
--
2.55.0.979.g7e5102b832-goog
^ permalink raw reply related [flat|nested] 10+ messages in thread* Re: [PATCH v9 7/7] KVM: arm64: Enforce strict SBZ checks in the FF-A proxy
2026-09-07 17:19 ` [PATCH v9 7/7] KVM: arm64: Enforce strict SBZ checks in the FF-A proxy Sebastian Ene
@ 2026-09-07 17:33 ` sashiko-bot
0 siblings, 0 replies; 10+ messages in thread
From: sashiko-bot @ 2026-09-07 17:33 UTC (permalink / raw)
To: Sebastian Ene; +Cc: kvmarm, Marc Zyngier, Oliver Upton
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] ffa_check_unused_args_sbz() incorrectly performs a full 64-bit check on unused arguments for SMC32 calls, violating the SMCCC and spuriously rejecting valid hypercalls.
- [Medium] Lockless concurrent read of hyp_ffa_version inside ffa_check_unused_args_sbz creates a data race when evaluated during concurrent FFA_VERSION calls.
--
commit 97873b3a67790aeb9b9e6b8c8672461b3304a15f
Author: Sebastian Ene <sebastianene@google.com>
KVM: arm64: Enforce strict SBZ checks in the FF-A proxy
This commit introduces a helper method ffa_check_unused_args_sbz to enforce
strict arguments checking when the hypervisor acts as a relayer between the
host and Trustzone. It adds checks across various FF-A handlers to ensure
unused arguments in SMC calls are strictly zeroed out.
> diff --git a/arch/arm64/kvm/hyp/nvhe/ffa.c b/arch/arm64/kvm/hyp/nvhe/ffa.c
> index 2281ac2e42fcb..5ad74ab265b57 100644
> --- a/arch/arm64/kvm/hyp/nvhe/ffa.c
> +++ b/arch/arm64/kvm/hyp/nvhe/ffa.c
> @@ -74,6 +74,21 @@ static u32 hyp_ffa_version;
> static bool has_version_negotiated;
> static hyp_spinlock_t version_lock;
>
> +static bool ffa_check_unused_args_sbz(struct kvm_cpu_context *ctxt, int first_reg)
> +{
> + DECLARE_REG(u32, func_id, ctxt, 0);
> + int reg, end_reg = 7;
> +
> + if (hyp_ffa_version >= FFA_VERSION_1_2 && ARM_SMCCC_IS_64(func_id))
[Severity: Medium]
Could this lockless read of hyp_ffa_version create a data race?
When the host kernel executes concurrent FFA_VERSION calls, one CPU might
evaluate the hyp_ffa_version >= FFA_VERSION_1_2 condition here in
ffa_check_unused_args_sbz(), while another CPU mutates hyp_ffa_version under
version_lock in do_ffa_version().
Although the 32-bit read compiles to a single atomic load on ARM64 and the
result is ultimately discarded for FFA_VERSION because
ARM_SMCCC_IS_64(func_id) evaluates to false, it is still an unprotected
concurrent access to shared state.
Would reversing the condition to check ARM_SMCCC_IS_64(func_id) first safely
short-circuit the read for SMC32 calls like FFA_VERSION?
> + end_reg = 17;
> + for (reg = first_reg; reg <= end_reg; reg++) {
> + if (cpu_reg(ctxt, reg))
> + return true;
[Severity: High]
Does ffa_check_unused_args_sbz() incorrectly perform a full 64-bit check on
unused arguments for SMC32 calls?
Under the SMCCC 1.2 specification, for SMC32 calls, only the lower 32 bits
of the registers (W0-W7) are used, and the upper 32 bits are UNPREDICTABLE.
However, cpu_reg(ctxt, reg) returns the full 64-bit register value.
If a compliant host issues any SMC32 FF-A hypercall (such as FFA_VERSION)
and leaves non-zero residual data in the upper 32 bits of the unused
registers, will this strictly reject valid SMC32 hypercalls with
FFA_RET_INVALID_PARAMETERS?
Should the register value be masked to 32 bits when ARM_SMCCC_IS_64(func_id)
is false?
> + }
> +
> + return false;
> +}
> +
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260907171930.4037166-1-sebastianene@google.com?part=7
^ permalink raw reply [flat|nested] 10+ messages in thread