Skip to contentSkip to conversation

crypto: cmh - add Rambus CryptoManager Hub driver

PATCH Superseded Alex Ousherovitch 4 participants 44 messages Sep 17 – Oct 8

Subsystems (6)

v5 of 8 Superseded Latest is v8 →

lore
Share & tools
lore
#0 lore raw

v5 cover crypto: cmh - add Rambus CryptoManager Hub driver

crypto: cmh - add Rambus CryptoManager Hub hardware crypto accelerator

This series adds a driver for the Rambus CryptoManager Hub (CMH), a hardware cryptographic accelerator IP from Cryptography Research at Rambus Inc. (https://www.rambus.com/cryptographyresearch/).
CMH provides a broad set of symmetric, asymmetric, and post-quantum cryptographic algorithms accelerated in hardware, accessed via a mailbox-based Virtual Command Queue (VCQ) interface.

The hardware is a platform device matched via device tree (compatible = "rambus,cmh-v1030"). It exposes a single MMIO register region (SIC) with per-mailbox doorbell, status, and command registers. Each mailbox has DMA-coherent queue memory for VCQ command submission and completion.

Driver architecture:

In-kernel users /dev/cmh_mgmt (ioctl)
(dm-crypt, IPsec, kTLS, fscrypt) (key management)

       |                                        |
       v                                        v
  +----------------------------------------------------+
  |        Kernel Crypto API + hwrng (72 total)        |
  |   ahash | skcipher | aead | akcipher | sig | kpp   |
  +----------------------------------------------------+
       |                                           |
       v                                           v
  +------------------+    +------------------------+
  | Transaction Mgr  |--->| Key / Mgmt subsystem   |
  | (kthread, CMQ)   |    | (datastore, ioctl ops) |
  +------------------+    +------------------------+
       |
       v
  +------------------+     +-------------------+
  | MQI (VCQ pack,   |---->| Response Handler  |
  |  DMA map, submit)|     | (threaded IRQ,    |
  +------------------+     |  watchdog, unmap) |
       |                   +-------------------+
       v                          ^
  +-----------+              +-----------+
  | Hardware  |--- IRQ ----->| Hardware  |
  | (mailbox) |              | (mailbox) |
  +-----------+              +-----------+

The transaction manager runs as a dedicated kthread that pulls requests from a central command queue, packs VCQ entries, maps DMA buffers, and submits to the least-loaded mailbox. Completion is handled by per-mailbox threaded IRQs. The driver returns -EINPROGRESS for async crypto requests and supports the CRYPTO_TFM_REQ_MAY_BACKLOG flag for queue-full backpressure.

Registered algorithms (72 total):

  Type       Count  Algorithms
  ---------  -----  --------------------------------------------------
  ahash         15  SHA-{224,256,384,512}, SHA3-{224,256,384,512},
                     SHAKE-{128,256}, cSHAKE-{128,256},
                     KMAC-{128,256}, SM3
  ahash(HMAC)    8  HMAC-SHA-{224,256,384,512},
                     HMAC-SHA3-{224,256,384,512}
  ahash(MAC)     4  CMAC(AES), CMAC(SM4), XCBC(SM4), Poly1305
  skcipher      11  AES-{ECB,CBC,CTR,CFB,XTS},
                     SM4-{ECB,CBC,CTR,CFB,XTS}, ChaCha20
  aead           6  AES-{GCM,CCM}, SM4-{GCM,CCM},
                     rfc7539(chacha20,poly1305),
                     rfc7539esp(chacha20,poly1305)
  akcipher       1  RSA (2048--4096 bit; 512/1024 legacy/test)
  sig           23  ECDSA P-{256,384,521}, SM2 (verify-only),
                     ML-DSA-{44,65,87},
                     SLH-DSA (12 parameter sets),
                     LMS, LMS-HSS, XMSS, XMSS-MT
  kpp            3  ECDH P-{256,384}, X25519
  hwrng          1  DRBG-backed /dev/hwrng

The keyed MACs (HMAC, CMAC, XCBC, Poly1305) accumulate input for a single finalize-time submission -- the hardware has no keyed-MAC save/restore -- and fall back to a generic software MAC (Poly1305 uses the in-kernel library) once the input or a clone exceeds a 64 KB window, so they are not input-capped. KMAC has no software equivalent and keeps the cap; the driver selects the generic MAC/hash and Poly1305-library configs for the fallbacks.

Ioctl-only algorithms (not registered with the crypto API at all):
- EdDSA (Ed25519, Ed448): sign and verify
- ML-KEM (ML-KEM-512/768/1024): no standard kernel KEM API exists

The driver also exposes /dev/cmh_mgmt, a misc device for the hardware key-management plane: key provisioning and hardware-held-key operations that the in-kernel crypto API cannot express. Some of its ioctls name primitives the driver also registers; that overlap is deliberate and bounded (the ioctl path keeps private keys hardware-resident). The "crypto: cmh - add key provisioning and management" patch explains the split in full. The device requires CAP_SYS_ADMIN and is built conditionally on CONFIG_CRYPTO_DEV_CMH_MGMT (default n); when disabled the ioctl interface is absent while all kernel crypto API algorithms remain registered.

The ML-DSA sig algorithms are registered at priority 5001. The kernel's crypto/mldsa.c registers at priority 5000 with verify-only (sign returns -EOPNOTSUPP). Our driver provides full HW-accelerated sign + verify, so the higher priority ensures the hardware implementation is preferred when the driver is loaded.

Power management uses DEFINE_SIMPLE_DEV_PM_OPS. On suspend the transaction manager drains in-flight requests (configurable 10s timeout, returns -ECANCELED on timeout), stops the kthread, and masks IRQs. On resume it re-verifies SIC/boot status and restarts the kthread.

Dependencies:
- Kernel 7.1+ minimum; developed against Herbert Xu's cryptodev-2.6

    tree (7.3.0-rc1)

- sig_alg backend (upstream since 6.13)
- CMH eSW loaded independently by hardware before driver probe

The driver registers all algorithms through the standard in-kernel crypto API; in-kernel users (dm-crypt, fscrypt, IPsec, etc.) consume them directly. Key provisioning and hardware-held-key operations are exposed to user space via /dev/cmh_mgmt ioctls.

Public hardware documentation:
Product brief: https://go.rambus.com/ch-7xx-and-cc-7xx-product-brief
No public datasheets are currently available. The driver was developed against the Rambus CryptoManager Hub Hardware Reference Manual (Rambus Inc. confidential). Detailed hardware reference is available under NDA from Rambus Inc.; contact the maintainers listed in MAINTAINERS for access during review.

Tested on RISC-V and ARM64 QEMU emulation with the CMH hardware model (QEMU TCG, 512 MiB RAM). Also exercised on Xilinx VMK180 FPGA board with real CMH IP.

- testmgr: 41 CMH algorithm registrations matched by upstream test vectors, all pass; 30 names report "No test for" (PQC families, KMAC, cSHAKE - no upstream vectors yet).
- kselftest tools/testing/selftests/drivers/crypto/cmh:

    6 pass, 0 fail.

checkpatch.pl --strict: 0 errors, 0 warnings, 0 checks on all files (the only output is the expected per-file "does MAINTAINERS need updating?" reminder, satisfied by the MAINTAINERS patch). sparse (C=2): 0 warnings.
W=1 -Werror: clean.
make dt_binding_check: clean (dtschema validates the rambus,cmh-v1030.yaml binding).

Tested with the following debug options enabled simultaneously (submit-checklist "Test your code" item 1):
CONFIG_PROVE_LOCKING, CONFIG_PROVE_RCU, CONFIG_DEBUG_LOCK_ALLOC, CONFIG_DEBUG_OBJECTS_RCU_HEAD, CONFIG_SLUB_DEBUG, CONFIG_DEBUG_PAGEALLOC, CONFIG_DEBUG_MUTEXES, CONFIG_DEBUG_SPINLOCK, CONFIG_DEBUG_PREEMPT, CONFIG_DEBUG_ATOMIC_SLEEP.
Result: no lockdep warnings, no ODEBUG splats, no slab corruption.

Additionally tested (separate passes - mutually exclusive configs):
- CONFIG_KASAN + CONFIG_UBSAN + CONFIG_DEBUG_KMEMLEAK + CONFIG_KFENCE:
no sanitizer findings; KMEMLEAK scan reports 0 unreferenced objects.
- CONFIG_KCSAN (arm64; riscv64 lacks HAVE_ARCH_KCSAN):
0 data-race reports attributed to the driver.

Stack usage: worst-case under 1 KB on both riscv64 and arm64 (scripts/checkstack.pl). Hardware command buffers live in per-request context (heap-allocated by the crypto framework).

Alex Ousherovitch (19):
dt-bindings: crypto: add Rambus CryptoManager Hub
crypto: cmh - add core platform driver
crypto: cmh - add key provisioning and management
crypto: cmh - add SHA-2/SHA-3/SHAKE ahash
crypto: cmh - add HMAC ahash
crypto: cmh - add CSHAKE/KMAC ahash
crypto: cmh - add SM3 ahash
crypto: cmh - add AES skcipher/aead/cmac
crypto: cmh - add SM4 skcipher/aead/cmac/xcbc
crypto: cmh - add ChaCha20-Poly1305
crypto: cmh - add DRBG hwrng
crypto: cmh - add RSA akcipher
crypto: cmh - add ECDSA/SM2 sig
crypto: cmh - add ECDH/X25519 kpp
crypto: cmh - add ML-KEM/ML-DSA (QSE)
crypto: cmh - add SLH-DSA/LMS/XMSS (HCQ)
Documentation: ioctl: add CMH ioctl documentation and register 'J'
selftests: crypto: cmh - add kselftest for management ioctl
MAINTAINERS: add Rambus CryptoManager Hub (CMH)

---

Changes in v5:
- dt-bindings: crypto: cmh: rework the compatible and rambus,cores per the DT-bindings review -- require a SoC-specific compatible ahead of the "rambus,cmh-v1030" IP fallback using the inside-secure,eip93 "not: {}" idiom (which forbids a bare or placeholder compatible), and drop the example since none can validate until a real SoC is upstreamed; switch rambus,cores from hardware core-ID integers to a string-array of core names (hc/aes/sm4/sm3/hcq/qse/pke/ccp) and drop the hex-ID table; keep clocks and reset-gpios optional with a hardware-framed note (the management host owns clock and reset), and replace the ambiguous positional clocks item list with a count-bounded description. The driver maps the names to core IDs and rejects an unknown name.
- crypto: cmh: fix transaction-manager / response-handler races -- on a multi-VCQ error, FLUSH+drain instead of RESTARTing the eSW into freed slots; clear the watchdog-active flag before deleting the timer; serialise the mailbox TAIL doorbell against the wake re-poke; drain stragglers with -ECANCELED after a management FLUSH; ABORT on a sync timeout only when the request is at the mailbox HEAD; reject an over-large num_vcqs; and re-check the running flag under the queue lock.
- crypto: cmh: convert the SHA-2 / SHA-3 / SHAKE, SM3, and cSHAKE ahash drivers to CRYPTO_AHASH_ALG_BLOCK_ONLY per the v4 review -- drop the hand-rolled partial-block buffering and let the Crypto API hold back sub-block data. .update() hashes whole blocks and reports the leftover count for the API to re-buffer, .finup() also serves .final(), and export/import carry only the hardware checkpoint. The drivers no longer set CRYPTO_ALG_REQ_VIRT (BLOCK_ONLY buffering is scatterlist-based), so virtual-address ahash requests are no longer accepted.
- crypto: cmh: harden the streaming ahash drivers -- cap the bytes an AF_ALG client can pin per transform (HMAC / KMAC / AES-CMAC / SM4-CMAC / Poly1305) and give Poly1305 its own DMA-safe key buffer; reject an over-large one-shot hash / SM3 / cSHAKE linearisation with -EMSGSIZE; and make each MAC .final()/.finup() retry-safe by preserving the resumable state on a synchronous submit rejection.
- crypto: cmh: management-plane hardening -- serialise the /dev/cmh_mgmt ioctls under one mutex; scrub transient and partially-created datastore objects on the SM2-ECDH-hash and KIC/KEY error paths; guard the added-randomness DMA unmap on the buffer and zeroise it; reject RSA key sizes not a multiple of 8 bits; and allow 0-length ML-DSA messages.
- crypto: cmh: fix a mid-function declaration in the SLH-DSA sign path.
- Rebased onto current cryptodev-2.6 (7.3.0-rc1); no driver code changes were required. The 7.3 crypto changes (the lib/crypto AES-mode refactor, the internal xts_verify_key split, and the mod_devicetable.h -> device-id/ reorg) touch none of the crypto APIs the driver uses.

Changes in v4:
- dt-bindings: crypto: cmh: rename the per-mailbox child node to queue@N and describe its ring geometry as plain counts rather than log2 -- replace rambus,slots-log2 with rambus,num-slots (a power-of-two slot count) and rambus,strides-log2 with rambus,slot-stride-bytes (a power-of-two byte stride); the driver converts each to the register log2 encoding.
- crypto: cmh: convert the platform driver to module_platform_driver() and dev_err_probe(), and drop the single-instance guard.
- crypto: cmh: remove the informational dev_info() logging from the probe, register, remove, suspend and resume paths.
- crypto: cmh: drop every production module parameter -- the eSW boot timeout, hwrng quality and DRBG config become built-in constants and the command-queue/backlog depths move to debugfs (debug builds only); only debug-gated test knobs remain under CONFIG_CRYPTO_DEV_CMH_DEBUG.
- dt-bindings: crypto: cmh: rename the binding file to rambus,cmh-v1030.yaml to match the compatible string, and trim the clocks and interrupts property descriptions.
- crypto: cmh: move the /dev/cmh_mgmt rationale (why its ioctl surface does not duplicate the registered crypto-API transforms) from the cover letter into the key-management patch commit message.
- crypto: cmh: bound the KEY_NEW/KEY_NEW_RANDOM datastore object length and scrub orphaned datastore objects on the management key-generation error paths
- crypto: cmh: further static-analysis error-path and input-validation fixes (management DMA-unmap sentinels; reject absent randomness/context pointers in the ML-KEM/ML-DSA/SLH-DSA ioctls; guard hash/sm3 finup length against u32 overflow; commit RSA key state only after full validation; clamp the ecdsa digit count before sizing).
- crypto: cmh: fix transaction-manager submit races and shared-IRQ setup (bound the multi-VCQ walk within vcq_data; arm the async per-request timer before the doorbell to avoid a completion race; de-duplicate shared mailbox virqs so probe does not fail with -EBUSY on platforms that share an interrupt line).
- crypto: cmh: fix symmetric stream and out-of-place AEAD output (declare chunksize for the CTR/CFB stream modes so the crypto layer buffers sub-block data instead of splitting the keystream; copy the AAD verbatim into the destination for out-of-place AES/SM4 AEAD).
- crypto: cmh: further keyed-hash and PKE hardening (validate raw NIST ECDH scalars with ecc_is_key_valid; reject the unimplemented PKE_ECDH DS-result mode instead of overrunning the output; defer the hash holdback update until after its allocations; bound the hmac fallback state to the export window; restore the management temp-dirty flag on flush failure; back off the hwrng blocking read on a transient DRBG error).
- crypto: cmh: stream cSHAKE incrementally in hardware (absorb full sponge rate-blocks per update via SAVE/RESTORE and hold back only the sub-rate tail) instead of buffering all input in kernel memory; any length, matching the plain hashes.
- crypto: cmh: make the streaming hash/sm3/cSHAKE .update() retry-safe -- defer moving the sub-rate tail into the holdback until after an accepted submit, so a queue-full -EAGAIN (no MAY_BACKLOG) leaves the request state pristine for the caller to retry.
- crypto: cmh: ECDH mgmt ioctl returns only the raw shared secret to host; drop the unimplemented DS-result flag and result_cid from the UAPI, with flags and the reserved fields rejected unless zero.
- dt-bindings: crypto: cmh: allow clock-names subsets -- core with an optionally-independent core-div2 and/or rt (oneOf) instead of a positional list that could not express [core, rt].
- crypto: cmh: register an algorithm family only when its hardware core is present in CORE_ENABLE, so an absent core advertises no crypto-API algorithms; the core-dispatch path also WARNs and bails on an absent core type as a backstop for the /dev/cmh_mgmt ioctl path.

Changes in v3:
- dt-bindings: crypto: cmh: rework the mailbox topology per DT review -- mailbox@N child nodes; cores discovered from CORE_ENABLE, not the DT.
- dt-bindings: crypto: cmh: adopt the "rambus" vendor prefix and a device-specific "rambus,cmh-v1030" compatible (the IP revision) per DT review; rename the per-mailbox properties to rambus,slots-log2 / rambus,strides-log2 / rambus,cores and the crypto driver-name prefix to rambus-cmh-*.
- dt-bindings: crypto: cmh: describe the optional functional clocks (core, core-div2, rt) and an optional host-driven reset-gpios; the driver enables all supplied clocks and acquires the optional reset line deasserted.
- crypto: cmh: register the platform driver from module_init() without unregistering on probe failure; propagate -EPROBE_DEFER from of_irq_get().
- crypto: cmh: harden the key-management and crypto error paths; fix three transaction-manager concurrency issues found by an automated kernel-style review of v2.
- crypto: cmh: further automated kernel-style review fixes (hwrng bounce buffer and short-read, truncated export state, RSA re-key unmap, MAC setkey ordering, CCM fallback alignment, persistent PKE/PQC key buffer).
- crypto: cmh: give the buffered keyed MACs (hmac, cmac, xcbc, poly1305) a software fallback past the 64 KB window instead of a hard input cap; KMAC keeps its hard cap and rejects export/import.
- crypto: cmh: rfc7539(chacha20,poly1305): always issue the AAD-final command, fixing -EIO on empty-AAD requests.
- crypto: cmh: chacha20 skcipher: leave req->iv unchanged on completion, matching the generic chacha20 skcipher.
- Documentation: cmh: describe the management ioctls as a permanent interface and add ioctl struct layouts; document the keyed-MAC software fallback and KMAC exception.

Changes in v2:
- crypto: cmh: wait for both eSW readiness bits at probe. The probe readiness gate polled SW_BOOT_STATUS for MISSION (bit 6, primary VCQ engine) only, but the sidecar engine signals readiness separately via MISSION2 (bit 7), asserted asynchronously. Gate on both bits so an operation offloaded to the sidecar cannot race an engine that is not yet up.
- crypto: cmh: compute cmac(sm4) of a zero-length message in software. The SM4 core mishandles an empty CMAC input, so -- exactly like the existing xcbc(sm4) empty-message path, and per NIST SP 800-38B -- the driver now derives the K2 subkey and computes the tag with a software cipher. Surfaced by the testmgr fuzz comparison against the generic cmac(sm4); no change for non-empty messages.
- Documentation: link cmh_mgmt.rst into the userspace-api/ioctl index toctree, fixing a "document isn't included in any toctree" htmldocs warning reported on the v1 posting of patch 17.
- crypto: cmh: carry the XTS block offset (xts_offset) inline in the AES INIT command, matching the updated CMH hardware ABI that retired the separate XTS_OFFSET command. Always 0 on the skcipher path (data units start at block 0); no functional change.
- MAINTAINERS: drop the internal moderated list ([email protected]) and the T: tree line from the CMH entry, per review. The driver goes through the crypto tree, so keep only [email protected] and no T: line.
- Rebased onto current cryptodev-2.6 (v7.2-rc1); no code changes were required (the merge window touches none of the crypto APIs the driver uses).

v1: https://lore.kernel.org/linux-crypto/[email protected]/
v2: https://lore.kernel.org/linux-crypto/[email protected]/
v3: https://lore.kernel.org/linux-crypto/[email protected]/
v4: https://lore.kernel.org/linux-crypto/[email protected]/

base-commit: 9695df3b1db4ac4534274d38ee16e3b9b0bf910e

Signature · 1 line
2.43.7
#1 lore raw

PATCH v5 1/19 dt-bindings: crypto: add Rambus CryptoManager Hub

Add device tree binding schema for the Rambus CryptoManager Hub (CMH) hardware crypto accelerator. The binding describes the parent SoC-level node with its SIC register region and one queue@N child node per mailbox the host owns, each carrying a reg (mailbox instance index), an optional interrupt, VCQ ring geometry (rambus,num-slots / rambus,slot-stride-bytes) and a rambus,cores affinity list. Which crypto cores are present is discovered from the SIC CORE_ENABLE register at probe, not described in the device tree.

Register the 'rambus' vendor prefix for Rambus Inc.

---
 .../bindings/crypto/rambus,cmh-v1030.yaml     | 151 ++++++++++++++++++
 .../devicetree/bindings/vendor-prefixes.yaml  |   2 +
 2 files changed, 153 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/crypto/rambus,cmh-v1030.yaml
Documentation/devicetree/bindings/crypto/rambus,cmh-v1030.yaml new file +151 -0
new file mode 100644
index 000000000000..a0df35bdc371
@@ -0,0 +1,151 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/crypto/rambus,cmh-v1030.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Rambus CryptoManager Hub (CMH) Hardware Crypto Accelerator
+
+maintainers:
+  - Alex Ousherovitch <[email protected]>
+  - Saravanakrishnan Krishnamoorthy <[email protected]>
+  - Joel Wittenauer <[email protected]>
+
+description: |
+  The Rambus CryptoManager Hub (CMH) is a hardware cryptographic accelerator
+  accessed via a mailbox-based VCQ (Virtual Command Queue) interface.  The
+  host writes VCQ command sequences into per-mailbox DMA queue buffers and
+  rings a doorbell; the CMH eSW processes them and signals completion via
+  interrupt.
+
+  The management host statically partitions the hardware mailboxes across
+  the SoC's host interfaces at integration time; the set of mailboxes a
+  given host owns is therefore fixed and not runtime-discoverable (a
+  mailbox locked to a host reads as unavailable in the SIC availability
+  register).  Each owned mailbox is described by a child node.  Which
+  crypto cores are present is a fixed silicon-build property indicated by
+  the SIC CORE_ENABLE register, so cores are not described in the device
+  tree.  Clock and reset are owned by the management host; a node
+  describing a non-management host has no clock or reset provider of its
+  own, so clocks and reset-gpios are optional.
+
+  CMH gates access to a locked mailbox by a hardware HOST ID presented on
+  the bus with every access, permitting only the owning host's ID.  An
+  integration must present a single, stable HOST ID for all accesses to a
+  given mailbox, independent of the issuing CPU (relevant on SMP hosts
+  whose interconnect encodes the issuing CPU in the HOST ID).
+
+properties:
+  compatible:
+    items:
+      - not: {}
+        description: SoC-specific compatible, e.g. vendor,soc-cmh
+      - const: rambus,cmh-v1030
+
+  reg:
+    maxItems: 1
+    description:
+      SIC (System Interface Controller) MMIO region.  The registers of
+      mailbox instance N are at offset N * 0x1000 within this region.
+
+  clocks:
+    minItems: 1
+    maxItems: 3
+    description:
+      The "core" functional clock, and optionally the half-rate "core-div2"
+      clock (present only on configurations with side-channel-protected
+      cores) and/or the "rt" real-time tick clock.  See clock-names for the
+      valid combinations.
+
+  clock-names:
+    oneOf:
+      - items:
+          - const: core
+      - items:
+          - const: core
+          - const: core-div2
+      - items:
+          - const: core
+          - const: rt
+      - items:
+          - const: core
+          - const: core-div2
+          - const: rt
+
+  reset-gpios:
+    maxItems: 1
+    description:
+      Host-controlled reset for the CryptoManager Hub.  The hub has two
+      external, active-low reset inputs -- a power-on reset and a hard
+      reset; where a board routes one of them to a host GPIO, that line is
+      described here.
+
+  "#address-cells":
+    const: 1
+
+  "#size-cells":
+    const: 0
+
+patternProperties:
+  "^queue@[0-9a-f]+$":
+    type: object
+    description:
+      One node per hardware mailbox (VCQ command queue) this host owns.
+      The set of owned mailboxes is fixed by the management host at
+      integration time and enumerated here.
+    properties:
+      reg:
+        maxItems: 1
+        description:
+          0-based mailbox instance index.  The instance's registers are
+          at reg * 0x1000 within the SIC region.
+
+      interrupts:
+        maxItems: 1
+        description: Completion/error interrupt for this mailbox.
+
+      rambus,num-slots:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        enum: [2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192,
+               16384, 32768]
+        default: 64
+        description:
+          Number of VCQ ring slots for this mailbox's command queue in
+          host DMA memory.  This is a per-board, per-mailbox host-memory
+          ring geometry -- boards built around the same SoC (hence the
+          same compatible) may use different ring sizes, so it is
+          described per mailbox rather than derived from the compatible.
+
+      rambus,slot-stride-bytes:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        enum: [128, 256, 512, 1024]
+        default: 512
+        description:
+          Stride in bytes between consecutive VCQ ring slots for this
+          mailbox's command queue.  Like rambus,num-slots this is a
+          per-board host-memory ring geometry, not derived from the
+          compatible.
+
+      rambus,cores:
+        $ref: /schemas/types.yaml#/definitions/string-array
+        items:
+          enum: [hc, aes, sm4, sm3, hcq, qse, pke, ccp]
+        description: |
+          Core-affinity list: the crypto cores whose work is dispatched to
+          this mailbox.  A core may appear on at most one mailbox.  Cores
+          not listed on any mailbox are load-balanced across all mailboxes.
+          Optional (default: none -- the mailbox only serves the
+          load-balanced pool).
+
+    required:
+      - reg
+
+    additionalProperties: false
+
+required:
+  - compatible
+  - reg
+  - "#address-cells"
+  - "#size-cells"
+
+additionalProperties: false
Documentation/devicetree/bindings/vendor-prefixes.yaml +2 -0
index ba2002969373..364e53c31045 100644
@@ -1397,6 +1397,8 @@ patternProperties:
     description: RaidSonic Technology GmbH
   "^ralink,.*":
     description: Mediatek/Ralink Technology Corp.
+  "^rambus,.*":
+    description: Rambus Inc.
   "^ramtron,.*":
     description: Ramtron International
   "^raspberrypi,.*":
Signature · 1 line
2.43.7
#2 lore raw

Re: [PATCH v5 01/19] dt-bindings: crypto: add Rambus CryptoManager Hub

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider: - [Medium] dt-bindings: unsatisfiable 'not: {}' compatible schema rule - [Low] dt-bindings: missing…

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] dt-bindings: unsatisfiable 'not: {}' compatible schema rule
- [Low] dt-bindings: missing mandatory 'examples' schema section
--

commit 3ce20b70e7ce37fd253621a799e998d6f340d240
Author: Alex Ousherovitch <[email protected]>

dt-bindings: crypto: add Rambus CryptoManager Hub

Add device tree binding schema for the Rambus CryptoManager Hub (CMH) hardware crypto accelerator. The binding describes the parent SoC-level node with its SIC register region and one queue@N child node per mailbox the host owns, each carrying a reg (mailbox instance index), an optional interrupt, VCQ ring geometry (rambus,num-slots / rambus,slot-stride-bytes) and a rambus,cores affinity list. Which crypto cores are present is discovered from the SIC CORE_ENABLE register at probe, not described in the device tree.

Quoted 5 lines
Documentation/devicetree/bindings/crypto/rambus,cmh-v1030.yaml new file +0 -0
new file mode 100644
index 0000000000000..a0df35bdc371d

[ ... ]

Documentation/devicetree/bindings/crypto/rambus,cmh-v1030.yaml line 43

Quoted 6 lines
Documentation/devicetree/bindings/crypto/rambus,cmh-v1030.yaml new file +6 -0
+properties:
+  compatible:
+    items:
+      - not: {}
+        description: SoC-specific compatible, e.g. vendor,soc-cmh
+      - const: rambus,cmh-v1030

[Severity: Medium]
In JSON Schema, {} is an empty schema that matches any value. Therefore, the not: {} constraint in properties.compatible matches nothing and evaluates to false for all inputs.

Any device tree that supplies a valid 2-element compatible string (e.g., "vendor,soc-cmh", "rambus,cmh-v1030") will unconditionally fail validation via dt_binding_check.

Could this compatible constraint be modified so valid inputs can pass?

[ ... ]

Documentation/devicetree/bindings/crypto/rambus,cmh-v1030.yaml line 151

Quoted 7 lines
Documentation/devicetree/bindings/crypto/rambus,cmh-v1030.yaml new file +7 -0
+required:
+  - compatible
+  - reg
+  - "#address-cells"
+  - "#size-cells"
+
+additionalProperties: false

[Severity: Low]
This schema definition completely omits the required examples section at the end of the file.

Without an example, the kernel's dt_binding_check machinery cannot properly validate the schema's internal logic against a simulated valid device tree node. This effectively hides the not: {} bug from automated testing.

Can an examples section be included to enable proper schema testing?

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
maintainer
#3 lore raw

Re: [PATCH v5 01/19] dt-bindings: crypto: add Rambus CryptoManager Hub

In reply to Alex Ousherovitch
Quoted 89 lines · Alex Ousherovitch

Add device tree binding schema for the Rambus CryptoManager Hub (CMH) hardware crypto accelerator. The binding describes the parent SoC-level node with its SIC register region and one queue@N child node per mailbox the host owns, each carrying a reg (mailbox instance index), an optional interrupt, VCQ ring geometry (rambus,num-slots / rambus,slot-stride-bytes) and a rambus,cores affinity list. Which crypto cores are present is discovered from the SIC CORE_ENABLE register at probe, not described in the device tree.

Register the 'rambus' vendor prefix for Rambus Inc.

---
 .../bindings/crypto/rambus,cmh-v1030.yaml     | 151 ++++++++++++++++++
 .../devicetree/bindings/vendor-prefixes.yaml  |   2 +
 2 files changed, 153 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/crypto/rambus,cmh-v1030.yaml
Documentation/devicetree/bindings/crypto/rambus,cmh-v1030.yaml new file +63 -0
new file mode 100644
index 000000000000..a0df35bdc371
@@ -0,0 +1,151 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/crypto/rambus,cmh-v1030.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Rambus CryptoManager Hub (CMH) Hardware Crypto Accelerator
+
+maintainers:
+  - Alex Ousherovitch <[email protected]>
+  - Saravanakrishnan Krishnamoorthy <[email protected]>
+  - Joel Wittenauer <[email protected]>
+
+description: |
+  The Rambus CryptoManager Hub (CMH) is a hardware cryptographic accelerator
+  accessed via a mailbox-based VCQ (Virtual Command Queue) interface.  The
+  host writes VCQ command sequences into per-mailbox DMA queue buffers and
+  rings a doorbell; the CMH eSW processes them and signals completion via
+  interrupt.
+
+  The management host statically partitions the hardware mailboxes across
+  the SoC's host interfaces at integration time; the set of mailboxes a
+  given host owns is therefore fixed and not runtime-discoverable (a
+  mailbox locked to a host reads as unavailable in the SIC availability
+  register).  Each owned mailbox is described by a child node.  Which
+  crypto cores are present is a fixed silicon-build property indicated by
+  the SIC CORE_ENABLE register, so cores are not described in the device
+  tree.  Clock and reset are owned by the management host; a node
+  describing a non-management host has no clock or reset provider of its
+  own, so clocks and reset-gpios are optional.
+
+  CMH gates access to a locked mailbox by a hardware HOST ID presented on
+  the bus with every access, permitting only the owning host's ID.  An
+  integration must present a single, stable HOST ID for all accesses to a
+  given mailbox, independent of the issuing CPU (relevant on SMP hosts
+  whose interconnect encodes the issuing CPU in the HOST ID).
+
+properties:
+  compatible:
+    items:
+      - not: {}
+        description: SoC-specific compatible, e.g. vendor,soc-cmh
+      - const: rambus,cmh-v1030
+
+  reg:
+    maxItems: 1
+    description:
+      SIC (System Interface Controller) MMIO region.  The registers of
+      mailbox instance N are at offset N * 0x1000 within this region.
+
+  clocks:
+    minItems: 1
+    maxItems: 3
+    description:
+      The "core" functional clock, and optionally the half-rate "core-div2"
+      clock (present only on configurations with side-channel-protected
+      cores) and/or the "rt" real-time tick clock.  See clock-names for the
+      valid combinations.
+
+  clock-names:
+    oneOf:
+      - items:
+          - const: core

Documentation/devicetree/bindings/crypto/rambus,cmh-v1030.yaml line 73

Quoted 10 lines
Documentation/devicetree/bindings/crypto/rambus,cmh-v1030.yaml new file +10 -0
+      - items:
+          - const: core
+          - const: core-div2
+      - items:
+          - const: core
+          - const: rt
+      - items:
+          - const: core
+          - const: core-div2
+          - const: rt

Can be simplified to:

items:
- const: core
- enum: [ core-div2, rt ]
- const: rt

Quoted 18 lines
Documentation/devicetree/bindings/crypto/rambus,cmh-v1030.yaml new file +18 -0
+
+  reset-gpios:
+    maxItems: 1
+    description:
+      Host-controlled reset for the CryptoManager Hub.  The hub has two
+      external, active-low reset inputs -- a power-on reset and a hard
+      reset; where a board routes one of them to a host GPIO, that line is
+      described here.
+
+  "#address-cells":
+    const: 1
+
+  "#size-cells":
+    const: 0
+
+patternProperties:
+  "^queue@[0-9a-f]+$":
+    type: object

Documentation/devicetree/bindings/crypto/rambus,cmh-v1030.yaml line 101

Quoted 10 lines
Documentation/devicetree/bindings/crypto/rambus,cmh-v1030.yaml new file +10 -0
+    description:
+      One node per hardware mailbox (VCQ command queue) this host owns.
+      The set of owned mailboxes is fixed by the management host at
+      integration time and enumerated here.
+    properties:
+      reg:
+        maxItems: 1
+        description:
+          0-based mailbox instance index.  The instance's registers are
+          at reg * 0x1000 within the SIC region.

Is there a maximum number of instances? If so, 'maximum: N'.

Rob

#4 lore raw

RE: [PATCH v5 01/19] dt-bindings: crypto: add Rambus CryptoManager Hub

Quoted 9 lines · Rob Herring

Documentation/devicetree/bindings/crypto/rambus,cmh-v1030.yaml line 61

Quoted 2 lines
Documentation/devicetree/bindings/crypto/rambus,cmh-v1030.yaml new file +2 -0
+  clock-names:
+    oneOf:

[...]
Can be simplified to:

items:
- const: core
- enum: [ core-div2, rt ]
- const: rt

Thanks, I'll use that, with minItems: 1 so the lone "core" case still validates:

clock-names:
minItems: 1
items:
- const: core
- enum: [ core-div2, rt ]
- const: rt

Quoted 4 lines

Review

Quoted 2 lines
(quoted diff) +2 -0
+      reg:
+        maxItems: 1

[...]
Is there a maximum number of instances? If so, 'maximum: N'.

Yes -- the hardware supports up to 64 mailbox instances, so the index is 0..63. I'll add 'maximum: 63' to the queue reg.

Both will be in v6.

Thanks,
Alex

#5 lore raw

PATCH v5 2/19 crypto: cmh - add core platform driver

In reply to Alex Ousherovitch

Add the Rambus CryptoManager Hub (CMH) hardware crypto accelerator core platform driver. This patch provides:

- Platform driver registration and probe/remove lifecycle
- Hardware configuration and core discovery
- Mailbox Queue Interface (MQI) for VCQ command submission
- Transaction manager with async completion and backlog support
- Result handler with threaded-IRQ completion
- DMA buffer management
- Debugfs instrumentation (when CONFIG_CRYPTO_DEV_CMH_DEBUG=y)
- Sysfs attributes (fw_version, hw_version, boot_status, mbx_available, mbx_count)
- Kconfig and Makefile integration

No crypto algorithms are registered yet -- those follow in subsequent patches.

The driver communicates with the hardware via a mailbox-based VCQ (Virtual Command Queue) interface. Each crypto operation is packed into VCQ command entries, submitted to a mailbox, and completed asynchronously via interrupt.

MODULE_IMPORT_NS(CRYPTO_INTERNAL) imports two symbols:

- crypto_cipher_setkey() [crypto/cipher.c, EXPORT_SYMBOL_NS_GPL]
- crypto_cipher_encrypt_one() [crypto/cipher.c, EXPORT_SYMBOL_NS_GPL]

These are the single-block cipher API used for software-fallback paths:
CCM empty-input tag computation (2 ECB encryptions + XOR) and XCBC(SM4) empty-message workaround (3 ECB encryptions + XOR). No public wrapper exists; this is the same pattern used by in-tree crypto/ccm.c, crypto/cmac.c, and crypto/xcbc.c.

---
 Documentation/ABI/testing/debugfs-driver-cmh  |  171 ++
 Documentation/ABI/testing/sysfs-driver-cmh    |   67 +
 Documentation/crypto/device_drivers/cmh.rst   |  357 +++
 Documentation/crypto/device_drivers/index.rst |    1 +
 drivers/crypto/Kconfig                        |    1 +
 drivers/crypto/Makefile                       |    1 +
 drivers/crypto/cmh/Kconfig                    |   65 +
 drivers/crypto/cmh/Makefile                   |   25 +
 drivers/crypto/cmh/cmh_config.c               |  619 +++++
 drivers/crypto/cmh/cmh_debugfs.c              |  289 +++
 drivers/crypto/cmh/cmh_dma.c                  |  379 +++
 drivers/crypto/cmh/cmh_main.c                 |  343 +++
 drivers/crypto/cmh/cmh_mqi.c                  |  344 +++
 drivers/crypto/cmh/cmh_rh.c                   | 1178 +++++++++
 drivers/crypto/cmh/cmh_sysfs.c                |  108 +
 drivers/crypto/cmh/cmh_txn.c                  | 2173 +++++++++++++++++
 drivers/crypto/cmh/include/cmh.h              |   24 +
 drivers/crypto/cmh/include/cmh_aes_abi.h      |   98 +
 drivers/crypto/cmh/include/cmh_ccp_abi.h      |  108 +
 drivers/crypto/cmh/include/cmh_config.h       |  105 +
 drivers/crypto/cmh/include/cmh_debugfs.h      |   90 +
 drivers/crypto/cmh/include/cmh_dma.h          |  219 ++
 drivers/crypto/cmh/include/cmh_drbg_abi.h     |   67 +
 drivers/crypto/cmh/include/cmh_eac_abi.h      |   44 +
 drivers/crypto/cmh/include/cmh_hc_abi.h       |  162 ++
 drivers/crypto/cmh/include/cmh_hcq_abi.h      |  221 ++
 drivers/crypto/cmh/include/cmh_kic_abi.h      |   77 +
 drivers/crypto/cmh/include/cmh_mqi.h          |   35 +
 drivers/crypto/cmh/include/cmh_pke_abi.h      |  272 +++
 drivers/crypto/cmh/include/cmh_qse_abi.h      |  181 ++
 drivers/crypto/cmh/include/cmh_registers.h    |  161 ++
 drivers/crypto/cmh/include/cmh_rh.h           |   93 +
 drivers/crypto/cmh/include/cmh_rng.h          |   31 +
 drivers/crypto/cmh/include/cmh_sm3_abi.h      |   79 +
 drivers/crypto/cmh/include/cmh_sm4_abi.h      |  101 +
 drivers/crypto/cmh/include/cmh_sys_abi.h      |  148 ++
 drivers/crypto/cmh/include/cmh_sysfs.h        |   14 +
 drivers/crypto/cmh/include/cmh_txn.h          |  491 ++++
 drivers/crypto/cmh/include/cmh_vcq.h          |  288 +++
 39 files changed, 9230 insertions(+)
 create mode 100644 Documentation/ABI/testing/debugfs-driver-cmh
 create mode 100644 Documentation/ABI/testing/sysfs-driver-cmh
 create mode 100644 Documentation/crypto/device_drivers/cmh.rst
 create mode 100644 drivers/crypto/cmh/Kconfig
 create mode 100644 drivers/crypto/cmh/Makefile
 create mode 100644 drivers/crypto/cmh/cmh_config.c
 create mode 100644 drivers/crypto/cmh/cmh_debugfs.c
 create mode 100644 drivers/crypto/cmh/cmh_dma.c
 create mode 100644 drivers/crypto/cmh/cmh_main.c
 create mode 100644 drivers/crypto/cmh/cmh_mqi.c
 create mode 100644 drivers/crypto/cmh/cmh_rh.c
 create mode 100644 drivers/crypto/cmh/cmh_sysfs.c
 create mode 100644 drivers/crypto/cmh/cmh_txn.c
 create mode 100644 drivers/crypto/cmh/include/cmh.h
 create mode 100644 drivers/crypto/cmh/include/cmh_aes_abi.h
 create mode 100644 drivers/crypto/cmh/include/cmh_ccp_abi.h
 create mode 100644 drivers/crypto/cmh/include/cmh_config.h
 create mode 100644 drivers/crypto/cmh/include/cmh_debugfs.h
 create mode 100644 drivers/crypto/cmh/include/cmh_dma.h
 create mode 100644 drivers/crypto/cmh/include/cmh_drbg_abi.h
 create mode 100644 drivers/crypto/cmh/include/cmh_eac_abi.h
 create mode 100644 drivers/crypto/cmh/include/cmh_hc_abi.h
 create mode 100644 drivers/crypto/cmh/include/cmh_hcq_abi.h
 create mode 100644 drivers/crypto/cmh/include/cmh_kic_abi.h
 create mode 100644 drivers/crypto/cmh/include/cmh_mqi.h
 create mode 100644 drivers/crypto/cmh/include/cmh_pke_abi.h
 create mode 100644 drivers/crypto/cmh/include/cmh_qse_abi.h
 create mode 100644 drivers/crypto/cmh/include/cmh_registers.h
 create mode 100644 drivers/crypto/cmh/include/cmh_rh.h
 create mode 100644 drivers/crypto/cmh/include/cmh_rng.h
 create mode 100644 drivers/crypto/cmh/include/cmh_sm3_abi.h
 create mode 100644 drivers/crypto/cmh/include/cmh_sm4_abi.h
 create mode 100644 drivers/crypto/cmh/include/cmh_sys_abi.h
 create mode 100644 drivers/crypto/cmh/include/cmh_sysfs.h
 create mode 100644 drivers/crypto/cmh/include/cmh_txn.h
 create mode 100644 drivers/crypto/cmh/include/cmh_vcq.h
Documentation/ABI/testing/debugfs-driver-cmh new file +171 -0
new file mode 100644
index 000000000000..21c2d0fbb171
@@ -0,0 +1,171 @@
+What:		/sys/kernel/debug/cmh/mbx<N>/vcqs_submitted
+Date:		June 2026
+KernelVersion:	7.1
+Contact:	[email protected]
+Description:
+		(RO) Total number of VCQ command entries submitted to
+		mailbox N since the driver was loaded.
+
+What:		/sys/kernel/debug/cmh/mbx<N>/vcqs_completed
+Date:		June 2026
+KernelVersion:	7.1
+Contact:	[email protected]
+Description:
+		(RO) Total number of VCQ command completions received
+		from mailbox N.
+
+What:		/sys/kernel/debug/cmh/mbx<N>/vcqs_errors
+Date:		June 2026
+KernelVersion:	7.1
+Contact:	[email protected]
+Description:
+		(RO) Total number of error completions received from
+		mailbox N.
+
+What:		/sys/kernel/debug/cmh/mbx<N>/queue_full_count
+Date:		June 2026
+KernelVersion:	7.1
+Contact:	[email protected]
+Description:
+		(RO) Number of times the transaction manager skipped
+		mailbox N because its in-flight queue was full.
+
+What:		/sys/kernel/debug/cmh/mbx<N>/max_queue_depth
+Date:		June 2026
+KernelVersion:	7.1
+Contact:	[email protected]
+Description:
+		(RO) High-water mark of in-flight transactions on
+		mailbox N.
+
+What:		/sys/kernel/debug/cmh/mbx<N>/inject_abort
+Date:		June 2026
+KernelVersion:	7.1
+Contact:	[email protected]
+Description:
+		(WO) Write any value to inject an MBX_COMMAND_ABORT on
+		mailbox N.  The abort triggers error-IRQ handling that
+		completes all in-flight transactions with -EIO and then
+		issues MBX_COMMAND_RESTART to resume the mailbox.
+		Only available when CONFIG_CRYPTO_DEV_CMH_DEBUG is enabled.
+
+What:		/sys/kernel/debug/cmh/mbx<N>/force_drain
+Date:		June 2026
+KernelVersion:	7.1
+Contact:	[email protected]
+Description:
+		(WO) Write any value to unconditionally FLUSH and drain
+		all pending transactions on mailbox N, completing each
+		with -ECANCELED, and reset all recovery bookkeeping
+		(including the wedged flag).  The mailbox is re-enabled
+		for new work immediately; no hardware health verification
+		is performed.  Use as a last-resort recovery when the eSW
+		is unresponsive and normal ABORT/RESTART escalation has
+		not recovered the mailbox.
+		Only available when CONFIG_CRYPTO_DEV_CMH_DEBUG is enabled.
+
+What:		/sys/kernel/debug/cmh/tm/cmq_posts
+Date:		June 2026
+KernelVersion:	7.1
+Contact:	[email protected]
+Description:
+		(RO) Total number of cmh_tm_post_command() calls (one
+		per crypto request submitted to the transaction manager).
+
+What:		/sys/kernel/debug/cmh/tm/cmq_depth_max
+Date:		June 2026
+KernelVersion:	7.1
+Contact:	[email protected]
+Description:
+		(RO) High-water mark of the command queue length.
+
+What:		/sys/kernel/debug/cmh/tm/cmq_eagain_count
+Date:		June 2026
+KernelVersion:	7.1
+Contact:	[email protected]
+Description:
+		(RO) Number of times the command queue was full and
+		returned -EAGAIN to the caller.
+
+What:		/sys/kernel/debug/cmh/tm/backoff_count
+Date:		June 2026
+KernelVersion:	7.1
+Contact:	[email protected]
+Description:
+		(RO) Number of times the transaction manager backed off
+		because all mailbox queues were full.
+
+What:		/sys/kernel/debug/cmh/tm/async_timeout_count
+Date:		June 2026
+KernelVersion:	7.1
+Contact:	[email protected]
+Description:
+		(RO) Number of async crypto requests that timed out
+		waiting for hardware completion.
+
+What:		/sys/kernel/debug/cmh/config/async_timeout_ms
+Date:		June 2026
+KernelVersion:	7.1
+Contact:	[email protected]
+Description:
+		(RW) Async request timeout in milliseconds.  On timeout
+		the driver issues MBX_COMMAND_ABORT; if the eSW is
+		unresponsive, the watchdog escalates through RESTART,
+		FLUSH, and force-drain to bound D-state duration.
+
+What:		/sys/kernel/debug/cmh/config/vcq_timeout_ms
+Date:		June 2026
+KernelVersion:	7.1
+Contact:	[email protected]
+Description:
+		(RW) VCQ command timeout in milliseconds.
+
+What:		/sys/kernel/debug/cmh/config/slow_op_timeout_ms
+Date:		June 2026
+KernelVersion:	7.1
+Contact:	[email protected]
+Description:
+		(RW) Slow-operation timeout in milliseconds.  Used for
+		operations known to take longer (e.g. RSA key generation,
+		PQC key generation).
+
+What:		/sys/kernel/debug/cmh/config/drain_timeout_ms
+Date:		June 2026
+KernelVersion:	7.1
+Contact:	[email protected]
+Description:
+		(RW) Drain timeout in milliseconds.  Maximum time to wait
+		for all in-flight transactions to complete during driver
+		removal or suspend.
+
+What:		/sys/kernel/debug/cmh/config/watchdog_ms
+Date:		June 2026
+KernelVersion:	7.1
+Contact:	[email protected]
+Description:
+		(RW) Result-handler watchdog interval in milliseconds.
+		Detects missed IRQs, stuck mailboxes, and abort-stall
+		conditions.  Clamped to a 10 ms minimum.
+
+What:		/sys/kernel/debug/cmh/config/drbg_timeout_ms
+Date:		June 2026
+KernelVersion:	7.1
+Contact:	[email protected]
+Description:
+		(RW) DRBG self-seed timeout in milliseconds.
+
+What:		/sys/kernel/debug/cmh/config/cmq_max_depth
+Date:		August 2026
+KernelVersion:	7.2
+Contact:	[email protected]
+Description:
+		(RW) Maximum number of pending commands in the central
+		Command Message Queue.
+
+What:		/sys/kernel/debug/cmh/config/backlog_max_depth
+Date:		August 2026
+KernelVersion:	7.2
+Contact:	[email protected]
+Description:
+		(RW) Maximum depth of the backlog queue for
+		CRYPTO_TFM_REQ_MAY_BACKLOG requests (0 disables backlog).
Documentation/ABI/testing/sysfs-driver-cmh new file +67 -0

67 lines not on this page · raw message

Documentation/crypto/device_drivers/cmh.rst new file +357 -0

357 lines not on this page · raw message

Documentation/crypto/device_drivers/index.rst +1 -0
index c81d311ac61b..c0247fc97bf8 100644
@@ -6,4 +6,5 @@ Hardware Device Driver Specific Documentation
 .. toctree::
    :maxdepth: 1
 
+   cmh
    octeontx2
drivers/crypto/Kconfig +1 -0
index 0189dfdcbbe1..9716b85b8e4b 100644
@@ -831,4 +831,5 @@ source "drivers/crypto/starfive/Kconfig"
 source "drivers/crypto/inside-secure/eip93/Kconfig"
 source "drivers/crypto/ti/Kconfig"
 
+source "drivers/crypto/cmh/Kconfig"
 endif # CRYPTO_HW
drivers/crypto/Makefile +1 -0
index 2c33b83f3cfa..dae0d5f0500d 100644
@@ -46,3 +46,4 @@ obj-y += intel/
 obj-y += starfive/
 obj-y += cavium/
 obj-y += ti/
+obj-$(CONFIG_CRYPTO_DEV_CMH) += cmh/
drivers/crypto/cmh/Kconfig new file +65 -0

65 lines not on this page · raw message

drivers/crypto/cmh/Makefile new file +25 -0
new file mode 100644
index 000000000000..742e65e3917e
@@ -0,0 +1,25 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for the Rambus CryptoManager Hub (CMH) hardware crypto accelerator driver.
+#
+
+obj-$(CONFIG_CRYPTO_DEV_CMH) += cmh.o
+
+cmh-y := \
+	cmh_main.o \
+	cmh_config.o \
+	cmh_mqi.o \
+	cmh_txn.o \
+	cmh_rh.o \
+	cmh_dma.o \
+	cmh_sysfs.o
+
+ccflags-y += -I$(src)/include
+
+# Suppress -Woverride-init for the [0 ... N] = -1 range-initializer pattern
+# (standard kernel idiom for sparse lookup tables with a default value).
+CFLAGS_cmh_config.o += -Wno-override-init
+
+# Debug instrumentation: per-mailbox debugfs counters.
+# cmh_debugfs.o is linked into the composite cmh.o (same tristate).
+cmh-$(CONFIG_CRYPTO_DEV_CMH_DEBUG) += cmh_debugfs.o
drivers/crypto/cmh/cmh_config.c new file +619 -0

619 lines not on this page · raw message

drivers/crypto/cmh/cmh_debugfs.c new file +289 -0

289 lines not on this page · raw message

drivers/crypto/cmh/cmh_dma.c new file +379 -0

379 lines not on this page · raw message

drivers/crypto/cmh/cmh_main.c new file +343 -0

343 lines not on this page · raw message

drivers/crypto/cmh/cmh_mqi.c new file +344 -0

344 lines not on this page · raw message

drivers/crypto/cmh/cmh_rh.c new file +1178 -0

327 lines not on this page · raw message

drivers/crypto/cmh/cmh_sysfs.c new file +108 -0

108 lines not on this page · raw message

drivers/crypto/cmh/cmh_txn.c new file +2173 -0

2,173 lines not on this page · raw message

drivers/crypto/cmh/include/cmh.h new file +24 -0
new file mode 100644
index 000000000000..97a7bc764d9b

Lines of this file are not shown. View the raw message.

drivers/crypto/cmh/include/cmh_aes_abi.h new file +98 -0

98 lines not on this page · raw message

drivers/crypto/cmh/include/cmh_ccp_abi.h new file +108 -0

108 lines not on this page · raw message

drivers/crypto/cmh/include/cmh_config.h new file +105 -0

105 lines not on this page · raw message

drivers/crypto/cmh/include/cmh_debugfs.h new file +90 -0

90 lines not on this page · raw message

drivers/crypto/cmh/include/cmh_dma.h new file +219 -0

219 lines not on this page · raw message

drivers/crypto/cmh/include/cmh_drbg_abi.h new file +67 -0

67 lines not on this page · raw message

drivers/crypto/cmh/include/cmh_eac_abi.h new file +44 -0

44 lines not on this page · raw message

drivers/crypto/cmh/include/cmh_hc_abi.h new file +162 -0

162 lines not on this page · raw message

drivers/crypto/cmh/include/cmh_hcq_abi.h new file +221 -0

221 lines not on this page · raw message

drivers/crypto/cmh/include/cmh_kic_abi.h new file +77 -0

77 lines not on this page · raw message

drivers/crypto/cmh/include/cmh_mqi.h new file +35 -0
new file mode 100644
index 000000000000..202d52b86fb8

Lines of this file are not shown. View the raw message.

drivers/crypto/cmh/include/cmh_pke_abi.h new file +272 -0

272 lines not on this page · raw message

drivers/crypto/cmh/include/cmh_qse_abi.h new file +181 -0

181 lines not on this page · raw message

drivers/crypto/cmh/include/cmh_registers.h new file +161 -0

161 lines not on this page · raw message

drivers/crypto/cmh/include/cmh_rh.h new file +93 -0

93 lines not on this page · raw message

drivers/crypto/cmh/include/cmh_rng.h new file +31 -0
new file mode 100644
index 000000000000..7d24682890c7

Lines of this file are not shown. View the raw message.

drivers/crypto/cmh/include/cmh_sm3_abi.h new file +79 -0

79 lines not on this page · raw message

drivers/crypto/cmh/include/cmh_sm4_abi.h new file +101 -0

101 lines not on this page · raw message

drivers/crypto/cmh/include/cmh_sys_abi.h new file +148 -0

148 lines not on this page · raw message

drivers/crypto/cmh/include/cmh_sysfs.h new file +14 -0
new file mode 100644
index 000000000000..864cf1c8fa00

Lines of this file are not shown. View the raw message.

drivers/crypto/cmh/include/cmh_txn.h new file +491 -0

491 lines not on this page · raw message

drivers/crypto/cmh/include/cmh_vcq.h new file +288 -0

288 lines not on this page · raw message

The rest of this diff is not shown. View the raw message.

Signature · 1 line
2.43.7

Part of the diff is not shown here. View the raw message.

#6 lore raw

Re: [PATCH v5 02/19] crypto: cmh - add core platform driver

Thank you for your contribution! Sashiko AI review found 13 potential issue(s) to consider: - [High] crypto: cmh: DMA use-after-free due to race in tm_submit_sync_tmo cancellation - [High] crypto…

Thank you for your contribution! Sashiko AI review found 13 potential issue(s) to consider:
- [High] crypto: cmh: DMA use-after-free due to race in tm_submit_sync_tmo cancellation
- [High] crypto: cmh: missing interrupt events due to TOCTOU race in cmh_rh_thread
- [High] crypto: cmh: infinite loop and DoS when target_mbx is wedged
- [High] crypto: cmh: DMA use-after-free due to uncoordinated VCQ submission during error recovery
- [High] crypto: cmh: use-after-free during teardown due to flawed module unload ordering
- [High] crypto: cmh: global state corruption and memory leak on multiple device probes
- [High] crypto: cmh: DMA use-after-free by draining queues before MBX_COMMAND_FLUSH completes
- [High] crypto: cmh: TOCTOU race in cmh_tm_flush_mbx enables hardware state corruption
- [High] crypto: cmh: DMA use-after-free when 5-second ABORT timeout expires in sync submission
- [High] crypto: cmh: DMA corruption on resume due to uninitialized mailbox registers
- [High] crypto: cmh: DMA use-after-free during quiesce by force-completing without hardware abort
- [Medium] crypto: cmh: concurrency bug in debugfs inject_abort_write missing rh_process_lock
- [Low] crypto: cmh: build error due to undefined kzalloc_obj macro
--

commit 6323a082ef9c58d5cee85659d61674ed5dff3c03
Author: Alex Ousherovitch <[email protected]>
Subject: crypto: cmh - add core platform driver

This commit adds the core platform driver for the Rambus CryptoManager Hub hardware cryptographic accelerator. It provides driver registration, hardware configuration, a mailbox queue interface, transaction management, and request completion handling.

Quoted 16 lines
drivers/crypto/cmh/cmh_main.c +0 -0
@@ -181,13 +181,13 @@ static int cmh_probe(struct platform_device *pdev)
 
 	cmh_debugfs_init(cfg);
 
 	/* Initialise mailbox queue interface */
 	ret = cmh_mqi_init(cfg);
 	if (ret)
 		goto err_mqi_init;
 
 	/* Initialise transaction manager */
 	ret = cmh_tm_init(cfg);
 	if (ret)
 		goto err_tm_init;
 

drivers/crypto/cmh/cmh_main.c

Quoted 2 lines
drivers/crypto/cmh/cmh_main.c +0 -0
 	/* Initialise response handler */
 	ret = cmh_rh_init(cfg);

[Severity: High]
Does this sequence safely handle multiple device probes?

The driver's subsystems store their state in global singleton static structures (like tm.txqs and rh.mbx). If the device tree contains multiple nodes, it looks like a second probe call will unconditionally overwrite these global pointers, permanently leaking the memory and kthreads of the first instance and leading to double-frees or use-after-free conditions.

Quoted 13 lines

[ ... ]

drivers/crypto/cmh/cmh_main.c +0 -0
@@ -201,11 +201,11 @@ static void cmh_remove(struct platform_device *pdev)
 
 	if (!dev)
 		return;
 
 	cfg = &dev->config;
 
 	cmh_rh_cleanup(cfg);
 	cmh_tm_cleanup();
 	cmh_mqi_cleanup(cfg);
 	cmh_debugfs_cleanup();
 	cmh_dma_cleanup();
Quoted 1 line

}

[Severity: High]
Could this teardown order cause a use-after-free in the running transaction manager thread?

The call to cmh_rh_cleanup() frees the rh.mbx array, but the transaction manager kthread isn't stopped until the subsequent call to cmh_tm_cleanup(). While the array is being freed, the running thread can call cmh_rh_mbx_is_wedged(), which directly dereferences the now-freed rh.mbx memory.

Quoted 13 lines

[ ... ]

drivers/crypto/cmh/cmh_main.c +0 -0
@@ -271,11 +271,11 @@ static int cmh_resume(struct device *dev)
 	if (ret) {
 		dev_err(dev, "resume: CMH eSW health check failed (%d)\n",
 			ret);
 		return ret;
 	}
 
 	/*
 	 * cmh_rh_resume() is void: it only re-syncs MMIO head pointers,
 	 * clears stale interrupt status bits (W1C), re-enables interrupt
 	 * masks, and re-arms the watchdog timer -- none of which can fail
 	 * after the SIC health check above has confirmed HW accessibility.

drivers/crypto/cmh/cmh_main.c

Quoted 4 lines
drivers/crypto/cmh/cmh_main.c +0 -0
 	 */
 	cmh_rh_resume(&cmh->config);
 
 	ret = cmh_tm_resume();

[Severity: High]
Are we missing a step to reprogram the mailbox configuration registers upon resuming from sleep?

When the system resumes from a state like S3, the device might have lost power and reset its internal registers to defaults. Because registers like R_MBX_QUEUE_LO and R_MBX_QUEUE_SLOTS are not restored before restarting the transaction manager thread, the hardware queue engine might use uninitialized base addresses, resulting in IOMMU faults or memory corruption.

Quoted 12 lines
drivers/crypto/cmh/cmh_debugfs.c +0 -0
@@ -70,9 +70,9 @@ static ssize_t inject_abort_write(struct file *file,
 				  const char __user *ubuf,
 				  size_t count, loff_t *ppos)
 {
 	u32 idx = (u32)(unsigned long)file->private_data;
 	void __iomem *base;
 
 	if (!dbgfs.cfg || idx >= dbgfs.cfg->mbx_count)
 		return -EINVAL;
 

drivers/crypto/cmh/cmh_debugfs.c

Quoted 3 lines
drivers/crypto/cmh/cmh_debugfs.c +0 -0
 	base = dbgfs.cfg->mailboxes[idx].reg_base;
 	dev_warn(cmh_dev(), "debugfs: injecting ABORT on mbx[%u]\n", idx);
 	cmh_reg_write32(MBX_COMMAND_ABORT, base, R_MBX_COMMAND);

[Severity: Medium]
Should this register write be protected by rh_process_lock?

Writing directly to R_MBX_COMMAND without holding the lock creates a concurrency race with the watchdog timer or response handler threads, which also write to this register for recovery commands. Using the exported cmh_rh_abort_mbx() would safely take the lock.

Quoted 12 lines
drivers/crypto/cmh/cmh_rh.c +0 -0
@@ -391,9 +391,9 @@ static void cmh_rh_process_mbx(u32 mbx_idx, u32 new_head, u32 irq_bits)
 		txn = cmh_tm_peek_transaction(mbx_idx);
 		if (txn && txn->first_vcq_id != txn->last_vcq_id) {
 			dev_warn_ratelimited(cmh_dev(),
 					     "rh: mbx[%u] multi-VCQ error vcq=%u..%u -- FLUSH+drain\n",
 					     mbx_idx, txn->first_vcq_id,
 					     txn->last_vcq_id);
 			cmh_rh_stat_inc_errors(mbx_idx);
 			cmh_reg_write32(MBX_IRQ_MASK, base, R_MBX_INTERRUPT);
 			cmh_reg_write32(MBX_COMMAND_FLUSH, base, R_MBX_COMMAND);

drivers/crypto/cmh/cmh_rh.c

Quoted 2 lines
drivers/crypto/cmh/cmh_rh.c +0 -0
 			cmh_rh_poke_tail(base);
 			cmh_rh_drain_mbx(mbx_idx, error);

[Severity: High]
Does draining the mailbox synchronously immediately after writing the FLUSH command risk a use-after-free on the DMA buffers?

The hardware FLUSH command is asynchronous. Calling cmh_rh_drain_mbx() right away completes the transactions and signals the callers to unmap and free their DMA buffers. The hardware engine might still be actively processing the aborted commands and writing to those freed addresses until the flush is actually acknowledged.

Additionally, is there missing mutual exclusion between this error recovery path and new VCQ submissions?

This executes under rh_process_lock, but the transaction manager thread submits new VCQs under txq->dispatch_lock. This allows the TM to ring the hardware doorbell and enqueue a new transaction while the RH is draining the queue. The RH will blindly pop the TM thread's new transaction and complete it with an error, while the hardware proceeds to execute it on freed memory.

drivers/crypto/cmh/cmh_rh.c static irqreturn_t cmh_rh_thread(int irq, void *data) · line 543

Quoted 10 lines

[ ... ]

drivers/crypto/cmh/cmh_rh.c +0 -0
@@ -536,11 +536,11 @@ static irqreturn_t cmh_rh_thread(int irq, void *data)
 		for (i = 0; i < cfg->mbx_count; i++) {
 			u32 new_head, irq_bits;
 
 			if (!READ_ONCE(rh.mbx[i].pending))
 				continue;
 
 			irq_bits = (u32)atomic_xchg(&rh.mbx[i].irq_bits, 0);
 			WRITE_ONCE(rh.mbx[i].pending, false);

[Severity: High]
Could unconditionally setting pending to false here introduce a race condition that loses interrupt events?

If a hardirq fires exactly between the atomic_xchg() and the WRITE_ONCE(), the hardirq will set pending to true and accumulate new bits into irq_bits. The WRITE_ONCE() then overwrites pending to false, causing the threaded handler to ignore the new interrupt on the next pass, leaving stale error bits in irq_bits.

Quoted 11 lines

[ ... ]

drivers/crypto/cmh/cmh_rh.c +0 -0
@@ -714,9 +714,9 @@ static void cmh_rh_watchdog_fn(struct timer_list *t)
 					dev_err(cmh_dev(),
 						"rh: watchdog: mbx[%u] RESTART unresponsive after %u ticks, escalating to FLUSH (attempt %u/%u)\n",
 						i, rh.mbx[i].restart_retries,
 						rh.mbx[i].flush_count,
 						CMH_RH_FLUSH_MAX_FAILURES);
 					cmh_reg_write32(MBX_IRQ_MASK,
 							base,
 							R_MBX_INTERRUPT);
 					cmh_reg_write32(MBX_COMMAND_FLUSH,

drivers/crypto/cmh/cmh_rh.c

Quoted 4 lines
drivers/crypto/cmh/cmh_rh.c +0 -0
 							base,
 							R_MBX_COMMAND);
 					cmh_rh_poke_tail(base);
 					cmh_rh_drain_mbx(i, -EIO);

[Severity: High]
Similar to the processing path above, does draining immediately after escalating to a FLUSH command cause a DMA use-after-free?

The watchdog completes the transactions and causes their buffers to be freed without waiting for the hardware to process the FLUSH command.

drivers/crypto/cmh/cmh_txn.c static int resolve_mbx(struct command_msg *msg) · line 661

Quoted 13 lines
drivers/crypto/cmh/cmh_txn.c +0 -0
@@ -652,10 +652,10 @@ static int resolve_mbx(struct command_msg *msg)
 {
 	u32 slots = msg->num_vcqs > 0 ? msg->num_vcqs : 1;
 
 	if (msg->target_mbx >= 0 &&
 	    (u32)msg->target_mbx < tm.cfg->mbx_count) {
 		struct cmh_mbx_config *m =
 			&tm.cfg->mailboxes[msg->target_mbx];
 
 		if (cmh_rh_mbx_is_wedged((u32)msg->target_mbx))
 			return -EAGAIN;

[Severity: High]
If the pinned target mailbox is permanently wedged, this returns -EAGAIN. Will this cause an infinite loop in the transaction manager thread?

In cmh_tm_thread(), any negative error code other than -EMSGSIZE is treated as a temporary queue full condition. The thread will place the message back at the front of the queue and sleep, indefinitely blocking all other requests in the command message queue.

Quoted 13 lines

[ ... ]

drivers/crypto/cmh/cmh_txn.c +0 -0
@@ -716,11 +716,11 @@ static int submit_vcq(struct command_msg *msg, u32 mbx_idx)
 	u32 tail, stride_bytes, offset = 0;
 	unsigned long flags;
 	u32 v;
 
 	mutex_lock(&txq->dispatch_lock);
 
 	/* Read current tail (first VCQ ID) */
 	tail = cmh_reg_read32(mbx->reg_base, R_MBX_QUEUE_TAIL);
 	stride_bytes = 1U << mbx->stride_log2;
 
 	/* Allocate transaction tracking object */
Quoted 1 line

txn = kzalloc_obj(*txn, GFP_KERNEL);

[Severity: Low]
Is kzalloc_obj a macro defined somewhere in this tree?

It doesn't appear to be a standard kernel memory allocation function, which will cause a build error.

Quoted 15 lines

[ ... ]

drivers/crypto/cmh/cmh_txn.c +0 -0
@@ -832,10 +832,10 @@ static int submit_vcq(struct command_msg *msg, u32 mbx_idx)
 	spin_lock_irqsave(&txq->lock, flags);
 	list_add_tail(&txn->list, &txq->head);
 	txq->depth++;
 	spin_unlock_irqrestore(&txq->lock, flags);
 
 	/*
 	 * Arm the per-request timeout BEFORE the doorbell (async only): once
 	 * the doorbell rings, HW can complete and the TXQ can pop and free the
 	 * txn concurrently, so arming afterwards races that free and can leave
 	 * timer_delete() in cmh_txn_finish() unable to drop the timer ref.
drivers/crypto/cmh/cmh_txn.c +0 -0
 	 */
 	if (msg->timeout_jiffies)
 		mod_timer(&txn->timeout_timer,

drivers/crypto/cmh/cmh_txn.c

Quoted 10 lines
drivers/crypto/cmh/cmh_txn.c +0 -0
 			  jiffies + msg->timeout_jiffies);
 
 	/*
 	 * Ring doorbell: advance tail by number of VCQs submitted.
 	 * Serialise against cmh_tm_poke_tail() so a concurrent re-poke
 	 * cannot roll TAIL back over this advance.
 	 */
 	spin_lock_irqsave(&cmh_mbx_tail_lock, flags);
 	cmh_reg_write32(tail + num_vcqs, mbx->reg_base, R_MBX_QUEUE_TAIL);
 	spin_unlock_irqrestore(&cmh_mbx_tail_lock, flags);

[Severity: High]
As mentioned earlier, does this enqueue and hardware doorbell sequence need to be synchronized with the response handler's error recovery path to avoid submitting VCQs into a flushed queue?

Quoted 12 lines

[ ... ]

drivers/crypto/cmh/cmh_txn.c +0 -0
@@ -874,10 +874,10 @@ static int cmh_tm_thread(void *data)
 	while (!kthread_should_stop()) {
 		/* Wait for work or stop signal */
 		wait_event_interruptible(tm.cmq_waitq,
 					 !list_empty(&tm.cmq) || kthread_should_stop());
 
 		if (kthread_should_stop())
 			break;
 
 		/* Dequeue one command message */
 		spin_lock_irqsave(&tm.cmq_lock, flags);

drivers/crypto/cmh/cmh_txn.c

Quoted 6 lines
drivers/crypto/cmh/cmh_txn.c +0 -0
 		if (list_empty(&tm.cmq)) {
 			spin_unlock_irqrestore(&tm.cmq_lock, flags);
 			continue;
 		}
 		msg = list_first_entry(&tm.cmq, struct command_msg, list);
 		list_del_init(&msg->list);

[Severity: High]
Does temporarily removing the message from the list here break the cancellation logic in cmh_tm_submit_sync_tmo()?

If the caller's initial wait_for_completion_timeout expires while the TM thread has dequeued the message to evaluate mailbox availability, the caller's cmh_tm_try_cancel_command() will return false. The caller then assumes the transaction is owned by the hardware and proceeds to abandon it.

Quoted 13 lines

[ ... ]

drivers/crypto/cmh/cmh_txn.c +0 -0
@@ -1241,11 +1241,11 @@ void cmh_tm_quiesce(void)
 			spin_lock_irqsave(&tm.txqs[i].lock, flags);
 			list_splice_init(&tm.txqs[i].head, &drain);
 			tm.txqs[i].depth = 0;
 			spin_unlock_irqrestore(&tm.txqs[i].lock, flags);
 
 			list_for_each_entry_safe(txn, tmp_txn, &drain, list) {
 				list_del(&txn->list);
 
 				if (timer_delete_sync(&txn->timeout_timer))
 					txn_put(txn);
 

drivers/crypto/cmh/cmh_txn.c

Quoted 7 lines
drivers/crypto/cmh/cmh_txn.c +0 -0
 				old = atomic_cmpxchg(&txn->state,
 						     TXN_INFLIGHT,
 						     TXN_COMPLETE);
 				if (txn->complete) {
 					if (old == TXN_INFLIGHT)
 						txn->complete(txn->completion_data,
 							      -ECANCELED);

[Severity: High]
Does force-completing the remaining transactions here cause a use-after-free if the hardware is not actually aborted?

If the drain timeout expires, this signals the caller to free their DMA buffers by returning -ECANCELED. However, since the hardware mailbox was never issued a FLUSH or ABORT command, a slow hardware operation could eventually finish and corrupt the freed memory.

drivers/crypto/cmh/cmh_txn.c int cmh_tm_submit_sync_tmo(struct vcq_cmd *vcq_cmds, u32 vcq_count, · line 1551

Quoted 11 lines

[ ... ]

drivers/crypto/cmh/cmh_txn.c +0 -0
@@ -1543,10 +1543,10 @@ int cmh_tm_submit_sync_tmo(struct vcq_cmd *vcq_cmds, u32 vcq_count,
 	dev_dbg(cmh_dev(), "tm: submit_sync posted cmd 0x%08x, waiting...\n",
 		msg->command_id);
 
 	left = wait_for_completion_timeout(&sync->done, timeout_hz);
 	if (!left) {
 		dev_err(cmh_dev(),
 			"tm: submit_sync timeout (%lums) cmd=0x%08x\n",
 			timeout_hz * 1000 / HZ, msg->command_id);
 		if (cmh_tm_try_cancel_command(msg)) {

[Severity: High]
As mentioned earlier, does this cancellation check fail incorrectly if the TM thread temporarily removed the message to evaluate mailbox availability?

Quoted 20 lines

[ ... ]

drivers/crypto/cmh/cmh_txn.c +0 -0
@@ -1599,10 +1599,10 @@ int cmh_tm_submit_sync_tmo(struct vcq_cmd *vcq_cmds, u32 vcq_count,
 			 * wait for the RH completion (ABORT triggers
 			 * MBX_ERROR_IRQ within microseconds).  Fixed
 			 * 5 s ceiling -- not configurable because if
 			 * ABORT doesn't complete in this window the
 			 * HW is wedged and more waiting won't help.
 			 */
 			left = wait_for_completion_timeout(&sync->done,
 							   5 * HZ);
 			if (!left) {
 				/*
drivers/crypto/cmh/cmh_txn.c +0 -0
 				 * ABORT did not complete within 5 s -- the HW
 				 * is wedged.  Unlike cmh_tm_submit_sync_noabort,
 				 * this path sets no orphan_cb, so the caller's
 				 * DMA buffers are NOT orphaned here: the caller
 				 * frees them on the -ETIMEDOUT below.  If the
 				 * eSW later recovers and DMAs into them that is
 				 * a use-after-free -- an accepted residual for a
 				 * path that cannot be reached unless ABORT

drivers/crypto/cmh/cmh_txn.c

Quoted 10 lines
drivers/crypto/cmh/cmh_txn.c +0 -0
 				 * itself hangs for 5 s (HW already wedged).
 				 */
 				dev_err(cmh_dev(),
 					"tm: abort timeout (5s) cmd=0x%08x - HW wedged\n",
 					msg->command_id);
 			}
 			cmh_sync_ctx_put(sync);  /* drop waiter ref */
 			command_msg_put(msg);    /* drop waiter ref on msg */
 		}
 		return -ETIMEDOUT;

[Severity: High]
Does returning -ETIMEDOUT here after the 5-second wait expires create a guaranteed use-after-free if the hardware eventually recovers?

Since the caller frees the DMA buffers without the transaction transitioning to TXN_TIMED_OUT, the watchdog's abort-stall detector won't forcibly flush the mailbox. If the hardware is stalled and later recovers, it will resume executing the VCQ into the freed memory.

drivers/crypto/cmh/cmh_txn.c int cmh_tm_flush_mbx(s32 mbx_idx) · line 1940

Quoted 12 lines

[ ... ]

drivers/crypto/cmh/cmh_txn.c +0 -0
@@ -1931,10 +1931,10 @@ int cmh_tm_flush_mbx(s32 mbx_idx)
 
 	/* Ensure no command is already pending */
 	if (cmh_reg_read32(base, R_MBX_COMMAND) != 0) {
 		mutex_unlock(&txq->dispatch_lock);
 		return -EBUSY;
 	}
 
 	cmh_reg_write32(MBX_COMMAND_FLUSH, base, R_MBX_COMMAND);
 
 	/* Poll until eSW clears the command register */

[Severity: High]
Could a concurrent RESTART command overwrite this FLUSH command?

This function acquires dispatch_lock but not rh_process_lock. A concurrent error detection in the response handler watchdog could write MBX_COMMAND_RESTART to the exact same register. The register would eventually clear when the RESTART completes, causing this function to falsely assume the hardware queue was successfully flushed. This can lead to memory corruption when the hardware continues processing the remaining items in the queue while the caller has freed them.

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=2
#7 lore raw

PATCH v5 3/19 crypto: cmh - add key provisioning and management

In reply to Alex Ousherovitch

The in-kernel crypto API cannot express the CMH management plane, so this patch adds a character device (/dev/cmh_mgmt) for it. The ioctl commands fall into two groups; the overlap with the transforms the driver also registers is deliberate and bounded:

(1) Operations with no crypto API representation - the majority. The API has no transform type or verb for these, so a character device is the only available UAPI:
- hardware key lifecycle: create, import, export, derive, destroy, enumerate (keystore CRUD) - no keystore verb
- KIC key derivation (HKDF, AES-CMAC-KDF, DKEK)
- asymmetric key generation (RSA, EC, EdDSA, ML-DSA, SLH-DSA) and public-key derivation - the API has no keygen verb
- ML-KEM encapsulate/decapsulate - no kernel KEM API exists
- SM2 encrypt/decrypt and key exchange (multi-step GM/T 0003)
- EdDSA sign/verify - not registered with the crypto API
- EAC Chip Authentication and DRBG (re)configuration

(2) Hardware-held-key operations on algorithms that ARE also registered (RSA decrypt, ECDSA/ML-DSA/SLH-DSA sign, ECDH). These name the same primitives as the registered akcipher/sig/kpp transforms, but the crypto API set_priv_key()/set_secret() accept only raw key bytes supplied by the caller; they cannot reference a private key that is generated inside, and never leaves, the hardware datastore - the central security property of this device. The ioctl path keeps the private key hardware-resident, while the registered transforms serve raw-key in-kernel users. The two paths are complementary, not redundant.

The subsystem provides:

- Key provisioning: create, import, derive, and destroy hardware keys stored in the CMH datastore
- System object management: allocate and free CMH system objects
- Management ioctl interface (/dev/cmh_mgmt): key lifecycle, KIC key derivation, PKE (RSA, ECDSA, ECDH, EdDSA), PQC (ML-KEM, ML-DSA, SLH-DSA), SM2, EAC, and DRBG reseeding
- SM2 ioctl handlers: encrypt, decrypt, sign, and key exchange -- multi-step protocol flows not expressible through the crypto API sig interface
- UAPI header: cmh_mgmt_ioctl.h (ioctl definitions and structures)

The device requires CAP_SYS_ADMIN for open() and is built conditionally on CONFIG_CRYPTO_DEV_CMH_MGMT (default n); when disabled the ioctl interface is absent while all kernel crypto API algorithms remain registered.

---
 Documentation/ABI/testing/cmh-mgmt       |  136 ++
 drivers/crypto/cmh/Kconfig               |   19 +
 drivers/crypto/cmh/Makefile              |   11 +-
 drivers/crypto/cmh/cmh_key.c             |  164 ++
 drivers/crypto/cmh/cmh_main.c            |    9 +
 drivers/crypto/cmh/cmh_mgmt.c            | 1770 ++++++++++++++++++++++
 drivers/crypto/cmh/cmh_mgmt_pke.c        | 1143 ++++++++++++++
 drivers/crypto/cmh/cmh_mgmt_pqc.c        | 1365 +++++++++++++++++
 drivers/crypto/cmh/cmh_pke_sm2.c         |  862 +++++++++++
 drivers/crypto/cmh/cmh_sys.c             |  376 +++++
 drivers/crypto/cmh/include/cmh_key.h     |   82 +
 drivers/crypto/cmh/include/cmh_mgmt.h    |   69 +
 drivers/crypto/cmh/include/cmh_pke.h     |  245 +++
 drivers/crypto/cmh/include/cmh_pke_sm2.h |   30 +
 drivers/crypto/cmh/include/cmh_pqc.h     |   25 +
 drivers/crypto/cmh/include/cmh_sys.h     |  111 ++
 include/uapi/linux/cmh_mgmt_ioctl.h      |  902 +++++++++++
 17 files changed, 7318 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/ABI/testing/cmh-mgmt
 create mode 100644 drivers/crypto/cmh/cmh_key.c
 create mode 100644 drivers/crypto/cmh/cmh_mgmt.c
 create mode 100644 drivers/crypto/cmh/cmh_mgmt_pke.c
 create mode 100644 drivers/crypto/cmh/cmh_mgmt_pqc.c
 create mode 100644 drivers/crypto/cmh/cmh_pke_sm2.c
 create mode 100644 drivers/crypto/cmh/cmh_sys.c
 create mode 100644 drivers/crypto/cmh/include/cmh_key.h
 create mode 100644 drivers/crypto/cmh/include/cmh_mgmt.h
 create mode 100644 drivers/crypto/cmh/include/cmh_pke.h
 create mode 100644 drivers/crypto/cmh/include/cmh_pke_sm2.h
 create mode 100644 drivers/crypto/cmh/include/cmh_pqc.h
 create mode 100644 drivers/crypto/cmh/include/cmh_sys.h
 create mode 100644 include/uapi/linux/cmh_mgmt_ioctl.h
Documentation/ABI/testing/cmh-mgmt new file +136 -0
new file mode 100644
index 000000000000..7da2630edb20
@@ -0,0 +1,136 @@
+What:		/dev/cmh_mgmt
+Date:		June 2026
+KernelVersion:	7.1
+Contact:	[email protected]
+Description:
+		Character device (misc) providing a management and
+		key-operations ioctl interface to the Rambus CryptoManager Hub
+		hardware crypto accelerator.  Used for operations that
+		cannot be represented through the standard in-kernel
+		crypto API: datastore key CRUD, key derivation,
+		asymmetric crypto (EdDSA, SM2), and post-quantum crypto
+		(ML-KEM, ML-DSA, SLH-DSA).
+
+		The ioctl magic is 'J'.  All struct arguments are
+		versioned via a leading __u32 version field set to
+		CMH_MGMT_V1 (1).
+
+		Ioctl commands are grouped by function:
+
+		**Key Management (0x01-0x0E):**
+
+		- CMH_IOCTL_KEY_NEW (0x01): Allocate a new datastore slot.
+		  Accepts ds_type (CMH_DS_* constant), key length, flags,
+		  and caller ID.  Returns a 64-bit key reference.
+
+		- CMH_IOCTL_KEY_WRITE (0x02): Write key material into
+		  a previously allocated datastore slot.  Supports
+		  plaintext or wrapped key import via a wrapping key ref.
+
+		- CMH_IOCTL_KEY_READ (0x03): Read key material from
+		  a datastore slot, optionally wrapped.  Returns data
+		  plus a 16-byte SYS header for wrapped reads.
+
+		- CMH_IOCTL_KEY_FIND (0x04): Look up a key reference
+		  by caller ID (CID).
+
+		- CMH_IOCTL_KEY_GRANT (0x05): Grant access to a key.
+
+		- CMH_IOCTL_KEY_DELETE (0x06): Delete a datastore slot.
+
+		- CMH_IOCTL_DS_EXPORT (0x07): Export the entire datastore
+		  as an encrypted blob.
+
+		- CMH_IOCTL_DS_IMPORT (0x08): Import a previously exported
+		  datastore blob.
+
+		- CMH_IOCTL_KEY_NEW_RANDOM (0x0B): Allocate a datastore
+		  slot and fill it with hardware-generated random data.
+
+		- CMH_IOCTL_KEY_LIST (0x0E): List active datastore entries,
+		  returning CIDs, types, lengths, and flags.
+
+		**Key Derivation -- KIC (0x09-0x0D):**
+
+		- CMH_IOCTL_KIC_HKDF1 (0x09): HKDF-Extract step.
+		- CMH_IOCTL_KIC_HKDF2 (0x0A): HKDF-Expand step.
+		- CMH_IOCTL_KIC_AES_CMAC_KDF (0x0C): AES-CMAC KDF.
+		- CMH_IOCTL_KIC_DKEK_DERIVE (0x0D): DKEK derivation.
+
+		**EAC -- Error and Alarm (0x0F):**
+
+		- CMH_IOCTL_EAC_READ (0x0F): Read and clear hardware
+		  error, alarm, and safety notification registers.
+
+		**PKE -- Public Key Engine (0x10-0x1C):**
+
+		- CMH_IOCTL_PKE_RSA_ENC (0x10): RSA public-key encrypt.
+		- CMH_IOCTL_PKE_RSA_DEC (0x11): RSA private-key decrypt.
+		- CMH_IOCTL_PKE_RSA_CRT_DEC (0x12): RSA-CRT decrypt.
+		- CMH_IOCTL_PKE_RSA_KEYGEN (0x13): RSA key pair generation.
+		- CMH_IOCTL_PKE_ECDSA_SIGN (0x14): ECDSA sign.
+		- CMH_IOCTL_PKE_ECDH (0x16): ECDH shared secret.
+		- CMH_IOCTL_PKE_ECDH_KEYGEN (0x17): ECDH key pair generation.
+		- CMH_IOCTL_PKE_EDDSA_SIGN (0x18): EdDSA sign (Ed25519/Ed448).
+		- CMH_IOCTL_PKE_EDDSA_VERIFY (0x19): EdDSA verify.
+		- CMH_IOCTL_PKE_EC_KEYGEN (0x1A): EC key pair generation.
+		- CMH_IOCTL_PKE_EC_PUBGEN (0x1B): EC public key derivation.
+		- CMH_IOCTL_PKE_EDDSA_KEYGEN_SCA (0x1C): EdDSA SCA-protected
+		  key generation.
+
+		**PQC -- Post-Quantum Crypto (0x20-0x2D):**
+
+		- CMH_IOCTL_ML_KEM_KEYGEN (0x20): ML-KEM key pair generation
+		  (modes 512/768/1024).
+		- CMH_IOCTL_ML_KEM_ENC (0x21): ML-KEM encapsulation.
+		- CMH_IOCTL_ML_KEM_DEC (0x22): ML-KEM decapsulation.
+		- CMH_IOCTL_ML_DSA_KEYGEN (0x23): ML-DSA key pair generation
+		  (modes 44/65/87).
+		- CMH_IOCTL_ML_DSA_SIGN (0x24): ML-DSA sign.
+		- CMH_IOCTL_SLHDSA_KEYGEN (0x28): SLH-DSA key pair generation
+		  (12 parameter sets).
+		- CMH_IOCTL_SLHDSA_SIGN (0x29): SLH-DSA sign.
+		- CMH_IOCTL_SLHDSA_SIGN_PREHASH (0x2D): SLH-DSA prehash sign.
+
+		**SM2 Operations (0x30-0x37):**
+
+		- CMH_IOCTL_SM2_ECDH_KEYGEN (0x30): SM2 ephemeral key gen.
+		- CMH_IOCTL_SM2_ECDH (0x31): SM2 key exchange.
+		- CMH_IOCTL_SM2_DEC_POINT (0x32): SM2 decrypt (point step).
+		- CMH_IOCTL_SM2_ENC_POINT (0x33): SM2 encrypt (point step).
+		- CMH_IOCTL_SM2_ID_DIGEST (0x34): SM2 ID digest (ZA).
+		- CMH_IOCTL_SM2_ECDH_HASH (0x35): SM2 key exchange hash step.
+		- CMH_IOCTL_SM2_DEC_HASH (0x36): SM2 decrypt (hash step).
+		- CMH_IOCTL_SM2_ENC_HASH (0x37): SM2 encrypt (hash step).
+
+		The SM2 encrypt/decrypt hash-step ioctls accept payloads
+		of at most 32 bytes.  The underlying hardware KDF emits a
+		single 32-byte SM3 block, so longer messages cannot be
+		processed in a single command and are rejected with
+		-EINVAL.
+
+		**DRBG Management (0x40):**
+
+		- CMH_IOCTL_DRBG_CONFIG (0x40): Configure the hardware
+		  DRBG entropy ratio and security strength.  Normally
+		  called once at system start-up before hwrng reads.
+
+		All structs contain ``__reserved`` fields that must be
+		zero; the driver returns ``-EINVAL`` if any reserved field
+		is non-zero.  This ensures forward compatibility when
+		reserved fields gain meaning in future versions.
+
+		All ioctls return 0 on success or a negative errno on
+		failure.  Common errors:
+
+		- EINVAL:  Invalid version, parameter, key type, or
+		  non-zero reserved field.
+		- ENOENT:  Key reference not found in datastore.
+		- ENOMEM:  DMA allocation failure.
+		- EBUSY:   Hardware mailbox full.
+		- ETIMEDOUT: VCQ operation timed out.
+		- EFAULT:  Bad user-space pointer.
+
+		The ioctl UAPI header is <linux/cmh_mgmt_ioctl.h>.
+		All structures, constants, and type definitions are
+		documented in that header file.
drivers/crypto/cmh/Kconfig +19 -0
index fca66d5e2f89..512e7b3bdc59 100644
@@ -63,3 +63,22 @@ config CRYPTO_DEV_CMH_DEBUG
 	  Useful for bringup, validation, and performance analysis.
 	  Not recommended for production.
 
+
+config CRYPTO_DEV_CMH_MGMT
+	bool "CMH management ioctl device (/dev/cmh_mgmt)"
+	depends on CRYPTO_DEV_CMH
+	default n
+	help
+	  Expose /dev/cmh_mgmt, a misc device providing ioctl commands
+	  for operations that have no kernel crypto API binding: hardware
+	  key lifecycle (create, import, derive, destroy), KIC key
+	  derivation, PQC keygen/encaps/decaps (ML-KEM, ML-DSA, SLH-DSA),
+	  EdDSA sign/verify, SM2 key exchange, and DRBG
+	  configuration.
+
+	  The device requires CAP_SYS_ADMIN.  Disabling this option
+	  removes the ioctl interface but all kernel crypto API
+	  algorithms (consumed by in-kernel users and validated by the
+	  crypto test manager) remain fully functional.
+
+	  If unsure, say N.
drivers/crypto/cmh/Makefile +10 -1
index 742e65e3917e..bb7772555d6a 100644
@@ -12,7 +12,16 @@ cmh-y := \
 	cmh_txn.o \
 	cmh_rh.o \
 	cmh_dma.o \
-	cmh_sysfs.o
+	cmh_sysfs.o \
+	cmh_key.o \
+	cmh_sys.o
+
+# Management ioctl device (/dev/cmh_mgmt): key lifecycle, PKE, PQC ioctls.
+cmh-$(CONFIG_CRYPTO_DEV_CMH_MGMT) += \
+	cmh_mgmt.o \
+	cmh_mgmt_pke.o \
+	cmh_mgmt_pqc.o \
+	cmh_pke_sm2.o
 
 ccflags-y += -I$(src)/include
 
drivers/crypto/cmh/cmh_key.c new file +164 -0

164 lines not on this page · raw message

drivers/crypto/cmh/cmh_main.c +9 -0
index c037e8daa877..d7753c4630ba 100644
@@ -31,6 +31,7 @@
 #include "cmh_mqi.h"
 #include "cmh_txn.h"
 #include "cmh_rh.h"
+#include "cmh_mgmt.h"
 #include "cmh_registers.h"
 #include "cmh_debugfs.h"
 #include "cmh_sysfs.h"
@@ -201,10 +202,17 @@ static int cmh_probe(struct platform_device *pdev)
 	if (ret)
 		goto err_rh_init;
 
+	/* Register key management device (/dev/cmh_mgmt) */
+	ret = cmh_mgmt_register();
+	if (ret)
+		goto err_mgmt_register;
+
 	platform_set_drvdata(pdev, dev);
 
 	return 0;
 
+err_mgmt_register:
+	cmh_rh_cleanup(cfg);
 err_rh_init:
 	cmh_tm_cleanup();
 err_tm_init:
@@ -229,6 +237,7 @@ static void cmh_remove(struct platform_device *pdev)
 
 	cfg = &dev->config;
 
+	cmh_mgmt_unregister();
 	cmh_rh_cleanup(cfg);
 	cmh_tm_cleanup();
 	cmh_mqi_cleanup(cfg);
drivers/crypto/cmh/cmh_mgmt.c new file +1770 -0

1,770 lines not on this page · raw message

drivers/crypto/cmh/cmh_mgmt_pke.c new file +1143 -0

860 lines not on this page · raw message

drivers/crypto/cmh/cmh_mgmt_pqc.c new file +1365 -0

1,365 lines not on this page · raw message

drivers/crypto/cmh/cmh_pke_sm2.c new file +862 -0

862 lines not on this page · raw message

drivers/crypto/cmh/cmh_sys.c new file +376 -0

376 lines not on this page · raw message

drivers/crypto/cmh/include/cmh_key.h new file +82 -0

82 lines not on this page · raw message

drivers/crypto/cmh/include/cmh_mgmt.h new file +69 -0

69 lines not on this page · raw message

drivers/crypto/cmh/include/cmh_pke.h new file +245 -0

245 lines not on this page · raw message

drivers/crypto/cmh/include/cmh_pke_sm2.h new file +30 -0
new file mode 100644
index 000000000000..a2c7164b8d49

Lines of this file are not shown. View the raw message.

drivers/crypto/cmh/include/cmh_pqc.h new file +25 -0
new file mode 100644
index 000000000000..cd4761a0ce5c

Lines of this file are not shown. View the raw message.

drivers/crypto/cmh/include/cmh_sys.h new file +111 -0

111 lines not on this page · raw message

include/uapi/linux/cmh_mgmt_ioctl.h new file +902 -0

902 lines not on this page · raw message

The rest of this diff is not shown. View the raw message.

Signature · 1 line
2.43.7

Part of the diff is not shown here. View the raw message.

#8 lore raw

Re: [PATCH v5 03/19] crypto: cmh - add key provisioning and management

Thank you for your contribution! Sashiko AI review found 8 potential issue(s) to consider: - [Critical] crypto: cmh: Transaction abort timeout leads to Use-After-Free of DMA buffers - [High] crypto…

Thank you for your contribution! Sashiko AI review found 8 potential issue(s) to consider:
- [Critical] crypto: cmh: Transaction abort timeout leads to Use-After-Free of DMA buffers
- [High] crypto: cmh: Unmapped DMA address 0 is unmapped on error paths in PQC sign ioctls
- [High] crypto: cmh: cmh_mgmt_sm2_ecdh_hash() omits PKE_SWAP_FLAGS corrupting the shared key
- [High] crypto: cmh: Hardcoded PKE_SWAP_FLAGS corrupts ECDH operations for X25519 and Curve448
- [High] crypto: cmh: Standard crypto requests are randomly aborted by management ioctls
- [Medium] crypto: cmh: Resource leak in cmh_mgmt_sm2_ecdh_hash() error path
- [Medium] crypto: cmh: Guarding DMA unmap with && dma leaks mapping if valid address is 0
- [Medium] crypto: cmh: TOCTOU race on shared hardware temp store across multiple ioctls --

commit 48c89e33b36bd86891b285934734edd42955fb45
Author: Alex Ousherovitch <[email protected]>
Subject: crypto: cmh - add key provisioning and management

This commit adds a character device (/dev/cmh_mgmt) to expose CMH management operations such as key provisioning, derivation, asymmetric cryptography, and post-quantum cryptography algorithms.

Quoted 9 lines
drivers/crypto/cmh/cmh_txn.c +0 -0
@@ -1453,30 +1453,25 @@ int cmh_tm_submit_sync_tmo(struct vcq_cmd *vcq_cmds, u32 vcq_count,
 			left = wait_for_completion_timeout(&sync->done,
 							   5 * HZ);
 			if (!left) {
 				/*
 				 * ABORT did not complete within 5 s -- the HW

[ ... ]

drivers/crypto/cmh/cmh_txn.c

Quoted 8 lines
drivers/crypto/cmh/cmh_txn.c +0 -0
 				dev_err(cmh_dev(),
 					"tm: abort timeout (5s) cmd=0x%08x - HW wedged\n",
 					msg->command_id);
 			}
 			cmh_sync_ctx_put(sync);  /* drop waiter ref */
 			command_msg_put(msg);    /* drop waiter ref on msg */
 		}
 		return -ETIMEDOUT;

[Severity: Critical]
Is there a risk of a use-after-free here if the transaction abort times out?

When cmh_tm_submit_sync_tmo() returns -ETIMEDOUT, the callers proceed to free their destination buffers. If the hardware is merely stalled rather than completely wedged, and it subsequently completes the DMA operation, could it write directly into the freed kernel memory?

Quoted 12 lines
drivers/crypto/cmh/cmh_mgmt.c +0 -0
@@ -1083,10 +1083,10 @@ static int cmh_mgmt_kic_aes_cmac_kdf(void __user *argp)
 	if (label_buf) {
 		cmh_dma_unmap_single(label_dma, req.label_len, DMA_TO_DEVICE);
 		kfree(label_buf);
 		label_buf = NULL;
 	}
 
 	if (ret)
 		goto out_ref_cmac;

[ ... ]

drivers/crypto/cmh/cmh_mgmt.c

Quoted 3 lines

out_unmap_label_cmac:

drivers/crypto/cmh/cmh_mgmt.c +0 -0
 	if (label_buf && !cmh_dma_map_error(label_dma) && label_dma)
 		cmh_dma_unmap_single(label_dma, req.label_len, DMA_TO_DEVICE);

[Severity: Medium]
Does checking && label_dma potentially leak the DMA mapping?

Since a physical address of 0 can be a valid mapped DMA address on some systems, skipping the unmap when the address evaluates to false seems like it could result in a resource leak.

[ ... ]

drivers/crypto/cmh/cmh_mgmt.c static long cmh_mgmt_ioctl_locked(struct file *file, unsigned int cmd, · line 1519

Quoted 8 lines
drivers/crypto/cmh/cmh_mgmt.c +0 -0
@@ -1513,10 +1513,10 @@ static long cmh_mgmt_ioctl_locked(struct file *file, unsigned int cmd,
 				  void __user *argp)
 {
 	int ret;
 
 	if (cmh_mgmt_needs_temp_flush(cmd) &&
 	    atomic_xchg(&mgmt_temp_dirty, 0)) {
 		ret = cmh_tm_flush_mbx(MGMT_MBX);

[Severity: High]
Could this flush inadvertently cancel unrelated kernel crypto requests?

Standard crypto API requests are assigned mailboxes via round-robin, which can include MGMT_MBX. When a management ioctl calls cmh_tm_flush_mbx() to clear the temporary datastore stack, it issues a hardware command that discards all queued commands. Will this forcefully abort in-flight crypto requests with -ECANCELED?

[ ... ]

drivers/crypto/cmh/cmh_mgmt.c static long cmh_mgmt_ioctl(struct file *file, unsigned int cmd, · line 1659

Quoted 11 lines
drivers/crypto/cmh/cmh_mgmt.c +0 -0
@@ -1650,10 +1650,10 @@ static long cmh_mgmt_ioctl(struct file *file, unsigned int cmd,
 			   unsigned long arg)
 {
 	void __user *argp = (void __user *)arg;
 	long ret;
 
 	mutex_lock(&cmh_mgmt_lock);
 	ret = cmh_mgmt_ioctl_locked(file, cmd, argp);
 	mutex_unlock(&cmh_mgmt_lock);
 	return ret;
 }

[Severity: Medium]
Is it possible to hit a TOCTOU race on the shared hardware temp store here?

Cross-ioctl flows targeting the temp store execute as separate ioctl calls. Because cmh_mgmt_lock is released between them, couldn't a concurrent ioctl from another process interleave, flush or overwrite the temporary datastore, and destroy the first process's key material?

drivers/crypto/cmh/cmh_mgmt_pke.c int cmh_mgmt_pke_ecdh(void __user *argp) · line 630

Quoted 11 lines
drivers/crypto/cmh/cmh_mgmt_pke.c +0 -0
@@ -624,10 +624,10 @@ int cmh_mgmt_pke_ecdh(void __user *argp)
 	if (req.flags || req.__reserved || req.__reserved2)
 		return -EINVAL;
 	clen = cmh_pke_validate_curve(req.curve);
 	if (!clen)
 		return -EINVAL;
 
 	swap = PKE_SWAP_FLAGS;

[Severity: High]
Does hardcoding PKE_SWAP_FLAGS here corrupt ECDH operations for X25519 and Curve448?

Edwards and Montgomery curves use native little-endian byte ordering and must not be byte-swapped by the hardware. Should this use the pke_swap_flags() helper instead?

[ ... ]

drivers/crypto/cmh/cmh_mgmt_pke.c int cmh_mgmt_pke_ecdh_keygen(void __user *argp) · line 715

Quoted 5 lines
drivers/crypto/cmh/cmh_mgmt_pke.c +0 -0
@@ -712,10 +712,10 @@ int cmh_mgmt_pke_ecdh_keygen(void __user *argp)
 	vcq_set_header(&vcq[0], PKE_VCQ_CMDS_MIN);
 	vcq_add_pke_ecdh_keygen(&vcq[1], pke_cid, req.curve, clen,
 				pkx_dma, req.key_ref,
 				PKE_SWAP_FLAGS);

[Severity: High]
Similarly, can hardcoding PKE_SWAP_FLAGS in this VCQ builder corrupt the generated keys for non-Weierstrass curves?

Using the curve helper would ensure correct byte ordering for Curve25519 and Curve448.

Quoted 15 lines
drivers/crypto/cmh/cmh_mgmt_pqc.c +0 -0
@@ -1178,10 +1178,10 @@ int cmh_mgmt_slhdsa_sign(void __user *argp)
 	vcq_set_header(&vcq[0], HCQ_VCQ_CMDS_MIN);
 	vcq_add_hcq_slhdsa_sign(&vcq[1], hcq_cid, req.parameter_set,
 				req.msg_len, req.ctx_len,
 				rnd_dma, msg_dma, ctx_dma,
 				req.sk, sig_dma);
 	vcq_add_hcq_flush(&vcq[2], hcq_cid);
 
 	ret = cmh_tm_submit_sync_tmo(vcq, HCQ_VCQ_CMDS_MIN, 1, MGMT_MBX,
 				     cmh_tm_slow_op_timeout_jiffies());
 

out_unmap:

drivers/crypto/cmh/cmh_mgmt_pqc.c

Quoted 2 lines
drivers/crypto/cmh/cmh_mgmt_pqc.c +0 -0
 	if (rnd_buf && !cmh_dma_map_error(rnd_dma))
 		cmh_dma_unmap_single(rnd_dma, n_val, DMA_TO_DEVICE);

[Severity: High]
Can this lead to unmapping physical address 0?

The variable rnd_dma is initialized to 0. If rnd_buf is allocated but a subsequent mapping fails, the code branches to out_unmap. Since checking map error on 0 is typically false, this attempts to unmap 0, which violates the DMA API and could trigger kernel panics or IOMMU faults.

[ ... ]

Quoted 11 lines
drivers/crypto/cmh/cmh_mgmt_pqc.c +0 -0
@@ -1328,10 +1328,10 @@ int cmh_mgmt_slhdsa_sign_prehash(void __user *argp)
 	vcq_set_header(&vcq[0], HCQ_VCQ_CMDS_MIN);
 	vcq_add_hcq_slhdsa_sign_prehash(&vcq[1], hcq_cid,
 					hcq_cmd, req.parameter_set,
 					req.prehash_algo,
 					req.msg_len, req.ctx_len,
 					rnd_dma, msg_dma, ctx_dma,
 					req.sk, sig_dma);
 	vcq_add_hcq_flush(&vcq[2], hcq_cid);
 
 	ret = cmh_tm_submit_sync_tmo(vcq, HCQ_VCQ_CMDS_MIN, 1, MGMT_MBX,

drivers/crypto/cmh/cmh_mgmt_pqc.c

Quoted 5 lines
drivers/crypto/cmh/cmh_mgmt_pqc.c +0 -0
 				     cmh_tm_slow_op_timeout_jiffies());
 
 out_unmap:
 	if (rnd_buf && !cmh_dma_map_error(rnd_dma))
 		cmh_dma_unmap_single(rnd_dma, n_val, DMA_TO_DEVICE);

[Severity: High]
Does this exhibit the same unmapped address 0 issue as seen above?

If rnd_buf is allocated but rnd_dma mapping was skipped or a later mapping fails, unmapping 0 will occur here as well.

Quoted 14 lines
drivers/crypto/cmh/cmh_pke_sm2.c +0 -0
@@ -646,10 +646,10 @@ int cmh_mgmt_sm2_ecdh_hash(void __user *argp)
 	vcq_set_header(&vcq[0], 4);
 	vcq_add_sys_new(&vcq[1], 0, ref_dma, SM2_SHARED_KEY_LEN);
 	vcq[1].id |= PKE_SWAP_FLAGS;
 	vcq_add_pke_sm2_ecdh_hash(&vcq[2], core_id, peer_dig_dma, dig_dma,
 				  req.shared_point_ref, SYS_REF_LAST,
 				  sk_type, PKE_SWAP_FLAGS);
 	vcq_add_pke_flush(&vcq[3], core_id);
 
 	ret = cmh_tm_submit_sync_mbx(vcq, 4, 1, MGMT_MBX);
 	if (ret)
Quoted 1 line

goto out_unmap;

[Severity: Medium]
Is there a resource leak if Phase 1 fails?

When the sync submit fails, the code jumps to out_unmap but bypasses the scrub operation. Without calling cmh_mgmt_ds_scrub(), the already-allocated datastore object from sys_new will remain, causing a persistent datastore resource leak.

[ ... ]

drivers/crypto/cmh/cmh_pke_sm2.c int cmh_mgmt_sm2_ecdh_hash(void __user *argp) · line 660

Quoted 8 lines
drivers/crypto/cmh/cmh_pke_sm2.c +0 -0
@@ -654,10 +654,10 @@ int cmh_mgmt_sm2_ecdh_hash(void __user *argp)
 	/* Sync bounce buffer so CPU sees the DMA-written ref */
 	cmh_dma_sync_for_cpu(ref_dma, sizeof(u64), DMA_FROM_DEVICE);
 
 	/* Phase 2: read shared key from DS -> DMA */
 	vcq_set_header(&vcq[0], 3);
 	vcq_add_sys_data(&vcq[1], *ref_buf, sk_dma, SM2_SHARED_KEY_LEN);
 	vcq_add_sys_flush(&vcq[2]);

[Severity: High]
Will omitting PKE_SWAP_FLAGS here corrupt the shared key?

The SM2 key exchange requires PKE_SWAP_FLAGS on both its sys_new and sys_data commands to byte-reverse the payload from the internal Weierstrass format. Skipping this flag on Phase 2's sys_data command leaves the output shared key with the wrong byte order, which would break SM2 key exchange interoperability.

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=3
#9 lore raw

PATCH v5 4/19 crypto: cmh - add SHA-2/SHA-3/SHAKE ahash

In reply to Alex Ousherovitch

Register ahash algorithms for SHA-224, SHA-256, SHA-384, SHA-512, SHA3-224, SHA3-256, SHA3-384, SHA3-512, SHAKE128, and SHAKE256 using the CMH hash core (core ID 0x02).

The drivers set CRYPTO_AHASH_ALG_BLOCK_ONLY so the Crypto API buffers partial blocks; they support incremental update/finup and export/import for request cloning.

---
 drivers/crypto/cmh/Makefile           |   3 +-
 drivers/crypto/cmh/cmh_hash.c         | 812 ++++++++++++++++++++++++++
 drivers/crypto/cmh/cmh_main.c         |   9 +
 drivers/crypto/cmh/include/cmh_hash.h |  27 +
 4 files changed, 850 insertions(+), 1 deletion(-)
 create mode 100644 drivers/crypto/cmh/cmh_hash.c
 create mode 100644 drivers/crypto/cmh/include/cmh_hash.h
drivers/crypto/cmh/Makefile +2 -1
index bb7772555d6a..79c94d87e9ee 100644
@@ -14,7 +14,8 @@ cmh-y := \
 	cmh_dma.o \
 	cmh_sysfs.o \
 	cmh_key.o \
-	cmh_sys.o
+	cmh_sys.o \
+	cmh_hash.o
 
 # Management ioctl device (/dev/cmh_mgmt): key lifecycle, PKE, PQC ioctls.
 cmh-$(CONFIG_CRYPTO_DEV_CMH_MGMT) += \
drivers/crypto/cmh/cmh_hash.c new file +812 -0

812 lines not on this page · raw message

drivers/crypto/cmh/cmh_main.c +9 -0
index d7753c4630ba..50218f19ad6f 100644
@@ -31,6 +31,7 @@
 #include "cmh_mqi.h"
 #include "cmh_txn.h"
 #include "cmh_rh.h"
+#include "cmh_hash.h"
 #include "cmh_mgmt.h"
 #include "cmh_registers.h"
 #include "cmh_debugfs.h"
@@ -202,6 +203,11 @@ static int cmh_probe(struct platform_device *pdev)
 	if (ret)
 		goto err_rh_init;
 
+	/* Register hash algorithms with the kernel crypto API */
+	ret = cmh_hash_register();
+	if (ret)
+		goto err_hash_register;
+
 	/* Register key management device (/dev/cmh_mgmt) */
 	ret = cmh_mgmt_register();
 	if (ret)
@@ -212,6 +218,8 @@ static int cmh_probe(struct platform_device *pdev)
 	return 0;
 
 err_mgmt_register:
+	cmh_hash_unregister();
+err_hash_register:
 	cmh_rh_cleanup(cfg);
 err_rh_init:
 	cmh_tm_cleanup();
@@ -238,6 +246,7 @@ static void cmh_remove(struct platform_device *pdev)
 	cfg = &dev->config;
 
 	cmh_mgmt_unregister();
+	cmh_hash_unregister();
 	cmh_rh_cleanup(cfg);
 	cmh_tm_cleanup();
 	cmh_mqi_cleanup(cfg);
drivers/crypto/cmh/include/cmh_hash.h new file +27 -0
new file mode 100644
index 000000000000..198e557be280
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2026 Cryptography Research, Inc. (CRI).
+ * CMH LKM -- Kernel Crypto API Hash Driver
+ *
+ * Registers ahash algorithms (SHA-2, SHA-3, and SHAKE families) with the
+ * Linux crypto subsystem.  These are CRYPTO_AHASH_ALG_BLOCK_ONLY drivers,
+ * so the Crypto API buffers partial blocks and hands the driver only
+ * whole-block-aligned data:
+ *
+ *   .init()   -> software-only: zero per-request context
+ *   .update() -> INIT [+ RESTORE] + UPDATE(full blocks) + SAVE + FLUSH
+ *                (also serves final: the API calls finup with nbytes == 0)
+ *   .digest() -> INIT + UPDATE + FINAL + FLUSH (single-shot)
+ *   .export() -> software-only: copy the HC checkpoint
+ *   .import() -> software-only: restore the HC checkpoint
+ */
+
+#ifndef CMH_HASH_H
+#define CMH_HASH_H
+
+#include "cmh_config.h"
+
+int  cmh_hash_register(void);
+void cmh_hash_unregister(void);
+
+#endif /* CMH_HASH_H */
Signature · 1 line
2.43.7
#10 lore raw

Re: [PATCH v5 04/19] crypto: cmh - add SHA-2/SHA-3/SHAKE ahash

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Medium] crypto: cmh: ahash rejects valid large scatterlists --

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] crypto: cmh: ahash rejects valid large scatterlists
--

commit 75a869d1380414cdb3e2f319fd8862f445b10395

Author: Alex Ousherovitch <[email protected]>
Date:   Thu Sep 17 22:59:13 2026 +0000

crypto: cmh - add SHA-2/SHA-3/SHAKE ahash

This commit registers ahash algorithms for the SHA-2, SHA-3, and SHAKE families using the CMH hash core. It implements incremental update/finup and export/import for request cloning, relying on the crypto API's partial block buffering.

Quoted 5 lines
drivers/crypto/cmh/cmh_hash.c new file +0 -0
new file mode 100644
index 0000000000000..1acc8bdab3522

[ ... ]

Quoted 32 lines
drivers/crypto/cmh/cmh_hash.c new file +32 -0
+static int cmh_hash_update(struct ahash_request *req)
+{
+	struct cmh_hash_reqctx *rctx = ahash_request_ctx(req);
+	const struct cmh_hash_alg_info *info = rctx->info;
+	struct vcq_cmd cmds[CMH_HASH_MAX_PAYLOAD];
+	struct core_dispatch d;
+	u32 block_size = info->block_size;
+	u32 full_len;
+	u32 idx;
+	int ret;
+	gfp_t gfp;
+
+	if (rctx->error)
+		return rctx->error;
+
+	if (!req->nbytes)
+		return 0;
+
+	/*
+	 * block_size is not always a power of two (SHA-3 rates: 144/136/
+	 * 104/72), so use modulo -- round_down() would corrupt the split.
+	 */
+	rctx->update_remainder = req->nbytes % block_size;
+	full_len = req->nbytes - rctx->update_remainder;
+
+	gfp = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ?
+	      GFP_KERNEL : GFP_ATOMIC;
+
+	/*
+	 * Reject a single update whose linearisation would exceed the largest
+	 * kmalloc: return a permanent -EMSGSIZE ("message too long") rather
+	 * than a transient -ENOMEM the client would keep retrying.

drivers/crypto/cmh/cmh_hash.c line 378

Quoted 10 lines
drivers/crypto/cmh/cmh_hash.c new file +10 -0
+	 */
+	if (full_len > KMALLOC_MAX_SIZE)
+		return -EMSGSIZE;
+
+	/*
+	 * Linearise the block-aligned prefix from the scatterlist.
+	 * __GFP_NOWARN keeps a borderline-large (but sub-cap) request from
+	 * splatting the page allocator if it still cannot be satisfied.
+	 */
+	rctx->data_buf = kmalloc(full_len, gfp | __GFP_NOWARN);

[Severity: Medium]
Since the Linux crypto API contract permits arbitrary-sized inputs via scatterlists, is it okay to impose an allocation limit here?

A caller submitting an update with a large nbytes could be rejected with -EMSGSIZE or fail with -ENOMEM due to physical memory fragmentation. Could this code process the scatterlist in smaller chunks instead of attempting to linearise the entire payload into a single physically contiguous buffer?

[ ... ]

Quoted 11 lines
drivers/crypto/cmh/cmh_hash.c new file +11 -0
+static int cmh_hash_finup(struct ahash_request *req)
+{
+	struct cmh_hash_reqctx *rctx = ahash_request_ctx(req);
+	u32 data_len = req->nbytes;
+	u8 *data_buf = NULL;
+	gfp_t gfp;
+
+	if (rctx->error)
+		return rctx->error;
+
+	if (data_len == 0)

drivers/crypto/cmh/cmh_hash.c line 669

Quoted 10 lines
drivers/crypto/cmh/cmh_hash.c new file +10 -0
+		return cmh_hash_submit_final(req, NULL, 0);
+
+	/* Reject an oversized linearisation with a permanent -EMSGSIZE. */
+	if (data_len > KMALLOC_MAX_SIZE)
+		return -EMSGSIZE;
+
+	gfp = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ?
+	      GFP_KERNEL : GFP_ATOMIC;
+
+	data_buf = kmalloc(data_len, gfp | __GFP_NOWARN);

[Severity: Medium]
Does this code also need to process the scatterlist in chunks?

Similar to cmh_hash_update(), attempting to allocate a contiguous buffer for the entire finalization payload restricts the maximum input size and violates the ahash scatterlist API contract.

Quoted 8 lines
drivers/crypto/cmh/cmh_hash.c new file +8 -0
+	if (!data_buf)
+		return -ENOMEM;
+
+	scatterwalk_map_and_copy(data_buf, req->src, 0, data_len, 0);
+
+	return cmh_hash_submit_final(req, data_buf, data_len);
+}
+
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=4
maintainer
#11 lore raw

Re: [PATCH v5 04/19] crypto: cmh - add SHA-2/SHA-3/SHAKE ahash

In reply to Alex Ousherovitch

drivers/crypto/cmh/cmh_hash.c line 774

Quoted 5 lines · Alex Ousherovitch
drivers/crypto/cmh/cmh_hash.c new file +4 -0
+		alg->halg.base.cra_flags       = CRYPTO_ALG_KERN_DRIVER_ONLY |
+						 CRYPTO_ALG_NO_FALLBACK |
+						 CRYPTO_ALG_ASYNC |
+						 CRYPTO_AHASH_ALG_BLOCK_ONLY;

Why did you set the NO_FALLBACK flag? This is only meant to be used by very specific cases such as s390.

Cheers,

Signature · 3 lines
Email: Herbert Xu <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
#12 lore raw

RE: [PATCH v5 04/19] crypto: cmh - add SHA-2/SHA-3/SHAKE ahash

Quoted 2 lines · Herbert Xu

Why did you set the NO_FALLBACK flag? This is only meant to be used by very specific cases such as s390.

Being async, these algs get NEED_FALLBACK forced by ahash_prepare_alg() unless NO_FALLBACK is set, so crypto_ahash_init_tfm() tries to allocate a same-name synchronous REQ_VIRT provider -- which doesn't work here:

- shake128/256, cshake, kmac and poly1305 have no matching provider registered in this tree, so the allocation fails and the transform can't be created at all. NO_FALLBACK is required to instantiate them.

- sha2, sha3 and sm3 do have a software provider, so the transform loads, but the auto-fallback can't stand in for the hardware on the streaming
path: our exported state is the opaque HW save/restore checkpoint, not the canonical state, so a multi-part export/import round-trip through the fallback misinterprets it (and for SHA-2/SHA-3 the statesize exceeds HASH_MAX_STATESIZE, so ahash_do_req_chain() returns -ENOSYS). A one-shot digest could still use the software provider, but a fallback that only covers one-shot and corrupts streaming isn't usable.

Same flag as s390, same underlying reason -- no generic transform can stand in for the hardware -- though the obstruction differs: protected keys there, opaque (and for SHA-2/SHA-3 oversized) HW state here.

Thanks,
Alex

maintainer
#13 lore raw

Re: [PATCH v5 04/19] crypto: cmh - add SHA-2/SHA-3/SHAKE ahash

Quoted 4 lines · Alex

- shake128/256, cshake, kmac and poly1305 have no matching provider registered in this tree, so the allocation fails and the transform can't be created at all. NO_FALLBACK is required to instantiate them.

Hang on, if an algorithm isn't even implemented in generic C for the Crypto API, then it should not be implemented by a driver either.

The reason these algorithms aren't in the Crypto API is because they have no users.

So please drop them.

Quoted 8 lines

- sha2, sha3 and sm3 do have a software provider, so the transform loads, but the auto-fallback can't stand in for the hardware on the streaming
path: our exported state is the opaque HW save/restore checkpoint, not the canonical state, so a multi-part export/import round-trip through the fallback misinterprets it (and for SHA-2/SHA-3 the statesize exceeds HASH_MAX_STATESIZE, so ahash_do_req_chain() returns -ENOSYS). A one-shot digest could still use the software provider, but a fallback that only covers one-shot and corrupts streaming isn't usable.

Sorry, that is not supported by our API. If you cannot export the hash state in a compatible format, then you will have to switch over to fallbacks and only support digest operations.

Please also elaborate what you mean by opaque checkpoint, does it contain the entire hash state or not?

Cheers,

Signature · 3 lines
Email: Herbert Xu <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
#14 lore raw

RE: [PATCH v5 04/19] crypto: cmh - add SHA-2/SHA-3/SHAKE ahash

Quoted 8 lines · Herbert Xu

Hang on, if an algorithm isn't even implemented in generic C for the Crypto API, then it should not be implemented by a driver either.

The reason these algorithms aren't in the Crypto API is because they have no users.

So please drop them.

Understood. v6 drops SHAKE-128/256, cSHAKE-128/256, KMAC-128/256 and the standalone Poly1305.

Quoted 3 lines

Sorry, that is not supported by our API. If you cannot export the hash state in a compatible format, then you will have to switch over to fallbacks and only support digest operations.

Will do. For the algorithms that have a generic provider -- SHA-2, SHA-3, SM3, HMAC(SHA-2/SHA-3), CMAC(AES), CMAC(SM4) and XCBC(SM4) -- v6 switches to the fallback/digest-only model:

- drop the NO_FALLBACK / BLOCK_ONLY / REQ_VIRT flags and the hand-rolled partial-block and fallback handling, and let the Crypto API install the generic fallback;
- hardware-accelerate .digest() only;
- route everything else -- .init()/.update()/.final()/.finup()/ .export()/.import(), and .setkey() for the keyed ones -- through the fallback, so the statesize and the exported state are the generic ones.

That also answers your NO_FALLBACK question: the flag is gone.

Quoted 2 lines

Please also elaborate what you mean by opaque checkpoint, does it contain the entire hash state or not?

It holds everything needed to resume, but not in a portable layout. The SAVE output is a fixed-size hardware container (600 bytes worst case) holding the core's internal state, the buffered partial block, the block counters, the mode and a CRC. The state portion varies by algorithm:

- SHA-3/SHAKE: the 200-byte Keccak state is stored as two shares (the core is DPA/side-channel protected), so it is not the canonical state.
- SHA-2: a single 64-byte register block plus the partial block and byte count, in a hardware-internal layout.
- Keyed SHA-3 HMAC state cannot be saved by the hardware at all.

None of these is the canonical export format the API needs, so the fallback/digest-only model above is the right fit and we are not pursuing incremental hashing upstream.

One process question, if you don't mind: we would like to fold as much as possible into v6 rather than spinning several revisions. Have you had a chance to look at the rest of the series, or should we expect further comments on the remaining patches? No rush at all -- it would just help us decide whether to post v6 now or hold it until the rest of your feedback has landed.

Thanks for the review.

Alex

#15 lore raw

RE: [PATCH v5 04/19] crypto: cmh - add SHA-2/SHA-3/SHAKE ahash

Quoted 7 lines · Alex

For the algorithms that have a generic provider -- SHA-2, SHA-3, SM3, HMAC(SHA-2/SHA-3), CMAC(AES), CMAC(SM4) and XCBC(SM4) -- v6 switches to the fallback/digest-only model:

- drop the NO_FALLBACK / BLOCK_ONLY / REQ_VIRT flags [...]

That also answers your NO_FALLBACK question: the flag is gone.

One correction to the above before I post v6, so it doesn't look like a quiet regression in the patches: that holds for SHA-2, SHA-3, SM3 and HMAC, but not for CMAC(AES), CMAC(SM4) and XCBC(SM4) -- those three keep NO_FALLBACK and REQ_VIRT.

The reason is the generic fallback itself. crypto/cmac.c and crypto/xcbc.c implement only descsize, with no export_core/import_core, so the core marks them NO_EXPORT_CORE and crypto_ahash_init_tfm() cannot wrap them as crypto_ahash_fb() -- that allocation carries the bit in its mask and fails. For an async digest-only MAC that leaves no choice:
ahash_prepare_alg() forces NEED_FALLBACK unless NO_FALLBACK is set, and the fallback it would otherwise build is unallocatable here. So these three set NO_FALLBACK, keep REQ_VIRT, and allocate the same generic cmac/xcbc transform themselves to service the non-digest paths.

Behaviorally they match the hashes -- hardware .digest() only, with .init/.update/.final/.export/.import forwarded to the generic transform (crypto_ahash_fb() where the core provides it, a driver-allocated one for these three) and the virtual-address path in software; only the flag differs. HMAC does not hit this because crypto/hmac.c provides export_core/import_core. BLOCK_ONLY is gone everywhere, as described, and the rest of that message stands.

If you'd rather these three didn't carry the flag, I can drop cmac(aes), cmac(sm4) and xcbc(sm4) from the driver instead.

Thanks,
Alex

maintainer
#16 lore raw

Re: [PATCH v5 04/19] crypto: cmh - add SHA-2/SHA-3/SHAKE ahash

In reply to Ousherovitch, Alex
Quoted 9 lines · Alex
Quoted 3 lines

Please also elaborate what you mean by opaque checkpoint, does it contain the entire hash state or not?

It holds everything needed to resume, but not in a portable layout. The SAVE output is a fixed-size hardware container (600 bytes worst case) holding the core's internal state, the buffered partial block, the block counters, the mode and a CRC. The state portion varies by algorithm:

Quoted 6 lines

- SHA-3/SHAKE: the 200-byte Keccak state is stored as two shares (the core is DPA/side-channel protected), so it is not the canonical state.
- SHA-2: a single 64-byte register block plus the partial block and byte count, in a hardware-internal layout.
- Keyed SHA-3 HMAC state cannot be saved by the hardware at all.

So it sounds like the info is there. Is it possible to transform this to the format that we use?

Quoted 3 lines

None of these is the canonical export format the API needs, so the fallback/digest-only model above is the right fit and we are not pursuing incremental hashing upstream.

That's we have the export and import functions, to transcribe the hardware hash state into a standard format.

Quoted 6 lines

One process question, if you don't mind: we would like to fold as much as possible into v6 rather than spinning several revisions. Have you had a chance to look at the rest of the series, or should we expect further comments on the remaining patches? No rush at all -- it would just help us decide whether to post v6 now or hold it until the rest of your feedback has landed.

I would appreciate it if you can break the series into smaller chunks. Perhaps add the algorithms which are the least problematic first.

Thanks,

Signature · 3 lines
Email: Herbert Xu <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
#17 lore raw

RE: [PATCH v5 04/19] crypto: cmh - add SHA-2/SHA-3/SHAKE ahash

Quoted 2 lines · Herbert Xu

So it sounds like the info is there. Is it possible to transform this to the format that we use?

Not on this device -- there is no canonical state to transcribe.

The working state exists only inside the core, in SCA-masked (two-share) form; the mask entropy is generated and consumed entirely in hardware and never leaves it, so software cannot reconstruct the plain chaining state. The only snapshot the device offers is a fixed-size opaque container (a flat word array with a CRC, no portable layout) -- not the canonical state and not convertible to it. Keyed modes (HMAC) cannot be snapshotted at all.

So export()/import() has nothing to transcribe. v6 therefore does what you described: for the hashes (SHA-2/SHA-3, SM3) and HMAC the driver registers with the generic fallback and hardware-accelerates .digest() only; the incremental and export/import paths use the generic state. SHAKE/cSHAKE/KMAC and the standalone Poly1305 are dropped per your earlier note.

Quoted 3 lines

I would appreciate it if you can break the series into smaller chunks. Perhaps add the algorithms which are the least problematic first.

Will do -- a few self-contained, bisect-clean series, least problematic first, each sent once the previous is applied. Tentatively:

1. Core: platform driver (probe, DMA, mailbox/VCQ, transaction manager) + DT binding + MAINTAINERS; registers no algorithms.
2. Symmetric: AES, SM4, ChaCha20-Poly1305, and the DRBG hwrng.
3. Hashes: SHA-2/SHA-3, SM3, HMAC (fallback/digest-only as above).
4. Asymmetric and post-quantum algorithms and their key-management interface.

I'll start with (1); happy to adjust the granularity.

Thanks,
Alex

#18 lore raw

PATCH v5 5/19 crypto: cmh - add HMAC ahash

In reply to Alex Ousherovitch

Register ahash algorithms for HMAC-SHA-224, HMAC-SHA-256, HMAC-SHA-384, HMAC-SHA-512, HMAC-SHA3-224, HMAC-SHA3-256, HMAC-SHA3-384, and HMAC-SHA3-512 using the CMH hash core.

HMAC is deliberately not CRYPTO_AHASH_ALG_BLOCK_ONLY, unlike the plain
hashes: the hardware has no keyed-MAC save/restore, so a MAC cannot be computed block-incrementally. The driver accumulates the request input and submits it in a single HW transaction at finalize. Above a 64KB hardware window it switches transparently to the generic software HMAC, so there is no input-size limit.

---
 drivers/crypto/cmh/Makefile           |   3 +-
 drivers/crypto/cmh/cmh_hmac.c         | 908 ++++++++++++++++++++++++++
 drivers/crypto/cmh/cmh_main.c         |   9 +
 drivers/crypto/cmh/include/cmh_hmac.h |  16 +
 4 files changed, 935 insertions(+), 1 deletion(-)
 create mode 100644 drivers/crypto/cmh/cmh_hmac.c
 create mode 100644 drivers/crypto/cmh/include/cmh_hmac.h
drivers/crypto/cmh/Makefile +2 -1
index 79c94d87e9ee..acd1827cc084 100644
@@ -15,7 +15,8 @@ cmh-y := \
 	cmh_sysfs.o \
 	cmh_key.o \
 	cmh_sys.o \
-	cmh_hash.o
+	cmh_hash.o \
+	cmh_hmac.o
 
 # Management ioctl device (/dev/cmh_mgmt): key lifecycle, PKE, PQC ioctls.
 cmh-$(CONFIG_CRYPTO_DEV_CMH_MGMT) += \
drivers/crypto/cmh/cmh_hmac.c new file +908 -0

908 lines not on this page · raw message

drivers/crypto/cmh/cmh_main.c +9 -0
index 50218f19ad6f..589363cc4b28 100644
@@ -32,6 +32,7 @@
 #include "cmh_txn.h"
 #include "cmh_rh.h"
 #include "cmh_hash.h"
+#include "cmh_hmac.h"
 #include "cmh_mgmt.h"
 #include "cmh_registers.h"
 #include "cmh_debugfs.h"
@@ -208,6 +209,11 @@ static int cmh_probe(struct platform_device *pdev)
 	if (ret)
 		goto err_hash_register;
 
+	/* Register HMAC hash algorithms */
+	ret = cmh_hmac_register();
+	if (ret)
+		goto err_hmac_register;
+
 	/* Register key management device (/dev/cmh_mgmt) */
 	ret = cmh_mgmt_register();
 	if (ret)
@@ -218,6 +224,8 @@ static int cmh_probe(struct platform_device *pdev)
 	return 0;
 
 err_mgmt_register:
+	cmh_hmac_unregister();
+err_hmac_register:
 	cmh_hash_unregister();
 err_hash_register:
 	cmh_rh_cleanup(cfg);
@@ -246,6 +254,7 @@ static void cmh_remove(struct platform_device *pdev)
 	cfg = &dev->config;
 
 	cmh_mgmt_unregister();
+	cmh_hmac_unregister();
 	cmh_hash_unregister();
 	cmh_rh_cleanup(cfg);
 	cmh_tm_cleanup();
drivers/crypto/cmh/include/cmh_hmac.h new file +16 -0
new file mode 100644
index 000000000000..fb1a11fb76eb
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2026 Cryptography Research, Inc. (CRI).
+ * CMH LKM -- Kernel Crypto API HMAC Driver
+ *
+ * Registers HMAC ahash algorithms (HMAC-SHA-2, HMAC-SHA-3) with the
+ * Linux crypto subsystem using HC_CMD_HMAC.
+ */
+
+#ifndef CMH_HMAC_H
+#define CMH_HMAC_H
+
+int  cmh_hmac_register(void);
+void cmh_hmac_unregister(void);
+
+#endif /* CMH_HMAC_H */
Signature · 1 line
2.43.7
#19 lore raw

Re: [PATCH v5 05/19] crypto: cmh - add HMAC ahash

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider: - [High] crypto: cmh: missing bounds check in cmh_hmac_import allows unbounded memory allocation - [High]…

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [High] crypto: cmh: missing bounds check in cmh_hmac_import allows unbounded memory allocation
- [High] crypto: cmh: under-accounting of chunk struct overhead allows extreme memory exhaustion
- [Medium] crypto: cmh: freeing millions of chunks under spin_lock_bh can trigger a softlockup
- [Medium] crypto: cmh: DMA buffer shares a cache line with CPU-modified variables --

commit e7307bc7cf1e65f0adb503e546d45a39b86900bd
Author: Alex Ousherovitch <[email protected]>

crypto: cmh - add HMAC ahash

This commit registers HMAC ahash algorithms (HMAC-SHA-2 and HMAC-SHA-3) using the CMH hash core. It implements a self-contained transaction model using accumulated inputs, with a generic software fallback for payloads above 64KB.

Quoted 4 lines
drivers/crypto/cmh/cmh_hmac.c new file +0 -0
new file mode 100644

[ ... ]

drivers/crypto/cmh/cmh_hmac.c line 137

Quoted 9 lines
drivers/crypto/cmh/cmh_hmac.c new file +8 -0
@@ -136,7 +136,7 @@
+/* Per-Request State */
+
+struct cmh_hmac_chunk {
+	struct list_head  list;
+	struct list_head  tfm_node; /* per-tfm orphan tracking */
+	u32               len;
+	u8                data[];
+};

[Severity: Medium]
Does this structure layout place the data buffer on the same cache line as the list heads?

Since the data buffer is mapped for DMA, could concurrent list modifications in cmh_hmac_update() dirty the cache line while a transfer is in progress, potentially violating mapping rules on non-coherent architectures?

[ ... ]

Quoted 2 lines
drivers/crypto/cmh/cmh_hmac.c new file +2 -0
+static int cmh_hmac_update(struct ahash_request *req)
+{

[ ... ]

Quoted 9 lines
drivers/crypto/cmh/cmh_hmac.c new file +9 -0
+	chunk = kmalloc(sizeof(*chunk) + req->nbytes,
+			req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ?
+			GFP_KERNEL : GFP_ATOMIC);
+	if (!chunk) {
+		rctx->error = -ENOMEM;
+		goto err_free_chunks;
+	}
+
+	chunk->len = req->nbytes;

[ ... ]

drivers/crypto/cmh/cmh_hmac.c line 464

Quoted 11 lines
drivers/crypto/cmh/cmh_hmac.c new file +11 -0
+	spin_lock_bh(&tctx->chunk_lock);
+	if (tctx->tfm_buffered + chunk->len > CMH_HMAC_TFM_MAX_BUFFERED) {
+		spin_unlock_bh(&tctx->chunk_lock);
+		kfree_sensitive(chunk);
+		rctx->error = -ENOMEM;
+		goto err_free_chunks;
+	}
+	list_add_tail(&chunk->list, &rctx->chunks);
+	list_add_tail(&chunk->tfm_node, &tctx->all_chunks);
+	tctx->tfm_buffered += chunk->len;
+	spin_unlock_bh(&tctx->chunk_lock);

[Severity: High]
Are we only accounting for the payload length here, instead of the full size of the allocated struct?

Since the chunk header is 36 bytes (often rounded up to 64 bytes by the slab allocator), could repeated 1-byte updates allow pinning roughly 1GB of kernel memory per transform socket without exceeding the 16MB budget?

[ ... ]

Quoted 2 lines
drivers/crypto/cmh/cmh_hmac.c new file +2 -0
+static int cmh_hmac_import(struct ahash_request *req, const void *in)
+{

[ ... ]

drivers/crypto/cmh/cmh_hmac.c line 755

Quoted 13 lines
drivers/crypto/cmh/cmh_hmac.c new file +13 -0
+	if (state->total_len) {
+		chunk = kmalloc(sizeof(*chunk) + state->total_len,
+				req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ?
+				GFP_KERNEL : GFP_ATOMIC);
+		if (!chunk)
+			return -ENOMEM;
+		chunk->len = state->total_len;
+		memcpy(chunk->data, state->data, state->total_len);
+		spin_lock_bh(&tctx->chunk_lock);
+		list_add_tail(&chunk->list, &rctx->chunks);
+		list_add_tail(&chunk->tfm_node, &tctx->all_chunks);
+		tctx->tfm_buffered += chunk->len;
+		spin_unlock_bh(&tctx->chunk_lock);

[Severity: High]
Should we verify if the budget is exceeded before appending the imported chunk and adding to tctx->tfm_buffered?

Without a check against CMH_HMAC_TFM_MAX_BUFFERED, could an unprivileged user repeatedly call accept() on a socket to clone its state and cause unbounded kernel memory allocation?

[ ... ]

drivers/crypto/cmh/cmh_hmac.c line 819

Quoted 13 lines
drivers/crypto/cmh/cmh_hmac.c new file +13 -0
+static void cmh_hmac_cra_exit(struct crypto_tfm *tfm)
+{
+	struct cmh_hmac_tfm_ctx *tctx = crypto_tfm_ctx(tfm);
+	struct cmh_hmac_chunk *chunk, *tmp;
+
+	/* Free any orphaned chunks (e.g. testmgr export/reimport poison) */
+	spin_lock_bh(&tctx->chunk_lock);
+	list_for_each_entry_safe(chunk, tmp, &tctx->all_chunks, tfm_node) {
+		list_del(&chunk->tfm_node);
+		tctx->tfm_buffered -= chunk->len;
+		kfree_sensitive(chunk);
+	}
+	spin_unlock_bh(&tctx->chunk_lock);

[Severity: Medium]
Is it safe to free potentially large numbers of chunks while holding the spinlock with softirqs disabled?

If the 16MB budget contains millions of small chunks (due to the accounting size issue mentioned earlier), could this loop take significant CPU time and risk triggering a soft or hard lockup panic?

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=5
#20 lore raw

PATCH v5 6/19 crypto: cmh - add CSHAKE/KMAC ahash

In reply to Alex Ousherovitch

Register ahash algorithms for cSHAKE128, cSHAKE256, KMAC128, and KMAC256 using the CMH hash core.

cSHAKE is unkeyed, so like SHAKE it is CRYPTO_AHASH_ALG_BLOCK_ONLY and supports incremental update and export/import. KMAC is keyed: the hardware has no keyed-MAC save/restore, so (like HMAC) it is not block-only and accumulates the input for a single finalize-time submission. KMAC has no generic software equivalent, so its input is capped at the 64KB hardware window.

---
 drivers/crypto/cmh/Makefile             |   4 +-
 drivers/crypto/cmh/cmh_cshake.c         | 873 ++++++++++++++++++++++++
 drivers/crypto/cmh/cmh_kmac.c           | 690 +++++++++++++++++++
 drivers/crypto/cmh/cmh_main.c           |  18 +
 drivers/crypto/cmh/include/cmh_cshake.h |  16 +
 drivers/crypto/cmh/include/cmh_kmac.h   |  16 +
 6 files changed, 1616 insertions(+), 1 deletion(-)
 create mode 100644 drivers/crypto/cmh/cmh_cshake.c
 create mode 100644 drivers/crypto/cmh/cmh_kmac.c
 create mode 100644 drivers/crypto/cmh/include/cmh_cshake.h
 create mode 100644 drivers/crypto/cmh/include/cmh_kmac.h
drivers/crypto/cmh/Makefile +3 -1
index acd1827cc084..3ab154744658 100644
@@ -16,7 +16,9 @@ cmh-y := \
 	cmh_key.o \
 	cmh_sys.o \
 	cmh_hash.o \
-	cmh_hmac.o
+	cmh_hmac.o \
+	cmh_cshake.o \
+	cmh_kmac.o
 
 # Management ioctl device (/dev/cmh_mgmt): key lifecycle, PKE, PQC ioctls.
 cmh-$(CONFIG_CRYPTO_DEV_CMH_MGMT) += \
drivers/crypto/cmh/cmh_cshake.c new file +873 -0

873 lines not on this page · raw message

drivers/crypto/cmh/cmh_kmac.c new file +690 -0

690 lines not on this page · raw message

drivers/crypto/cmh/cmh_main.c +18 -0
index 589363cc4b28..474b438fc18a 100644
@@ -33,6 +33,8 @@
 #include "cmh_rh.h"
 #include "cmh_hash.h"
 #include "cmh_hmac.h"
+#include "cmh_cshake.h"
+#include "cmh_kmac.h"
 #include "cmh_mgmt.h"
 #include "cmh_registers.h"
 #include "cmh_debugfs.h"
@@ -214,6 +216,16 @@ static int cmh_probe(struct platform_device *pdev)
 	if (ret)
 		goto err_hmac_register;
 
+	/* Register CSHAKE hash algorithms */
+	ret = cmh_cshake_register();
+	if (ret)
+		goto err_cshake_register;
+
+	/* Register KMAC hash algorithms */
+	ret = cmh_kmac_register();
+	if (ret)
+		goto err_kmac_register;
+
 	/* Register key management device (/dev/cmh_mgmt) */
 	ret = cmh_mgmt_register();
 	if (ret)
@@ -224,6 +236,10 @@ static int cmh_probe(struct platform_device *pdev)
 	return 0;
 
 err_mgmt_register:
+	cmh_kmac_unregister();
+err_kmac_register:
+	cmh_cshake_unregister();
+err_cshake_register:
 	cmh_hmac_unregister();
 err_hmac_register:
 	cmh_hash_unregister();
@@ -254,6 +270,8 @@ static void cmh_remove(struct platform_device *pdev)
 	cfg = &dev->config;
 
 	cmh_mgmt_unregister();
+	cmh_kmac_unregister();
+	cmh_cshake_unregister();
 	cmh_hmac_unregister();
 	cmh_hash_unregister();
 	cmh_rh_cleanup(cfg);
drivers/crypto/cmh/include/cmh_cshake.h new file +16 -0
new file mode 100644
index 000000000000..9bafe0baf52f
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2026 Cryptography Research, Inc. (CRI).
+ * CMH LKM -- Kernel Crypto API CSHAKE Driver
+ *
+ * Registers cSHAKE-128 and cSHAKE-256 ahash algorithms using
+ * HC_CMD_CSHAKE with inline customization string S.
+ */
+
+#ifndef CMH_CSHAKE_H
+#define CMH_CSHAKE_H
+
+int  cmh_cshake_register(void);
+void cmh_cshake_unregister(void);
+
+#endif /* CMH_CSHAKE_H */
drivers/crypto/cmh/include/cmh_kmac.h new file +16 -0
new file mode 100644
index 000000000000..b3c92d71a0b6
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2026 Cryptography Research, Inc. (CRI).
+ * CMH LKM -- Kernel Crypto API KMAC Driver
+ *
+ * Registers KMAC-128 and KMAC-256 ahash algorithms using
+ * HC_CMD_KMAC with inline customization string S.
+ */
+
+#ifndef CMH_KMAC_H
+#define CMH_KMAC_H
+
+int  cmh_kmac_register(void);
+void cmh_kmac_unregister(void);
+
+#endif /* CMH_KMAC_H */
Signature · 1 line
2.43.7
#21 lore raw

Re: [PATCH v5 06/19] crypto: cmh - add CSHAKE/KMAC ahash

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider: - [High] crypto: cmh: cshake arbitrary length kmalloc causes ENOMEM/EMSGSIZE - [High] crypto: cmh: kmac…

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [High] crypto: cmh: cshake arbitrary length kmalloc causes ENOMEM/EMSGSIZE
- [High] crypto: cmh: kmac init on active request leaks chunks causing TFM DoS
- [High] crypto: cmh: kmac finup duplicates data on EAGAIN retry
- [Medium] crypto: cmh: kmac final error path allows empty MAC generation on retry --

commit c5367ee10d2ec6e4de159d32bb1d2e8f203ad0f6
Author: Alex Ousherovitch <[email protected]>

crypto: cmh - add CSHAKE/KMAC ahash

This commit registers ahash algorithms for cSHAKE128, cSHAKE256, KMAC128, and KMAC256 using the CMH hash core. CSHAKE supports incremental update and export/import, while KMAC accumulates the input for a single finalize-time submission.

Quoted 6 lines
drivers/crypto/cmh/cmh_cshake.c new file +0 -0
new file mode 100644
index 0000000000000..56a6453a0e4fe
@@ -0,0 +1,873 @@

[ ... ]

Quoted 2 lines
drivers/crypto/cmh/cmh_cshake.c new file +2 -0
+static int cmh_cshake_update(struct ahash_request *req)
+{

[ ... ]

drivers/crypto/cmh/cmh_cshake.c line 447

Quoted 11 lines
drivers/crypto/cmh/cmh_cshake.c new file +11 -0
+	/*
+	 * Reject a single update whose linearisation would exceed the largest
+	 * kmalloc: return a permanent -EMSGSIZE ("message too long") rather
+	 * than a transient -ENOMEM the client would keep retrying.
+	 */
+	if (full_len > KMALLOC_MAX_SIZE)
+		return -EMSGSIZE;
+
+	rctx->data_buf = kmalloc(full_len, gfp | __GFP_NOWARN);
+	if (!rctx->data_buf)
+		return -ENOMEM;

[Severity: High]
Does this code artificially limit standard ahash capabilities? The ahash API requires drivers to support arbitrary-length inputs provided as scatterlists.

By linearizing the entire input scatterlist into a single contiguous kmalloc buffer, inputs larger than KMALLOC_MAX_SIZE are rejected with -EMSGSIZE.

Even for large inputs below this limit, relying on high-order contiguous allocations is prone to -ENOMEM failures under memory fragmentation.

[ ... ]

Quoted 2 lines
drivers/crypto/cmh/cmh_cshake.c new file +2 -0
+static int cmh_cshake_finup(struct ahash_request *req)
+{

[ ... ]

drivers/crypto/cmh/cmh_cshake.c line 698

Quoted 8 lines
drivers/crypto/cmh/cmh_cshake.c new file +8 -0
+	/* Reject an oversized linearisation with a permanent -EMSGSIZE. */
+	if (data_len > KMALLOC_MAX_SIZE)
+		return -EMSGSIZE;
+
+	gfp = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ?
+	      GFP_KERNEL : GFP_ATOMIC;
+
+	data_buf = kmalloc(data_len, gfp | __GFP_NOWARN);

[Severity: High]
Is this the same single-buffer allocation pattern repeated here?

This appears to also break standard API usage by failing on large inputs.

Quoted 6 lines
drivers/crypto/cmh/cmh_kmac.c new file +0 -0
new file mode 100644
index 0000000000000..97ff36af13a07
@@ -0,0 +1,690 @@

[ ... ]

drivers/crypto/cmh/cmh_kmac.c line 297

Quoted 13 lines
drivers/crypto/cmh/cmh_kmac.c new file +13 -0
+static int cmh_kmac_init(struct ahash_request *req)
+{
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+	struct cmh_kmac_reqctx *rctx = ahash_request_ctx(req);
+
+	rctx->info = cmh_kmac_get_info(tfm);
+	rctx->error = 0;
+	INIT_LIST_HEAD(&rctx->chunks);
+	rctx->num_chunks = 0;
+	rctx->total_len = 0;
+
+	return 0;
+}

[Severity: High]
Could this leak previously accumulated chunks on an active request?

Re-initializing an active request is permitted by the kernel crypto API to abort a stream and restart. This code resets the list with INIT_LIST_HEAD without calling cmh_kmac_free_chunks() to free any existing data.

The chunks would remain orphaned on tctx->all_chunks, permanently consuming the per-TFM memory cap. Repeated aborts/re-inits will exhaust CMH_KMAC_TFM_MAX_BUFFERED, breaking all subsequent operations on the TFM with -ENOMEM.

[ ... ]

Quoted 2 lines
drivers/crypto/cmh/cmh_kmac.c new file +2 -0
+static int cmh_kmac_final(struct ahash_request *req)
+{

[ ... ]

drivers/crypto/cmh/cmh_kmac.c line 524

Quoted 4 lines
drivers/crypto/cmh/cmh_kmac.c new file +4 -0
+out_free:
+	cmh_kmac_free_chunks(rctx, tctx);
+	return ret;
+}

[Severity: Medium]
Will this error path fail to prevent subsequent calls from silently hashing an empty buffer?

If a synchronous failure occurs and the code jumps to out_free, it destroys the accumulated input state but doesn't set rctx->error = ret.

If the caller retries the failed operation, the driver will see 0 chunks and no error, and compute a MAC for an empty string instead of returning the failure.

[ ... ]

drivers/crypto/cmh/cmh_kmac.c line 535

Quoted 10 lines
drivers/crypto/cmh/cmh_kmac.c new file +10 -0
+static int cmh_kmac_finup(struct ahash_request *req)
+{
+	int ret;
+
+	ret = cmh_kmac_update(req);
+	if (ret)
+		return ret;
+
+	return cmh_kmac_final(req);
+}

[Severity: High]
Does this logic duplicate data if the operation is retried?

If cmh_kmac_final() fails with -EAGAIN or -EBUSY, it intentionally retains accumulated chunks so the caller can retry the submission. However, if the original operation was crypto_ahash_finup(), the caller will retry finup.

This will call cmh_kmac_update() again, unconditionally allocating and appending the input data to rctx->chunks, which duplicates the input data and causes the retried operation to output an incorrect MAC.

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=6
#22 lore raw

PATCH v5 7/19 crypto: cmh - add SM3 ahash

In reply to Alex Ousherovitch

Register the SM3 ahash algorithm using the CMH SM3 core (core ID 0x05). Supports incremental update/finup/final and export/import.

---
 drivers/crypto/cmh/Makefile          |   3 +-
 drivers/crypto/cmh/cmh_main.c        |   9 +
 drivers/crypto/cmh/cmh_sm3.c         | 604 +++++++++++++++++++++++++++
 drivers/crypto/cmh/include/cmh_sm3.h |  28 ++
 4 files changed, 643 insertions(+), 1 deletion(-)
 create mode 100644 drivers/crypto/cmh/cmh_sm3.c
 create mode 100644 drivers/crypto/cmh/include/cmh_sm3.h
drivers/crypto/cmh/Makefile +2 -1
index 3ab154744658..664b2a20bc19 100644
@@ -18,7 +18,8 @@ cmh-y := \
 	cmh_hash.o \
 	cmh_hmac.o \
 	cmh_cshake.o \
-	cmh_kmac.o
+	cmh_kmac.o \
+	cmh_sm3.o
 
 # Management ioctl device (/dev/cmh_mgmt): key lifecycle, PKE, PQC ioctls.
 cmh-$(CONFIG_CRYPTO_DEV_CMH_MGMT) += \
drivers/crypto/cmh/cmh_main.c +9 -0
index 474b438fc18a..4ad1500d8e49 100644
@@ -35,6 +35,7 @@
 #include "cmh_hmac.h"
 #include "cmh_cshake.h"
 #include "cmh_kmac.h"
+#include "cmh_sm3.h"
 #include "cmh_mgmt.h"
 #include "cmh_registers.h"
 #include "cmh_debugfs.h"
@@ -226,6 +227,11 @@ static int cmh_probe(struct platform_device *pdev)
 	if (ret)
 		goto err_kmac_register;
 
+	/* Register SM3 hash algorithm */
+	ret = cmh_sm3_register();
+	if (ret)
+		goto err_sm3_register;
+
 	/* Register key management device (/dev/cmh_mgmt) */
 	ret = cmh_mgmt_register();
 	if (ret)
@@ -236,6 +242,8 @@ static int cmh_probe(struct platform_device *pdev)
 	return 0;
 
 err_mgmt_register:
+	cmh_sm3_unregister();
+err_sm3_register:
 	cmh_kmac_unregister();
 err_kmac_register:
 	cmh_cshake_unregister();
@@ -270,6 +278,7 @@ static void cmh_remove(struct platform_device *pdev)
 	cfg = &dev->config;
 
 	cmh_mgmt_unregister();
+	cmh_sm3_unregister();
 	cmh_kmac_unregister();
 	cmh_cshake_unregister();
 	cmh_hmac_unregister();
drivers/crypto/cmh/cmh_sm3.c new file +604 -0

604 lines not on this page · raw message

drivers/crypto/cmh/include/cmh_sm3.h new file +28 -0
new file mode 100644
index 000000000000..962078b051b4
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2026 Cryptography Research, Inc. (CRI).
+ * CMH LKM -- SM3 Hash Driver
+ *
+ * Registers an ahash algorithm for SM3 (GB/T 32905-2016) with the
+ * Linux crypto subsystem using the CMH SM3 core (CORE_ID_SM3).
+ * This is a CRYPTO_AHASH_ALG_BLOCK_ONLY driver (same model as
+ * cmh_hash.c), so the Crypto API buffers partial blocks and hands the
+ * driver only whole-block-aligned data:
+ *
+ *   .init()   -> software-only: zero per-request context
+ *   .update() -> SM3_CMD_INIT [+ RESTORE] + UPDATE(full blocks) + SAVE + FLUSH
+ *                (also serves final: the API calls finup with nbytes == 0)
+ *   .digest() -> INIT + UPDATE + FINAL + FLUSH (single-shot)
+ *   .export() -> software-only: copy the SM3 checkpoint
+ *   .import() -> software-only: restore the SM3 checkpoint
+ */
+
+#ifndef CMH_SM3_H
+#define CMH_SM3_H
+
+#include "cmh_config.h"
+
+int  cmh_sm3_register(void);
+void cmh_sm3_unregister(void);
+
+#endif /* CMH_SM3_H */
Signature · 1 line
2.43.7
#23 lore raw

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

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [High] mm: memory cgroup bypass via unaccounted kmalloc in SM3 driver --

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] mm: memory cgroup bypass via unaccounted kmalloc in SM3 driver
--

commit c89ac2586e3512c64b328b90ba8ba1dd9b26ecc6
Author: Alex Ousherovitch <[email protected]>

crypto: cmh - add SM3 ahash

This commit registers the SM3 ahash algorithm using the CMH SM3 core. It supports incremental update, finup, final, and export/import operations.

Quoted 5 lines
drivers/crypto/cmh/cmh_sm3.c new file +0 -0
new file mode 100644
index 0000000000000..a08341512e5d6

[ ... ]

Quoted 2 lines
drivers/crypto/cmh/cmh_sm3.c new file +2 -0
+static int cmh_sm3_update(struct ahash_request *req)
+{

[ ... ]

Quoted 4 lines
drivers/crypto/cmh/cmh_sm3.c new file +4 -0
+	gfp = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ?
+	      GFP_KERNEL : GFP_ATOMIC;
+
+	/*

drivers/crypto/cmh/cmh_sm3.c line 230

Quoted 10 lines
drivers/crypto/cmh/cmh_sm3.c new file +10 -0
+	 * Reject a single update whose linearisation would exceed the largest
+	 * kmalloc: return a permanent -EMSGSIZE ("message too long") rather
+	 * than a transient -ENOMEM the client would keep retrying.  __GFP_NOWARN
+	 * keeps a borderline-large (but sub-cap) request quiet if it still
+	 * cannot be satisfied.
+	 */
+	if (full_len > KMALLOC_MAX_SIZE)
+		return -EMSGSIZE;
+
+	rctx->data_buf = kmalloc(full_len, gfp | __GFP_NOWARN);

[Severity: High]
Should this allocation be charged to the caller's memory cgroup by adding the __GFP_ACCOUNT flag to the gfp mask?

Since the crypto API is accessible to untrusted local users via AF_ALG, an unprivileged user can submit numerous large asynchronous hash requests. Because this kmalloc can allocate up to KMALLOC_MAX_SIZE bytes without accounting, could this allow a malicious container to bypass its memory limits and exhaust kernel memory, leading to a host-wide out-of-memory condition?

Quoted 2 lines
drivers/crypto/cmh/cmh_sm3.c new file +2 -0
+	if (!rctx->data_buf)
+		return -ENOMEM;

[ ... ]

Quoted 2 lines
drivers/crypto/cmh/cmh_sm3.c new file +2 -0
+static int cmh_sm3_finup(struct ahash_request *req)
+{

[ ... ]

drivers/crypto/cmh/cmh_sm3.c line 498

Quoted 8 lines
drivers/crypto/cmh/cmh_sm3.c new file +8 -0
+	/* Reject an oversized linearisation with a permanent -EMSGSIZE. */
+	if (data_len > KMALLOC_MAX_SIZE)
+		return -EMSGSIZE;
+
+	gfp = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ?
+	      GFP_KERNEL : GFP_ATOMIC;
+
+	data_buf = kmalloc(data_len, gfp | __GFP_NOWARN);

[Severity: High]
Does this allocation also need __GFP_ACCOUNT for the same reason?

Like the update path above, this allocates unaccounted buffers based on user input length, which could be abused to bypass memory container limits during finalization.

Quoted 7 lines
drivers/crypto/cmh/cmh_sm3.c new file +7 -0
+	if (!data_buf)
+		return -ENOMEM;
+
+	scatterwalk_map_and_copy(data_buf, req->src, 0, data_len, 0);
+
+	return cmh_sm3_submit_final(req, data_buf, data_len);
+}
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=7
#24 lore raw

PATCH v5 8/19 crypto: cmh - add AES skcipher/aead/cmac

In reply to Alex Ousherovitch

Register AES algorithms using the CMH AES core (core ID 0x03):
- skcipher: AES-ECB, AES-CBC, AES-CTR, AES-XTS, AES-CFB
- aead: AES-GCM, AES-CCM
- ahash: AES-CMAC

Supports 128, 192, and 256-bit keys. AEAD algorithms handle associated data, payload, and authentication tag with correct encrypt/decrypt separation.

---
 drivers/crypto/cmh/Makefile          |    5 +-
 drivers/crypto/cmh/cmh_aes.c         |  755 +++++++++++++++++++
 drivers/crypto/cmh/cmh_aes_aead.c    | 1013 ++++++++++++++++++++++++++
 drivers/crypto/cmh/cmh_aes_cmac.c    |  741 +++++++++++++++++++
 drivers/crypto/cmh/cmh_main.c        |   25 +
 drivers/crypto/cmh/include/cmh_aes.h |   24 +
 6 files changed, 2562 insertions(+), 1 deletion(-)
 create mode 100644 drivers/crypto/cmh/cmh_aes.c
 create mode 100644 drivers/crypto/cmh/cmh_aes_aead.c
 create mode 100644 drivers/crypto/cmh/cmh_aes_cmac.c
 create mode 100644 drivers/crypto/cmh/include/cmh_aes.h
drivers/crypto/cmh/Makefile +4 -1
index 664b2a20bc19..c5dcfa4f7794 100644
@@ -19,7 +19,10 @@ cmh-y := \
 	cmh_hmac.o \
 	cmh_cshake.o \
 	cmh_kmac.o \
-	cmh_sm3.o
+	cmh_sm3.o \
+	cmh_aes.o \
+	cmh_aes_aead.o \
+	cmh_aes_cmac.o
 
 # Management ioctl device (/dev/cmh_mgmt): key lifecycle, PKE, PQC ioctls.
 cmh-$(CONFIG_CRYPTO_DEV_CMH_MGMT) += \
drivers/crypto/cmh/cmh_aes.c new file +755 -0

755 lines not on this page · raw message

drivers/crypto/cmh/cmh_aes_aead.c new file +1013 -0

1,013 lines not on this page · raw message

drivers/crypto/cmh/cmh_aes_cmac.c new file +741 -0

741 lines not on this page · raw message

drivers/crypto/cmh/cmh_main.c +25 -0
index 4ad1500d8e49..a9985ad95c7d 100644
@@ -36,6 +36,7 @@
 #include "cmh_cshake.h"
 #include "cmh_kmac.h"
 #include "cmh_sm3.h"
+#include "cmh_aes.h"
 #include "cmh_mgmt.h"
 #include "cmh_registers.h"
 #include "cmh_debugfs.h"
@@ -232,6 +233,21 @@ static int cmh_probe(struct platform_device *pdev)
 	if (ret)
 		goto err_sm3_register;
 
+	/* Register AES skcipher algorithms */
+	ret = cmh_aes_register();
+	if (ret)
+		goto err_aes_register;
+
+	/* Register AES AEAD algorithms (GCM, CCM) */
+	ret = cmh_aes_aead_register();
+	if (ret)
+		goto err_aes_aead_register;
+
+	/* Register AES CMAC algorithm */
+	ret = cmh_aes_cmac_register();
+	if (ret)
+		goto err_aes_cmac_register;
+
 	/* Register key management device (/dev/cmh_mgmt) */
 	ret = cmh_mgmt_register();
 	if (ret)
@@ -242,6 +258,12 @@ static int cmh_probe(struct platform_device *pdev)
 	return 0;
 
 err_mgmt_register:
+	cmh_aes_cmac_unregister();
+err_aes_cmac_register:
+	cmh_aes_aead_unregister();
+err_aes_aead_register:
+	cmh_aes_unregister();
+err_aes_register:
 	cmh_sm3_unregister();
 err_sm3_register:
 	cmh_kmac_unregister();
@@ -278,6 +300,9 @@ static void cmh_remove(struct platform_device *pdev)
 	cfg = &dev->config;
 
 	cmh_mgmt_unregister();
+	cmh_aes_cmac_unregister();
+	cmh_aes_aead_unregister();
+	cmh_aes_unregister();
 	cmh_sm3_unregister();
 	cmh_kmac_unregister();
 	cmh_cshake_unregister();
drivers/crypto/cmh/include/cmh_aes.h new file +24 -0
new file mode 100644
index 000000000000..591afaa36f85
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2026 Cryptography Research, Inc. (CRI).
+ * CMH LKM -- AES Crypto API Drivers
+ *
+ * Registers AES algorithms with the Linux crypto subsystem:
+ *   skcipher: ecb/cbc/ctr/cfb/xts(aes)
+ *   aead:     gcm/ccm(aes)
+ *   shash:    cmac(aes)
+ */
+
+#ifndef CMH_AES_H
+#define CMH_AES_H
+
+int  cmh_aes_register(void);
+void cmh_aes_unregister(void);
+
+int  cmh_aes_aead_register(void);
+void cmh_aes_aead_unregister(void);
+
+int  cmh_aes_cmac_register(void);
+void cmh_aes_cmac_unregister(void);
+
+#endif /* CMH_AES_H */
Signature · 1 line
2.43.7
#25 lore raw

Re: [PATCH v5 08/19] crypto: cmh - add AES skcipher/aead/cmac

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [High] crypto: cmh: unbounded memory leak and TFM bricking in cmac(aes) AF_ALG path --

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] crypto: cmh: unbounded memory leak and TFM bricking in cmac(aes) AF_ALG path --

commit a4044451c1e906d90442c0bef45c7be8c8846c42
Author: Alex Ousherovitch <[email protected]>

crypto: cmh - add AES skcipher/aead/cmac

This commit registers AES algorithms (skcipher, aead, cmac) using the CMH AES core. It handles associated data, payloads, and authentication tags for AEAD and supports 128, 192, and 256-bit keys.

Quoted 3 lines
drivers/crypto/cmh/cmh_aes_cmac.c new file +0 -0

[ ... ]

drivers/crypto/cmh/cmh_aes_cmac.c line 239

Quoted 8 lines
drivers/crypto/cmh/cmh_aes_cmac.c new file +8 -0
+static int cmh_aes_cmac_init(struct ahash_request *req)
+{
+	struct cmh_aes_cmac_reqctx *rctx = ahash_request_ctx(req);
+
+	memset(rctx, 0, sizeof(*rctx));
+	INIT_LIST_HEAD(&rctx->chunks);
+	return 0;
+}

[Severity: High]
Does this unconditionally wipe the request context? If the request already has chunks attached to rctx->chunks, it looks like they will be permanently orphaned and leaked. For example, if a user repeatedly resets an active request via the AF_ALG interface, this might permanently consume the quota until the transform is bricked.

[ ... ]

Quoted 2 lines
drivers/crypto/cmh/cmh_aes_cmac.c new file +2 -0
+static int cmh_aes_cmac_final(struct ahash_request *req)
+{

[ ... ]

Quoted 9 lines
drivers/crypto/cmh/cmh_aes_cmac.c new file +9 -0
+	if (ret) {
+		/*
+		 * Synchronous rejection (e.g. -EAGAIN: CMQ full, no backlog).
+		 * Free only the per-submit transients and keep the accumulated
+		 * chunks intact so the caller can retry the identical final().
+		 * If no retry comes, cra_exit reclaims the orphaned chunks; the
+		 * per-tfm buffered-byte cap bounds how much stays pinned.
+		 */
+		if (rctx->total_len > 0 && !cmh_dma_map_error(rctx->in_dma))

drivers/crypto/cmh/cmh_aes_cmac.c line 491

Quoted 10 lines
drivers/crypto/cmh/cmh_aes_cmac.c new file +10 -0
+			cmh_dma_unmap_single(rctx->in_dma, rctx->total_len,
+					     DMA_TO_DEVICE);
+		cmh_dma_unmap_single(rctx->tag_dma, AES_CMAC_DIGEST_SIZE,
+				     DMA_FROM_DEVICE);
+		kfree(rctx->tag_buf);
+		rctx->tag_buf = NULL;
+		kfree_sensitive(rctx->buf);
+		rctx->buf = NULL;
+		/* Keep chunks + total_len so the retry rebuilds the buffer. */
+		return ret;

[Severity: High]
Is there a risk of leaking these accumulated chunks on a synchronous error? The comment mentions keeping them so the caller can retry, but if the caller ultimately drops the request instead of retrying, these chunks appear to be left orphaned.

[ ... ]

Quoted 2 lines
drivers/crypto/cmh/cmh_aes_cmac.c new file +2 -0
+static int cmh_aes_cmac_import(struct ahash_request *req, const void *in)
+{

[ ... ]

Quoted 7 lines
drivers/crypto/cmh/cmh_aes_cmac.c new file +7 -0
+	if (state->total_len) {
+		chunk = kmalloc(sizeof(*chunk) + state->total_len,
+				req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ?
+				GFP_KERNEL : GFP_ATOMIC);
+		if (!chunk)
+			return -ENOMEM;
+		chunk->len = state->total_len;

drivers/crypto/cmh/cmh_aes_cmac.c line 608

Quoted 10 lines
drivers/crypto/cmh/cmh_aes_cmac.c new file +10 -0
+		memcpy(chunk->data, state->data, state->total_len);
+		spin_lock_bh(&tctx->chunk_lock);
+		list_add_tail(&chunk->list, &rctx->chunks);
+		list_add_tail(&chunk->tfm_node, &tctx->all_chunks);
+		tctx->tfm_buffered += chunk->len;
+		spin_unlock_bh(&tctx->chunk_lock);
+		rctx->total_len = state->total_len;
+	}
+	return 0;
+}

[Severity: High]
Can an unprivileged user bypass the CMH_AES_CMAC_TFM_MAX_BUFFERED quota here?

The cmac(aes) driver imposes a 16MB limit on tctx->tfm_buffered during updates. However, this import function allocates memory and adds to tctx->tfm_buffered without checking that limit.

If a user creates an ahash socket via AF_ALG, clones the socket repeatedly with accept() (which triggers import()), and closes the child socket, could this lead to unbounded kernel memory allocation and an OOM denial of service?

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=8
#26 lore raw

PATCH v5 9/19 crypto: cmh - add SM4 skcipher/aead/cmac/xcbc

In reply to Alex Ousherovitch

Register SM4 algorithms using the CMH SM4 core (core ID 0x04):
- skcipher: SM4-ECB, SM4-CBC, SM4-CTR, SM4-XTS, SM4-CFB
- aead: SM4-GCM, SM4-CCM
- ahash: SM4-CMAC, SM4-XCBC

---
 drivers/crypto/cmh/Makefile           |   5 +-
 drivers/crypto/cmh/cmh_main.c         |  25 +
 drivers/crypto/cmh/cmh_sm4_aead.c     | 884 +++++++++++++++++++++++
 drivers/crypto/cmh/cmh_sm4_cmac.c     | 968 ++++++++++++++++++++++++++
 drivers/crypto/cmh/cmh_sm4_skcipher.c | 709 +++++++++++++++++++
 drivers/crypto/cmh/include/cmh_sm4.h  |  24 +
 6 files changed, 2614 insertions(+), 1 deletion(-)
 create mode 100644 drivers/crypto/cmh/cmh_sm4_aead.c
 create mode 100644 drivers/crypto/cmh/cmh_sm4_cmac.c
 create mode 100644 drivers/crypto/cmh/cmh_sm4_skcipher.c
 create mode 100644 drivers/crypto/cmh/include/cmh_sm4.h
drivers/crypto/cmh/Makefile +4 -1
index c5dcfa4f7794..032c863d856e 100644
@@ -22,7 +22,10 @@ cmh-y := \
 	cmh_sm3.o \
 	cmh_aes.o \
 	cmh_aes_aead.o \
-	cmh_aes_cmac.o
+	cmh_aes_cmac.o \
+	cmh_sm4_skcipher.o \
+	cmh_sm4_aead.o \
+	cmh_sm4_cmac.o
 
 # Management ioctl device (/dev/cmh_mgmt): key lifecycle, PKE, PQC ioctls.
 cmh-$(CONFIG_CRYPTO_DEV_CMH_MGMT) += \
drivers/crypto/cmh/cmh_main.c +25 -0
index a9985ad95c7d..410941cc04e4 100644
@@ -37,6 +37,7 @@
 #include "cmh_kmac.h"
 #include "cmh_sm3.h"
 #include "cmh_aes.h"
+#include "cmh_sm4.h"
 #include "cmh_mgmt.h"
 #include "cmh_registers.h"
 #include "cmh_debugfs.h"
@@ -248,6 +249,21 @@ static int cmh_probe(struct platform_device *pdev)
 	if (ret)
 		goto err_aes_cmac_register;
 
+	/* Register SM4 skcipher algorithms */
+	ret = cmh_sm4_register();
+	if (ret)
+		goto err_sm4_register;
+
+	/* Register SM4 AEAD algorithms (GCM, CCM) */
+	ret = cmh_sm4_aead_register();
+	if (ret)
+		goto err_sm4_aead_register;
+
+	/* Register SM4 CMAC/XCBC algorithms */
+	ret = cmh_sm4_cmac_register();
+	if (ret)
+		goto err_sm4_cmac_register;
+
 	/* Register key management device (/dev/cmh_mgmt) */
 	ret = cmh_mgmt_register();
 	if (ret)
@@ -258,6 +274,12 @@ static int cmh_probe(struct platform_device *pdev)
 	return 0;
 
 err_mgmt_register:
+	cmh_sm4_cmac_unregister();
+err_sm4_cmac_register:
+	cmh_sm4_aead_unregister();
+err_sm4_aead_register:
+	cmh_sm4_unregister();
+err_sm4_register:
 	cmh_aes_cmac_unregister();
 err_aes_cmac_register:
 	cmh_aes_aead_unregister();
@@ -300,6 +322,9 @@ static void cmh_remove(struct platform_device *pdev)
 	cfg = &dev->config;
 
 	cmh_mgmt_unregister();
+	cmh_sm4_cmac_unregister();
+	cmh_sm4_aead_unregister();
+	cmh_sm4_unregister();
 	cmh_aes_cmac_unregister();
 	cmh_aes_aead_unregister();
 	cmh_aes_unregister();
drivers/crypto/cmh/cmh_sm4_aead.c new file +884 -0

884 lines not on this page · raw message

drivers/crypto/cmh/cmh_sm4_cmac.c new file +968 -0

968 lines not on this page · raw message

drivers/crypto/cmh/cmh_sm4_skcipher.c new file +709 -0

709 lines not on this page · raw message

drivers/crypto/cmh/include/cmh_sm4.h new file +24 -0
new file mode 100644
index 000000000000..9f4b0fb918db
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2026 Cryptography Research, Inc. (CRI).
+ * CMH LKM -- SM4 Crypto API Drivers
+ *
+ * Registers SM4 algorithms with the Linux crypto subsystem:
+ *   skcipher: ecb/cbc/ctr/cfb/xts(sm4)
+ *   aead:     gcm/ccm(sm4)
+ *   shash:    cmac/xcbc(sm4)
+ */
+
+#ifndef CMH_SM4_H
+#define CMH_SM4_H
+
+int  cmh_sm4_register(void);
+void cmh_sm4_unregister(void);
+
+int  cmh_sm4_aead_register(void);
+void cmh_sm4_aead_unregister(void);
+
+int  cmh_sm4_cmac_register(void);
+void cmh_sm4_cmac_unregister(void);
+
+#endif /* CMH_SM4_H */
Signature · 1 line
2.43.7
#27 lore raw

Re: [PATCH v5 09/19] crypto: cmh - add SM4 skcipher/aead/cmac/xcbc

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [High] crypto: cmh: missing DoS limit check in cmh_sm4_mac_import allows memory exhaustion --

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] crypto: cmh: missing DoS limit check in cmh_sm4_mac_import allows memory exhaustion --

commit 60aa3a7525d3c5b378e645a473550b644da1ca56
Author: Alex Ousherovitch <[email protected]>

crypto: cmh - add SM4 skcipher/aead/cmac/xcbc

This commit registers SM4 skcipher, AEAD, and MAC (CMAC, XCBC) algorithms using the CMH SM4 core. It implements various fallback mechanisms for empty inputs and handles scatter-gather logic by linearizing memory buffers.

Quoted 5 lines
drivers/crypto/cmh/cmh_sm4_cmac.c new file +0 -0
new file mode 100644
index 0000000000000..abeadce312c09

[ ... ]

Quoted 7 lines
drivers/crypto/cmh/cmh_sm4_cmac.c new file +7 -0
+static int cmh_sm4_mac_import(struct ahash_request *req, const void *in)
+{
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+	struct cmh_sm4_mac_tfm_ctx *tctx = crypto_ahash_ctx(tfm);
+	struct cmh_sm4_mac_reqctx *rctx = ahash_request_ctx(req);
+	const struct cmh_sm4_mac_export_state *state = in;
+	struct cmh_sm4_mac_chunk *chunk;

[ ... ]

drivers/crypto/cmh/cmh_sm4_cmac.c line 783

Quoted 13 lines
drivers/crypto/cmh/cmh_sm4_cmac.c new file +13 -0
+	if (state->total_len) {
+		chunk = kmalloc(sizeof(*chunk) + state->total_len,
+				req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ?
+				GFP_KERNEL : GFP_ATOMIC);
+		if (!chunk)
+			return -ENOMEM;
+		chunk->len = state->total_len;
+		memcpy(chunk->data, state->data, state->total_len);
+		spin_lock_bh(&tctx->chunk_lock);
+		list_add_tail(&chunk->list, &rctx->chunks);
+		list_add_tail(&chunk->tfm_node, &tctx->all_chunks);
+		tctx->tfm_buffered += chunk->len;
+		spin_unlock_bh(&tctx->chunk_lock);

[Severity: High]
Does this code allow an unbounded memory allocation bypass?

When an AF_ALG socket is created for cmac(sm4) or xcbc(sm4), a user can write some data so it gets buffered, and then repeatedly call accept() on the socket. Each accept() clones the request, triggering a crypto_ahash_export on the parent and a crypto_ahash_import on the child.

During cmh_sm4_mac_import(), the function allocates a new chunk for the imported data and adds it to the per-tfm list tctx->all_chunks. However, it does not check if the total buffered memory exceeds the CMH_SM4_MAC_TFM_MAX_BUFFERED limit, unlike cmh_sm4_mac_update().

If the user closes the child socket, the allocated chunks are abandoned in tctx->all_chunks. Repeating this indefinitely could exhaust kernel memory and cause a denial of service.

Quoted 4 lines
drivers/crypto/cmh/cmh_sm4_cmac.c new file +4 -0
+		rctx->total_len = state->total_len;
+	}
+	return 0;
+}
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=9
#28 lore raw

PATCH v5 10/19 crypto: cmh - add ChaCha20-Poly1305

In reply to Alex Ousherovitch

Register ChaCha20-Poly1305 AEAD and ChaCha20 skcipher algorithms using the CMH CCP core (core ID 0x18). Also registers the Poly1305 ahash for standalone use.

---
 drivers/crypto/cmh/Makefile          |   5 +-
 drivers/crypto/cmh/cmh_ccp.c         | 362 +++++++++++++
 drivers/crypto/cmh/cmh_ccp_aead.c    | 600 +++++++++++++++++++++
 drivers/crypto/cmh/cmh_ccp_poly.c    | 743 +++++++++++++++++++++++++++
 drivers/crypto/cmh/cmh_main.c        |  25 +
 drivers/crypto/cmh/include/cmh_ccp.h |  24 +
 6 files changed, 1758 insertions(+), 1 deletion(-)
 create mode 100644 drivers/crypto/cmh/cmh_ccp.c
 create mode 100644 drivers/crypto/cmh/cmh_ccp_aead.c
 create mode 100644 drivers/crypto/cmh/cmh_ccp_poly.c
 create mode 100644 drivers/crypto/cmh/include/cmh_ccp.h
drivers/crypto/cmh/Makefile +4 -1
index 032c863d856e..ef24879ba1f1 100644
@@ -25,7 +25,10 @@ cmh-y := \
 	cmh_aes_cmac.o \
 	cmh_sm4_skcipher.o \
 	cmh_sm4_aead.o \
-	cmh_sm4_cmac.o
+	cmh_sm4_cmac.o \
+	cmh_ccp.o \
+	cmh_ccp_aead.o \
+	cmh_ccp_poly.o
 
 # Management ioctl device (/dev/cmh_mgmt): key lifecycle, PKE, PQC ioctls.
 cmh-$(CONFIG_CRYPTO_DEV_CMH_MGMT) += \
drivers/crypto/cmh/cmh_ccp.c new file +362 -0

362 lines not on this page · raw message

drivers/crypto/cmh/cmh_ccp_aead.c new file +600 -0

600 lines not on this page · raw message

drivers/crypto/cmh/cmh_ccp_poly.c new file +743 -0

743 lines not on this page · raw message

drivers/crypto/cmh/cmh_main.c +25 -0
index 410941cc04e4..0738b9815a11 100644
@@ -38,6 +38,7 @@
 #include "cmh_sm3.h"
 #include "cmh_aes.h"
 #include "cmh_sm4.h"
+#include "cmh_ccp.h"
 #include "cmh_mgmt.h"
 #include "cmh_registers.h"
 #include "cmh_debugfs.h"
@@ -264,6 +265,21 @@ static int cmh_probe(struct platform_device *pdev)
 	if (ret)
 		goto err_sm4_cmac_register;
 
+	/* Register CCP ChaCha20 skcipher algorithm */
+	ret = cmh_ccp_register();
+	if (ret)
+		goto err_ccp_register;
+
+	/* Register CCP ChaCha20-Poly1305 AEAD (RFC 7539) */
+	ret = cmh_ccp_aead_register();
+	if (ret)
+		goto err_ccp_aead_register;
+
+	/* Register CCP Poly1305 shash algorithm */
+	ret = cmh_ccp_poly_register();
+	if (ret)
+		goto err_ccp_poly_register;
+
 	/* Register key management device (/dev/cmh_mgmt) */
 	ret = cmh_mgmt_register();
 	if (ret)
@@ -274,6 +290,12 @@ static int cmh_probe(struct platform_device *pdev)
 	return 0;
 
 err_mgmt_register:
+	cmh_ccp_poly_unregister();
+err_ccp_poly_register:
+	cmh_ccp_aead_unregister();
+err_ccp_aead_register:
+	cmh_ccp_unregister();
+err_ccp_register:
 	cmh_sm4_cmac_unregister();
 err_sm4_cmac_register:
 	cmh_sm4_aead_unregister();
@@ -322,6 +344,9 @@ static void cmh_remove(struct platform_device *pdev)
 	cfg = &dev->config;
 
 	cmh_mgmt_unregister();
+	cmh_ccp_poly_unregister();
+	cmh_ccp_aead_unregister();
+	cmh_ccp_unregister();
 	cmh_sm4_cmac_unregister();
 	cmh_sm4_aead_unregister();
 	cmh_sm4_unregister();
drivers/crypto/cmh/include/cmh_ccp.h new file +24 -0
new file mode 100644
index 000000000000..363d208cbceb
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2026 Cryptography Research, Inc. (CRI).
+ * CMH LKM -- CCP Crypto API Drivers
+ *
+ * Registers CCP algorithms with the Linux crypto subsystem:
+ *   skcipher: chacha20
+ *   shash:    poly1305
+ *   aead:     rfc7539(chacha20poly1305)
+ */
+
+#ifndef CMH_CCP_H
+#define CMH_CCP_H
+
+int  cmh_ccp_register(void);
+void cmh_ccp_unregister(void);
+
+int  cmh_ccp_aead_register(void);
+void cmh_ccp_aead_unregister(void);
+
+int  cmh_ccp_poly_register(void);
+void cmh_ccp_poly_unregister(void);
+
+#endif /* CMH_CCP_H */
Signature · 1 line
2.43.7
#29 lore raw

Re: [PATCH v5 10/19] crypto: cmh - add ChaCha20-Poly1305

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Medium] crypto: cmh: missing tfm_buffered increment in cmh_poly_import() causes underflow --

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] crypto: cmh: missing tfm_buffered increment in cmh_poly_import() causes underflow --

commit 8e2b87897bac0eee1fd1dfc15026269caab4f233
Author: Alex Ousherovitch <[email protected]>
Subject: crypto: cmh - add ChaCha20-Poly1305

This commit registers the ChaCha20-Poly1305 AEAD and ChaCha20 skcipher algorithms using the CMH CCP core. It also registers the Poly1305 ahash for standalone use.

Quoted 5 lines
drivers/crypto/cmh/cmh_ccp_poly.c new file +0 -0
new file mode 100644
index 0000000000000..d8482dd96d12c

[ ... ]

drivers/crypto/cmh/cmh_ccp_poly.c line 230

Quoted 10 lines
drivers/crypto/cmh/cmh_ccp_poly.c new file +10 -0
+static void cmh_poly_free_chunks(struct cmh_poly_reqctx *rctx,
+				 struct cmh_poly_tfm_ctx *tctx)
+{
+	struct cmh_poly_chunk *c, *tmp;
+
+	spin_lock_bh(&tctx->chunk_lock);
+	list_for_each_entry_safe(c, tmp, &rctx->chunks, list) {
+		list_del(&c->list);
+		list_del(&c->tfm_node);
+		tctx->tfm_buffered -= c->len;

[Severity: Medium]
Can this subtraction underflow if the chunk was created during an import?

This is where the underflow actually occurs when the request is freed, because the corresponding increment was missing in cmh_poly_import.

Quoted 5 lines
drivers/crypto/cmh/cmh_ccp_poly.c new file +5 -0
+		kfree_sensitive(c);
+	}
+	spin_unlock_bh(&tctx->chunk_lock);
+	rctx->total_len = 0;
+}

[ ... ]

Quoted 2 lines
drivers/crypto/cmh/cmh_ccp_poly.c new file +2 -0
+static int cmh_poly_import(struct ahash_request *req, const void *in)
+{

[ ... ]

drivers/crypto/cmh/cmh_ccp_poly.c line 621

Quoted 12 lines
drivers/crypto/cmh/cmh_ccp_poly.c new file +12 -0
+	if (state->total_len) {
+		chunk = kmalloc(sizeof(*chunk) + state->total_len,
+				req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ?
+				GFP_KERNEL : GFP_ATOMIC);
+		if (!chunk)
+			return -ENOMEM;
+		chunk->len = state->total_len;
+		memcpy(chunk->data, state->data, state->total_len);
+		list_add_tail(&chunk->list, &rctx->chunks);
+		spin_lock_bh(&tctx->chunk_lock);
+		list_add_tail(&chunk->tfm_node, &tctx->all_chunks);
+		spin_unlock_bh(&tctx->chunk_lock);

[Severity: Medium]
Should tctx->tfm_buffered be incremented here?

Since the newly allocated chunk is being added to the TFM tracking list, omitting the increment causes tctx->tfm_buffered to become unbalanced.

When a user creates an AF_ALG hash socket, writes data to it, and clones it via accept(), cmh_poly_import is called for the clone. When the sockets are closed, cmh_poly_free_chunks will subtract the chunk lengths from tctx->tfm_buffered twice (once for the parent, once for the clone).

Because the clone never added its length during import, the counter underflows to a massive positive value, permanently breaking the instance by causing subsequent update calls to spuriously fail with -ENOMEM.

Quoted 4 lines
drivers/crypto/cmh/cmh_ccp_poly.c new file +4 -0
+		rctx->total_len = state->total_len;
+	}
+	return 0;
+}
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=10
#30 lore raw

PATCH v5 11/19 crypto: cmh - add DRBG hwrng

In reply to Alex Ousherovitch

Register the CMH DRBG core (core ID 0x0f) as an hwrng provider. The hardware implements a NIST SP 800-90A compliant DRBG with automatic self-seeding.

---
 drivers/crypto/cmh/Makefile   |   3 +-
 drivers/crypto/cmh/cmh_main.c |   9 ++
 drivers/crypto/cmh/cmh_rng.c  | 281 ++++++++++++++++++++++++++++++++++
 3 files changed, 292 insertions(+), 1 deletion(-)
 create mode 100644 drivers/crypto/cmh/cmh_rng.c
drivers/crypto/cmh/Makefile +2 -1
index ef24879ba1f1..407fd2870f6d 100644
@@ -28,7 +28,8 @@ cmh-y := \
 	cmh_sm4_cmac.o \
 	cmh_ccp.o \
 	cmh_ccp_aead.o \
-	cmh_ccp_poly.o
+	cmh_ccp_poly.o \
+	cmh_rng.o
 
 # Management ioctl device (/dev/cmh_mgmt): key lifecycle, PKE, PQC ioctls.
 cmh-$(CONFIG_CRYPTO_DEV_CMH_MGMT) += \
drivers/crypto/cmh/cmh_main.c +9 -0
index 0738b9815a11..b06a5ea0df4f 100644
@@ -36,6 +36,7 @@
 #include "cmh_cshake.h"
 #include "cmh_kmac.h"
 #include "cmh_sm3.h"
+#include "cmh_rng.h"
 #include "cmh_aes.h"
 #include "cmh_sm4.h"
 #include "cmh_ccp.h"
@@ -235,6 +236,11 @@ static int cmh_probe(struct platform_device *pdev)
 	if (ret)
 		goto err_sm3_register;
 
+	/* Register hwrng backed by DRBG core */
+	ret = cmh_rng_register(pdev);
+	if (ret)
+		goto err_rng_register;
+
 	/* Register AES skcipher algorithms */
 	ret = cmh_aes_register();
 	if (ret)
@@ -308,6 +314,8 @@ static int cmh_probe(struct platform_device *pdev)
 err_aes_aead_register:
 	cmh_aes_unregister();
 err_aes_register:
+	cmh_rng_unregister();
+err_rng_register:
 	cmh_sm3_unregister();
 err_sm3_register:
 	cmh_kmac_unregister();
@@ -353,6 +361,7 @@ static void cmh_remove(struct platform_device *pdev)
 	cmh_aes_cmac_unregister();
 	cmh_aes_aead_unregister();
 	cmh_aes_unregister();
+	cmh_rng_unregister();
 	cmh_sm3_unregister();
 	cmh_kmac_unregister();
 	cmh_cshake_unregister();
drivers/crypto/cmh/cmh_rng.c new file +281 -0

281 lines not on this page · raw message

Signature · 1 line
2.43.7
#31 lore raw

Re: [PATCH v5 11/19] crypto: cmh - add DRBG hwrng

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider: - [High] rng: DMA use-after-free on module unload due to un-aborted DRBG operation - [Medium] rng: infinite…

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] rng: DMA use-after-free on module unload due to un-aborted DRBG operation
- [Medium] rng: infinite retry loop on fatal hardware error in cmh_rng_read()
- [Medium] rng: mailbox queue exhaustion from orphaned DRBG requests
--

commit 8d9076a5e8784ced0b9563b435b225e28e6737e2
Author: Alex Ousherovitch <[email protected]>

crypto: cmh - add DRBG hwrng

This commit registers the CMH DRBG core as a hardware RNG provider. It adds synchronous reads that map DMA buffers and submit VCQ commands through the transaction manager to gather entropy from the device.

Quoted 5 lines
drivers/crypto/cmh/cmh_rng.c new file +0 -0
new file mode 100644
index 0000000000000..a73634024e135

[ ... ]

drivers/crypto/cmh/cmh_rng.c line 130

Quoted 10 lines
drivers/crypto/cmh/cmh_rng.c new file +10 -0
+	/*
+	 * Use the noabort variant: if the MBX is occupied by a slow
+	 * operation (e.g. SLH-DSA sign at 120 s), we must not issue
+	 * MBX_COMMAND_ABORT -- that would kill the unrelated in-flight
+	 * VCQ.  On timeout with an in-flight VCQ (-EINPROGRESS), the
+	 * orphan callback defers DMA cleanup until the RH fires.
+	 */
+	ret = cmh_tm_submit_sync_noabort(vcq, DRBG_READ_VCQ_CMDS, 1,
+					 msecs_to_jiffies(drbg_timeout_ms),
+					 cmh_dma_orphan_free, orphan);

[Severity: High]
Could this cause a DMA use-after-free during module unload? Since cmh_tm_submit_sync_noabort() leaves the hardware operation running in the background, if the cmh module is unloaded, cmh_tm_cleanup() will force-cancel the transaction and trigger cmh_dma_orphan_free(). This unmaps and frees the DMA buffer while the hardware accelerator is still actively writing to it.

drivers/crypto/cmh/cmh_rng.c line 140

Quoted 10 lines
drivers/crypto/cmh/cmh_rng.c new file +10 -0
+	if (ret == -EINPROGRESS) {
+		/*
+		 * The orphan callback owns dmabuf and frees it on VCQ
+		 * completion.  Return 0 (not -EAGAIN): .read() only runs with
+		 * wait=true (see the !wait early return above), and the hwrng
+		 * core forwards a negative errno straight to a blocking read
+		 * whereas a 0 return makes it retry.
+		 */
+		return 0;
+	}

[Severity: Medium]
Does returning 0 here cause mailbox queue exhaustion? When 0 is returned on a timeout, the hwrng core immediately retries the read. Since the hardware might be blocked by a slow operation, won't this rapidly submit more DRBG requests until the Command Message Queue is completely filled with orphaned requests, blocking all other subsystems?

[ ... ]

Quoted 14 lines
drivers/crypto/cmh/cmh_rng.c new file +14 -0
+		switch (ret) {
+		case -EAGAIN:
+		case -EBUSY:
+		case -ETIMEDOUT:
+		case -EIO:
+		/*
+		 * -ENODEV: the TM is not running -- occurs when the
+		 * hwrng kthread (PF_NOFREEZE, not frozen during
+		 * suspend) calls .read() while the device is suspended.
+		 * Treat as transient: the TM restarts on resume.
+		 */
+		case -ENODEV:
+			dev_dbg_ratelimited(cmh_dev(),
+					    "rng: transient DRBG failure (rc=%d)\n",

drivers/crypto/cmh/cmh_rng.c line 179

Quoted 10 lines
drivers/crypto/cmh/cmh_rng.c new file +10 -0
+					    ret);
+			kfree_sensitive(dmabuf);
+			/*
+			 * Back off before the hwrng core re-issues the
+			 * blocking read: rng_dev_read() loops on a 0 return
+			 * with only a conditional need_resched, so a persistent
+			 * transient fault would otherwise spin the CPU.
+			 */
+			msleep(CMH_DRBG_RETRY_BACKOFF_MS);
+			return 0;

[Severity: Medium]
Will this create an infinite retry loop for fatal hardware errors? By masking -EIO to 0 and treating it as a transient error, rng_dev_read() will retry the read indefinitely if the accelerator encounters a persistent failure. Should fatal errors be propagated to break the loop instead of returning 0?

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=11
#32 lore raw

PATCH v5 12/19 crypto: cmh - add RSA akcipher

In reply to Alex Ousherovitch

Register the RSA akcipher algorithm using the CMH PKE core (core ID 0x0a). Supports encrypt, decrypt, sign, and verify operations with 2048, 3072, and 4096-bit keys. 512- and 1024-bit keys are also accepted for legacy/test interoperability. Includes common PKE helpers shared by subsequent ECDSA and ECDH patches.

---
 drivers/crypto/cmh/Makefile         |   4 +-
 drivers/crypto/cmh/cmh_main.c       |   9 +
 drivers/crypto/cmh/cmh_pke_common.c | 578 +++++++++++++++++++++++++
 drivers/crypto/cmh/cmh_pke_rsa.c    | 644 ++++++++++++++++++++++++++++
 4 files changed, 1234 insertions(+), 1 deletion(-)
 create mode 100644 drivers/crypto/cmh/cmh_pke_common.c
 create mode 100644 drivers/crypto/cmh/cmh_pke_rsa.c
drivers/crypto/cmh/Makefile +3 -1
index 407fd2870f6d..cdbcc8cdac5f 100644
@@ -29,7 +29,9 @@ cmh-y := \
 	cmh_ccp.o \
 	cmh_ccp_aead.o \
 	cmh_ccp_poly.o \
-	cmh_rng.o
+	cmh_rng.o \
+	cmh_pke_common.o \
+	cmh_pke_rsa.o
 
 # Management ioctl device (/dev/cmh_mgmt): key lifecycle, PKE, PQC ioctls.
 cmh-$(CONFIG_CRYPTO_DEV_CMH_MGMT) += \
drivers/crypto/cmh/cmh_main.c +9 -0
index b06a5ea0df4f..23346bbf11b0 100644
@@ -40,6 +40,7 @@
 #include "cmh_aes.h"
 #include "cmh_sm4.h"
 #include "cmh_ccp.h"
+#include "cmh_pke.h"
 #include "cmh_mgmt.h"
 #include "cmh_registers.h"
 #include "cmh_debugfs.h"
@@ -286,6 +287,11 @@ static int cmh_probe(struct platform_device *pdev)
 	if (ret)
 		goto err_ccp_poly_register;
 
+	/* Register PKE RSA akcipher */
+	ret = cmh_pke_rsa_register();
+	if (ret)
+		goto err_pke_rsa_register;
+
 	/* Register key management device (/dev/cmh_mgmt) */
 	ret = cmh_mgmt_register();
 	if (ret)
@@ -296,6 +302,8 @@ static int cmh_probe(struct platform_device *pdev)
 	return 0;
 
 err_mgmt_register:
+	cmh_pke_rsa_unregister();
+err_pke_rsa_register:
 	cmh_ccp_poly_unregister();
 err_ccp_poly_register:
 	cmh_ccp_aead_unregister();
@@ -352,6 +360,7 @@ static void cmh_remove(struct platform_device *pdev)
 	cfg = &dev->config;
 
 	cmh_mgmt_unregister();
+	cmh_pke_rsa_unregister();
 	cmh_ccp_poly_unregister();
 	cmh_ccp_aead_unregister();
 	cmh_ccp_unregister();
drivers/crypto/cmh/cmh_pke_common.c new file +578 -0

578 lines not on this page · raw message

drivers/crypto/cmh/cmh_pke_rsa.c new file +644 -0

644 lines not on this page · raw message

Signature · 1 line
2.43.7
#33 lore raw

Re: [PATCH v5 12/19] crypto: cmh - add RSA akcipher

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Medium] crypto: cmh: partial tfm state corruption on set_pub_key failure --

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] crypto: cmh: partial tfm state corruption on set_pub_key failure --

commit 245d9a370fc37764e90c38f7f7cb69490074e21e
Author: Alex Ousherovitch <[email protected]>

crypto: cmh - add RSA akcipher

This commit registers the RSA akcipher algorithm using the CMH PKE core, supporting encryption, decryption, signing, and verification operations for multiple key sizes.

Quoted 5 lines
drivers/crypto/cmh/cmh_pke_rsa.c new file +0 -0
new file mode 100644
index 0000000000000..251ae8275865d

[ ... ]

Quoted 8 lines
drivers/crypto/cmh/cmh_pke_rsa.c new file +8 -0
+static int cmh_rsa_set_pub_key(struct crypto_akcipher *tfm,
+			       const void *key, unsigned int keylen)
+{
+	struct cmh_rsa_tfm_ctx *ctx = cmh_rsa_ctx(tfm);
+	struct rsa_key rsa = {};
+	u32 bits;
+	int ret;
+

drivers/crypto/cmh/cmh_pke_rsa.c line 432

Quoted 10 lines
drivers/crypto/cmh/cmh_pke_rsa.c new file +10 -0
+	/*
+	 * Re-keying: release any private-key state (and its persistent DMA
+	 * mapping) left by a prior set_priv_key so it is not leaked until
+	 * exit_tfm and cannot be mistaken for the new public key.
+	 */
+	cmh_key_destroy(&ctx->key);
+
+	ret = rsa_parse_pub_key(&rsa, key, keylen);
+	if (ret)
+		return ret;

[Severity: Medium]
Does this leave the transform in a partially corrupted state if parsing fails?

If cmh_rsa_set_pub_key() is called after a key pair has already been configured, the private key is destroyed early. If rsa_parse_pub_key() then fails, the function returns without updating or clearing the existing public key.

Userspace could potentially trigger this via the AF_ALG socket interface by passing malformed key material. This would leave the transform in an inconsistent state where encryption still works using the old public key, but decryption fails.

Should the old private key be preserved until the new public key is fully validated, or should the entire transform state be wiped on error?

The same pattern also appears in cmh_rsa_set_priv_key() where the old private key could be left active while the public key is freed on a failure during key material setup.

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=12
#34 lore raw

PATCH v5 13/19 crypto: cmh - add ECDSA/SM2 sig

In reply to Alex Ousherovitch

Register ECDSA and SM2 sig algorithms using the CMH PKE core. Supports P-256, P-384, P-521, and SM2 curves for sign and verify operations. SM2 is registered as verify-only via the crypto API; full SM2 operations (encrypt, decrypt, key exchange) are available through the /dev/cmh_mgmt ioctl interface.

---
 drivers/crypto/cmh/Makefile        |   3 +-
 drivers/crypto/cmh/cmh_main.c      |   8 +
 drivers/crypto/cmh/cmh_pke_ecdsa.c | 610 +++++++++++++++++++++++++++++
 3 files changed, 620 insertions(+), 1 deletion(-)
 create mode 100644 drivers/crypto/cmh/cmh_pke_ecdsa.c
drivers/crypto/cmh/Makefile +2 -1
index cdbcc8cdac5f..ae1f74a93e99 100644
@@ -31,7 +31,8 @@ cmh-y := \
 	cmh_ccp_poly.o \
 	cmh_rng.o \
 	cmh_pke_common.o \
-	cmh_pke_rsa.o
+	cmh_pke_rsa.o \
+	cmh_pke_ecdsa.o
 
 # Management ioctl device (/dev/cmh_mgmt): key lifecycle, PKE, PQC ioctls.
 cmh-$(CONFIG_CRYPTO_DEV_CMH_MGMT) += \
drivers/crypto/cmh/cmh_main.c +8 -0
index 23346bbf11b0..b5b12f56a68e 100644
@@ -292,6 +292,11 @@ static int cmh_probe(struct platform_device *pdev)
 	if (ret)
 		goto err_pke_rsa_register;
 
+	/* Register PKE ECDSA/SM2 sig */
+	ret = cmh_pke_ecdsa_register();
+	if (ret)
+		goto err_pke_ecdsa_register;
+
 	/* Register key management device (/dev/cmh_mgmt) */
 	ret = cmh_mgmt_register();
 	if (ret)
@@ -302,6 +307,8 @@ static int cmh_probe(struct platform_device *pdev)
 	return 0;
 
 err_mgmt_register:
+	cmh_pke_ecdsa_unregister();
+err_pke_ecdsa_register:
 	cmh_pke_rsa_unregister();
 err_pke_rsa_register:
 	cmh_ccp_poly_unregister();
@@ -360,6 +367,7 @@ static void cmh_remove(struct platform_device *pdev)
 	cfg = &dev->config;
 
 	cmh_mgmt_unregister();
+	cmh_pke_ecdsa_unregister();
 	cmh_pke_rsa_unregister();
 	cmh_ccp_poly_unregister();
 	cmh_ccp_aead_unregister();
drivers/crypto/cmh/cmh_pke_ecdsa.c new file +610 -0

610 lines not on this page · raw message

Signature · 1 line
2.43.7
#35 lore raw

PATCH v5 14/19 crypto: cmh - add ECDH/X25519 kpp

In reply to Alex Ousherovitch

Register ECDH and X25519 kpp algorithms using the CMH PKE core. Supports P-256, P-384, and Curve25519 for key agreement.

---
 drivers/crypto/cmh/Makefile       |   3 +-
 drivers/crypto/cmh/cmh_main.c     |   8 +
 drivers/crypto/cmh/cmh_pke_ecdh.c | 817 ++++++++++++++++++++++++++++++
 3 files changed, 827 insertions(+), 1 deletion(-)
 create mode 100644 drivers/crypto/cmh/cmh_pke_ecdh.c
drivers/crypto/cmh/Makefile +2 -1
index ae1f74a93e99..da420d0ec1fe 100644
@@ -32,7 +32,8 @@ cmh-y := \
 	cmh_rng.o \
 	cmh_pke_common.o \
 	cmh_pke_rsa.o \
-	cmh_pke_ecdsa.o
+	cmh_pke_ecdsa.o \
+	cmh_pke_ecdh.o
 
 # Management ioctl device (/dev/cmh_mgmt): key lifecycle, PKE, PQC ioctls.
 cmh-$(CONFIG_CRYPTO_DEV_CMH_MGMT) += \
drivers/crypto/cmh/cmh_main.c +8 -0
index b5b12f56a68e..93d939e8fc4e 100644
@@ -297,6 +297,11 @@ static int cmh_probe(struct platform_device *pdev)
 	if (ret)
 		goto err_pke_ecdsa_register;
 
+	/* Register PKE ECDH/X25519 kpp */
+	ret = cmh_pke_ecdh_register();
+	if (ret)
+		goto err_pke_ecdh_register;
+
 	/* Register key management device (/dev/cmh_mgmt) */
 	ret = cmh_mgmt_register();
 	if (ret)
@@ -307,6 +312,8 @@ static int cmh_probe(struct platform_device *pdev)
 	return 0;
 
 err_mgmt_register:
+	cmh_pke_ecdh_unregister();
+err_pke_ecdh_register:
 	cmh_pke_ecdsa_unregister();
 err_pke_ecdsa_register:
 	cmh_pke_rsa_unregister();
@@ -367,6 +374,7 @@ static void cmh_remove(struct platform_device *pdev)
 	cfg = &dev->config;
 
 	cmh_mgmt_unregister();
+	cmh_pke_ecdh_unregister();
 	cmh_pke_ecdsa_unregister();
 	cmh_pke_rsa_unregister();
 	cmh_ccp_poly_unregister();
drivers/crypto/cmh/cmh_pke_ecdh.c new file +817 -0

817 lines not on this page · raw message

Signature · 1 line
2.43.7
#36 lore raw

PATCH v5 15/19 crypto: cmh - add ML-KEM/ML-DSA (QSE)

In reply to Alex Ousherovitch

Register ML-KEM (Kyber) and ML-DSA (Dilithium) algorithms using the CMH QSE core (core ID 0x09). ML-KEM is ioctl-only (keygen, encaps, decaps). ML-DSA is registered as a sig algorithm with priority 5001 to override the kernel's verify-only mldsa implementation at priority 5000. This follows the established pattern where hardware drivers override software-only fallbacks (e.g. ccp at 300 over generic AES at 100, qat similarly). The CMH driver provides full HW-accelerated sign + verify vs the kernel's verify-only software implementation.

Includes cmh_pqc_sizes.c with compile-time tables of PQC key and signature sizes for all supported parameter sets.

---
 drivers/crypto/cmh/Makefile        |   5 +-
 drivers/crypto/cmh/cmh_main.c      |   9 +
 drivers/crypto/cmh/cmh_pqc_mldsa.c | 415 +++++++++++++++++++++++++++++
 drivers/crypto/cmh/cmh_pqc_sizes.c |  39 +++
 drivers/crypto/cmh/cmh_qse.c       | 211 +++++++++++++++
 5 files changed, 678 insertions(+), 1 deletion(-)
 create mode 100644 drivers/crypto/cmh/cmh_pqc_mldsa.c
 create mode 100644 drivers/crypto/cmh/cmh_pqc_sizes.c
 create mode 100644 drivers/crypto/cmh/cmh_qse.c
drivers/crypto/cmh/Makefile +4 -1
index da420d0ec1fe..7196d992487e 100644
@@ -33,7 +33,10 @@ cmh-y := \
 	cmh_pke_common.o \
 	cmh_pke_rsa.o \
 	cmh_pke_ecdsa.o \
-	cmh_pke_ecdh.o
+	cmh_pke_ecdh.o \
+	cmh_qse.o \
+	cmh_pqc_mldsa.o \
+	cmh_pqc_sizes.o
 
 # Management ioctl device (/dev/cmh_mgmt): key lifecycle, PKE, PQC ioctls.
 cmh-$(CONFIG_CRYPTO_DEV_CMH_MGMT) += \
drivers/crypto/cmh/cmh_main.c +9 -0
index 93d939e8fc4e..7dfcdf395175 100644
@@ -41,6 +41,7 @@
 #include "cmh_sm4.h"
 #include "cmh_ccp.h"
 #include "cmh_pke.h"
+#include "cmh_pqc.h"
 #include "cmh_mgmt.h"
 #include "cmh_registers.h"
 #include "cmh_debugfs.h"
@@ -302,6 +303,11 @@ static int cmh_probe(struct platform_device *pdev)
 	if (ret)
 		goto err_pke_ecdh_register;
 
+	/* Register PQC ML-KEM/ML-DSA */
+	ret = cmh_pqc_mldsa_register();
+	if (ret)
+		goto err_pqc_mldsa_register;
+
 	/* Register key management device (/dev/cmh_mgmt) */
 	ret = cmh_mgmt_register();
 	if (ret)
@@ -312,6 +318,8 @@ static int cmh_probe(struct platform_device *pdev)
 	return 0;
 
 err_mgmt_register:
+	cmh_pqc_mldsa_unregister();
+err_pqc_mldsa_register:
 	cmh_pke_ecdh_unregister();
 err_pke_ecdh_register:
 	cmh_pke_ecdsa_unregister();
@@ -374,6 +382,7 @@ static void cmh_remove(struct platform_device *pdev)
 	cfg = &dev->config;
 
 	cmh_mgmt_unregister();
+	cmh_pqc_mldsa_unregister();
 	cmh_pke_ecdh_unregister();
 	cmh_pke_ecdsa_unregister();
 	cmh_pke_rsa_unregister();
drivers/crypto/cmh/cmh_pqc_mldsa.c new file +415 -0

415 lines not on this page · raw message

drivers/crypto/cmh/cmh_pqc_sizes.c new file +39 -0
new file mode 100644
index 000000000000..39e3d56f4312
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2026 Cryptography Research, Inc. (CRI).
+ * CMH LKM -- PQC Algorithm Size Tables
+ *
+ * Centralised ML-DSA and SLH-DSA parameter-size arrays.  Declared
+ * extern in cmh_qse_abi.h / cmh_hcq_abi.h, defined here once to
+ * avoid per-TU duplication.
+ */
+
+#include <linux/build_bug.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+
+#include "cmh_qse_abi.h"
+#include "cmh_hcq_abi.h"
+
+/* ML-DSA size tables (indexed by ml_dsa_mode_idx()) */
+const u32 ml_dsa_pk_size[3]  = { 1312U, 1952U, 2592U };
+const u32 ml_dsa_sk_size[3]  = { 2560U, 4032U, 4896U };
+const u32 ml_dsa_sk_size_masked[3] = { 3360U, 5472U, 6368U };
+const u32 ml_dsa_sig_size[3] = { 2420U, 3309U, 4627U };
+
+static_assert(ARRAY_SIZE(ml_dsa_pk_size) == ARRAY_SIZE(ml_dsa_sk_size));
+static_assert(ARRAY_SIZE(ml_dsa_pk_size) == ARRAY_SIZE(ml_dsa_sk_size_masked));
+static_assert(ARRAY_SIZE(ml_dsa_pk_size) == ARRAY_SIZE(ml_dsa_sig_size));
+
+/* SLH-DSA n-values and signature sizes (indexed by param_set - 1) */
+const u32 slhdsa_n[12] = {
+	16, 16, 24, 24, 32, 32,		/* SHAKE 128s/f, 192s/f, 256s/f */
+	16, 16, 24, 24, 32, 32,		/* SHA2 128s/f, 192s/f, 256s/f */
+};
+
+const u32 slhdsa_sig_size[12] = {
+	7856,  17088, 16224, 35664, 29792, 49856,	/* SHAKE */
+	7856,  17088, 16224, 35664, 29792, 49856,	/* SHA2 */
+};
+
+static_assert(ARRAY_SIZE(slhdsa_n) == ARRAY_SIZE(slhdsa_sig_size));
drivers/crypto/cmh/cmh_qse.c new file +211 -0

211 lines not on this page · raw message

Signature · 1 line
2.43.7
#37 lore raw

PATCH v5 16/19 crypto: cmh - add SLH-DSA/LMS/XMSS (HCQ)

In reply to Alex Ousherovitch

Register SLH-DSA, LMS, LMS-HSS, XMSS, and XMSS-MT algorithms using the CMH HCQ core (core ID 0x08). SLH-DSA is registered as a sig algorithm with sign and verify support. LMS, LMS-HSS, XMSS, and XMSS-MT are registered as verify-only sig algorithms: their stateful signing semantics (one-time-key private state the signer must track) are not modeled by the kernel crypto API, so only verification is exposed.

---
 drivers/crypto/cmh/Makefile         |   6 +-
 drivers/crypto/cmh/cmh_hcq.c        | 313 +++++++++++++++++++++++
 drivers/crypto/cmh/cmh_main.c       |  24 ++
 drivers/crypto/cmh/cmh_pqc_lms.c    | 244 ++++++++++++++++++
 drivers/crypto/cmh/cmh_pqc_slhdsa.c | 382 ++++++++++++++++++++++++++++
 drivers/crypto/cmh/cmh_pqc_xmss.c   | 244 ++++++++++++++++++
 6 files changed, 1212 insertions(+), 1 deletion(-)
 create mode 100644 drivers/crypto/cmh/cmh_hcq.c
 create mode 100644 drivers/crypto/cmh/cmh_pqc_lms.c
 create mode 100644 drivers/crypto/cmh/cmh_pqc_slhdsa.c
 create mode 100644 drivers/crypto/cmh/cmh_pqc_xmss.c
drivers/crypto/cmh/Makefile +5 -1
index 7196d992487e..a78311bf3195 100644
@@ -36,7 +36,11 @@ cmh-y := \
 	cmh_pke_ecdh.o \
 	cmh_qse.o \
 	cmh_pqc_mldsa.o \
-	cmh_pqc_sizes.o
+	cmh_pqc_sizes.o \
+	cmh_hcq.o \
+	cmh_pqc_slhdsa.o \
+	cmh_pqc_lms.o \
+	cmh_pqc_xmss.o
 
 # Management ioctl device (/dev/cmh_mgmt): key lifecycle, PKE, PQC ioctls.
 cmh-$(CONFIG_CRYPTO_DEV_CMH_MGMT) += \
drivers/crypto/cmh/cmh_hcq.c new file +313 -0

313 lines not on this page · raw message

drivers/crypto/cmh/cmh_main.c +24 -0
index 7dfcdf395175..bed18321f535 100644
@@ -308,6 +308,21 @@ static int cmh_probe(struct platform_device *pdev)
 	if (ret)
 		goto err_pqc_mldsa_register;
 
+	/* Register PQC SLH-DSA */
+	ret = cmh_pqc_slhdsa_register();
+	if (ret)
+		goto err_pqc_slhdsa_register;
+
+	/* Register PQC LMS */
+	ret = cmh_pqc_lms_register();
+	if (ret)
+		goto err_pqc_lms_register;
+
+	/* Register PQC XMSS */
+	ret = cmh_pqc_xmss_register();
+	if (ret)
+		goto err_pqc_xmss_register;
+
 	/* Register key management device (/dev/cmh_mgmt) */
 	ret = cmh_mgmt_register();
 	if (ret)
@@ -318,6 +333,12 @@ static int cmh_probe(struct platform_device *pdev)
 	return 0;
 
 err_mgmt_register:
+	cmh_pqc_xmss_unregister();
+err_pqc_xmss_register:
+	cmh_pqc_lms_unregister();
+err_pqc_lms_register:
+	cmh_pqc_slhdsa_unregister();
+err_pqc_slhdsa_register:
 	cmh_pqc_mldsa_unregister();
 err_pqc_mldsa_register:
 	cmh_pke_ecdh_unregister();
@@ -382,6 +403,9 @@ static void cmh_remove(struct platform_device *pdev)
 	cfg = &dev->config;
 
 	cmh_mgmt_unregister();
+	cmh_pqc_xmss_unregister();
+	cmh_pqc_lms_unregister();
+	cmh_pqc_slhdsa_unregister();
 	cmh_pqc_mldsa_unregister();
 	cmh_pke_ecdh_unregister();
 	cmh_pke_ecdsa_unregister();
drivers/crypto/cmh/cmh_pqc_lms.c new file +244 -0

244 lines not on this page · raw message

drivers/crypto/cmh/cmh_pqc_slhdsa.c new file +382 -0

382 lines not on this page · raw message

drivers/crypto/cmh/cmh_pqc_xmss.c new file +244 -0

244 lines not on this page · raw message

Signature · 7 lines
2.43.7


_______________________________________________
linux-riscv mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-riscv
#38 lore raw

PATCH v5 17/19 Documentation: ioctl: add CMH ioctl documentation and register 'J'

In reply to Alex Ousherovitch

Add Documentation/userspace-api/ioctl/cmh_mgmt.rst documenting the ioctl commands on the /dev/cmh_mgmt misc device for the Rambus CryptoManager Hub (CMH) hardware crypto accelerator driver. Covers key management, KIC key derivation, PKE (RSA, ECDSA, ECDH, EdDSA), PQC (ML-KEM, ML-DSA, SLH-DSA), SM2, EAC, and DRBG. Link the page into the userspace-api/ioctl index toctree.

Register ioctl magic number 'J' (0x4A) in ioctl-number.rst. The driver uses ioctls 0x01-0x40.

---
 .../userspace-api/ioctl/cmh_mgmt.rst          | 1292 +++++++++++++++++
 Documentation/userspace-api/ioctl/index.rst   |    1 +
 .../userspace-api/ioctl/ioctl-number.rst      |    1 +
 3 files changed, 1294 insertions(+)
 create mode 100644 Documentation/userspace-api/ioctl/cmh_mgmt.rst
Documentation/userspace-api/ioctl/cmh_mgmt.rst new file +1292 -0
new file mode 100644
index 000000000000..c02bac128787
@@ -0,0 +1,1292 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=============================================
+CMH Key Management ioctl Interface (cmh_mgmt)
+=============================================
+
+:Author: Cryptography Research, Inc. (CRI)
+:Maintainer: [email protected]
+
+Introduction
+============
+
+The ``/dev/cmh_mgmt`` character device provides user-space access to key
+management, key derivation, public-key, and post-quantum cryptographic
+operations on the CryptoManager Hub (CMH) hardware accelerator.
+
+The device is created by the ``cmh`` kernel module as a ``misc_device``.
+All operations are synchronous -- the ioctl blocks until the hardware
+completes.  Opening the device requires ``CAP_SYS_ADMIN``.
+
+All ioctl argument structures are versioned: user space sets the
+``version`` field to ``CMH_MGMT_V1`` (currently 1).  This allows the
+driver to extend structures in the future without breaking the ABI.
+
+Data types and ioctl numbers are defined in
+``<uapi/linux/cmh_mgmt_ioctl.h>``.  The ioctl type letter is ``'J'``
+(0x4A).
+
+Error Handling
+==============
+
+Unless otherwise noted, all ioctls return 0 on success and a negative
+errno on failure.  Common error codes:
+
+========== =============================================================
+``EINVAL`` Invalid ``version`` field, unsupported parameter, or
+           out-of-range length.
+``EFAULT`` Failed to copy data to/from user space.
+``ENOMEM`` Kernel memory allocation failed.
+``EIO``    Hardware returned an error (eSW command failure).
+``ENOENT`` Key not found (``KEY_FIND``, ``KEY_LIST``).
+========== =============================================================
+
+Datastore Concepts
+==================
+
+The CMH hardware maintains an embedded datastore managed by the eSW
+firmware.  Objects in the datastore are identified by a 64-bit reference
+(``ref``) and optionally by a 64-bit Content ID (``cid``).
+
+Two storage classes exist:
+
+**Temporary (SYS_REF_TEMP)**
+  Lifetime is scoped to a single mailbox slot.  The eSW firmware
+  reclaims the object when the slot is reused.  Used for raw-key
+  provisioning via ``KEY_NEW`` + ``KEY_WRITE``.
+
+**Persistent (SYS_REF_PERSIST)**
+  Survives across mailbox slots.  Requires explicit deletion via
+  ``KEY_DELETE``.  Identified by CID; resolved to a per-mailbox ref
+  via ``KEY_FIND``.
+
+Mailbox Dispatch
+================
+
+All ``/dev/cmh_mgmt`` ioctls are submitted on a single management
+mailbox.  This is a structural requirement of the eSW datastore model,
+not a tunable:
+
+* Datastore access control is **per-mailbox**.  ``KEY_NEW`` grants the
+  creating mailbox read/write/execute access; other mailboxes have none
+  until granted.  The returned 64-bit ``ref`` encodes a randomised
+  offset and does **not** carry the owning mailbox, so an operation that
+  receives only a ``ref`` (``KEY_GRANT``, ``KEY_READ``, ``KEY_DELETE``,
+  ``DS_EXPORT``) cannot itself determine which mailbox owns the object.
+  Using one fixed management mailbox guarantees that a key's create,
+  modify, grant, read and hardware-held-key compute steps all share the
+  mailbox that holds its access rights, without exposing mailbox
+  identity in the UABI.  User space may still widen a key's access to
+  additional mailboxes via ``KEY_GRANT``.
+
+* The eSW ``SYS_REF_TEMP`` scratch store is per-mailbox and persists
+  across ioctl calls, so a multi-step flow that derives into
+  ``SYS_REF_TEMP`` (for example a ``KIC_*`` derivation) and later
+  consumes it (``DS_EXPORT`` with ``wrap_key = SYS_REF_TEMP``) requires
+  both calls to use the same mailbox.
+
+Per-mailbox ``rambus,cores`` device-tree affinity applies to the *stateless*
+in-kernel crypto API path, which carries no datastore state between
+requests and is balanced across mailboxes by the driver.
+
+Key Types
+=========
+
+The ``ds_type`` field in ``KEY_NEW`` and ``KEY_WRITE`` selects the
+datastore object type.  Values are defined as ``CMH_DS_*`` constants:
+
+=================================  =====  ==============================
+Constant                           Value  Description
+=================================  =====  ==============================
+``CMH_DS_RAW_VALUE``               1      Raw byte array
+``CMH_DS_AES_KEY``                 2      AES key (128/192/256-bit)
+``CMH_DS_AES_XTS_KEY``             3      AES-XTS key (256/512-bit)
+``CMH_DS_HMAC_KEY``                4      HMAC key
+``CMH_DS_KMAC_KEY``                5      KMAC key
+``CMH_DS_SM4_KEY``                 6      SM4 key (128-bit)
+``CMH_DS_CHACHA20_KEY``            7      ChaCha20 key (256-bit)
+``CMH_DS_RSA_PRIV_KEY``            10     RSA private key
+``CMH_DS_RSA_PUB_KEY``             11     RSA public key
+``CMH_DS_RSA_CRT_KEY``             12     RSA CRT private key
+``CMH_DS_ECDSA_PRIV_KEY``          13     ECDSA private key
+``CMH_DS_ECDSA_PUB_KEY``           14     ECDSA public key
+``CMH_DS_ECDH_PRIV_KEY``           15     ECDH private key
+``CMH_DS_EDDSA_PRIV_KEY``          16     EdDSA private key
+``CMH_DS_SHARED_SECRET``           17     Shared secret
+``CMH_DS_SM2_PRIV_KEY``            18     SM2 private key
+``CMH_DS_ML_KEM_DK``               20     ML-KEM decapsulation key
+``CMH_DS_ML_DSA_SK``               21     ML-DSA secret key
+``CMH_DS_SLHDSA_SK``               25     SLH-DSA secret key
+=================================  =====  ==============================
+
+Key Flags
+=========
+
+The ``flags`` field in ``KEY_NEW`` and ``KEY_WRITE`` is a bitmask:
+
+==================  ===========  ========================================
+Flag                Bit          Description
+==================  ===========  ========================================
+``CMH_FLAG_PT``     16           Key can be read as plaintext
+``CMH_FLAG_XC``     17           Key can be exported over XC bus
+``CMH_FLAG_SCA``    18           SCA key stored in 2 shares
+==================  ===========  ========================================
+
+Elliptic Curve IDs
+==================
+
+Curve identifiers for PKE operations (``curve`` field):
+
+==========================  =====
+Constant                    Value
+==========================  =====
+``CMH_CURVE_P192``          0x01
+``CMH_CURVE_P224``          0x02
+``CMH_CURVE_P256``          0x03
+``CMH_CURVE_P384``          0x04
+``CMH_CURVE_P521``          0x05
+``CMH_CURVE_SECP256K1``     0x07
+``CMH_CURVE_BP192R1``       0x11
+``CMH_CURVE_BP224R1``       0x12
+``CMH_CURVE_BP256R1``       0x13
+``CMH_CURVE_BP320R1``       0x14
+``CMH_CURVE_BP384R1``       0x15
+``CMH_CURVE_BP512R1``       0x16
+``CMH_CURVE_SM2``           0x18
+``CMH_CURVE_25519``         0x21
+``CMH_CURVE_448``           0x22
+==========================  =====
+
+Key Management ioctls
+=====================
+
+CMH_IOCTL_KEY_NEW
+-----------------
+
+Create a new empty datastore object.
+
+:Direction: ``_IOWR``
+:Number: 0x01
+:Argument: ``struct cmh_ioctl_key_new``
+
+::
+
+  struct cmh_ioctl_key_new {
+      __u32 version;     /* must be CMH_MGMT_V1 */
+      __u32 ds_type;     /* CMH_DS_* key type */
+      __u32 len;         /* key length in bytes */
+      __u32 flags;       /* CMH_FLAG_* */
+      __u64 cid;         /* caller ID (name) for the key */
+      __u64 ref;         /* [out] key reference */
+  };
+
+The returned ``ref`` is used in subsequent ``KEY_WRITE``, ``KEY_READ``,
+and crypto operation ioctls.
+
+CMH_IOCTL_KEY_NEW_RANDOM
+------------------------
+
+Create a new datastore object filled with hardware-generated random data.
+
+:Direction: ``_IOWR``
+:Number: 0x0B
+:Argument: ``struct cmh_ioctl_key_new``
+
+Same structure as ``KEY_NEW``.  The hardware DRBG fills the object with
+``len`` random bytes.
+
+CMH_IOCTL_KEY_WRITE
+-------------------
+
+Write key material into a previously created datastore object.
+
+:Direction: ``_IOW``
+:Number: 0x02
+:Argument: ``struct cmh_ioctl_key_write``
+
+::
+
+  struct cmh_ioctl_key_write {
+      __u32 version;
+      __u32 len;         /* key data length */
+      __u32 ds_type;     /* CMH_DS_* key type */
+      __u32 flags;       /* CMH_FLAG_* */
+      __u64 ref;         /* key reference from KEY_NEW */
+      __u64 wrap_key;    /* wrapping key ref (CMH_REF_NONE = plaintext) */
+      __u64 data;        /* user-space pointer to key material */
+  };
+
+If ``wrap_key`` is ``CMH_REF_NONE`` (0), key material is written in
+plaintext.  Otherwise, the data is unwrapped using the specified
+wrapping key.
+
+CMH_IOCTL_KEY_READ
+------------------
+
+Read key material from a datastore object.
+
+:Direction: ``_IOWR``
+:Number: 0x03
+:Argument: ``struct cmh_ioctl_key_read``
+
+::
+
+  struct cmh_ioctl_key_read {
+      __u32 version;
+      __u32 len;         /* buffer length */
+      __u64 ref;         /* key reference */
+      __u64 wrap_key;    /* wrapping key ref (CMH_REF_NONE = plaintext) */
+      __u64 data;        /* user-space pointer to output buffer */
+      __u32 out_len;     /* [out] actual bytes written */
+      __u32 __reserved;
+  };
+
+Plaintext reads require the ``CMH_FLAG_PT`` attribute on the key.
+The eSW prepends a 16-byte header (``CMH_SYS_WRAP_HDR_SIZE``) even
+for plaintext reads; the output buffer must accommodate this.  The
+output overhead is ``CMH_DS_EXPORT_OVERHEAD_PLAIN`` (16 bytes) for
+plaintext reads and ``CMH_DS_EXPORT_OVERHEAD_WRAPPED`` (48 bytes:
+16-byte header + 16-byte nonce + 16-byte tag) for wrapped reads.
+
+CMH_IOCTL_KEY_FIND
+------------------
+
+Resolve a Content ID to a datastore reference.
+
+:Direction: ``_IOWR``
+:Number: 0x04
+:Argument: ``struct cmh_ioctl_key_find``
+
+::
+
+  struct cmh_ioctl_key_find {
+      __u32 version;
+      __u32 __reserved;
+      __u64 cid;         /* caller ID to search for */
+      __u64 ref;         /* [out] resolved key reference */
+      __u32 len;         /* [out] key length */
+      __u32 type;        /* [out] key type */
+  };
+
+Returns ``-ENOENT`` if no object with the given CID exists.
+
+CMH_IOCTL_KEY_LIST
+------------------
+
+Iterate datastore objects.
+
+:Direction: ``_IOWR``
+:Number: 0x0E
+:Argument: ``struct cmh_ioctl_key_list``
+
+::
+
+  struct cmh_ioctl_key_list {
+      __u32 version;
+      __u32 __reserved;
+      __u64 start_ref;   /* starting DS reference (0 = first) */
+      __u64 ref;         /* [out] object reference */
+      __u64 cid;         /* [out] caller ID */
+      __u32 len;         /* [out] object length */
+      __u32 type;        /* [out] object type */
+  };
+
+Pass ``start_ref=0`` to begin from the first object.  On return, pass
+the returned ``ref`` as ``start_ref`` in the next call.  Iteration ends
+when ``ref == 0``.
+
+CMH_IOCTL_KEY_GRANT
+-------------------
+
+Set per-mailbox access permissions on a datastore object.
+
+:Direction: ``_IOW``
+:Number: 0x05
+:Argument: ``struct cmh_ioctl_key_grant``
+
+::
+
+  struct cmh_ioctl_key_grant {
+      __u32 version;
+      __u32 __reserved;
+      __u64 ref;         /* key reference */
+      __u64 read;        /* per-MBX read permission bitfield */
+      __u64 write;       /* per-MBX write permission bitfield */
+      __u64 execute;     /* per-MBX execute permission bitfield */
+  };
+
+CMH_IOCTL_KEY_DELETE
+--------------------
+
+Delete a datastore object (persistent keys only).
+
+:Direction: ``_IOW``
+:Number: 0x06
+:Argument: ``struct cmh_ioctl_key_grant``
+
+Uses the same structure as ``KEY_GRANT``; only the ``ref`` field is
+used.
+
+Datastore Export/Import ioctls
+==============================
+
+CMH_IOCTL_DS_EXPORT
+-------------------
+
+Export the entire datastore as an encrypted blob.
+
+:Direction: ``_IOWR``
+:Number: 0x07
+:Argument: ``struct cmh_ioctl_ds_export``
+
+::
+
+  struct cmh_ioctl_ds_export {
+      __u32 version;
+      __u32 len;         /* buffer length */
+      __u64 cid;         /* caller ID for response tagging */
+      __u64 wrap_key;    /* wrapping key ref (CMH_REF_NONE = plaintext) */
+      __u64 data;        /* user-space pointer to output buffer */
+      __u32 out_len;     /* [out] actual bytes written */
+      __u32 __reserved;
+  };
+
+CMH_IOCTL_DS_IMPORT
+-------------------
+
+Import a previously exported datastore blob.
+
+:Direction: ``_IOW``
+:Number: 0x08
+:Argument: ``struct cmh_ioctl_ds_import``
+
+::
+
+  struct cmh_ioctl_ds_import {
+      __u32 version;
+      __u32 len;         /* blob length */
+      __u64 wrap_key;    /* wrapping key ref (CMH_REF_NONE = plaintext) */
+      __u64 data;        /* user-space pointer to import blob */
+  };
+
+Key Derivation ioctls (KIC)
+===========================
+
+The Key Initialization Core (KIC) provides hardware key derivation from
+OTP-provisioned base keys.  Up to 8 base keys are available
+(``CMH_KIC_KEY1`` through ``CMH_KIC_KEY8``).
+
+CMH_IOCTL_KIC_HKDF1
+--------------------
+
+HKDF-based key derivation (single-step, label only).
+
+:Direction: ``_IOWR``
+:Number: 0x09
+:Argument: ``struct cmh_ioctl_kic_hkdf1``
+
+::
+
+  struct cmh_ioctl_kic_hkdf1 {
+      __u32 version;
+      __u32 key_len;     /* output key length */
+      __u64 base_key;    /* KIC base key reference */
+      __u64 cid;         /* CID for the new DS entry */
+      __u64 label;       /* user-space pointer to label data */
+      __u32 label_len;   /* label length in bytes */
+      __u32 flags;       /* CMH_KIC_FLAG_* */
+      __u64 ref;         /* [out] derived key reference */
+  };
+
+If ``CMH_KIC_FLAG_TEMP`` is set, the result is stored in the temporary
+datastore (not persistent).
+
+CMH_IOCTL_KIC_HKDF2
+--------------------
+
+HKDF-based key derivation (two-step, with salt key).
+
+:Direction: ``_IOWR``
+:Number: 0x0A
+:Argument: ``struct cmh_ioctl_kic_hkdf2``
+
+::
+
+  struct cmh_ioctl_kic_hkdf2 {
+      __u32 version;
+      __u32 key_len;
+      __u64 base_key;
+      __u64 salt_key;    /* salt key reference (CMH_REF_NONE = no salt) */
+      __u64 cid;
+      __u64 label;
+      __u32 label_len;
+      __u32 flags;
+      __u64 ref;         /* [out] derived key reference */
+  };
+
+CMH_IOCTL_KIC_AES_CMAC_KDF
+---------------------------
+
+AES-CMAC-based key derivation (NIST SP 800-108).
+
+:Direction: ``_IOWR``
+:Number: 0x0C
+:Argument: ``struct cmh_ioctl_kic_aes_cmac_kdf``
+
+::
+
+  struct cmh_ioctl_kic_aes_cmac_kdf {
+      __u32 version;
+      __u32 key_len;     /* base & output key length (must be 32) */
+      __u64 base_key;
+      __u64 cid;
+      __u64 label;
+      __u32 label_len;
+      __u32 flags;
+      __u64 ref;         /* [out] derived key reference */
+  };
+
+CMH_IOCTL_KIC_DKEK_DERIVE
+--------------------------
+
+Derive a Device Key Encryption Key (DKEK) for secure key export.
+
+:Direction: ``_IOWR``
+:Number: 0x0D
+:Argument: ``struct cmh_ioctl_kic_dkek_derive``
+
+::
+
+  struct cmh_ioctl_kic_dkek_derive {
+      __u32 version;
+      __u32 host_id;     /* target host ID (0 = caller's own) */
+      __u64 base_key;
+      __u64 cid;
+      __u64 metadata;    /* user-space pointer to metadata */
+      __u32 metadata_len;
+      __u32 flags;
+      __u64 ref;         /* [out] derived KEK reference */
+  };
+
+PKE (Public Key Engine) ioctls
+==============================
+
+RSA Operations
+--------------
+
+CMH_IOCTL_PKE_RSA_ENC
+~~~~~~~~~~~~~~~~~~~~~~
+
+RSA public-key encryption.
+
+:Direction: ``_IOWR``
+:Number: 0x10
+:Argument: ``struct cmh_ioctl_pke_rsa_enc``
+
+::
+
+  struct cmh_ioctl_pke_rsa_enc {
+      __u32 version;
+      __u32 bits;        /* RSA key size in bits (512-4096) */
+      __u64 e;           /* user-space pointer to public exponent */
+      __u32 e_len;       /* exponent length in bytes */
+      __u32 __reserved;
+      __u64 n;           /* user-space pointer to modulus */
+      __u64 input;       /* user-space pointer to input data */
+      __u64 output;      /* user-space pointer to output buffer */
+  };
+
+The public key (e, n) is passed as raw user-space buffers.
+
+CMH_IOCTL_PKE_RSA_DEC
+~~~~~~~~~~~~~~~~~~~~~~
+
+RSA private-key decryption using a datastore key reference.
+
+:Direction: ``_IOWR``
+:Number: 0x11
+:Argument: ``struct cmh_ioctl_pke_rsa_dec``
+
+::
+
+  struct cmh_ioctl_pke_rsa_dec {
+      __u32 version;
+      __u32 bits;
+      __u64 e;           /* public exponent */
+      __u32 e_len;
+      __u32 __reserved;
+      __u64 n;           /* modulus */
+      __u64 input;       /* ciphertext */
+      __u64 output;      /* plaintext output */
+      __u64 key_ref;     /* private key DS reference */
+  };
+
+CMH_IOCTL_PKE_RSA_CRT_DEC
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+RSA CRT private-key decryption (faster, uses CRT key format).
+
+:Direction: ``_IOWR``
+:Number: 0x12
+:Argument: ``struct cmh_ioctl_pke_rsa_crt_dec``
+
+::
+
+  struct cmh_ioctl_pke_rsa_crt_dec {
+      __u32 version;
+      __u32 bits;
+      __u64 e;
+      __u32 e_len;
+      __u32 __reserved;
+      __u64 n;
+      __u64 input;
+      __u64 output;
+      __u64 crt_ref;     /* CRT key DS reference */
+  };
+
+CMH_IOCTL_PKE_RSA_KEYGEN
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Generate an RSA key pair in hardware.
+
+:Direction: ``_IOWR``
+:Number: 0x13
+:Argument: ``struct cmh_ioctl_pke_rsa_keygen``
+
+::
+
+  struct cmh_ioctl_pke_rsa_keygen {
+      __u32 version;
+      __u32 bits;        /* key size in bits */
+      __u64 e;           /* user-space pointer to public exponent */
+      __u32 e_len;
+      __u32 flags;       /* CMH_FLAG_* */
+      __u64 n;           /* [out] user-space pointer to modulus buffer */
+      __u64 d_cid;       /* CID for private key DS entry */
+      __u64 d_ref;       /* [out] private key reference */
+      __u64 crt_cid;     /* CID for CRT key DS entry (0 = skip CRT) */
+      __u64 crt_ref;     /* [out] CRT key reference */
+  };
+
+Returns private key and optional CRT key as datastore references.
+The modulus is written back to user space.
+
+ECDSA Operations
+----------------
+
+CMH_IOCTL_PKE_ECDSA_SIGN
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ECDSA signature generation using a datastore private key.
+
+:Direction: ``_IOWR``
+:Number: 0x14
+:Argument: ``struct cmh_ioctl_pke_ecdsa_sign``
+
+::
+
+  struct cmh_ioctl_pke_ecdsa_sign {
+      __u32 version;
+      __u32 curve;       /* ABI curve ID (e.g. 0x03 = P-256) */
+      __u64 digest;      /* user-space pointer to hash digest */
+      __u32 digest_len;  /* digest length in bytes */
+      __u32 __reserved;
+      __u64 signature;   /* [out] user-space pointer to (r,s) */
+      __u64 key_ref;     /* private key DS reference */
+  };
+
+CMH_IOCTL_PKE_ECDH
+~~~~~~~~~~~~~~~~~~~
+
+Compute ECDH shared secret from a peer public key and a datastore
+private key.
+
+:Direction: ``_IOWR``
+:Number: 0x16
+:Argument: ``struct cmh_ioctl_pke_ecdh``
+
+::
+
+  struct cmh_ioctl_pke_ecdh {
+      __u32 version;
+      __u32 curve;
+      __u64 peer_key_x;  /* user-space pointer to peer public key X */
+      __u64 key_ref;     /* private key DS reference */
+      __u32 flags;       /* reserved, must be 0 */
+      __u32 __reserved;
+      __u64 __reserved2; /* reserved, must be 0 */
+      __u64 output;      /* [out] raw shared secret */
+  };
+
+CMH_IOCTL_PKE_ECDH_KEYGEN
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Derive a public key from a datastore private key.
+
+:Direction: ``_IOWR``
+:Number: 0x17
+:Argument: ``struct cmh_ioctl_pke_ecdh_keygen``
+
+::
+
+  struct cmh_ioctl_pke_ecdh_keygen {
+      __u32 version;
+      __u32 curve;
+      __u64 key_ref;       /* private key DS reference */
+      __u64 public_key_x;  /* [out] user-space pointer to public key X */
+  };
+
+EdDSA Operations
+----------------
+
+CMH_IOCTL_PKE_EDDSA_SIGN
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+EdDSA (Ed25519/Ed448) signature generation.
+
+:Direction: ``_IOWR``
+:Number: 0x18
+:Argument: ``struct cmh_ioctl_pke_eddsa_sign``
+
+::
+
+  struct cmh_ioctl_pke_eddsa_sign {
+      __u32 version;
+      __u32 curve;       /* CURVE_25519 or CURVE_448 */
+      __u64 digest;      /* user-space ptr to message (not digest) */
+      __u32 digest_len;
+      __u32 __reserved;
+      __u64 signature;   /* [out] user-space pointer to signature */
+      __u64 key_ref;     /* private key DS reference */
+  };
+
+Note: the ``digest`` field is the full message (pure EdDSA), not a
+pre-computed hash.
+
+CMH_IOCTL_PKE_EDDSA_VERIFY
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+EdDSA signature verification.
+
+:Direction: ``_IOW``
+:Number: 0x19
+:Argument: ``struct cmh_ioctl_pke_eddsa_verify``
+
+::
+
+  struct cmh_ioctl_pke_eddsa_verify {
+      __u32 version;
+      __u32 curve;
+      __u64 digest;
+      __u32 digest_len;
+      __u32 __reserved;
+      __u64 signature;
+      __u64 public_key_y;  /* user-space pointer to public key Y */
+  };
+
+EC Key Management
+-----------------
+
+CMH_IOCTL_PKE_EC_KEYGEN
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Generate an EC private key in the hardware datastore.
+
+:Direction: ``_IOWR``
+:Number: 0x1A
+:Argument: ``struct cmh_ioctl_pke_ec_keygen``
+
+::
+
+  struct cmh_ioctl_pke_ec_keygen {
+      __u32 version;
+      __u32 curve;
+      __u32 flags;       /* CMH_FLAG_* */
+      __u32 __reserved;
+      __u64 cid;         /* CID for the new key DS entry */
+      __u64 ref;         /* [out] private key reference */
+  };
+
+CMH_IOCTL_PKE_EC_PUBGEN
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Derive the public key from a datastore private key.
+
+:Direction: ``_IOWR``
+:Number: 0x1B
+:Argument: ``struct cmh_ioctl_pke_ec_pubgen``
+
+::
+
+  struct cmh_ioctl_pke_ec_pubgen {
+      __u32 version;
+      __u32 curve;
+      __u64 key_ref;     /* private key DS reference */
+      __u64 public_key;  /* [out] user-space pointer to public key */
+  };
+
+CMH_IOCTL_PKE_EDDSA_KEYGEN_SCA
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Generate a 2-share SCA-protected Ed448 private key.
+
+:Direction: ``_IOWR``
+:Number: 0x1C
+:Argument: ``struct cmh_ioctl_pke_eddsa_keygen_sca``
+
+::
+
+  struct cmh_ioctl_pke_eddsa_keygen_sca {
+      __u32 version;
+      __u32 curve;       /* must be CURVE_448 */
+      __u64 key_ref;     /* input: normal Ed448 private key DS ref */
+      __u64 cid;         /* CID for the new SCA key DS entry */
+      __u64 sca_ref;     /* [out] SCA private key reference */
+  };
+
+Post-Quantum Cryptography (PQC) ioctls
+=======================================
+
+PQC operations support the following flags in the ``flags`` field:
+
+============================  ====  ====================================
+Flag                          Bit   Description
+============================  ====  ====================================
+``CMH_QSE_FLAG_MASKED``       0     Use masked (SCA-resistant) HW path
+``CMH_QSE_FLAG_DS_REF``       1     Store key output in DS, return ref
+``CMH_QSE_FLAG_HW_RNG``       2     Use HW RNG for seed/randomness
+============================  ====  ====================================
+
+ML-KEM (FIPS 203)
+-----------------
+
+CMH_IOCTL_ML_KEM_KEYGEN
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Generate an ML-KEM key pair.
+
+:Direction: ``_IOWR``
+:Number: 0x20
+:Argument: ``struct cmh_ioctl_ml_kem_keygen``
+
+::
+
+  struct cmh_ioctl_ml_kem_keygen {
+      __u32 version;
+      __u32 k;           /* security parameter: 2/3/4 */
+      __u32 flags;       /* CMH_QSE_FLAG_* */
+      __u32 __reserved;
+      __u64 seed;        /* user-space pointer to seed (or 0 for HW RNG) */
+      __u64 z;           /* user-space pointer to z (or 0 for HW RNG) */
+      __u64 ek;          /* [out] user-space pointer to encapsulation key */
+      __u64 dk;          /* [out] user-space pointer to decapsulation key,
+                          *       or [out] DS ref if CMH_QSE_FLAG_DS_REF */
+      __u64 dk_cid;      /* CID for DS entry (if DS_REF) */
+      __u64 dk_ref;      /* [out] dk DS reference (if DS_REF) */
+  };
+
+Security parameter ``k`` selects the strength: 2 (ML-KEM-512),
+3 (ML-KEM-768), or 4 (ML-KEM-1024).
+
+CMH_IOCTL_ML_KEM_ENC
+~~~~~~~~~~~~~~~~~~~~~
+
+ML-KEM encapsulation.  Produces ciphertext and shared secret.
+
+:Direction: ``_IOWR``
+:Number: 0x21
+:Argument: ``struct cmh_ioctl_ml_kem_enc``
+
+::
+
+  struct cmh_ioctl_ml_kem_enc {
+      __u32 version;
+      __u32 k;
+      __u32 flags;       /* CMH_QSE_FLAG_* */
+      __u32 __reserved;
+      __u64 coin;        /* user-space pointer to random coin (or 0) */
+      __u64 ek;          /* user-space pointer to encapsulation key */
+      __u64 ct;          /* [out] user-space pointer to ciphertext */
+      __u64 ss;          /* [out] user-space pointer to shared secret */
+      __u64 __reserved2[2];  /* reserved for future use */
+  };
+
+CMH_IOCTL_ML_KEM_DEC
+~~~~~~~~~~~~~~~~~~~~~
+
+ML-KEM decapsulation.  Recovers shared secret from ciphertext.
+
+:Direction: ``_IOWR``
+:Number: 0x22
+:Argument: ``struct cmh_ioctl_ml_kem_dec``
+
+::
+
+  struct cmh_ioctl_ml_kem_dec {
+      __u32 version;
+      __u32 k;
+      __u32 flags;       /* CMH_QSE_FLAG_* */
+      __u32 __reserved;
+      __u64 ct;          /* user-space pointer to ciphertext */
+      __u64 dk;          /* user-space pointer to dk or DS ref */
+      __u64 ss;          /* [out] user-space pointer to shared secret */
+      __u64 __reserved2[2];  /* reserved for future use */
+  };
+
+ML-DSA (FIPS 204)
+-----------------
+
+CMH_IOCTL_ML_DSA_KEYGEN
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Generate an ML-DSA key pair.
+
+:Direction: ``_IOWR``
+:Number: 0x23
+:Argument: ``struct cmh_ioctl_ml_dsa_keygen``
+
+::
+
+  struct cmh_ioctl_ml_dsa_keygen {
+      __u32 version;
+      __u32 mode;        /* security parameter: 2/3/5 */
+      __u32 flags;       /* CMH_QSE_FLAG_* */
+      __u32 __reserved;
+      __u64 seed;        /* user-space pointer to seed (or 0 for HW RNG) */
+      __u64 pk;          /* [out] user-space pointer to public key */
+      __u64 sk;          /* [out] user-space pointer to secret key,
+                          *       or [out] DS ref if CMH_QSE_FLAG_DS_REF */
+      __u64 sk_cid;      /* CID for DS entry (if DS_REF) */
+      __u64 sk_ref;      /* [out] sk DS reference (if DS_REF) */
+  };
+
+Security parameter ``mode`` selects the strength: 2 (ML-DSA-44),
+3 (ML-DSA-65), or 5 (ML-DSA-87).
+
+.. note::
+
+   When ``CMH_QSE_FLAG_DS_REF`` keeps the secret key in the datastore,
+   the public key returned in ``pk`` is the only copy: there is no
+   operation to derive the public key from the secret-key reference
+   for ML-DSA.  User space must persist ``pk`` at keygen time.
+
+CMH_IOCTL_ML_DSA_SIGN
+~~~~~~~~~~~~~~~~~~~~~~
+
+ML-DSA signature generation.
+
+:Direction: ``_IOWR``
+:Number: 0x24
+:Argument: ``struct cmh_ioctl_ml_dsa_sign``
+
+::
+
+  struct cmh_ioctl_ml_dsa_sign {
+      __u32 version;
+      __u32 mode;
+      __u32 flags;       /* CMH_QSE_FLAG_* */
+      __u32 mlen;        /* message length in bytes */
+      __u64 m;           /* user-space pointer to message */
+      __u64 sk;          /* user-space pointer to sk or DS ref */
+      __u64 sig;         /* [out] user-space pointer to signature */
+      __u64 rnd;         /* user-space pointer to randomness (or 0) */
+  };
+
+If ``mlen`` is set to ``CMH_ML_DSA_MLEN_EXTERNAL_MU`` (0xFFFFFFFF),
+the ``m`` pointer is interpreted as a 64-byte pre-hashed mu value
+(ExternalMu mode).
+
+CMH_IOCTL_SLHDSA_KEYGEN
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Generate an SLH-DSA key pair.
+
+:Direction: ``_IOWR``
+:Number: 0x28
+:Argument: ``struct cmh_ioctl_slhdsa_keygen``
+
+::
+
+  struct cmh_ioctl_slhdsa_keygen {
+      __u32 version;
+      __u32 parameter_set;  /* HCQ_SLHDSA_SHAKE_128S .. SHA2_256F */
+      __u32 flags;          /* CMH_QSE_FLAG_DS_REF */
+      __u32 __reserved;
+      __u64 seed;           /* user-space pointer to seed */
+      __u64 pk;             /* [out] user-space pointer to public key */
+      __u64 sk;             /* [out] user-space pointer to secret key,
+                             *       or [out] DS ref if CMH_QSE_FLAG_DS_REF */
+      __u64 sk_cid;         /* CID for DS entry (if DS_REF) */
+      __u64 sk_ref;         /* [out] sk DS reference (if DS_REF) */
+  };
+
+.. note::
+
+   When ``CMH_QSE_FLAG_DS_REF`` keeps the secret key in the datastore,
+   the public key returned in ``pk`` is the only copy: there is no
+   operation to derive the public key from the secret-key reference
+   for SLH-DSA.  User space must persist ``pk`` at keygen time.
+
+CMH_IOCTL_SLHDSA_SIGN
+~~~~~~~~~~~~~~~~~~~~~~
+
+SLH-DSA signature generation (pure mode).
+
+:Direction: ``_IOWR``
+:Number: 0x29
+:Argument: ``struct cmh_ioctl_slhdsa_sign``
+
+::
+
+  struct cmh_ioctl_slhdsa_sign {
+      __u32 version;
+      __u32 parameter_set;
+      __u32 msg_len;
+      __u32 ctx_len;
+      __u64 msg;         /* user-space pointer to message */
+      __u64 ctx;         /* user-space pointer to context (or 0) */
+      __u64 sk;          /* DS ref for secret key */
+      __u64 sig;         /* [out] user-space pointer to signature */
+      __u64 add_random;  /* user-space pointer to addl. randomness (or 0) */
+  };
+
+CMH_IOCTL_SLHDSA_SIGN_PREHASH
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+SLH-DSA pre-hash signature generation.
+
+:Direction: ``_IOWR``
+:Number: 0x2D
+:Argument: ``struct cmh_ioctl_slhdsa_sign_prehash``
+
+::
+
+  struct cmh_ioctl_slhdsa_sign_prehash {
+      __u32 version;
+      __u32 parameter_set;
+      __u32 prehash_algo;  /* CMH_SLHDSA_PREHASH_* */
+      __u32 digest;        /* 0 = raw msg (eSW hashes), 1 = pre-computed */
+      __u32 msg_len;
+      __u32 ctx_len;
+      __u64 msg;           /* user-space pointer to message/digest */
+      __u64 ctx;           /* user-space pointer to context (or 0) */
+      __u64 sk;            /* DS ref for secret key */
+      __u64 sig;           /* [out] user-space pointer to signature */
+      __u64 add_random;    /* user-space pointer to addl. randomness (or 0) */
+  };
+
+The ``prehash_algo`` field selects the hash algorithm
+(``CMH_SLHDSA_PREHASH_SHA256``, etc.).
+
+CMH_IOCTL_SM2_ENC_POINT
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+:Direction: ``_IOWR``
+:Number: 0x33
+:Argument: ``struct cmh_ioctl_sm2_enc_point``
+
+::
+
+  struct cmh_ioctl_sm2_enc_point {
+      __u32 version;
+      __u32 nonce_len;   /* 0 = HW generates, 32 = caller provides */
+      __u64 nonce;       /* user-space pointer to nonce (or 0) */
+      __u64 public_key;  /* user-space pointer to public key (64B) */
+      __u64 ciphertext;  /* [out] user-space pointer to C1 (64B) */
+      __u64 enc_point;   /* [out] user-space pointer to enc point (64B) */
+  };
+
+CMH_IOCTL_SM2_ENC_HASH
+~~~~~~~~~~~~~~~~~~~~~~~
+
+:Direction: ``_IOWR``
+:Number: 0x37
+:Argument: ``struct cmh_ioctl_sm2_enc_hash``
+
+::
+
+  struct cmh_ioctl_sm2_enc_hash {
+      __u32 version;
+      __u32 message_len;  /* message length (1..32) */
+      __u64 message;      /* user-space pointer to plaintext */
+      __u64 enc_point;    /* user-space pointer to enc point (64B) */
+      __u64 ciphertext;   /* [out] user-space pointer to ciphertext */
+  };
+
+CMH_IOCTL_SM2_DEC_POINT
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+:Direction: ``_IOWR``
+:Number: 0x32
+:Argument: ``struct cmh_ioctl_sm2_dec_point``
+
+::
+
+  struct cmh_ioctl_sm2_dec_point {
+      __u32 version;
+      __u32 ciphertext_len;  /* total ciphertext length (97..128) */
+      __u64 ciphertext;      /* user-space pointer to ciphertext (64B: C1) */
+      __u64 dec_point;       /* [out] user-space pointer to dec point (64B) */
+      __u64 key_ref;         /* private key DS reference */
+  };
+
+CMH_IOCTL_SM2_DEC_HASH
+~~~~~~~~~~~~~~~~~~~~~~~
+
+:Direction: ``_IOWR``
+:Number: 0x36
+:Argument: ``struct cmh_ioctl_sm2_dec_hash``
+
+::
+
+  struct cmh_ioctl_sm2_dec_hash {
+      __u32 version;
+      __u32 ciphertext_len;  /* ciphertext length (97..128) */
+      __u64 ciphertext;      /* user-space pointer to full ciphertext */
+      __u64 dec_point;       /* user-space pointer to dec point (64B) */
+      __u64 plaintext;       /* [out] user-space pointer to plaintext */
+  };
+
+SM2 Key Exchange (GM/T 0003.3)
+------------------------------
+
+The key exchange protocol is a multi-step flow:
+
+1. ``EC_KEYGEN(CMH_CURVE_SM2)`` -- generate a long-lived private key.
+2. ``EC_PUBGEN`` -- derive the public key.
+3. ``SM2_ID_DIGEST`` -- compute the SM3 identity digest (ZA).
+4. ``SM2_ECDH_KEYGEN`` -- generate an ephemeral session key.
+5. Exchange session keys with the peer.
+6. ``SM2_ECDH`` -- compute the shared point.
+7. ``SM2_ECDH_HASH`` -- derive the shared key from the shared point
+   and both parties' ZA digests.
+
+CMH_IOCTL_SM2_ECDH_KEYGEN
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+:Direction: ``_IOWR``
+:Number: 0x30
+:Argument: ``struct cmh_ioctl_sm2_ecdh_keygen``
+
+::
+
+  struct cmh_ioctl_sm2_ecdh_keygen {
+      __u32 version;
+      __u32 nonce_len;    /* 0 = HW generates r (written back), 32 = caller */
+      __u64 nonce;        /* [in/out] user-space pointer to nonce buffer (32B) */
+      __u64 session_key;  /* [out] user-space pointer to R=r*G (64B) */
+  };
+
+``nonce_len`` must be 0 or 32.  If ``nonce_len=0``, the hardware
+generates the ephemeral scalar and writes it back to the ``nonce``
+buffer.
+
+CMH_IOCTL_SM2_ECDH
+~~~~~~~~~~~~~~~~~~~
+
+:Direction: ``_IOWR``
+:Number: 0x31
+:Argument: ``struct cmh_ioctl_sm2_ecdh``
+
+::
+
+  struct cmh_ioctl_sm2_ecdh {
+      __u32 version;
+      __u32 nonce_len;         /* 0 = HW generates, 32 = caller provides */
+      __u64 nonce;             /* [in/out] user-space pointer to nonce r (32B) */
+      __u64 peer_public_key;   /* user-space pointer to peer pub key (64B) */
+      __u64 peer_session_key;  /* user-space pointer to peer session key (64B) */
+      __u64 key_ref;           /* private key DS reference */
+      __u64 shared_point;      /* [out] user-space pointer to shared point (64B) */
+      __u64 shared_point_ref;  /* [in/out] 0 = read-back; &ref = keep DS */
+  };
+
+If ``shared_point_ref`` points to a non-zero value, the shared point
+is kept in the datastore for use by ``SM2_ECDH_HASH``.
+
+CMH_IOCTL_SM2_ID_DIGEST
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Compute the SM3 identity digest (ZA) for a public key and identity
+string.
+
+:Direction: ``_IOWR``
+:Number: 0x34
+:Argument: ``struct cmh_ioctl_sm2_id_digest``
+
+::
+
+  struct cmh_ioctl_sm2_id_digest {
+      __u32 version;
+      __u32 id_len;      /* identity length in bytes (<=32) */
+      __u64 id;          /* user-space pointer to identity string */
+      __u64 public_key;  /* user-space pointer to public key (64B) */
+      __u64 digest;      /* [out] user-space pointer to ZA digest (32B) */
+  };
+
+CMH_IOCTL_SM2_ECDH_HASH
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Derive the shared key from the shared point and ZA digests.
+
+:Direction: ``_IOWR``
+:Number: 0x35
+:Argument: ``struct cmh_ioctl_sm2_ecdh_hash``
+
+::
+
+  struct cmh_ioctl_sm2_ecdh_hash {
+      __u32 version;
+      __u32 __reserved;
+      __u64 peer_id_digest;    /* ptr to Z_A -- initiator's digest (32B) */
+      __u64 id_digest;         /* ptr to Z_B -- responder's digest (32B) */
+      __u64 shared_point_ref;  /* DS reference from SM2_ECDH */
+      __u64 shared_key;        /* [out] ptr to shared key (16B) */
+  };
+
+.. important::
+
+   The digest fields use **absolute** ordering per GM/T 0003.3, not
+   relative own/peer ordering.  Both parties must pass:
+
+   - ``peer_id_digest`` = Z_A (initiator's digest) -- hashed first
+   - ``id_digest`` = Z_B (responder's digest) -- hashed second
+
+Hardware Management ioctls
+==========================
+
+CMH_IOCTL_EAC_READ
+-------------------
+
+Read and clear the hardware Error and Alarm Controller registers.
+
+:Direction: ``_IOWR``
+:Number: 0x0F
+:Argument: ``struct cmh_ioctl_eac_read``
+
+::
+
+  struct cmh_ioctl_eac_read {
+      __u32 version;
+      __u32 __reserved;
+      __u64 mailbox_notification;
+      __u32 hw_error;
+      __u32 hw_nmi;
+      __u32 hw_panic;
+      __u32 safety_fatal;
+      __u32 safety_notification;
+      __u32 sw_info0;
+      __u32 sw_info1;
+      __u32 sram_bank_errors[4];
+      __u32 __pad;
+  };
+
+The eSW atomically reads and clears the registers on each call.
+Successive reads show only new events since the last read.
+
+CMH_IOCTL_DRBG_CONFIG
+----------------------
+
+Configure the hardware DRBG before first use.
+
+:Direction: ``_IOW``
+:Number: 0x40
+:Argument: ``struct cmh_ioctl_drbg_config``
+
+::
+
+  struct cmh_ioctl_drbg_config {
+      __u32 version;
+      __u32 entropy_ratio;       /* CMH_DRBG_RATIO_* */
+      __u32 security_strength;   /* CMH_DRBG_STRENGTH_* */
+      __u32 __reserved;
+  };
+
+This is a management operation normally performed once at system
+startup.  Must be called before any ``hwrng`` reads or DRBG generate
+operations.
+
+ioctl Number Summary
+====================
+
+======================================  ====  ====  =========================================
+ioctl                                   Dir   Seq   Argument
+======================================  ====  ====  =========================================
+``CMH_IOCTL_KEY_NEW``                   IOWR  0x01  ``cmh_ioctl_key_new``
+``CMH_IOCTL_KEY_WRITE``                 IOW   0x02  ``cmh_ioctl_key_write``
+``CMH_IOCTL_KEY_READ``                  IOWR  0x03  ``cmh_ioctl_key_read``
+``CMH_IOCTL_KEY_FIND``                  IOWR  0x04  ``cmh_ioctl_key_find``
+``CMH_IOCTL_KEY_GRANT``                 IOW   0x05  ``cmh_ioctl_key_grant``
+``CMH_IOCTL_KEY_DELETE``                IOW   0x06  ``cmh_ioctl_key_grant``
+``CMH_IOCTL_DS_EXPORT``                 IOWR  0x07  ``cmh_ioctl_ds_export``
+``CMH_IOCTL_DS_IMPORT``                 IOW   0x08  ``cmh_ioctl_ds_import``
+``CMH_IOCTL_KIC_HKDF1``                 IOWR  0x09  ``cmh_ioctl_kic_hkdf1``
+``CMH_IOCTL_KIC_HKDF2``                 IOWR  0x0A  ``cmh_ioctl_kic_hkdf2``
+``CMH_IOCTL_KEY_NEW_RANDOM``            IOWR  0x0B  ``cmh_ioctl_key_new``
+``CMH_IOCTL_KIC_AES_CMAC_KDF``          IOWR  0x0C  ``cmh_ioctl_kic_aes_cmac_kdf``
+``CMH_IOCTL_KIC_DKEK_DERIVE``           IOWR  0x0D  ``cmh_ioctl_kic_dkek_derive``
+``CMH_IOCTL_KEY_LIST``                  IOWR  0x0E  ``cmh_ioctl_key_list``
+``CMH_IOCTL_EAC_READ``                  IOWR  0x0F  ``cmh_ioctl_eac_read``
+``CMH_IOCTL_PKE_RSA_ENC``               IOWR  0x10  ``cmh_ioctl_pke_rsa_enc``
+``CMH_IOCTL_PKE_RSA_DEC``               IOWR  0x11  ``cmh_ioctl_pke_rsa_dec``
+``CMH_IOCTL_PKE_RSA_CRT_DEC``           IOWR  0x12  ``cmh_ioctl_pke_rsa_crt_dec``
+``CMH_IOCTL_PKE_RSA_KEYGEN``            IOWR  0x13  ``cmh_ioctl_pke_rsa_keygen``
+``CMH_IOCTL_PKE_ECDSA_SIGN``            IOWR  0x14  ``cmh_ioctl_pke_ecdsa_sign``
+``CMH_IOCTL_PKE_ECDH``                  IOWR  0x16  ``cmh_ioctl_pke_ecdh``
+``CMH_IOCTL_PKE_ECDH_KEYGEN``           IOWR  0x17  ``cmh_ioctl_pke_ecdh_keygen``
+``CMH_IOCTL_PKE_EDDSA_SIGN``            IOWR  0x18  ``cmh_ioctl_pke_eddsa_sign``
+``CMH_IOCTL_PKE_EDDSA_VERIFY``          IOW   0x19  ``cmh_ioctl_pke_eddsa_verify``
+``CMH_IOCTL_PKE_EC_KEYGEN``             IOWR  0x1A  ``cmh_ioctl_pke_ec_keygen``
+``CMH_IOCTL_PKE_EC_PUBGEN``             IOWR  0x1B  ``cmh_ioctl_pke_ec_pubgen``
+``CMH_IOCTL_PKE_EDDSA_KEYGEN_SCA``      IOWR  0x1C  ``cmh_ioctl_pke_eddsa_keygen_sca``
+``CMH_IOCTL_ML_KEM_KEYGEN``             IOWR  0x20  ``cmh_ioctl_ml_kem_keygen``
+``CMH_IOCTL_ML_KEM_ENC``                IOWR  0x21  ``cmh_ioctl_ml_kem_enc``
+``CMH_IOCTL_ML_KEM_DEC``                IOWR  0x22  ``cmh_ioctl_ml_kem_dec``
+``CMH_IOCTL_ML_DSA_KEYGEN``             IOWR  0x23  ``cmh_ioctl_ml_dsa_keygen``
+``CMH_IOCTL_ML_DSA_SIGN``               IOWR  0x24  ``cmh_ioctl_ml_dsa_sign``
+``CMH_IOCTL_SLHDSA_KEYGEN``             IOWR  0x28  ``cmh_ioctl_slhdsa_keygen``
+``CMH_IOCTL_SLHDSA_SIGN``               IOWR  0x29  ``cmh_ioctl_slhdsa_sign``
+``CMH_IOCTL_SLHDSA_SIGN_PREHASH``       IOWR  0x2D  ``cmh_ioctl_slhdsa_sign_prehash``
+``CMH_IOCTL_SM2_ECDH_KEYGEN``           IOWR  0x30  ``cmh_ioctl_sm2_ecdh_keygen``
+``CMH_IOCTL_SM2_ECDH``                  IOWR  0x31  ``cmh_ioctl_sm2_ecdh``
+``CMH_IOCTL_SM2_DEC_POINT``             IOWR  0x32  ``cmh_ioctl_sm2_dec_point``
+``CMH_IOCTL_SM2_ENC_POINT``             IOWR  0x33  ``cmh_ioctl_sm2_enc_point``
+``CMH_IOCTL_SM2_ID_DIGEST``             IOWR  0x34  ``cmh_ioctl_sm2_id_digest``
+``CMH_IOCTL_SM2_ECDH_HASH``             IOWR  0x35  ``cmh_ioctl_sm2_ecdh_hash``
+``CMH_IOCTL_SM2_DEC_HASH``              IOWR  0x36  ``cmh_ioctl_sm2_dec_hash``
+``CMH_IOCTL_SM2_ENC_HASH``              IOWR  0x37  ``cmh_ioctl_sm2_enc_hash``
+``CMH_IOCTL_DRBG_CONFIG``               IOW   0x40  ``cmh_ioctl_drbg_config``
+======================================  ====  ====  =========================================
+
+Relationship to the in-kernel crypto API
+=========================================
+
+The main reason these operations are exposed as ioctls, rather than
+through the standard in-kernel crypto API, is the CMH datastore key
+model: an ioctl can operate on a *datastore-referenced* (hardware-held)
+key, identified only by a ``ref`` or CID, whose raw bytes the CPU never
+sees.  The standard crypto API cannot express this -- every
+``.setkey()`` takes raw key material -- so hardware key lifecycle
+(create, import, derive, grant, destroy) and compute-on-hardware-held-key
+operations have no crypto API equivalent and are only reachable here.
+
+These ioctls remain supported.  Where an operation can *also* be
+expressed through a standard kernel abstraction, additional in-kernel
+crypto API bindings may be added over time; when such a binding lands the
+driver registers through it, and the ioctl continues to be maintained for
+backward compatibility:
+
+- **EdDSA** (``CMH_IOCTL_PKE_EDDSA_*``): a kernel ``sig`` binding may be
+  added once ed25519/ed448 algorithm types are accepted upstream.
+
+- **ML-KEM** (``CMH_IOCTL_ML_KEM_*``): a kernel KEM binding may be added
+  once the in-flight KEM subsystem series lands.
+
+- **Key lifecycle** (``CMH_IOCTL_KEY_*``): integration with the kernel
+  KEYS subsystem (trusted-keys / encrypted-keys) may be evaluated as a
+  follow-up series.
+
+Operations that are inherently vendor-specific (EAC Chip Authentication,
+KIC key derivation, SM2 key exchange, DRBG configuration, datastore
+export/import) have no corresponding kernel abstraction and are expected
+to remain ioctl-only.
Documentation/userspace-api/ioctl/index.rst +1 -0
index 475675eae086..bf88bb6b9a6f 100644
@@ -12,4 +12,5 @@ IOCTLs
    ioctl-decoding
 
    cdrom
+   cmh_mgmt
    hdio
Documentation/userspace-api/ioctl/ioctl-number.rst +1 -0
index 2fc53093752d..25f020c7e367 100644
@@ -170,6 +170,7 @@ Code  Seq#    Include File                                             Comments
 'I'   all    linux/isdn.h                                              conflict!
 'I'   00-0F  drivers/isdn/divert/isdn_divert.h                         conflict!
 'I'   40-4F  linux/mISDNif.h                                           conflict!
+'J'   01-40  uapi/linux/cmh_mgmt_ioctl.h                               Rambus CryptoManager Hub (CMH)
 'K'   all    linux/kd.h
 'L'   00-1F  linux/loop.h                                              conflict!
 'L'   10-1F  drivers/scsi/mpt3sas/mpt3sas_ctl.h                        conflict!
Signature · 1 line
2.43.7
#39 lore raw

Re: [PATCH v5 17/19] Documentation: ioctl: add CMH ioctl documentation and register 'J'

Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider: - [High] crypto: cmh: race condition on shared SYS_REF_TEMP state across ioctls - [Medium] crypto: cmh…

Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
- [High] crypto: cmh: race condition on shared SYS_REF_TEMP state across ioctls
- [Medium] crypto: cmh: UAPI bypasses standard Linux crypto and keys subsystems
- [Medium] crypto: cmh: missing explicit output buffer lengths in UAPI structs
- [Medium] crypto: cmh: dangerous naming of SM2 ECDH digest fields
- [Low] crypto: cmh: static inline version field violates UAPI extensibility guidelines --

commit 80c4f648ec1405769d1e6246fab5f42797923a76
Author: Alex Ousherovitch <[email protected]>

Documentation: ioctl: add CMH ioctl documentation and register 'J'

Add Documentation/userspace-api/ioctl/cmh_mgmt.rst documenting the ioctl commands on the /dev/cmh_mgmt misc device for the Rambus CryptoManager Hub (CMH) hardware crypto accelerator driver. Covers key management, KIC key derivation, PKE (RSA, ECDSA, ECDH, EdDSA), PQC (ML-KEM, ML-DSA, SLH-DSA), SM2, EAC, and DRBG.

Quoted 18 lines
Documentation/userspace-api/ioctl/cmh_mgmt.rst new file +12 -0
new file mode 100644
index 0000000000000..c02bac1287874
@@ -0,0 +1,1292 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=============================================
+CMH Key Management ioctl Interface (cmh_mgmt)
+=============================================
+
+:Author: Cryptography Research, Inc. (CRI)
+:Maintainer: [email protected]
+
+Introduction
+============
+

Documentation/userspace-api/ioctl/cmh_mgmt.rst line 22

Quoted 10 lines
Documentation/userspace-api/ioctl/cmh_mgmt.rst new file +10 -0
+The ``/dev/cmh_mgmt`` character device provides user-space access to key
+management, key derivation, public-key, and post-quantum cryptographic
+operations on the CryptoManager Hub (CMH) hardware accelerator.
+
+The device is created by the ``cmh`` kernel module as a ``misc_device``.
+All operations are synchronous -- the ioctl blocks until the hardware
+completes.  Opening the device requires ``CAP_SYS_ADMIN``.
+
+All ioctl argument structures are versioned: user space sets the
+``version`` field to ``CMH_MGMT_V1`` (currently 1).  This allows the

[Severity: Low]
Does this UAPI extensibility design match current kernel standards? Using a static inline version field forces the driver to maintain brittle switch statements for every struct version. Standard kernel practice relies on size-based extensibility (copy_struct_from_user combined with _IOC_SIZE).

Quoted 1 line
Documentation/userspace-api/ioctl/cmh_mgmt.rst new file +1 -0
+driver to extend structures in the future without breaking the ABI.

[ ... ]

Quoted 12 lines
Documentation/userspace-api/ioctl/cmh_mgmt.rst new file +12 -0
+Mailbox Dispatch
+================
+
+All ``/dev/cmh_mgmt`` ioctls are submitted on a single management
+mailbox.  This is a structural requirement of the eSW datastore model,
+not a tunable:
+
+* Datastore access control is **per-mailbox**.  ``KEY_NEW`` grants the
+  creating mailbox read/write/execute access; other mailboxes have none
+  until granted.  The returned 64-bit ``ref`` encodes a randomised
+  offset and does **not** carry the owning mailbox, so an operation that
+  receives only a ``ref`` (``KEY_GRANT``, ``KEY_READ``, ``KEY_DELETE``,

Documentation/userspace-api/ioctl/cmh_mgmt.rst line 84

Quoted 10 lines
Documentation/userspace-api/ioctl/cmh_mgmt.rst new file +10 -0
+  ``DS_EXPORT``) cannot itself determine which mailbox owns the object.
+  Using one fixed management mailbox guarantees that a key's create,
+  modify, grant, read and hardware-held-key compute steps all share the
+  mailbox that holds its access rights, without exposing mailbox
+  identity in the UABI.  User space may still widen a key's access to
+  additional mailboxes via ``KEY_GRANT``.
+
+* The eSW ``SYS_REF_TEMP`` scratch store is per-mailbox and persists
+  across ioctl calls, so a multi-step flow that derives into
+  ``SYS_REF_TEMP`` (for example a ``KIC_*`` derivation) and later

[Severity: High]
Does this globally shared resource map multi-step flows without isolation?

Because all operations are directed to a single management mailbox, concurrent calls from different user-space contexts could overwrite each other's temporary state in SYS_REF_TEMP, leading to cross-process key material leakage or data corruption.

Quoted 2 lines
Documentation/userspace-api/ioctl/cmh_mgmt.rst new file +2 -0
+  consumes it (``DS_EXPORT`` with ``wrap_key = SYS_REF_TEMP``) requires
+  both calls to use the same mailbox.

[ ... ]

Quoted 11 lines
Documentation/userspace-api/ioctl/cmh_mgmt.rst new file +11 -0
+CMH_IOCTL_PKE_RSA_ENC
+~~~~~~~~~~~~~~~~~~~~~~
+
+RSA public-key encryption.
+
+:Direction: ``_IOWR``
+:Number: 0x10
+:Argument: ``struct cmh_ioctl_pke_rsa_enc``
+
+::
+

Documentation/userspace-api/ioctl/cmh_mgmt.rst line 497

Quoted 10 lines
Documentation/userspace-api/ioctl/cmh_mgmt.rst new file +10 -0
+  struct cmh_ioctl_pke_rsa_enc {
+      __u32 version;
+      __u32 bits;        /* RSA key size in bits (512-4096) */
+      __u64 e;           /* user-space pointer to public exponent */
+      __u32 e_len;       /* exponent length in bytes */
+      __u32 __reserved;
+      __u64 n;           /* user-space pointer to modulus */
+      __u64 input;       /* user-space pointer to input data */
+      __u64 output;      /* user-space pointer to output buffer */
+  };

[Severity: Medium]
Can the kernel blindly overwrite user-space memory here?

Since there is no explicit output length field like output_len in cmh_ioctl_pke_rsa_enc or cmh_ioctl_sm2_enc_hash, if user-space allocates a small buffer but specifies a large key size (e.g. bits=4096), the driver might infer the output size from the bits parameter and overwrite memory outside the provided buffer.

[ ... ]

Quoted 6 lines
Documentation/userspace-api/ioctl/cmh_mgmt.rst new file +6 -0
+CMH_IOCTL_SM2_ECDH_HASH
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Derive the shared key from the shared point and ZA digests.
+
+:Direction: ``_IOWR``

Documentation/userspace-api/ioctl/cmh_mgmt.rst line 1142

Quoted 10 lines
Documentation/userspace-api/ioctl/cmh_mgmt.rst new file +10 -0
+:Number: 0x35
+:Argument: ``struct cmh_ioctl_sm2_ecdh_hash``
+
+::
+
+  struct cmh_ioctl_sm2_ecdh_hash {
+      __u32 version;
+      __u32 __reserved;
+      __u64 peer_id_digest;    /* ptr to Z_A -- initiator's digest (32B) */
+      __u64 id_digest;         /* ptr to Z_B -- responder's digest (32B) */

[Severity: Medium]
Could this naming cause developer confusion and incorrect key derivations?

The terms peer_id_digest and id_digest imply a relative relationship to the caller, but the API requires absolute ordering (Initiator = Z_A, Responder = Z_B). An initiator would be forced to unintuitively pass their own digest into the peer_id_digest field.

Quoted 3 lines
Documentation/userspace-api/ioctl/cmh_mgmt.rst new file +3 -0
+      __u64 shared_point_ref;  /* DS reference from SM2_ECDH */
+      __u64 shared_key;        /* [out] ptr to shared key (16B) */
+  };

[ ... ]

Documentation/userspace-api/ioctl/cmh_mgmt.rst line 1266

Quoted 6 lines
Documentation/userspace-api/ioctl/cmh_mgmt.rst new file +6 -0
+Relationship to the in-kernel crypto API
+=========================================
+
+The main reason these operations are exposed as ioctls, rather than
+through the standard in-kernel crypto API, is the CMH datastore key
+model: an ioctl can operate on a *datastore-referenced* (hardware-held)

[Severity: Medium]
Is this justification for bypassing standard kernel subsystems accurate?

The claim is that standard crypto .setkey() requires raw key material, which justifies the custom ioctl interface. However, some of these custom ioctls (like CMH_IOCTL_PKE_RSA_ENC) still accept raw bytes. Furthermore, the standard Asymmetric Keys (security/keys/) subsystem natively supports opaque, hardware-held tokens.

Quoted 5 lines
Documentation/userspace-api/ioctl/cmh_mgmt.rst new file +5 -0
+key, identified only by a ``ref`` or CID, whose raw bytes the CPU never
+sees.  The standard crypto API cannot express this -- every
+``.setkey()`` takes raw key material -- so hardware key lifecycle
+(create, import, derive, grant, destroy) and compute-on-hardware-held-key
+operations have no crypto API equivalent and are only reachable here.
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=17
#40 lore raw

PATCH v5 18/19 selftests: crypto: cmh - add kselftest for management ioctl

In reply to Alex Ousherovitch

Add a minimal kselftest exercising the /dev/cmh_mgmt ioctl interface:

- open/close the device node
- invalid ioctl returns -ENOTTY
- bad version field returns -EINVAL
- KEY_NEW + KEY_DELETE lifecycle
- KIC HKDF1 key derivation
- ML-KEM-768 keygen via hardware RNG

Tests use the kselftest_harness.h fixture framework and output TAP. Tests that require hardware features not present on the device under test are gracefully skipped (SKIP).

---
 tools/testing/selftests/Makefile              |   1 +
 .../selftests/drivers/crypto/cmh/Makefile     |   6 +
 .../drivers/crypto/cmh/cmh_mgmt_test.c        | 183 ++++++++++++++++++
 .../selftests/drivers/crypto/cmh/config       |   1 +
 4 files changed, 191 insertions(+)
 create mode 100644 tools/testing/selftests/drivers/crypto/cmh/Makefile
 create mode 100644 tools/testing/selftests/drivers/crypto/cmh/cmh_mgmt_test.c
 create mode 100644 tools/testing/selftests/drivers/crypto/cmh/config
tools/testing/selftests/Makefile +1 -0
index 2d960626750e..71eed3f8b591 100644
@@ -19,6 +19,7 @@ TARGETS += dax
 TARGETS += devices/error_logs
 TARGETS += devices/probe
 TARGETS += dmabuf-heaps
+TARGETS += drivers/crypto/cmh
 TARGETS += drivers/dma-buf
 TARGETS += drivers/ntsync
 TARGETS += drivers/s390x/uvdevice
tools/testing/selftests/drivers/crypto/cmh/Makefile new file +6 -0
new file mode 100644
index 000000000000..86cb63839b27
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0
+TEST_GEN_PROGS := cmh_mgmt_test
+
+CFLAGS += -Wall -Wno-misleading-indentation -O2 $(KHDR_INCLUDES)
+
+include ../../../lib.mk
tools/testing/selftests/drivers/crypto/cmh/cmh_mgmt_test.c new file +183 -0

183 lines not on this page · raw message

tools/testing/selftests/drivers/crypto/cmh/config new file +1 -0
new file mode 100644
index 000000000000..063c1dd0e23b
@@ -0,0 +1 @@
+CONFIG_CRYPTO_DEV_CMH=m
Signature · 1 line
2.43.7
#41 lore raw

PATCH v5 19/19 MAINTAINERS: add Rambus CryptoManager Hub (CMH)

In reply to Alex Ousherovitch

Add MAINTAINERS entry for the Rambus CryptoManager Hub (CMH) hardware crypto accelerator driver under drivers/crypto/cmh/.

---
 MAINTAINERS | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)
MAINTAINERS +17 -0
index c3bcdcaa9b92..9e7bcc4ba834 100644
@@ -22760,6 +22760,23 @@ L:	[email protected]
 S:	Maintained
 F:	drivers/net/wireless/ralink/
 
+RAMBUS CRYPTOMANAGER HUB (CMH) HARDWARE CRYPTO ACCELERATOR
+M:	Alex Ousherovitch <[email protected]>
+M:	Saravanakrishnan Krishnamoorthy <[email protected]>
+R:	Joel Wittenauer <[email protected]>
+R:	Thi Nguyen <[email protected]>
+L:	[email protected]
+S:	Maintained
+F:	Documentation/ABI/testing/cmh-mgmt
+F:	Documentation/ABI/testing/debugfs-driver-cmh
+F:	Documentation/ABI/testing/sysfs-driver-cmh
+F:	Documentation/crypto/device_drivers/cmh.rst
+F:	Documentation/devicetree/bindings/crypto/rambus,cmh-v1030.yaml
+F:	Documentation/userspace-api/ioctl/cmh_mgmt.rst
+F:	drivers/crypto/cmh/
+F:	include/uapi/linux/cmh_mgmt_ioctl.h
+F:	tools/testing/selftests/drivers/crypto/cmh/
+
 RAMDISK RAM BLOCK DEVICE DRIVER
 M:	Jens Axboe <[email protected]>
 S:	Maintained
Signature · 1 line
2.43.7
maintainer
#42 lore raw
In reply to Alex Ousherovitch
Quoted 1 line · Alex Ousherovitch

crypto: cmh - add Rambus CryptoManager Hub hardware crypto accelerator

Please check the Sashiko review, it is not happy with your patches:

https://sashiko.dev/#/patchset/20260917225929.2494111-1-aousherovitch%40rambus.com

Thanks,

Signature · 3 lines
Email: Herbert Xu <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
#43 lore raw
Quoted 2 lines · Herbert Xu

Please check the Sashiko review, it is not happy with your patches:
https://sashiko.dev/#/patchset/20260917225929.2494111-1-aousherovitch%40rambus.com

Thanks, we went through the whole Sashiko list. A number of the findings are false positives against this tree -- e.g. the dt-bindings "unsatisfiable compatible"/"missing example" items are the eip93 idiom Conor asked us to follow, "kzalloc_obj undefined" is a real slab.h macro, and most of the "unprivileged AF_ALG OOM" DoS class isn't reachable because AF_ALG bind is closed for KERN_DRIVER_ONLY|ASYNC algorithms on this kernel.

The substantive ones we did address for the next reroll: the MAC/hash .import() accounting symmetry (incl. a poly1305 counter underflow), several DMA-unmap-of-address-0 guards on PQC/KIC error paths, lost-interrupt ordering in the ring handler, a wedged-mailbox -EIO path, and the MAC finup idempotency fixes. A residual class around async-cancel DMA teardown is called out explicitly rather than papered over. Details will be in the v6 changelog.

Thanks,
Alex