From nobody Mon Apr 13 03:29:55 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) client-ip=192.237.175.120; envelope-from=xen-devel-bounces@lists.xenproject.org; helo=lists.xenproject.org; Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=fail(p=none dis=none) header.from=arm.com Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1770830180643126.4267133284568; Wed, 11 Feb 2026 09:16:20 -0800 (PST) Received: from list by lists.xenproject.org with outflank-mailman.1227994.1534373 (Exim 4.92) (envelope-from ) id 1vqDop-000528-Ui; Wed, 11 Feb 2026 17:16:03 +0000 Received: by outflank-mailman (output) from mailman id 1227994.1534373; Wed, 11 Feb 2026 17:16:03 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1vqDop-00051c-MS; Wed, 11 Feb 2026 17:16:03 +0000 Received: by outflank-mailman (input) for mailman id 1227994; Wed, 11 Feb 2026 17:16:02 +0000 Received: from se1-gles-sth1-in.inumbo.com ([159.253.27.254] helo=se1-gles-sth1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1vqDoo-0004tt-CH for xen-devel@lists.xenproject.org; Wed, 11 Feb 2026 17:16:02 +0000 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by se1-gles-sth1.inumbo.com (Halon) with ESMTP id 56820d96-076d-11f1-b162-2bf370ae4941; Wed, 11 Feb 2026 18:16:01 +0100 (CET) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 307D1339; Wed, 11 Feb 2026 09:15:54 -0800 (PST) Received: from C3HXLD123V.arm.com (unknown [10.57.53.46]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 4BBCE3F63F; Wed, 11 Feb 2026 09:15:59 -0800 (PST) X-Outflank-Mailman: Message body and most headers restored to incoming version X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: 56820d96-076d-11f1-b162-2bf370ae4941 From: Bertrand Marquis To: xen-devel@lists.xenproject.org Cc: Volodymyr Babchuk , Jens Wiklander , Stefano Stabellini , Julien Grall , Michal Orzel Subject: [PATCH v2 03/12] xen/arm: ffa: Harden shm page parsing Date: Wed, 11 Feb 2026 18:15:27 +0100 Message-ID: <5189cce4272700616ff5a39870566abc72a1acd2.1770826406.git.bertrand.marquis@arm.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ZM-MESSAGEID: 1770830182044158500 Content-Type: text/plain; charset="utf-8" get_shm_pages() uses unchecked address arithmetic and does not enforce alignment, so malformed descriptors can cause overflow or slip through validation. The reclaim path also repeats handle-to-shm-mem conversion in multiple places, duplicating error handling. Harden page parsing and reclaim handling: - add ffa_safe_addr_add() and use it to detect address overflows - enforce alignment checks in get_shm_pages() and return FF-A errors - introduce ffa_secure_reclaim() and use it for MEM_RECLAIM and teardown - simplify ffa_mem_share() argument handling and allow max page count While there rename ffa_mem_share to ffa_spmc_share and ffa_mem_reclaim to ffa_spmc_reclaim to have coherent names with other parts of ffa implementation for SMC wrappers to the SPMC. Functional impact: invalid or misaligned memory ranges now fail earlier with proper error codes; behavior for valid descriptors is unchanged. Signed-off-by: Bertrand Marquis Reviewed-by: Jens Wiklander --- Changes since v1: - rename ffa_mem_share to ffa_spmc_share and ffa_mem_reclaim to ffa_spmc_reclaim - remove unused frag_len --- xen/arch/arm/tee/ffa_private.h | 11 +++++++ xen/arch/arm/tee/ffa_shm.c | 60 ++++++++++++++++------------------ 2 files changed, 40 insertions(+), 31 deletions(-) diff --git a/xen/arch/arm/tee/ffa_private.h b/xen/arch/arm/tee/ffa_private.h index b625f1c72914..58562d8e733c 100644 --- a/xen/arch/arm/tee/ffa_private.h +++ b/xen/arch/arm/tee/ffa_private.h @@ -632,4 +632,15 @@ static inline void ffa_uuid_set(struct ffa_uuid *id, u= int32_t val0, id->val[1] =3D ((uint64_t)val3 << 32U) | val2; } =20 +/* + * Common overflow-safe helper to verify that adding a number of pages to = an + * address will not wrap around. + */ +static inline bool ffa_safe_addr_add(uint64_t addr, uint64_t pages) +{ + uint64_t off =3D pages * FFA_PAGE_SIZE; + + return (off / FFA_PAGE_SIZE) =3D=3D pages && addr <=3D UINT64_MAX - of= f; +} + #endif /*__FFA_PRIVATE_H__*/ diff --git a/xen/arch/arm/tee/ffa_shm.c b/xen/arch/arm/tee/ffa_shm.c index 90800e44a86a..adc7e645a1c7 100644 --- a/xen/arch/arm/tee/ffa_shm.c +++ b/xen/arch/arm/tee/ffa_shm.c @@ -96,16 +96,14 @@ struct ffa_shm_mem { struct page_info *pages[]; }; =20 -static int32_t ffa_mem_share(uint32_t tot_len, uint32_t frag_len, - register_t addr, uint32_t pg_count, - uint64_t *handle) +static int32_t ffa_spmc_share(uint32_t tot_len, uint64_t *handle) { struct arm_smccc_1_2_regs arg =3D { .a0 =3D FFA_MEM_SHARE_64, .a1 =3D tot_len, - .a2 =3D frag_len, - .a3 =3D addr, - .a4 =3D pg_count, + .a2 =3D tot_len, + .a3 =3D 0, + .a4 =3D 0, }; struct arm_smccc_1_2_regs resp; =20 @@ -131,12 +129,16 @@ static int32_t ffa_mem_share(uint32_t tot_len, uint32= _t frag_len, } } =20 -static int32_t ffa_mem_reclaim(uint32_t handle_lo, uint32_t handle_hi, - uint32_t flags) +static int32_t ffa_spmc_reclaim(struct ffa_shm_mem *shm, uint32_t flags) { + register_t handle_hi; + register_t handle_lo; + if ( !ffa_fw_supports_fid(FFA_MEM_RECLAIM) ) return FFA_RET_NOT_SUPPORTED; =20 + uint64_to_regpair(&handle_hi, &handle_lo, shm->handle); + return ffa_simple_call(FFA_MEM_RECLAIM, handle_lo, handle_hi, flags, 0= ); } =20 @@ -145,7 +147,7 @@ static int32_t ffa_mem_reclaim(uint32_t handle_lo, uint= 32_t handle_hi, * this function fails then the caller is still expected to call * put_shm_pages() as a cleanup. */ -static int get_shm_pages(struct domain *d, struct ffa_shm_mem *shm, +static int32_t get_shm_pages(struct domain *d, struct ffa_shm_mem *shm, const struct ffa_address_range *range, uint32_t range_count) { @@ -156,17 +158,26 @@ static int get_shm_pages(struct domain *d, struct ffa= _shm_mem *shm, p2m_type_t t; uint64_t addr; uint64_t page_count; + uint64_t gaddr; =20 for ( n =3D 0; n < range_count; n++ ) { page_count =3D ACCESS_ONCE(range[n].page_count); addr =3D ACCESS_ONCE(range[n].address); + + if ( !IS_ALIGNED(addr, FFA_PAGE_SIZE) ) + return FFA_RET_INVALID_PARAMETERS; + for ( m =3D 0; m < page_count; m++ ) { if ( pg_idx >=3D shm->page_count ) return FFA_RET_INVALID_PARAMETERS; =20 - gfn =3D gaddr_to_gfn(addr + m * FFA_PAGE_SIZE); + if ( !ffa_safe_addr_add(addr, m) ) + return FFA_RET_INVALID_PARAMETERS; + + gaddr =3D addr + m * FFA_PAGE_SIZE; + gfn =3D gaddr_to_gfn(gaddr); shm->pages[pg_idx] =3D get_page_from_gfn(d, gfn_x(gfn), &t, P2M_ALLOC); if ( !shm->pages[pg_idx] ) @@ -180,7 +191,7 @@ static int get_shm_pages(struct domain *d, struct ffa_s= hm_mem *shm, =20 /* The ranges must add up */ if ( pg_idx < shm->page_count ) - return FFA_RET_INVALID_PARAMETERS; + return FFA_RET_INVALID_PARAMETERS; =20 return FFA_RET_OK; } @@ -198,15 +209,11 @@ static void put_shm_pages(struct ffa_shm_mem *shm) =20 static bool inc_ctx_shm_count(struct domain *d, struct ffa_ctx *ctx) { - bool ret =3D true; + bool ret =3D false; =20 spin_lock(&ctx->lock); =20 - if ( ctx->shm_count >=3D FFA_MAX_SHM_COUNT ) - { - ret =3D false; - } - else + if ( ctx->shm_count < FFA_MAX_SHM_COUNT ) { /* * If this is the first shm added, increase the domain reference @@ -217,6 +224,7 @@ static bool inc_ctx_shm_count(struct domain *d, struct = ffa_ctx *ctx) get_knownalive_domain(d); =20 ctx->shm_count++; + ret =3D true; } =20 spin_unlock(&ctx->lock); @@ -251,7 +259,7 @@ static struct ffa_shm_mem *alloc_ffa_shm_mem(struct dom= ain *d, struct ffa_ctx *ctx =3D d->arch.tee; struct ffa_shm_mem *shm; =20 - if ( page_count >=3D FFA_MAX_SHM_PAGE_COUNT ) + if ( page_count > FFA_MAX_SHM_PAGE_COUNT ) return NULL; if ( !inc_ctx_shm_count(d, ctx) ) return NULL; @@ -297,7 +305,6 @@ static int share_shm(struct ffa_shm_mem *shm) struct ffa_address_range *addr_range; struct ffa_mem_region *region_descr; const unsigned int region_count =3D 1; - uint32_t frag_len; uint32_t tot_len; paddr_t last_pa; unsigned int n; @@ -350,7 +357,6 @@ static int share_shm(struct ffa_shm_mem *shm) } =20 addr_range =3D region_descr->address_range_array; - frag_len =3D ADDR_RANGE_OFFSET(descr->mem_access_count, region_count, = 1); last_pa =3D page_to_maddr(shm->pages[0]); init_range(addr_range, last_pa); for ( n =3D 1; n < shm->page_count; last_pa =3D pa, n++ ) @@ -362,12 +368,11 @@ static int share_shm(struct ffa_shm_mem *shm) continue; } =20 - frag_len +=3D sizeof(*addr_range); addr_range++; init_range(addr_range, pa); } =20 - ret =3D ffa_mem_share(tot_len, frag_len, 0, 0, &shm->handle); + ret =3D ffa_spmc_share(tot_len, &shm->handle); =20 out: ffa_rxtx_spmc_tx_release(); @@ -637,8 +642,6 @@ int32_t ffa_handle_mem_reclaim(uint64_t handle, uint32_= t flags) struct domain *d =3D current->domain; struct ffa_ctx *ctx =3D d->arch.tee; struct ffa_shm_mem *shm; - register_t handle_hi; - register_t handle_lo; int32_t ret; =20 if ( !ffa_fw_supports_fid(FFA_MEM_RECLAIM) ) @@ -652,8 +655,7 @@ int32_t ffa_handle_mem_reclaim(uint64_t handle, uint32_= t flags) if ( !shm ) return FFA_RET_INVALID_PARAMETERS; =20 - uint64_to_regpair(&handle_hi, &handle_lo, handle); - ret =3D ffa_mem_reclaim(handle_lo, handle_hi, flags); + ret =3D ffa_spmc_reclaim(shm, flags); =20 if ( ret ) { @@ -677,11 +679,7 @@ bool ffa_shm_domain_destroy(struct domain *d) =20 list_for_each_entry_safe(shm, tmp, &ctx->shm_list, list) { - register_t handle_hi; - register_t handle_lo; - - uint64_to_regpair(&handle_hi, &handle_lo, shm->handle); - res =3D ffa_mem_reclaim(handle_lo, handle_hi, 0); + res =3D ffa_spmc_reclaim(shm, 0); switch ( res ) { case FFA_RET_OK: printk(XENLOG_G_DEBUG "%pd: ffa: Reclaimed handle %#lx\n", --=20 2.52.0