From nobody Fri Oct 2 05:30:26 2026 Received: from smtp-relay-internal-1.canonical.com (smtp-relay-internal-1.canonical.com [185.125.188.123]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8D38C3C583A for ; Wed, 5 Aug 2026 04:19:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.125.188.123 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785903566; cv=none; b=cckbo65/QBzT+ripAzabFPiKBvoXl65esn0DqfKJx9TprkiTOW4bKdYR360Lp84sVK+95kPPA7Yrvm8GtBjY23S+gv0gBOCmk1C/l5bIFPDLiP1hD0odNv+Q5aTOHcU3Nv7ml5qMecKoHgOq1LeAbN53Y2JIh2+vQVyktM8dPAI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785903566; c=relaxed/simple; bh=acdSyytHjwZTJFehevO0SuRxzkFkKqkqGATugYLlyjQ=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=KqKvFZiwUQLMDJ5+S0swjDqviKVPYh5jPQZbzkuaUs9lDjBm6ujmCEIfJFBd6pCEmvTYkt6BSkZzE/86rUq6h6i6LAdavb9VuLQwKcRR/emB7gQtlGfmVp12Ocnqfmo9/oi9ExQ361OEEuSd31dnsteSqxyfHY/MSbb9e3kgG2k= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=canonical.com; spf=pass smtp.mailfrom=canonical.com; dkim=pass (4096-bit key) header.d=canonical.com header.i=@canonical.com header.b=J2BwAufe; arc=none smtp.client-ip=185.125.188.123 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=canonical.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=canonical.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (4096-bit key) header.d=canonical.com header.i=@canonical.com header.b="J2BwAufe" Received: from mail-pl1-f200.google.com (mail-pl1-f200.google.com [209.85.214.200]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by smtp-relay-internal-1.canonical.com (Postfix) with ESMTPS id 4534F3F998 for ; Wed, 5 Aug 2026 04:19:13 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20251003; t=1785903553; bh=IotapiTX6AHa/b6BpPv3QCPlwle1thAL9RRjZLrSjGM=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=J2BwAufejxcLuqLbAhei0bWSxAaRh3gGyRyDIm9j6zYHLmfJhr/awy+bpEM/LkxV+ dd6w7t1tGKYIHD0LmDaEEo1wfAeS56/kaWdGu6lsUVOU5JktdzqW5T0Ja6kLEwCSH+ lhwutgYW/J01NSTOHh02ZE+BObDfgb+0KQ03/8HriYd1QF2+G4H0G10SAmeRXAD+zZ Cx+U7TYCpe5vwSa3JP8faym99szjRXPgpeUln+8WDhImovQRBwg11LQRIa76FvXRlv EpFAZ2EsqSifzjTIKpbkskzgPdmHF23pxbWHDg78n+SkRxNiBWsRxSNyaNiLPA7eKl DiVzM9RY0LCXYs2gph+tfYNkSbveE1rvG6xuThKRQPmBjfMuxEjegcLt00cainCWFU H3P3K69YfCdpDNCamMfrvsmBbZUF2uvE4f0ZXEc6svQC9EoQDRuGP/kdvEeOLImlye RPyEdzhrpFXS3eE3be5TenfuCzETaXl8laOajI3qmqSnhqsbHmMWdCZg0fipF1cfNK /mtRLMqE1K51tP9YaE35QdiLV2+nsAWZdRpup+ciLsLo/SoYz9Zk6TDeNr4cIpOl1j bszNIIwMHIhtfaBiQ4ngwtCSS4pmvgMkL86pkQZogiOkWM7uOY/eFa17SQjxkSGZky +O/hh478AYlJLbOlhxWTFMwQ= Received: by mail-pl1-f200.google.com with SMTP id d9443c01a7336-2cfca8558d2so7931035ad.2 for ; Tue, 04 Aug 2026 21:19:13 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785903551; x=1786508351; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=IotapiTX6AHa/b6BpPv3QCPlwle1thAL9RRjZLrSjGM=; b=Ju+o/WCKOR2KFXJnzj7/XFZcAKtt2aEsqNwGYl3CAc1GAOp4WunQ0880LLmpXhjkwX Mlel12H8nmZ7eCXZGbq+sPwKKc8mmF7Y88VOJukQkie479Ifg3CI3A0AliTm27KUGaS6 jnn+yI9qmdqzb5uxoKH0dRJA+XCA2qPCJ1eRjO5NUAdkM4UzYk5H3qjdHCSFIoQJHpVG jHYxIG2SgXP8z3iUgF5phJAVbo19lpSkJ0S1c02n8O3C3dtjs8nD84epE6uQd4TxgZWG Ch1lBkY/kezGfOasv8E/niwlMC6IujjF5TgcGyofXOf3rSBHzJxXbaxh2qtVsNStcCD4 paaw== X-Forwarded-Encrypted: i=1; AHgh+RrDArwQM3WwDHK1PskJiskzm0gHnUBfU3OxsfdzibWf9052UBD74Y7i8nJrdgatqQL5xLPIYAuemROTNKc=@vger.kernel.org X-Gm-Message-State: AOJu0YypAN0wBJ+R1WuDIh/e7hEG4rIub3oIeuP9cJByE22jklofo6q0 HbjXQ9mETzo53UXxnY94oc84uM0s9Fkf1/iJiRPbMQ3lbuYLxsNgKvXcIIUNmt/gg89uL2CbV8i liaof5Sbs5k1EMOnO7R+All9HUE4Lj8qc6Qpmpi1jneOtseN+3s+eLXJCBkZr/36HESNKuL0Lo1 CB1p078A== X-Gm-Gg: AR+sD1116wwSv5HWSOWNtnMfgDudzbw7AhzbLRX/1niiFN1MqpPy/I/HPRq9H7BxqB0 cGNIp2x6zLD+RAHLawFAL3o+peTixthvCBb+/H0SteK+71gVpZ0ZV40XXt05sydEgV4z0tEeaEQ BWYXnp4by1/G3gSdcQz8Q/+TjBgOYgmyyVJxsudjvFRmHZ4AfyzjQeyVolGsa4+orw7hu9Loqlm MB7O7Tx6PXAFxkd6ATvOJDW7vD2qRTNQMgqAAm3XDMmy2dU98mo9Z+xMHJx5a5AdBUS4Kjoz8L/ JR6hRKmMd0IKRlNMhSRLg2w3ctgzk+fB4wYwpsTDC2WBRz067awIg5G36zsbnT1Zc2VvAfXalZM MvbYCJDmDwrU= X-Received: by 2002:a17:903:1a6f:b0:2ce:d957:59c4 with SMTP id d9443c01a7336-2d0ca7afcb6mr33854495ad.6.1785903551092; Tue, 04 Aug 2026 21:19:11 -0700 (PDT) X-Received: by 2002:a17:903:1a6f:b0:2ce:d957:59c4 with SMTP id d9443c01a7336-2d0ca7afcb6mr33854155ad.6.1785903550657; Tue, 04 Aug 2026 21:19:10 -0700 (PDT) Received: from ZBook.gateway ([123.208.39.53]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-31586402e53sm15842163eec.11.2026.08.04.21.19.06 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 04 Aug 2026 21:19:10 -0700 (PDT) From: Changwei Zou To: horia.geanta@nxp.com, pankaj.gupta@nxp.com, gaurav.jain@nxp.com, herbert@gondor.apana.org.au, davem@davemloft.net Cc: linux-crypto@vger.kernel.org, linux-kernel@vger.kernel.org, lukas@wunner.de, changwei.zou@canonical.com Subject: [PATCH] crypto: caam - Use bounce buffer for unaligned RSA destination buffers Date: Wed, 5 Aug 2026 14:19:02 +1000 Message-ID: <20260805041902.1575170-1-changwei.zou@canonical.com> X-Mailer: git-send-email 2.43.0 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The CAAM RSA driver directly DMA-maps the destination buffer supplied by the caller via req->dst without checking whether it meets the cacheline alignment requirements of DMA-incoherent hardware such as i.MX8. On CPUs with non-coherent DMA caches, if the destination buffer shares a cacheline with other data (i.e. it is not cacheline-aligned), cache writeback/invalidation during DMA can corrupt adjacent memory or cause stale data to be read back. This manifests as intermittent -EKEYREJECTED errors when loading signed kernel modules. When any segment of req->dst is not cacheline-aligned, allocate a single contiguous aligned bounce buffer covering the full dst_len, redirect the operation to it, and scatter-copy the result back to the original destination once the hardware has completed the operation. The intermittent error 'Key was rejected by service' on i.MX8 with CAAM can be triggered when loading signed kernel modules: for i in $(seq 1 100); do sudo modprobe xfs 2>&1 && echo "SUCCESS on attempt $i" \ && sudo rmmod xfs || echo "FAILED on attempt $i" done Signed-off-by: Changwei Zou Assisted-by: OpenCode:claude-sonnet-4.6 --- drivers/crypto/caam/caampkc.c | 66 ++++++++++++++++++++++++++++++++++- drivers/crypto/caam/caampkc.h | 6 ++++ 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/drivers/crypto/caam/caampkc.c b/drivers/crypto/caam/caampkc.c index cb001aa1de66..70300182f2ad 100644 --- a/drivers/crypto/caam/caampkc.c +++ b/drivers/crypto/caam/caampkc.c @@ -59,6 +59,37 @@ static void rsa_io_unmap(struct device *dev, struct rsa_= edesc *edesc, DMA_TO_DEVICE); } =20 +static int do_rsa_bounce_buf(struct akcipher_request *req) +{ + struct caam_rsa_req_ctx *req_ctx =3D akcipher_request_ctx(req); + int nents, err =3D 0; + + if (!req_ctx->bounce_buf) + return 0; + + /* Copy from aligned bounce buffer back to the original destination */ + nents =3D sg_nents_for_len(req_ctx->orig_dst, req->dst_len); + if (nents < 0) + err =3D nents; + else if (sg_copy_from_buffer(req_ctx->orig_dst, nents, + req_ctx->bounce_buf, req->dst_len) !=3D req->dst_len) + err =3D -EFAULT; + + kfree(req_ctx->bounce_buf); + req_ctx->bounce_buf =3D NULL; + req->dst =3D req_ctx->orig_dst; + + return err; +} + +static inline void rsa_bounce_buf_done(struct akcipher_request *req, int *= err) +{ + int cperr =3D do_rsa_bounce_buf(req); + + if (!*err) + *err =3D cperr; +} + static void rsa_pub_unmap(struct device *dev, struct rsa_edesc *edesc, struct akcipher_request *req) { @@ -138,6 +169,7 @@ static void rsa_pub_done(struct device *dev, u32 *desc,= u32 err, void *context) rsa_pub_unmap(dev, edesc, req); rsa_io_unmap(dev, edesc, req); kfree(edesc); + rsa_bounce_buf_done(req, &ecode); =20 /* * If no backlog flag, the completion of the request is done @@ -181,6 +213,7 @@ static void rsa_priv_f_done(struct device *dev, u32 *de= sc, u32 err, =20 rsa_io_unmap(dev, edesc, req); kfree(edesc); + rsa_bounce_buf_done(req, &ecode); =20 /* * If no backlog flag, the completion of the request is done @@ -291,11 +324,32 @@ static struct rsa_edesc *rsa_edesc_alloc(struct akcip= her_request *req, req_ctx->fixup_src_len); dst_nents =3D sg_nents_for_len(req->dst, req->dst_len); =20 + req_ctx->bounce_buf =3D NULL; + req_ctx->orig_dst =3D req->dst; + if (req->dst_len > 0) { + struct scatterlist *sg; + int i; + + for_each_sg(req->dst, sg, dst_nents, i) { + if (!IS_ALIGNED((unsigned long)sg_virt(sg), + dma_get_cache_alignment())) { + req_ctx->bounce_buf =3D kmalloc(req->dst_len, flags); + if (!req_ctx->bounce_buf) + return ERR_PTR(-ENOMEM); + sg_init_one(&req_ctx->dst, req_ctx->bounce_buf, + req->dst_len); + req->dst =3D &req_ctx->dst; + dst_nents =3D 1; + break; + } + } + } + mapped_src_nents =3D dma_map_sg(dev, req_ctx->fixup_src, src_nents, DMA_TO_DEVICE); if (unlikely(!mapped_src_nents)) { dev_err(dev, "unable to map source\n"); - return ERR_PTR(-ENOMEM); + goto bounce_fail; } mapped_dst_nents =3D dma_map_sg(dev, req->dst, dst_nents, DMA_FROM_DEVICE); @@ -368,6 +422,10 @@ static struct rsa_edesc *rsa_edesc_alloc(struct akciph= er_request *req, dma_unmap_sg(dev, req->dst, dst_nents, DMA_FROM_DEVICE); src_fail: dma_unmap_sg(dev, req_ctx->fixup_src, src_nents, DMA_TO_DEVICE); +bounce_fail: + kfree(req_ctx->bounce_buf); + req_ctx->bounce_buf =3D NULL; + req->dst =3D req_ctx->orig_dst; return ERR_PTR(-ENOMEM); } =20 @@ -394,6 +452,7 @@ static int akcipher_do_one_req(struct crypto_engine *en= gine, void *areq) rsa_pub_unmap(jrdev, req_ctx->edesc, req); rsa_io_unmap(jrdev, req_ctx->edesc, req); kfree(req_ctx->edesc); + rsa_bounce_buf_done(req, &ret); } else { ret =3D 0; } @@ -706,6 +765,7 @@ static int akcipher_enqueue_req(struct device *jrdev, } rsa_io_unmap(jrdev, edesc, req); kfree(edesc); + rsa_bounce_buf_done(req, &ret); } =20 return ret; @@ -747,6 +807,7 @@ static int caam_rsa_enc(struct akcipher_request *req) init_fail: rsa_io_unmap(jrdev, edesc, req); kfree(edesc); + rsa_bounce_buf_done(req, &ret); return ret; } =20 @@ -776,6 +837,7 @@ static int caam_rsa_dec_priv_f1(struct akcipher_request= *req) init_fail: rsa_io_unmap(jrdev, edesc, req); kfree(edesc); + rsa_bounce_buf_done(req, &ret); return ret; } =20 @@ -805,6 +867,7 @@ static int caam_rsa_dec_priv_f2(struct akcipher_request= *req) init_fail: rsa_io_unmap(jrdev, edesc, req); kfree(edesc); + rsa_bounce_buf_done(req, &ret); return ret; } =20 @@ -834,6 +897,7 @@ static int caam_rsa_dec_priv_f3(struct akcipher_request= *req) init_fail: rsa_io_unmap(jrdev, edesc, req); kfree(edesc); + rsa_bounce_buf_done(req, &ret); return ret; } =20 diff --git a/drivers/crypto/caam/caampkc.h b/drivers/crypto/caam/caampkc.h index 96d03704c9be..efad91d6058f 100644 --- a/drivers/crypto/caam/caampkc.h +++ b/drivers/crypto/caam/caampkc.h @@ -103,6 +103,9 @@ struct caam_rsa_ctx { * @src : input scatterlist (stripped of leading zeros) * @fixup_src : input scatterlist (that might be stripped of leading z= eros) * @fixup_src_len : length of the fixup_src input scatterlist + * @dst : destination scatterlist backed by bounce buffer (if ne= eded) + * @bounce_buf : DMA-aligned bounce buffer for destination (or NULL) + * @orig_dst : original destination scatterlist (before bounce substi= tution) * @edesc : s/w-extended rsa descriptor * @akcipher_op_done : callback used when operation is done */ @@ -110,6 +113,9 @@ struct caam_rsa_req_ctx { struct scatterlist src[2]; struct scatterlist *fixup_src; unsigned int fixup_src_len; + struct scatterlist dst; + u8 *bounce_buf; + struct scatterlist *orig_dst; struct rsa_edesc *edesc; void (*akcipher_op_done)(struct device *jrdev, u32 *desc, u32 err, void *context); --=20 2.43.0