Thread (41 messages) 41 messages, 4 authors, 18d ago

Re: [PATCH v4 07/19] crypto: cmh - add SM3 ahash

From: sashiko-bot@kernel.org
Date: 2026-08-25 22:28:48

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] Deterministic failure on large hash updates due to a single large kmalloc linearization.
- [High] Race condition leading to Use-After-Free or state corruption because the request context and input buffers are modified after asynchronous submission.
- [High] DMA mapping of an unaligned embedded structure member violates the DMA API, causes cache coherency corruption, and risks kernel panics if mapped from a vmap stack.
--

commit db71afa324a1c32abd2a50db9da6330962bdae16
Author: Alex Ousherovitch [off-list ref]

crypto: cmh - add SM3 ahash

Register the SM3 ahash algorithm using the CMH SM3 core. Supports
incremental update, finup, final, and export/import functionality.
quoted hunk ↗ jump to hunk
diff --git a/drivers/crypto/cmh/cmh_sm3.c b/drivers/crypto/cmh/cmh_sm3.c
new file mode 100644
index 0000000000000..8dbc46c30a40f
--- /dev/null
+++ b/drivers/crypto/cmh/cmh_sm3.c
[ ... ]
+struct cmh_sm3_reqctx {
+	int    error;
+	u32    hw_started;
+	u32    buf_len;
+	u32    has_checkpoint;
+	u8     checkpoint[SM3_CONTEXT_SIZE]; /* SM3 context from last SAVE */
+	/* DMA state for current async operation */
[ ... ]
+static int cmh_sm3_update(struct ahash_request *req)
+{
[ ... ]
+	/*
+	 * full_len is user-controlled and can exceed KMALLOC_MAX_SIZE for a
+	 * single large update; __GFP_NOWARN avoids splatting the page
+	 * allocator on an oversized request.
+	 */
+	rctx->data_buf = kmalloc(full_len, gfp | __GFP_NOWARN);
+	if (!rctx->data_buf)
+		return -ENOMEM;
[Severity: High]
Is it safe to assume the entire remaining data can be linearized into a
single kmalloc buffer? If a caller attempts to hash a large input (e.g.,
several megabytes) using the ahash API via AF_ALG, this allocation will
predictably fail for sizes exceeding KMALLOC_MAX_SIZE or under memory
fragmentation, which breaks the API contract.

[ ... ]
+	rctx->ckpt_dma = DMA_MAPPING_ERROR;
+	if (rctx->has_checkpoint) {
+		rctx->ckpt_dma = cmh_dma_map_single(rctx->checkpoint,
+						    SM3_CONTEXT_SIZE,
+						     DMA_TO_DEVICE);
[Severity: High]
Does mapping this inline checkpoint buffer violate the DMA API?

The checkpoint array is embedded directly inside struct cmh_sm3_reqctx without
ARCH_DMA_MINALIGN alignment, which can lead to cacheline corruption on
non-coherent architectures when adjacent fields are modified.

Additionally, if the request context is allocated on the stack (for instance
via AHASH_REQUEST_ON_STACK) on a system with CONFIG_VMAP_STACK enabled, mapping
a stack address results in a bogus physical address and can cause kernel
panics.

[ ... ]
+	ret = cmh_vcq_pack_and_submit_async(cmds, idx, rctx->packed,
+					    CMH_SM3_MAX_PACKED,
+					    d.mbx_idx,
+					    cmh_sm3_update_complete, req,
+					    !!(req->base.flags &
+					       CRYPTO_TFM_REQ_MAY_BACKLOG),
+					    cmh_tm_async_timeout_jiffies());
+	if (ret && ret != -EBUSY)
+		goto err_unmap_ckpt;
+
+	/*
+	 * Submit accepted (in flight or backlogged) -- only now move the tail
+	 * into the holdback.  A synchronous rejection above (e.g. -EAGAIN)
+	 * leaves rctx->buf/buf_len untouched so the caller can retry the
+	 * identical update.
+	 */
+	if (tail_len > 0) {
+		if (req->base.flags & CRYPTO_AHASH_REQ_VIRT)
+			memcpy(rctx->buf, req->svirt + from_src, tail_len);
+		else
+			scatterwalk_map_and_copy(rctx->buf, req->src,
+						 from_src, tail_len, 0);
+	}
+	rctx->buf_len = tail_len;
[Severity: High]
Is there a race condition here that could lead to a use-after-free or state
corruption?

This block modifies the holdback buffer (rctx->buf) and reads from the request
input (req->svirt or req->src) after ownership has already been yielded to the
hardware asynchronously via cmh_vcq_pack_and_submit_async().

If the hardware completes the operation quickly, the interrupt handler could
execute cmh_sm3_update_complete() on another CPU and signal completion to the
caller. The caller could then free or reuse the request and its scatterlists
while this thread is still copying the tail bytes from the freed memory.

[ ... ]
+static int cmh_sm3_submit_final(struct ahash_request *req,
+				u8 *data_buf, u32 data_len)
+{
[ ... ]
+	rctx->ckpt_dma = DMA_MAPPING_ERROR;
+	if (rctx->has_checkpoint) {
+		rctx->ckpt_dma = cmh_dma_map_single(rctx->checkpoint,
+						    SM3_CONTEXT_SIZE,
+						     DMA_TO_DEVICE);
[Severity: High]
Similarly, in the finalization stage, can mapping this embedded inline buffer
cause DMA API violations or kernel panics on vmap stacks?

[ ... ]
+static int cmh_sm3_finup(struct ahash_request *req)
+{
[ ... ]
+	gfp = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ?
+	      GFP_KERNEL : GFP_ATOMIC;
+
+	data_buf = kmalloc(data_len, gfp | __GFP_NOWARN);
+	if (!data_buf)
+		return -ENOMEM;
[Severity: High]
Does this finup path have the same issue with large inputs?

Because data_len could be very large depending on the caller, this single
kmalloc attempt could deterministically fail if it exceeds KMALLOC_MAX_SIZE,
similar to the issue in the update path.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260825221539.255951-1-aousherovitch@rambus.com?part=7
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help