Skip to contentSkip to conversation

crypto: cmh - add Rambus CryptoManager Hub driver

PATCH Superseded Alex Ousherovitch 4 participants 41 messages Aug 25 – Sep 11

Subsystems (6)

v4 of 8 Superseded Latest is v8 →

lore
Share & tools
lore
#0 lore raw

v4 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+ (based on Herbert Xu's cryptodev-2.6 tree, 7.2.0-rc1)
- sig_alg backend (upstream since 6.13)
- CRYPTO_AHASH_REQ_VIRT (native support, no REQ_VIRT interop fallback needed)
- 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 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]/

base-commit: 68554337b4aa63d8299edd58f5059d8470bc721b

Signature · 1 line
2.43.7
#1 lore raw

PATCH v4 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     | 194 ++++++++++++++++++
 .../devicetree/bindings/vendor-prefixes.yaml  |   2 +
 2 files changed, 196 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/crypto/rambus,cmh-v1030.yaml
Documentation/devicetree/bindings/crypto/rambus,cmh-v1030.yaml new file +194 -0
new file mode 100644
index 000000000000..d9598b0f3bbc
@@ -0,0 +1,194 @@
+# 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.
+
+  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:
+    const: rambus,cmh-v1030
+    description:
+      Identifies the CryptoManager Hub v1.030 IP revision (register map and
+      command ABI).  A specific SoC integration should list its own
+      "<vendor>,<soc>-cmh" compatible first with "rambus,cmh-v1030" as a
+      fallback; that extended form will be added when such a platform is
+      upstreamed.
+
+  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
+    items:
+      - description: Main functional clock ("core").
+      - description:
+          Half-rate "core-div2" clock (present only on configurations with
+          side-channel-protected cores) or the "rt" real-time tick clock.
+      - description: Real-time tick clock ("rt") for the internal timer.
+
+  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/uint32-array
+        items:
+          enum: [0x02, 0x03, 0x04, 0x05, 0x08, 0x09, 0x0a, 0x18]
+        description: |
+          Core-affinity list: the hardware core IDs whose work is
+          dispatched to this mailbox.  A core ID 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).
+
+          Because each core instance has a distinct ID, separate
+          instances of the same core type can be pinned to different
+          mailboxes.
+
+          Core IDs:
+            0x02 HC, 0x03 AES, 0x04 SM4, 0x05 SM3,
+            0x08 HCQ, 0x09 QSE, 0x0a PKE, 0x18 CCP.
+
+    required:
+      - reg
+
+    additionalProperties: false
+
+required:
+  - compatible
+  - reg
+  - "#address-cells"
+  - "#size-cells"
+
+additionalProperties: false
+
+examples:
+  - |
+    soc {
+        #address-cells = <2>;
+        #size-cells = <2>;
+
+        crypto@a4800000 {
+            compatible = "rambus,cmh-v1030";
+            reg = <0x0 0xa4800000 0x0 0x41000>;
+            clocks = <&cmh_core_clk>;
+            clock-names = "core";
+            #address-cells = <1>;
+            #size-cells = <0>;
+
+            /* Fast symmetric cores dedicated to mailbox 0:
+             * HC 0x02, AES 0x03, SM4 0x04, SM3 0x05, CCP 0x18 */
+            queue@0 {
+                reg = <0>;
+                interrupts = <1>;
+                rambus,cores = <0x02 0x03 0x04 0x05 0x18>;
+            };
+
+            /* Slow asymmetric/PQC cores dedicated to mailbox 1:
+             * HCQ 0x08, QSE 0x09, PKE 0x0a */
+            queue@1 {
+                reg = <1>;
+                interrupts = <2>;
+                rambus,cores = <0x08 0x09 0x0a>;
+                rambus,num-slots = <64>;
+                rambus,slot-stride-bytes = <512>;
+            };
+        };
+    };
Documentation/devicetree/bindings/vendor-prefixes.yaml +2 -0
index 396044f368e7..8b1a8f0a673d 100644
@@ -1371,6 +1371,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 v4 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] Properties `rambus,num-slots` and `rambus,slot-stride-bytes` describe software policy rather…

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] Properties rambus,num-slots and rambus,slot-stride-bytes describe software policy rather than hardware topology.
- [Low] The rambus,cores description contradicts its schema definition regarding multiple core instances. --

commit 8265e37ff871f85826a6ac586fd7dcad414998e4
Author: Alex Ousherovitch <[email protected]>

dt-bindings: crypto: add Rambus CryptoManager Hub

This commit adds the device tree binding schema for the Rambus CryptoManager Hub (CMH) hardware crypto accelerator. The binding describes the SoC-level node and its mailbox child nodes, detailing their respective registers, interrupts, and VCQ ring geometries.

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

[ ... ]

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

Quoted 11 lines
Documentation/devicetree/bindings/crypto/rambus,cmh-v1030.yaml new file +11 -0
+      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.

[Severity: Medium]
Do these properties describe OS software allocation policy rather than fixed hardware topology?

Device tree bindings are intended to describe immutable hardware or firmware interfaces. This property dictates the size of command queues in host DMA memory, which the host driver dynamically allocates and programs into hardware registers. Should software tuning parameters like this be excluded from the device tree?

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

Quoted 10 lines
Documentation/devicetree/bindings/crypto/rambus,cmh-v1030.yaml new file +10 -0
+
+      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.

[Severity: Medium]
Similarly, does this stride property represent software memory layout policy rather than a fixed hardware constraint?

Quoted 5 lines
Documentation/devicetree/bindings/crypto/rambus,cmh-v1030.yaml new file +5 -0
+
+      rambus,cores:
+        $ref: /schemas/types.yaml#/definitions/uint32-array
+        items:
+          enum: [0x02, 0x03, 0x04, 0x05, 0x08, 0x09, 0x0a, 0x18]

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

Quoted 10 lines
Documentation/devicetree/bindings/crypto/rambus,cmh-v1030.yaml new file +10 -0
+        description: |
+          Core-affinity list: the hardware core IDs whose work is
+          dispatched to this mailbox.  A core ID 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).
+
+          Because each core instance has a distinct ID, separate
+          instances of the same core type can be pinned to different
+          mailboxes.

[Severity: Low]
Is there a contradiction between this documentation and the schema definition?

The description implies support for multiple instances of the same core type distinguished by unique IDs, but the enum above strictly limits the valid IDs to exactly 8 specific values (exactly one for each core type). If a developer attempts to configure a second instance using a new ID, it will fail schema validation.

Quoted 4 lines
Documentation/devicetree/bindings/crypto/rambus,cmh-v1030.yaml new file +4 -0
+
+          Core IDs:
+            0x02 HC, 0x03 AES, 0x04 SM4, 0x05 SM3,
+            0x08 HCQ, 0x09 QSE, 0x0a PKE, 0x18 CCP.
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
#3 lore raw

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

In reply to Alex Ousherovitch
Quoted 60 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     | 194 ++++++++++++++++++
 .../devicetree/bindings/vendor-prefixes.yaml  |   2 +
 2 files changed, 196 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/crypto/rambus,cmh-v1030.yaml
Documentation/devicetree/bindings/crypto/rambus,cmh-v1030.yaml new file +34 -0
new file mode 100644
index 000000000000..d9598b0f3bbc
@@ -0,0 +1,194 @@
+# 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.
+
+  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).

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

Quoted 10 lines
Documentation/devicetree/bindings/crypto/rambus,cmh-v1030.yaml new file +10 -0
+
+properties:
+  compatible:
+    const: rambus,cmh-v1030
+    description:
+      Identifies the CryptoManager Hub v1.030 IP revision (register map and
+      command ABI).  A specific SoC integration should list its own
+      "<vendor>,<soc>-cmh" compatible first with "rambus,cmh-v1030" as a
+      fallback; that extended form will be added when such a platform is
+      upstreamed.

This commentary should just not be here.
Instead, do what's been done in sifive,clint.yaml for the clint2. I don't feel great about suggesting that, and it feels like it's becoming more common - although maybe that's a good thing because it means IP vendors are being more proactive about upstreaming.

Quoted 93 lines
Documentation/devicetree/bindings/crypto/rambus,cmh-v1030.yaml new file +93 -0
+
+  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
+    items:
+      - description: Main functional clock ("core").
+      - description:
+          Half-rate "core-div2" clock (present only on configurations with
+          side-channel-protected cores) or the "rt" real-time tick clock.
+      - description: Real-time tick clock ("rt") for the internal timer.
+
+  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/uint32-array
+        items:
+          enum: [0x02, 0x03, 0x04, 0x05, 0x08, 0x09, 0x0a, 0x18]
+        description: |
+          Core-affinity list: the hardware core IDs whose work is
+          dispatched to this mailbox.  A core ID may appear on at most one
+          mailbox.  Cores not listed on any mailbox are load-balanced

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

Quoted 10 lines
Documentation/devicetree/bindings/crypto/rambus,cmh-v1030.yaml new file +10 -0
+          across all mailboxes.  Optional (default: none -- the mailbox
+          only serves the load-balanced pool).
+
+          Because each core instance has a distinct ID, separate
+          instances of the same core type can be pinned to different
+          mailboxes.
+
+          Core IDs:
+            0x02 HC, 0x03 AES, 0x04 SM4, 0x05 SM3,
+            0x08 HCQ, 0x09 QSE, 0x0a PKE, 0x18 CCP.

You could just make this a string array, and then you'd not need this mapping of unintelligible hex values. Of course then your driver has to do it, but I'd rather see understandable (and portable, since a new revision could change the IDs) values in DT.

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

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

Surely clocks are also mandatory?

pw-bot: changes-requested

Cheers,
Conor.

Quoted 52 lines
Documentation/devicetree/bindings/crypto/rambus,cmh-v1030.yaml new file +36 -0
+
+additionalProperties: false
+
+examples:
+  - |
+    soc {
+        #address-cells = <2>;
+        #size-cells = <2>;
+
+        crypto@a4800000 {
+            compatible = "rambus,cmh-v1030";
+            reg = <0x0 0xa4800000 0x0 0x41000>;
+            clocks = <&cmh_core_clk>;
+            clock-names = "core";
+            #address-cells = <1>;
+            #size-cells = <0>;
+
+            /* Fast symmetric cores dedicated to mailbox 0:
+             * HC 0x02, AES 0x03, SM4 0x04, SM3 0x05, CCP 0x18 */
+            queue@0 {
+                reg = <0>;
+                interrupts = <1>;
+                rambus,cores = <0x02 0x03 0x04 0x05 0x18>;
+            };
+
+            /* Slow asymmetric/PQC cores dedicated to mailbox 1:
+             * HCQ 0x08, QSE 0x09, PKE 0x0a */
+            queue@1 {
+                reg = <1>;
+                interrupts = <2>;
+                rambus,cores = <0x08 0x09 0x0a>;
+                rambus,num-slots = <64>;
+                rambus,slot-stride-bytes = <512>;
+            };
+        };
+    };
Documentation/devicetree/bindings/vendor-prefixes.yaml +2 -0
index 396044f368e7..8b1a8f0a673d 100644
@@ -1371,6 +1371,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
#4 lore raw

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

Quoted 8 lines · Conor Dooley

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

Quoted 4 lines · Alex Ousherovitch
Documentation/devicetree/bindings/crypto/rambus,cmh-v1030.yaml new file +4 -0
+      command ABI).  A specific SoC integration should list its own
+      "<vendor>,<soc>-cmh" compatible first with "rambus,cmh-v1030" as a
+      fallback; that extended form will be added when such a platform is
+      upstreamed.

This commentary should just not be here.
Instead, do what's been done in sifive,clint.yaml for the clint2.

Will do -- I'll drop the prose and model the compatible on sifive,clint2 so the schema itself requires an SoC-specific compatible ahead of the IP fallback:

compatible:
items:
- {}
- const: rambus,cmh-v1030

Since that makes the two-item form the only valid one, I'll also move the binding example (and our test DTs) to it, using a placeholder SoC-specific compatible under the now-registered rambus prefix, e.g.

    compatible = "rambus,<soc>-cmh", "rambus,cmh-v1030";

and swap in the real "<vendor>,<soc>-cmh" string once the first integrating platform is upstreamed.

Quoted 10 lines

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

Quoted 4 lines
Documentation/devicetree/bindings/crypto/rambus,cmh-v1030.yaml new file +4 -0
+      rambus,cores:
+        $ref: /schemas/types.yaml#/definitions/uint32-array
+        items:
+          enum: [0x02, 0x03, 0x04, 0x05, 0x08, 0x09, 0x0a, 0x18]

[...]

You could just make this a string array, and then you'd not need this mapping of unintelligible hex values. Of course then your driver has to do it, but I'd rather see understandable (and portable, since a new revision could change the IDs) values in DT.

Agreed, that's clearly better. The next revision makes rambus,cores a string array and maps the names to core IDs in the driver, so the numbering can change across IP revisions without touching the DT:

    rambus,cores:
      $ref: /schemas/types.yaml#/definitions/string-array
      items:
        enum: [hc, aes, sm4, sm3, hcq, qse, pke, ccp]

(keeping the affinity semantics in the description -- a core appears on at most one queue, unlisted cores are load-balanced -- just without the hex table.)

Quoted 7 lines

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

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

Surely clocks are also mandatory?

They can't be mandatory for this binding -- there may be no clock provider for the node to reference:

- CMH is shared between hosts. The SIC presents up to four host interfaces; a designated management host owns the privileged configuration (clock, reset and power) while the other hosts are granted only a subset of mailboxes. A node describing a non-management host therefore has no clock/reset provider to point at -- those lines are driven by the management host or an SoC power controller.

- Even where a provider exists, only the main "core" clock is always fitted; "core-div2" is present only on builds that include the side-channel-protected slow cores, and "rt" is the real-time tick, which is why clock-names is a oneOf of subsets rather than a fixed list.

So I'd keep clocks (and reset-gpios) optional. I can add a one-line, hardware-framed note to the description if you'd like that rationale on record.

Thanks,
Alex

#5 lore raw

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

Quoted 19 lines · Alex
Quoted 8 lines · Conor Dooley

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

Quoted 4 lines · Alex Ousherovitch
Documentation/devicetree/bindings/crypto/rambus,cmh-v1030.yaml new file +4 -0
+      command ABI).  A specific SoC integration should list its own
+      "<vendor>,<soc>-cmh" compatible first with "rambus,cmh-v1030" as a
+      fallback; that extended form will be added when such a platform is
+      upstreamed.

This commentary should just not be here.
Instead, do what's been done in sifive,clint.yaml for the clint2.

Will do -- I'll drop the prose and model the compatible on sifive,clint2 so the schema itself requires an SoC-specific compatible ahead of the IP fallback:

compatible:
items:
- {}
- const: rambus,cmh-v1030

Quoted 8 lines

Since that makes the two-item form the only valid one, I'll also move the binding example (and our test DTs) to it, using a placeholder SoC-specific compatible under the now-registered rambus prefix, e.g.

    compatible = "rambus,<soc>-cmh", "rambus,cmh-v1030";

and swap in the real "<vendor>,<soc>-cmh" string once the first integrating platform is upstreamed.

With the correct syntax, which I think the sifive example I copied from doesn't have, but Documentation/devicetree/bindings/crypto/inside-secure,safexcel-eip93.yaml does, fake compatibles won't be permitted (and we would probably object to seeing them too). What we want is the binding to force people to use a soc-specific one to pass validation. Unfortunately this does mean you can't have an example because it won't pass the validation, which is annoying!

Quoted 49 lines
Quoted 11 lines

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

Quoted 5 lines
Documentation/devicetree/bindings/crypto/rambus,cmh-v1030.yaml new file +4 -0
+      rambus,cores:
+        $ref: /schemas/types.yaml#/definitions/uint32-array
+        items:
+          enum: [0x02, 0x03, 0x04, 0x05, 0x08, 0x09, 0x0a, 0x18]

[...]

You could just make this a string array, and then you'd not need this mapping of unintelligible hex values. Of course then your driver has to do it, but I'd rather see understandable (and portable, since a new revision could change the IDs) values in DT.

Agreed, that's clearly better. The next revision makes rambus,cores a string array and maps the names to core IDs in the driver, so the numbering can change across IP revisions without touching the DT:

    rambus,cores:
      $ref: /schemas/types.yaml#/definitions/string-array
      items:
        enum: [hc, aes, sm4, sm3, hcq, qse, pke, ccp]

(keeping the affinity semantics in the description -- a core appears on at most one queue, unlisted cores are load-balanced -- just without the hex table.)

Quoted 7 lines

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

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

Surely clocks are also mandatory?

They can't be mandatory for this binding -- there may be no clock provider for the node to reference:

- CMH is shared between hosts. The SIC presents up to four host interfaces; a designated management host owns the privileged configuration (clock, reset and power) while the other hosts are granted only a subset of mailboxes. A node describing a non-management host therefore has no clock/reset provider to point at -- those lines are driven by the management host or an SoC power controller.

- Even where a provider exists, only the main "core" clock is always fitted; "core-div2" is present only on builds that include the side-channel-protected slow cores, and "rt" is the real-time tick, which is why clock-names is a oneOf of subsets rather than a fixed list.

Quoted 3 lines

So I'd keep clocks (and reset-gpios) optional. I can add a one-line, hardware-framed note to the description if you'd like that rationale on record.

Please do, yeah.

Thanks,
Conor.

#6 lore raw

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

Quoted 8 lines · Conor Dooley

With the correct syntax, which I think the sifive example I copied from doesn't have, but Documentation/devicetree/bindings/crypto/inside-secure,safexcel-eip93.yaml does, fake compatibles won't be permitted (and we would probably object to seeing them too). What we want is the binding to force people to use a soc-specific one to pass validation. Unfortunately this does mean you can't have an example because it won't pass the validation, which is annoying!

Thanks, I'll follow the eip93 model. For v5 the compatible becomes:

compatible:
items:
- not: {}
description: SoC-specific compatible, e.g. vendor,soc-cmh
- const: rambus,cmh-v1030

and grows a oneOf branch for the concrete "vendor,soc-cmh" once the first integrating platform is upstreamed. I'll drop the examples block for now, as you say.

Quoted 5 lines
Quoted 3 lines

So I'd keep clocks (and reset-gpios) optional. I can add a one-line, hardware-framed note to the description if you'd like that rationale on record.

Please do, yeah.

Will do; I'll add to the description:

Clock and reset are owned by the CMH 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.

Thanks,
Alex

#7 lore raw

PATCH v4 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               |  579 +++++
 drivers/crypto/cmh/cmh_debugfs.c              |  289 +++
 drivers/crypto/cmh/cmh_dma.c                  |  373 +++
 drivers/crypto/cmh/cmh_main.c                 |  343 +++
 drivers/crypto/cmh/cmh_mqi.c                  |  344 +++
 drivers/crypto/cmh/cmh_rh.c                   | 1142 +++++++++
 drivers/crypto/cmh/cmh_sysfs.c                |  108 +
 drivers/crypto/cmh/cmh_txn.c                  | 2062 +++++++++++++++++
 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          |  479 ++++
 drivers/crypto/cmh/include/cmh_vcq.h          |  288 +++
 39 files changed, 9025 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 +579 -0

579 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 +373 -0

373 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 +1142 -0

373 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 +2062 -0

2,062 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 +479 -0

479 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.

#8 lore raw

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

Thank you for your contribution! Sashiko AI review found 10 potential issue(s) to consider: - [Critical] The synchronous submission timeout handler suffers from a TOCTOU race allowing…

Thank you for your contribution! Sashiko AI review found 10 potential issue(s) to consider:
- [Critical] The synchronous submission timeout handler suffers from a TOCTOU race allowing Use-After-Free, and an unconditional abort that corrupts unrelated transactions.
- [Critical] Error handling for multi-VCQ transactions causes DMA Use-After-Free by completing the transaction early while the hardware continues executing its remaining VCQs.
- [Critical] Concurrent read-modify-write of the R_MBX_QUEUE_TAIL hardware register overwrites newly submitted VCQs.
- [Critical] Mailbox FLUSH commands silently discard in-flight transactions, which the Response Handler falsely completes with SUCCESS.
- [Critical] A TOCTOU list manipulation race between the TM kthread and the sync submit cancellation path allows hardware to DMA into caller buffers after they have been freed.
- [Critical] The DMA scatter-gather descriptor array is allocated with kzalloc, which does not guarantee the 64-byte alignment required by the hardware.
- [High] Head-of-line blocking vulnerability in the Transaction Manager thread when submitting an oversized transaction.
- [High] The rh_watchdog timer re-arms itself during teardown because timer_delete_sync is called before clearing the rh.active flag.
- [High] Completion callbacks are invoked with the internal rh_process_lock spinlock held, risking AB-BA deadlocks with external subsystem locks.
- [High] A TOCTOU race in cmh_tm_post_command() checking the tm.running flag outside of the queue lock allows messages to be leaked during teardown. --

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

Adds the Rambus CryptoManager Hub (CMH) hardware crypto accelerator core platform driver. This includes platform registration, a Virtual Command Queue (VCQ) interface via mailbox, transaction manager, response handler, and sysfs/debugfs integration.

Quoted 2 lines
drivers/crypto/cmh/cmh_dma.c +0 -0

[ ... ]

drivers/crypto/cmh/cmh_dma.c struct cmh_sg_map *cmh_dma_build_sg(const struct cmh_dma_buf *bufs, u32 count, · line 255

Quoted 7 lines
drivers/crypto/cmh/cmh_dma.c +0 -0
@@ -250,7 +250,7 @@ struct cmh_sg_map *cmh_dma_build_sg(const struct cmh_dma_buf *bufs, u32 count,
 	/*
 	 * Allocate descriptor array with kmalloc and map for streaming DMA.
 	 * We map first to obtain items_dma (needed for .lli pointers),
 	 * then sync-for-cpu, fill descriptors, and sync-for-device.
 	 */
 	sgm->items = kzalloc(sgm->items_size, gfp);

[Severity: Critical]
Is it possible this allocation could cause a hardware DMA fault?

The hardware LLI format strictly requires 64-byte aligned descriptor chain pointers, but kzalloc() only guarantees the architecture's minimum DMA alignment (typically 8 or 16 bytes). Small allocations here might not satisfy the 64-byte requirement.

Quoted 2 lines
drivers/crypto/cmh/cmh_rh.c +0 -0

[ ... ]

Quoted 7 lines
drivers/crypto/cmh/cmh_rh.c +0 -0
@@ -152,5 +152,5 @@ static unsigned int watchdog_ms = CMH_RH_WATCHDOG_MS_DEFAULT;
 static void cmh_rh_poke_tail(void __iomem *base)
 {
 	u32 tail = cmh_reg_read32(base, R_MBX_QUEUE_TAIL);
 
 	cmh_reg_write32(tail, base, R_MBX_QUEUE_TAIL);

}

[Severity: Critical]
Could this sequence corrupt the hardware ring buffer?

If cmh_rh_poke_tail() runs concurrently from softirq/watchdog contexts and interleaves between submit_vcq()'s read and write of R_MBX_QUEUE_TAIL, it might read the old TAIL and overwrite the newly advanced TAIL written by submit_vcq().

This would roll back the hardware queue state and cause the next submission to overwrite unexecuted VCQs.

[ ... ]

drivers/crypto/cmh/cmh_rh.c

Quoted 10 lines
drivers/crypto/cmh/cmh_rh.c +0 -0
@@ -395,5 +395,5 @@ static void cmh_rh_process_mbx(u32 mbx_idx, u32 new_head, u32 irq_bits)
 		/* Now pop and fail the transaction that actually errored */
 		txn = cmh_tm_pop_transaction(mbx_idx);
 		if (txn) {
 			dev_dbg(cmh_dev(), "rh: mbx[%u] error-complete vcq=%u..%u\n",
 				mbx_idx, txn->first_vcq_id,
drivers/crypto/cmh/cmh_rh.c +0 -0
 				txn->last_vcq_id);
 			cmh_txn_finish(txn, error);
 			cmh_tm_txq_completion_notify();
 		} else {

[Severity: Critical]
If a multi-VCQ transaction encounters an error on a middle VCQ, could completing the transaction here cause a use-after-free?

When cmh_txn_finish() is called, the caller will unmap and free its DMA memory buffers while the hardware might still have subsequent VCQs left to process.

[ ... ]

drivers/crypto/cmh/cmh_rh.c static void cmh_rh_process_mbx(u32 mbx_idx, u32 new_head, u32 irq_bits) · line 421

Quoted 3 lines
drivers/crypto/cmh/cmh_rh.c +0 -0
@@ -420,2 +420,2 @@ static void cmh_rh_process_mbx(u32 mbx_idx, u32 new_head, u32 irq_bits)
 		cmh_reg_write32(MBX_IRQ_MASK, base, R_MBX_INTERRUPT);
 		cmh_reg_write32(MBX_COMMAND_RESTART, base, R_MBX_COMMAND);

[Severity: Critical]
Following up on the early completion above, does issuing MBX_COMMAND_RESTART here force the hardware to resume execution of the remaining VCQs from the failed transaction?

If the DMA buffers were already freed by the caller, this would lead to memory corruption when the hardware processes them.

[ ... ]

Quoted 23 lines
drivers/crypto/cmh/cmh_rh.c +0 -0
@@ -435,5 +435,5 @@ static void cmh_rh_process_mbx(u32 mbx_idx, u32 new_head, u32 irq_bits)
 	while ((txn = cmh_tm_peek_transaction(mbx_idx)) != NULL) {
 		if ((s32)(new_head - txn->last_vcq_id) <= 0) {
 			/*
 			 * Not yet complete.  An intermediate HEAD within a
 			 * multi-VCQ group is normal (the eSW advances HEAD
drivers/crypto/cmh/cmh_rh.c +0 -0
 			 * per VCQ), so log at debug level and wait for the
 			 * group to finish.
 			 */
 			if (txn->first_vcq_id != txn->last_vcq_id &&
 			    (s32)(new_head - txn->first_vcq_id) > 0)
 				dev_dbg_ratelimited(cmh_dev(),
 						    "rh: mbx[%u] head %u mid-group %u..%u\n",
 						    mbx_idx, new_head,
 						    txn->first_vcq_id,
 						    txn->last_vcq_id);
 			break;
 		}
 
 		txn = cmh_tm_pop_transaction(mbx_idx);
 		if (!txn)
 			break;
 

drivers/crypto/cmh/cmh_rh.c

Quoted 10 lines
drivers/crypto/cmh/cmh_rh.c +0 -0
 		dev_dbg(cmh_dev(), "rh: mbx[%u] complete vcq=%u..%u err=%d\n",
 			mbx_idx, txn->first_vcq_id, txn->last_vcq_id,
 			 error);
 
 		cmh_rh_stat_add_completed(mbx_idx, txn->first_vcq_id,
 					  txn->last_vcq_id);
 
 		cmh_txn_finish(txn, error);
 		cmh_tm_txq_completion_notify();
 	}

[Severity: Critical]
When a MBX_COMMAND_FLUSH command forces the hardware to discard the queue and set HEAD = TAIL, won't this loop misinterpret the discarded transactions as successful completions?

This would return garbage data to the caller instead of appropriately failing the aborted requests.

[ ... ]

Quoted 6 lines
drivers/crypto/cmh/cmh_rh.c +0 -0
@@ -446,5 +446,5 @@ static irqreturn_t cmh_rh_thread(int irq, void *data)
 
 			spin_lock_bh(&rh_process_lock);
 			new_head = cmh_reg_read32(cfg->mailboxes[i].reg_base,
 						  R_MBX_QUEUE_HEAD);
 

drivers/crypto/cmh/cmh_rh.c

Quoted 9 lines
drivers/crypto/cmh/cmh_rh.c +0 -0
 			if (new_head == rh.mbx[i].last_head && !irq_bits) {
 				spin_unlock_bh(&rh_process_lock);
 				continue;
 			}
 
 			cmh_rh_process_mbx(i, new_head, irq_bits);
 			rh.mbx[i].last_head = new_head;
 			spin_unlock_bh(&rh_process_lock);
 		}

[Severity: High]
Since cmh_rh_process_mbx() eventually invokes the caller-provided completion callback via cmh_txn_finish(), does holding rh_process_lock here risk an AB-BA deadlock?

If the crypto API callback acquires an external lock, and another thread holding that same lock calls into the driver (e.g. executing a timeout path that calls cmh_rh_abort_mbx()), they could deadlock.

[ ... ]

Quoted 16 lines
drivers/crypto/cmh/cmh_rh.c +0 -0
@@ -1023,7 +1023,7 @@ void cmh_rh_suspend(struct cmh_config *cfg)
 {
 	u32 i;
 
 	if (!rh.active)
 		return;
 
 	/* Stop the watchdog before masking HW interrupts */
drivers/crypto/cmh/cmh_rh.c +0 -0
 	timer_delete_sync(&rh_watchdog);
 
 	/* Mask MBX interrupts at the hardware level */
 	for (i = 0; i < cfg->mbx_count; i++)
 		cmh_reg_write32(0, cfg->mailboxes[i].reg_base,
 				R_MBX_INTERRUPT_MASK);
 
 	/*

drivers/crypto/cmh/cmh_rh.c

Quoted 10 lines
drivers/crypto/cmh/cmh_rh.c +0 -0
 	 * Ensure no threaded IRQ handler is still in-flight.
 	 * After masking, a handler may already have been scheduled.
 	 * synchronize_irq() waits for it to complete before we
 	 * proceed with suspend (which tears down TM state).
 	 */
 	for (i = 0; i < rh.nirqs; i++)
 		synchronize_irq(rh.irqs[i]);
 
 	rh.active = false;
 }

[Severity: High]
Does calling timer_delete_sync() before setting rh.active = false open a window for the timer to incorrectly re-arm itself?

If cmh_rh_watchdog_fn() is spinning concurrently on another CPU, it will complete, see rh.active is still true, and successfully call mod_timer(). This re-armed timer could later fire on freed memory.

The same pattern exists in cmh_rh_cleanup().

Quoted 2 lines
drivers/crypto/cmh/cmh_txn.c +0 -0

[ ... ]

Quoted 7 lines
drivers/crypto/cmh/cmh_txn.c +0 -0
@@ -611,6 +611,6 @@ static int select_mailbox(u32 slots_needed)
 {
 	u32 count = tm.cfg->mbx_count;
 	u32 start = tm.next_mbx;
 	u32 i;
 
 	for (i = 0; i < count; i++) {

drivers/crypto/cmh/cmh_txn.c

Quoted 9 lines
drivers/crypto/cmh/cmh_txn.c +0 -0
 		u32 idx = (start + i) % count;
 
 		if (cmh_rh_mbx_is_wedged(idx))
 			continue;
 
 		if (mbx_free_slots(&tm.cfg->mailboxes[idx]) >= slots_needed) {
 			tm.next_mbx = (idx + 1) % count;
 			return (int)idx;
 		}

[Severity: High]
If a request is submitted with a slots_needed value that exceeds the absolute maximum capacity of the mailbox ring buffer, won't this condition permanently fail?

[ ... ]

Quoted 4 lines
drivers/crypto/cmh/cmh_txn.c +0 -0
@@ -829,3 +829,3 @@ static int cmh_tm_thread(void *data)
 			spin_lock_irqsave(&tm.cmq_lock, flags);
 			list_add(&msg->list, &tm.cmq);
 			cmq_depth++;

drivers/crypto/cmh/cmh_txn.c

Quoted 10 lines
drivers/crypto/cmh/cmh_txn.c +0 -0
 			spin_unlock_irqrestore(&tm.cmq_lock, flags);
 
 			tmo = usecs_to_jiffies(CMH_TM_BACKOFF_MAX_US);
 			wait_event_interruptible_timeout(tm.cmq_waitq,
 							 kthread_should_stop() ||
 							 atomic_read(&txq_completion_gen) != gen,
 							 tmo ?: 1);
 			cmh_stat_inc_tm_backoff();
 			continue;
 		}

[Severity: High]
If the message failed to resolve a mailbox because it requested more VCQs than the queue can ever hold, putting it back at the head of tm.cmq will cause the kthread to retry it endlessly.

Could this create a head-of-line blocking livelock that stalls all other crypto operations on the system?

[ ... ]

Quoted 7 lines
drivers/crypto/cmh/cmh_txn.c +0 -0
@@ -1238,6 +1238,6 @@ bool cmh_tm_try_cancel_command(struct command_msg *msg)
 {
 	unsigned long flags;
 	bool cancelled = false;
 
 	spin_lock_irqsave(&tm.cmq_lock, flags);
 	if (!list_empty(&msg->list)) {

drivers/crypto/cmh/cmh_txn.c

Quoted 8 lines
drivers/crypto/cmh/cmh_txn.c +0 -0
 		list_del_init(&msg->list);
 		cmq_depth--;
 		cancelled = true;
 	}
 	spin_unlock_irqrestore(&tm.cmq_lock, flags);
 
 	return cancelled;
 }

[Severity: Critical]
Could this check return false incorrectly if cmh_tm_try_cancel_command() runs exactly when the TM thread has temporarily dequeued the message using list_del_init() to resolve a mailbox?

If the cancellation fails here, the caller might drop references and free DMA buffers, but the TM thread could subsequently re-add or submit the request, causing the hardware to DMA into freed memory.

[ ... ]

drivers/crypto/cmh/cmh_txn.c

Quoted 8 lines
drivers/crypto/cmh/cmh_txn.c +0 -0
@@ -1266,4 +1266,4 @@ int cmh_tm_post_command(struct command_msg *msg)
 {
 	unsigned long flags;
 
 	if (!READ_ONCE(tm.running))
drivers/crypto/cmh/cmh_txn.c +0 -0
 		return -ENODEV;
 
 	spin_lock_irqsave(&tm.cmq_lock, flags);

[Severity: High]
Is there a window here where a thread could check the tm.running flag, get preempted, and resume after cmh_tm_cleanup() has already stopped the TM thread and drained the queue?

The preempted thread would then acquire the lock and enqueue its message into a dead queue, leaking the memory and potentially hanging the caller indefinitely.

[ ... ]

drivers/crypto/cmh/cmh_txn.c

Quoted 13 lines
drivers/crypto/cmh/cmh_txn.c +0 -0
@@ -1453,7 +1453,7 @@ int cmh_tm_submit_sync_tmo(struct vcq_cmd *vcq_cmds, u32 vcq_count,
 			 * rh_process_lock, preventing clobber of a
 			 * concurrent RESTART/FLUSH from the watchdog.
 			 */
 			s32 abrt_mbx = READ_ONCE(msg->actual_mbx);
 
 			if (abrt_mbx >= 0 &&
 			    (u32)abrt_mbx < tm.cfg->mbx_count) {
drivers/crypto/cmh/cmh_txn.c +0 -0
 				dev_warn(cmh_dev(),
 					 "tm: aborting mbx[%d] cmd=0x%08x\n",
 					 abrt_mbx, msg->command_id);
 				cmh_rh_abort_mbx((u32)abrt_mbx);
 			}

[Severity: Critical]
Is it safe to issue an unconditional MBX_COMMAND_ABORT here based solely on msg->actual_mbx?

If the TM thread dequeued the request but hasn't updated actual_mbx yet, this skips the abort entirely, returning -ETIMEDOUT and letting the caller free DMA buffers while the hardware continues executing.

Conversely, if actual_mbx is set but this transaction has already completed, issuing an abort might spuriously terminate a completely unrelated transaction currently executing in the hardware.

[ ... ]

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

Quoted 5 lines
drivers/crypto/cmh/cmh_txn.c +0 -0
@@ -1609,4 +1609,4 @@ int cmh_tm_submit_async(struct vcq_cmd *vcq_cmds, u32 vcq_count,
 	msg->command_id      = vcq_cmds[1].id;
 	msg->vcq_count       = vcq_count;
 	msg->num_vcqs        = num_vcqs;
 	msg->target_mbx      = target_mbx;

[Severity: High]
Should there be validation here to reject the request if num_vcqs is larger than the maximum capacity of any mailbox?

If an impossibly large num_vcqs is accepted, it triggers the head-of-line blocking livelock described above.

[ ... ]

drivers/crypto/cmh/cmh_txn.c

Quoted 8 lines
drivers/crypto/cmh/cmh_txn.c +0 -0
@@ -1836,4 +1836,4 @@ 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;
drivers/crypto/cmh/cmh_txn.c +0 -0
 	}
 
 	cmh_reg_write32(MBX_COMMAND_FLUSH, base, R_MBX_COMMAND);

[Severity: Critical]
By issuing MBX_COMMAND_FLUSH here without verifying if the software transaction queue is empty (e.g. checking txq->depth == 0), aren't actively running VCQs silently destroyed?

Since submit_vcq() only updates TAIL and leaves COMMAND as 0, this check incorrectly assumes the mailbox is idle.

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

PATCH v4 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            | 1717 ++++++++++++++++++++++
 drivers/crypto/cmh/cmh_mgmt_pke.c        | 1139 ++++++++++++++
 drivers/crypto/cmh/cmh_mgmt_pqc.c        | 1365 +++++++++++++++++
 drivers/crypto/cmh/cmh_pke_sm2.c         |  848 +++++++++++
 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      |  892 +++++++++++
 17 files changed, 7237 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 +1717 -0

1,717 lines not on this page · raw message

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

913 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 +848 -0

848 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 +892 -0

892 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.

#10 lore raw

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

Thank you for your contribution! Sashiko AI review found 7 potential issue(s) to consider: - [High] Persistent datastore objects are permanently leaked on success and error paths, allowing…

Thank you for your contribution! Sashiko AI review found 7 potential issue(s) to consider:
- [High] Persistent datastore objects are permanently leaked on success and error paths, allowing unprivileged DoS of the hardware datastore.
- [High] Missing PKE_SWAP_FLAGS in cmh_mgmt_sm2_ecdh_hash causes cryptographic corruption.
- [High] Treating DMA address 0 as "absent" causes silent cryptographic degradation and mapping leaks.
- [High] Unprotected concurrent access to SYS_REF_TEMP allows cross-process crypto key theft and corruption.
- [High] RSA buffer lengths are calculated via truncation, causing hardware DMA overflows on unaligned key sizes.
- [Medium] Cryptographic randomness buffers are freed with kfree() instead of kfree_sensitive(), leaking secrets.
- [Medium] KEY_READ fails to apply the reverse byte-swap for PKE keys, returning obfuscated keys to userspace.
--

commit 67f85ec0363d5636a036b63752d2d0407ae36205
Author: Alex Ousherovitch <[email protected]>

crypto: cmh - add key provisioning and management

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, enabling datastore key lifecycle management, KIC derivation, and asymmetric/PQC operations that keep the private key hardware-resident.

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

[ ... ]

drivers/crypto/cmh/cmh_mgmt.c static int cmh_mgmt_key_read(void __user *argp) · line 279

Quoted 7 lines
drivers/crypto/cmh/cmh_mgmt.c new file +0 -0
@@ -274,6 +274,10 @@ static int cmh_mgmt_key_read(void __user *argp)
 		return -ENOMEM;
 	}
 
 	vcq_set_header(&vcq[0], MGMT_VCQ_CMDS);
 	vcq_add_sys_read(&vcq[1], req.ref, dma_addr, req.wrap_key, req.len);
 	vcq_add_sys_flush(&vcq[2]);

[Severity: Medium]
Does this command need to conditionally reverse the PKE byte swap?

If a user writes an RSA or ECC key via KEY_WRITE, the driver applies PKE_SWAP_FLAGS to store it in the internal big-endian representation.

Since the flags are not reversed here, could this return obfuscated, swapped keys back to userspace?

[ ... ]

drivers/crypto/cmh/cmh_mgmt.c static int cmh_mgmt_kic_hkdf1(void __user *argp)

Quoted 9 lines
drivers/crypto/cmh/cmh_mgmt.c new file +0 -0
@@ -661,6 +661,10 @@ static int cmh_mgmt_kic_hkdf1(void __user *argp)
 out_ref:
 	if (ref_buf) {
 		cmh_dma_unmap_single(ref_dma, sizeof(*ref_buf),
 				     DMA_FROM_DEVICE);
 		kfree(ref_buf);
 	}
 	return ret;
 }

[Severity: High]
Could this error path leak a persistent datastore object?

If cmh_tm_submit_sync_mbx() fails after the SYS_CMD_NEW command has already executed and allocated the slot, this path does not call cmh_mgmt_ds_scrub().

This appears to leave an orphaned slot in the hardware datastore. Could a caller repeatedly trigger timeouts or failures here to exhaust the finite datastore capacity?

[ ... ]

drivers/crypto/cmh/cmh_mgmt.c static int cmh_mgmt_kic_aes_cmac_kdf(void __user *argp) · line 1096

Quoted 4 lines
drivers/crypto/cmh/cmh_mgmt.c new file +0 -0
@@ -1094,6 +1094,10 @@ static int cmh_mgmt_kic_aes_cmac_kdf(void __user *argp)
 out_unmap_label_cmac:
 	if (label_buf && !cmh_dma_map_error(label_dma) && label_dma)
 		cmh_dma_unmap_single(label_dma, req.label_len, DMA_TO_DEVICE);

[Severity: High]
Is it safe to treat DMA address 0 as an invalid mapping here?

On many architectures, 0 is a valid IOVA. The && label_dma check means the mapping will be leaked if the label happens to map to address 0.

[ ... ]

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

Quoted 9 lines
drivers/crypto/cmh/cmh_mgmt.c new file +0 -0
@@ -1470,6 +1470,12 @@ static long cmh_mgmt_ioctl(struct file *file, unsigned int cmd,
 			   unsigned long arg)
 {
 	void __user *argp = (void __user *)arg;
 	int ret;
 
 	if (cmh_mgmt_needs_temp_flush(cmd) &&
 	    atomic_xchg(&mgmt_temp_dirty, 0)) {
 		ret = cmh_tm_flush_mbx(MGMT_MBX);

[Severity: High]
Is the per-mailbox SYS_REF_TEMP state fully protected here?

The lockless atomic_xchg combined with the lack of an ioctl-level mutex appears to leave the temporary key store vulnerable to concurrent clobbering.

If two processes interleave calls (e.g., one doing KIC_HKDF1 and another doing DS_EXPORT), could temporary keys derived by one process be exported or overwritten by the other?

Quoted 5 lines
drivers/crypto/cmh/cmh_mgmt_pke.c new file +0 -0
new file mode 100644
index 0000000000000..649ad20086579

[ ... ]

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

Quoted 7 lines
drivers/crypto/cmh/cmh_mgmt_pke.c new file +0 -0
@@ -50,6 +50,10 @@ int cmh_mgmt_pke_rsa_enc(void __user *argp)
 	if (req.bits < PKE_RSA_MIN_BITS || req.bits > PKE_RSA_MAX_BITS)
 		return -EINVAL;
 	if (!req.e_len || req.e_len > PKE_MAX_OPERAND)
 		return -EINVAL;
 
 	n_len = req.bits / 8;

[Severity: High]
If req.bits is not a multiple of 8 (e.g., 2049), does this integer division drop the fractional byte?

This would underestimate the required DMA buffer size.

Could the hardware then write more bytes than the buffer holds, leading to memory corruption or an IOMMU fault?

Quoted 5 lines
drivers/crypto/cmh/cmh_mgmt_pqc.c new file +0 -0
new file mode 100644
index 0000000000000..83af21eec716e

[ ... ]

drivers/crypto/cmh/cmh_mgmt_pqc.c int cmh_mgmt_ml_dsa_sign(void __user *argp) · line 854

Quoted 4 lines
drivers/crypto/cmh/cmh_mgmt_pqc.c new file +0 -0
@@ -852,6 +852,10 @@ int cmh_mgmt_ml_dsa_sign(void __user *argp)
 out_unmap:
 	if (rnd_dma && !cmh_dma_map_error(rnd_dma))
 		cmh_dma_unmap_single(rnd_dma, rnd_len, DMA_TO_DEVICE);

[Severity: High]
Is this if (rnd_dma) check correct for validating the DMA mapping?

As mentioned earlier, DMA address 0 is a valid IOVA on some platforms. If the mapping returns 0, this check evaluates to false and skips unmapping, which leaks the mapping.

If the hardware interprets a 0 pointer as absent randomness, could this also silently drop the randomness from the signature generation, degrading its security?

[ ... ]

drivers/crypto/cmh/cmh_mgmt_pqc.c int cmh_mgmt_ml_dsa_sign(void __user *argp)

Quoted 8 lines
drivers/crypto/cmh/cmh_mgmt_pqc.c new file +0 -0
@@ -869,6 +873,11 @@ int cmh_mgmt_ml_dsa_sign(void __user *argp)
 out_free:
 	kfree(rnd_buf);
 	kfree(sig_buf);
 	kfree(m_buf);
 	kfree_sensitive(sk_buf);
 	return ret;
 }

[Severity: Medium]
Should rnd_buf be cleared with kfree_sensitive() instead of kfree()?

This buffer holds the user's secret cryptographic randomness.

Freeing it without zeroization leaves sensitive secrets in the kernel heap, where they might be exposed by a memory leak vulnerability.

Quoted 5 lines
drivers/crypto/cmh/cmh_pke_sm2.c new file +0 -0
new file mode 100644
index 0000000000000..9daeaaa948281

[ ... ]

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

Quoted 5 lines
drivers/crypto/cmh/cmh_pke_sm2.c new file +0 -0
@@ -622,6 +622,10 @@ int cmh_mgmt_sm2_ecdh_hash(void __user *argp)
 	/* 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]
Does this missing PKE_SWAP_FLAGS cause cryptographic corruption?

In Phase 1 and in SM2_ECDH, the command is OR'd with PKE_SWAP_FLAGS to reverse the byte order.

Since vcq[1].id is not modified here, will the shared key be returned to userspace in the internal big-endian format rather than the host's format?

[ ... ]

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

Quoted 4 lines
drivers/crypto/cmh/cmh_pke_sm2.c new file +0 -0
@@ -651,6 +655,8 @@ int cmh_mgmt_sm2_ecdh_hash(void __user *argp)
 out_unmap:
 	if (!cmh_dma_map_error(ref_dma))
 		cmh_dma_unmap_single(ref_dma, sizeof(u64), DMA_FROM_DEVICE);

[Severity: High]
Is it possible that the persistent datastore object referenced by *ref_buf is permanently leaked here?

The *ref_buf object created by SYS_CMD_NEW is never scrubbed on the success path or the error path.

Could repeated calls to this ioctl exhaust the finite datastore capacity and brick the hardware until a reset?

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

PATCH v4 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).

Supports incremental update/finup/final, init/export/import for request cloning, and the CRYPTO_AHASH_REQ_VIRT flag for zero-copy from virtual buffers.

---
 drivers/crypto/cmh/Makefile           |   3 +-
 drivers/crypto/cmh/cmh_hash.c         | 898 ++++++++++++++++++++++++++
 drivers/crypto/cmh/cmh_main.c         |   9 +
 drivers/crypto/cmh/include/cmh_hash.h |  26 +
 4 files changed, 935 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 +898 -0

898 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 +26 -0
new file mode 100644
index 000000000000..bf17d3af7787
@@ -0,0 +1,26 @@
+/* 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.  Uses an incremental HW update model:
+ *
+ *   .init()   -> software-only: zero per-request context
+ *   .update() -> holdback partial blocks; submit full blocks via
+ *                INIT [+ RESTORE] + UPDATE + SAVE + FLUSH
+ *   .final()  -> INIT [+ RESTORE] [+ UPDATE(residual)] + FINAL + FLUSH
+ *   .digest() -> INIT + UPDATE + FINAL + FLUSH (single-shot)
+ *   .export() -> software-only: copy checkpoint + holdback
+ *   .import() -> software-only: restore checkpoint + holdback
+ */
+
+#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
#12 lore raw

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

Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider: - [High] DMA mapping the inline `rctx->checkpoint` buffer violates DMA API rules and causes memory…

Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
- [High] DMA mapping the inline rctx->checkpoint buffer violates DMA API rules and causes memory corruption due to cache-line sharing or stack mapping.
- [High] The driver linearizes arbitrary-length hash updates into a single kmalloc buffer, causing valid large updates to predictably fail with -ENOMEM.
- [High] Misusing the crypto API cra_blocksize for hardware alignment breaks SHAKE holdback logic, leading to hardware state corruption and potential buffer overflows.
- [High] Accessing req->src and rctx after submitting an asynchronous hardware request causes a Use-After-Free.
- [Medium] The commit message claims zero-copy support for virtual buffers, but the implementation unconditionally copies the data.
--

commit 100670a57b48ff51f5668c01fd9ada227bac5247
Author: Alex Ousherovitch <[email protected]>

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

This commit registers various ahash algorithms (SHA-2, SHA-3, SHAKE) using the CMH hash core. It implements the necessary operations for incremental updates, request cloning, and handles hardware submissions.

Quoted 3 lines

Supports incremental update/finup/final, init/export/import for request cloning, and the CRYPTO_AHASH_REQ_VIRT flag for zero-copy from virtual buffers.

[Severity: Medium]
Does the driver actually perform zero-copy DMA for virtual buffers?

Looking at cmh_hash_update() and cmh_hash_finup(), the implementation appears to unconditionally allocate a bounce buffer with kmalloc() and then executes a memcpy() from req->svirt into the bounce buffer. Is there a code path that avoids the allocation and directly maps the virtual buffer to DMA, or should the commit message be updated to reflect the copy?

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

[ ... ]

Quoted 7 lines
drivers/crypto/cmh/cmh_hash.c new file +7 -0
+	{
+		.hc_algo     = HC_ALGO_SHAKE128,
+		.digest_size = CMH_SHAKE128_DIGEST_SIZE,
+		.block_size  = 1,    /* XOF: no meaningful block for crypto API */
+		.alg_name    = "shake128",
+		.drv_name    = "rambus-cmh-shake128",
+	},

[ ... ]

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

[ ... ]

drivers/crypto/cmh/cmh_hash.c line 361

Quoted 5 lines
drivers/crypto/cmh/cmh_hash.c new file +5 -0
+	/* Not enough for a full block -- just buffer */
+	if (total_avail < block_size) {
+		if (req->base.flags & CRYPTO_AHASH_REQ_VIRT)
+			memcpy(rctx->buf + rctx->buf_len,
+			       req->svirt, req->nbytes);

[Severity: High]
Does this logic bypass the software holdback for SHAKE algorithms?

Because block_size is explicitly defined as 1 to indicate byte-oriented operation for the crypto API, the condition total_avail < block_size is practically never met (only when total_avail is 0).

The hardware Keccak cores require intermediate updates to be multiples of the algorithm's block rate (e.g., 168 bytes for SHAKE-128) to correctly save the state. Submitting unaligned arbitrary byte fragments might corrupt the hardware state. Additionally, CMH_HASH_MAX_BLOCK is 144, which would not be able to hold back a true SHAKE-128 block of 168 bytes without overflowing the array.

[ ... ]

drivers/crypto/cmh/cmh_hash.c line 383

Quoted 9 lines
drivers/crypto/cmh/cmh_hash.c new file +9 -0
+	/*
+	 * Linearise: holdback prefix + full blocks from scatterlist.
+	 * full_len is user-controlled and can exceed KMALLOC_MAX_SIZE for a
+	 * single large update; __GFP_NOWARN avoids splatting the page
+	 * allocator on an oversized request.
+	 */
+	rctx->data_buf = kmalloc(full_len, gfp | __GFP_NOWARN);
+	if (!rctx->data_buf)
+		return -ENOMEM;

[Severity: High]
Will legitimate large hash requests deterministically fail with -ENOMEM here?

The ahash API does not enforce a maximum size on req->nbytes, and clients like IPsec, IMA, or AF_ALG can submit very large scatterlists. Because kmalloc() is strictly limited to KMALLOC_MAX_SIZE and can fail earlier due to fragmentation, dynamically allocating a contiguous buffer for an arbitrary-length user-provided req->nbytes causes large updates to predictably fail with -ENOMEM.

[ ... ]

drivers/crypto/cmh/cmh_hash.c line 424

Quoted 5 lines
drivers/crypto/cmh/cmh_hash.c new file +5 -0
+	rctx->ckpt_dma = DMA_MAPPING_ERROR;
+	if (rctx->has_checkpoint) {
+		rctx->ckpt_dma = cmh_dma_map_single(rctx->checkpoint,
+						    HC_CONTEXT_SIZE,
+						     DMA_TO_DEVICE);

[Severity: High]
Does DMA mapping the inline rctx->checkpoint violate the DMA API rules?

The checkpoint array is embedded inline in struct cmh_hash_reqctx without being aligned to the cacheline. If the request context is allocated on the stack (e.g., via AHASH_REQUEST_ON_STACK), this maps stack memory for DMA, which is prohibited by the DMA API and may trigger a kernel panic.

Even if heap-allocated, the unaligned array shares a cache line with adjacent members like rctx->packed. Modifying these adjacent fields while DMA is active could corrupt the checkpoint data (or vice versa) on non-coherent architectures. This same mapping also happens in cmh_hash_submit_final().

[ ... ]

Quoted 14 lines
drivers/crypto/cmh/cmh_hash.c new file +14 -0
+	ret = cmh_vcq_pack_and_submit_async(cmds, idx, rctx->packed,
+					    CMH_HASH_MAX_PACKED,
+					    d.mbx_idx,
+					    cmh_hash_update_complete, req,
+					    !!(req->base.flags &
+					       CRYPTO_TFM_REQ_MAY_BACKLOG),
+					    cmh_tm_async_timeout_jiffies());
+	if (ret && ret != -EBUSY)
+		goto err_unmap_ckpt;
+
+	/*
+	 * Submit accepted (in flight or backlogged) -- only now move the tail
+	 * into the holdback.  A synchronous rejection above (e.g. -EAGAIN)
+	 * leaves rctx->buf/buf_len untouched so the caller can retry the

drivers/crypto/cmh/cmh_hash.c line 474

Quoted 10 lines
drivers/crypto/cmh/cmh_hash.c new file +10 -0
+	 * identical update.
+	 */
+	if (tail_len > 0) {
+		if (req->base.flags & CRYPTO_AHASH_REQ_VIRT)
+			memcpy(rctx->buf, req->svirt + from_src, tail_len);
+		else
+			scatterwalk_map_and_copy(rctx->buf, req->src,
+						 from_src, tail_len, 0);
+	}
+	rctx->buf_len = tail_len;

[Severity: High]
Can accessing req->src and rctx after submitting an asynchronous hardware request result in a use-after-free?

Once cmh_vcq_pack_and_submit_async() submits the request to the hardware, the completion callback cmh_hash_update_complete() could run immediately on another CPU and signal completion to the client. The client is then free to release the ahash_request (which contains rctx) and the source scatterlist (req->src).

If the original thread continues execution and attempts to copy the tail data into rctx->buf using req->src, it will access freed memory.

[ ... ]

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

[ ... ]

drivers/crypto/cmh/cmh_hash.c line 719

Quoted 6 lines
drivers/crypto/cmh/cmh_hash.c new file +6 -0
+	gfp = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ?
+	      GFP_KERNEL : GFP_ATOMIC;
+
+	data_buf = kmalloc(data_len, gfp | __GFP_NOWARN);
+	if (!data_buf)
+		return -ENOMEM;

[Severity: High]
Similar to the allocation in cmh_hash_update(), could this unbounded contiguous allocation fail deterministically for valid large requests?

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

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

In reply to Alex Ousherovitch
Quoted 3 lines · Alex Ousherovitch

+/*
+ * .update -- buffer incoming data, submit full blocks to HW.

Please drop block buffering in new drivers. The Crypto API handles this for you. Take a look at the aspeed driver for an example.

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 v4 04/19] crypto: cmh - add SHA-2/SHA-3/SHAKE ahash

Quoted 2 lines · Herbert Xu

Please drop block buffering in new drivers. The Crypto API handles this for you. Take a look at the aspeed driver for an example.

Done for v5. The SHA-2/SHA-3/SHAKE, SM3 and cSHAKE ahash drivers now set CRYPTO_AHASH_ALG_BLOCK_ONLY and let the Crypto API buffer partial blocks (modelled on drivers/crypto/aspeed). The hand-rolled holdback is gone.
Since BLOCK_ONLY's buffering is scatterlist-based, these drivers also drop CRYPTO_ALG_REQ_VIRT.
cSHAKE stays cra_blocksize 1 as an XOF, so the HC core buffers the sub-rate remainder across its context save/restore.

Thanks,
Alex

#15 lore raw

PATCH v4 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.

---
 drivers/crypto/cmh/Makefile           |   3 +-
 drivers/crypto/cmh/cmh_hmac.c         | 879 ++++++++++++++++++++++++++
 drivers/crypto/cmh/cmh_main.c         |   9 +
 drivers/crypto/cmh/include/cmh_hmac.h |  16 +
 4 files changed, 906 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 +879 -0

879 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
#16 lore raw

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

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [High] Unbounded kernel memory leak via abandoned or re-initialized AF_ALG requests due to chunks…

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Unbounded kernel memory leak via abandoned or re-initialized AF_ALG requests due to chunks orphaned in a shared TFM list. --

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

crypto: cmh - add HMAC ahash

This commit registers HMAC ahash algorithms for the CMH hash core, supporting HMAC-SHA-2 and HMAC-SHA-3. It implements a software accumulation buffer to handle intermediate HMAC state.

Quoted 5 lines
drivers/crypto/cmh/cmh_hmac.c new file +0 -0
new file mode 100644
index 0000000000000..528079f60bfa9

[ ... ]

drivers/crypto/cmh/cmh_hmac.c line 385

Quoted 8 lines
drivers/crypto/cmh/cmh_hmac.c new file +8 -0
+static int cmh_hmac_init(struct ahash_request *req)
+{
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+	struct cmh_hmac_reqctx *rctx = ahash_request_ctx(req);
+
+	rctx->info = cmh_hmac_get_info(tfm);
+	rctx->error = 0;
+	INIT_LIST_HEAD(&rctx->chunks);

[Severity: High]
If an active request is re-initialized by calling cmh_hmac_init(), does this INIT_LIST_HEAD() blindly wipe the list head and permanently sever access to previously accumulated chunks, leaving them stranded on the TFM list?

[ ... ]

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

[ ... ]

Quoted 8 lines
drivers/crypto/cmh/cmh_hmac.c new file +8 -0
+	chunk->len = req->nbytes;
+	if (req->base.flags & CRYPTO_AHASH_REQ_VIRT) {
+		memcpy(chunk->data, req->svirt, req->nbytes);
+	} else {
+		nents = sg_nents_for_len(req->src, req->nbytes);
+		if (nents < 0 ||
+		    sg_copy_to_buffer(req->src, nents,
+				      chunk->data, req->nbytes) != req->nbytes) {

drivers/crypto/cmh/cmh_hmac.c line 448

Quoted 10 lines
drivers/crypto/cmh/cmh_hmac.c new file +10 -0
+			kfree_sensitive(chunk);
+			rctx->error = -EINVAL;
+			goto err_free_chunks;
+		}
+	}
+
+	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: High]
Since chunks are added to the per-transform list to survive request destruction, doesn't this tie their lifecycle to the long-lived TFM?

Could this cause an unbounded kernel memory leak? An unprivileged local user can create an AF_ALG socket, call accept() to create child sockets sharing the same parent TFM, send data to allocate internal chunks here, and then close the child socket. Since the crypto API lacks a per-request destructor hook, the request context is freed without notifying the driver, leaving the chunks orphaned on the TFM list.

[ ... ]

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 691

Quoted 10 lines
drivers/crypto/cmh/cmh_hmac.c new file +10 -0
+	/*
+	 * Do NOT call free_chunks() here: the crypto API does not
+	 * guarantee the request context is in a valid state before
+	 * import(), so the list pointers may be stale or invalid.
+	 * Re-initialize from scratch instead.  Any pre-existing chunks
+	 * are tracked on tctx->all_chunks and freed in cra_exit.
+	 */
+	rctx->info = cmh_hmac_get_info(tfm);
+	rctx->error = 0;
+	INIT_LIST_HEAD(&rctx->chunks);

[Severity: High]
Similar to cmh_hmac_init(), does importing over an active request orphan its chunks? The comment acknowledges reliance on cmh_hmac_cra_exit() for cleanup, which confirms the memory remains tied up for the lifetime of the TFM.

[ ... ]

drivers/crypto/cmh/cmh_hmac.c line 790

Quoted 12 lines
drivers/crypto/cmh/cmh_hmac.c new file +12 -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);
+		kfree_sensitive(chunk);
+	}
+	spin_unlock_bh(&tctx->chunk_lock);

[Severity: High]
Sweeping orphaned chunks only at TFM destruction causes unbounded accumulation when many requests are created and destroyed over the lifetime of a single TFM. Is there a way to manage chunk lifetimes without tying them to the TFM?

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

PATCH v4 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 supports incremental update and export/import. KMAC has a 64KB data cap imposed by the hardware.

---
 drivers/crypto/cmh/Makefile             |   4 +-
 drivers/crypto/cmh/cmh_cshake.c         | 956 ++++++++++++++++++++++++
 drivers/crypto/cmh/cmh_kmac.c           | 642 ++++++++++++++++
 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, 1651 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 +956 -0

956 lines not on this page · raw message

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

642 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
#18 lore raw

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

Thank you for your contribution! Sashiko AI review found 7 potential issue(s) to consider: - [High] The driver illegally maps a request context field (`rctx->checkpoint`) for DMA, which may reside…

Thank you for your contribution! Sashiko AI review found 7 potential issue(s) to consider:
- [High] The driver illegally maps a request context field (rctx->checkpoint) for DMA, which may reside on the stack, causing IOMMU faults or memory corruption.
- [High] Unbounded kernel memory leak (OOM vector) on abandoned KMAC requests because dynamically allocated chunks are orphaned onto a TFM-scoped list.
- [High] Race condition between tail holdback updates and asynchronous completion handler.
- [High] Use of spin_lock_bh() on a lock that can be acquired from hardirq context.
- [Medium] Unbounded kmalloc in cmh_cshake_update and cmh_cshake_finup breaks the API contract for large inputs.
- [Medium] State destruction on retryable synchronous rejection breaks the crypto API contract in cSHAKE and KMAC.
- [Medium] Defining export/import stubs for unsupported algorithms breaks testmgr initialization.
--

commit 937f2b2e4d41db65f3412cfc2efce49cf5c88cf2
Author: Alex Ousherovitch <[email protected]>

crypto: cmh - add CSHAKE/KMAC ahash

Registers ahash algorithms for cSHAKE128, cSHAKE256, KMAC128, and KMAC256 using the CMH hash core. cSHAKE supports incremental update and export/import, while KMAC has a 64KB data cap.

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

[ ... ]

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 457

Quoted 3 lines
drivers/crypto/cmh/cmh_cshake.c new file +3 -0
+	rctx->data_buf = kmalloc(full_len, gfp | __GFP_NOWARN);
+	if (!rctx->data_buf)
+		return -ENOMEM;

[Severity: Medium]
Can this allocation fail for large inputs? The buffer size scales directly with the unconstrained user-supplied req->nbytes, which might trigger an unbounded allocation.

[ ... ]

drivers/crypto/cmh/cmh_cshake.c line 496

Quoted 5 lines
drivers/crypto/cmh/cmh_cshake.c new file +5 -0
+	rctx->ckpt_dma = DMA_MAPPING_ERROR;
+	if (rctx->has_checkpoint) {
+		rctx->ckpt_dma = cmh_dma_map_single(rctx->checkpoint,
+						    HC_CONTEXT_SIZE,
+						    DMA_TO_DEVICE);

[Severity: High]
Does this map stack memory directly for DMA?

If a caller uses AHASH_REQUEST_ON_STACK to allocate the request, mapping the inline context field rctx->checkpoint will generate invalid physical addresses on systems with CONFIG_VMAP_STACK enabled, causing IOMMU faults or memory corruption.

Quoted 5 lines
drivers/crypto/cmh/cmh_cshake.c new file +5 -0
+		if (cmh_dma_map_error(rctx->ckpt_dma)) {
+			ret = -ENOMEM;
+			goto err_unmap_save;
+		}
+	}

[ ... ]

Quoted 14 lines
drivers/crypto/cmh/cmh_cshake.c new file +14 -0
+	ret = cmh_vcq_pack_and_submit_async(cmds, idx, rctx->packed,
+					    CMH_CSHAKE_MAX_PACKED,
+					    d.mbx_idx,
+					    cmh_cshake_update_complete, req,
+					    !!(req->base.flags &
+					       CRYPTO_TFM_REQ_MAY_BACKLOG),
+					    cmh_tm_async_timeout_jiffies());
+	if (ret && ret != -EBUSY)
+		goto err_unmap_ckpt;
+
+	/*
+	 * Submit accepted (in flight or backlogged) -- only now move the tail
+	 * into the holdback.  A synchronous rejection above (e.g. -EAGAIN)
+	 * leaves rctx->buf/buf_len untouched so the caller can retry the

drivers/crypto/cmh/cmh_cshake.c line 538

Quoted 10 lines
drivers/crypto/cmh/cmh_cshake.c new file +10 -0
+	 * identical update.
+	 */
+	if (tail_len > 0) {
+		if (req->base.flags & CRYPTO_AHASH_REQ_VIRT)
+			memcpy(rctx->buf, req->svirt + from_src, tail_len);
+		else
+			scatterwalk_map_and_copy(rctx->buf, req->src,
+						 from_src, tail_len, 0);
+	}
+	rctx->buf_len = tail_len;

[Severity: High]
Does updating the tail holdback after submitting the asynchronous hardware command introduce a race condition?

If the hardware processing completes instantly, the callback executes and allows the caller to submit a new request while this thread is still modifying the holdback buffer, leading to state corruption.

Quoted 3 lines
drivers/crypto/cmh/cmh_cshake.c new file +3 -0
+
+	if (ret == -EBUSY)
+		return -EBUSY;

[ ... ]

Quoted 3 lines
drivers/crypto/cmh/cmh_cshake.c new file +3 -0
+static int cmh_cshake_submit_final(struct ahash_request *req,
+				   u8 *data_buf, u32 data_len)
+{

[ ... ]

drivers/crypto/cmh/cmh_cshake.c line 496

Quoted 5 lines
drivers/crypto/cmh/cmh_cshake.c new file +5 -0
+	rctx->ckpt_dma = DMA_MAPPING_ERROR;
+	if (rctx->has_checkpoint) {
+		rctx->ckpt_dma = cmh_dma_map_single(rctx->checkpoint,
+						    HC_CONTEXT_SIZE,
+						    DMA_TO_DEVICE);

[Severity: High]
Can this map a stack-allocated request context for DMA in the finalization path, leading to the same memory corruption issue if AHASH_REQUEST_ON_STACK is used?

Quoted 5 lines
drivers/crypto/cmh/cmh_cshake.c new file +5 -0
+		if (cmh_dma_map_error(rctx->ckpt_dma)) {
+			ret = -ENOMEM;
+			goto err_unmap_data;
+		}
+	}

[ ... ]

drivers/crypto/cmh/cmh_cshake.c line 700

Quoted 8 lines
drivers/crypto/cmh/cmh_cshake.c new file +8 -0
+err_free_digest:
+	kfree(rctx->digest_buf);
+	rctx->digest_buf = NULL;
+err_free_data:
+	kfree(data_buf);
+	rctx->data_buf = NULL;
+	cmh_cshake_free_reqctx(rctx);
+	return ret;

[Severity: Medium]
Does clearing has_checkpoint in this error path break the API contract?

If the hardware submission is rejected synchronously (e.g., -EAGAIN or -ENOSPC), the caller is expected to retry, but the ability to resume on retry has been destroyed.

Quoted 1 line

+}

[ ... ]

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 755

Quoted 6 lines
drivers/crypto/cmh/cmh_cshake.c new file +6 -0
+	gfp = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ?
+	      GFP_KERNEL : GFP_ATOMIC;
+
+	data_buf = kmalloc(data_len, gfp | __GFP_NOWARN);
+	if (!data_buf)
+		return -ENOMEM;

[Severity: Medium]
Will this unconstrained allocation fail if the caller provides a very large input for the combined update and final transaction?

[ ... ]

drivers/crypto/cmh/cmh_cshake.c line 771

Quoted 12 lines
drivers/crypto/cmh/cmh_cshake.c new file +12 -0
+	if (req->nbytes > 0) {
+		if (req->base.flags & CRYPTO_AHASH_REQ_VIRT)
+			memcpy(data_buf + rctx->buf_len,
+			       req->svirt, req->nbytes);
+		else
+			scatterwalk_map_and_copy(data_buf + rctx->buf_len,
+						 req->src, 0,
+						 req->nbytes, 0);
+	}
+
+	rctx->buf_len = 0;
+	return cmh_cshake_submit_final(req, data_buf, data_len);

[Severity: Medium]
Is it safe to clear rctx->buf_len before knowing if the hardware will accept the submission?

If cmh_cshake_submit_final() returns -EAGAIN, the caller will retry, but the holdback tail has already been cleared.

Quoted 1 line

+}

[ ... ]

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

[ ... ]

drivers/crypto/cmh/cmh_kmac.c line 148

Quoted 6 lines
drivers/crypto/cmh/cmh_kmac.c new file +6 -0
+static void cmh_kmac_free_chunks(struct cmh_kmac_reqctx *rctx,
+				 struct cmh_kmac_tfm_ctx *tctx)
+{
+	struct cmh_kmac_chunk *chunk, *tmp;
+
+	spin_lock_bh(&tctx->chunk_lock);

[Severity: High]
Could using spin_lock_bh() lead to deadlocks?

The crypto ahash API can be called from a hardirq context. Because spin_lock_bh() does not disable hardirqs, a hardware interrupt could spin indefinitely on this lock if it attempts to acquire it while a softirq already holds it.

Quoted 9 lines
drivers/crypto/cmh/cmh_kmac.c new file +9 -0
+	list_for_each_entry_safe(chunk, tmp, &rctx->chunks, list) {
+		list_del(&chunk->list);
+		list_del(&chunk->tfm_node);
+		kfree(chunk);
+	}
+	spin_unlock_bh(&tctx->chunk_lock);
+	rctx->num_chunks = 0;
+	rctx->total_len = 0;
+}

[ ... ]

drivers/crypto/cmh/cmh_kmac.c line 278

Quoted 8 lines
drivers/crypto/cmh/cmh_kmac.c new file +8 -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);

[Severity: High]
Does re-initializing the request list drop tracking of previously accumulated chunks?

If an earlier request was abandoned and not finalized properly, this leaves the chunks orphaned in the TFM-scoped tctx->all_chunks list, creating a memory leak.

Quoted 8 lines
drivers/crypto/cmh/cmh_kmac.c new file +8 -0
+	rctx->num_chunks = 0;
+	rctx->total_len = 0;
+
+	return 0;
+}
+
+static int cmh_kmac_update(struct ahash_request *req)
+{

[ ... ]

Quoted 16 lines
drivers/crypto/cmh/cmh_kmac.c new file +16 -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;
+	if (req->base.flags & CRYPTO_AHASH_REQ_VIRT) {
+		memcpy(chunk->data, req->svirt, req->nbytes);
+	} else {
+		nents = sg_nents_for_len(req->src, req->nbytes);
+		if (nents < 0 ||
+		    sg_copy_to_buffer(req->src, nents,
+				      chunk->data, req->nbytes) != req->nbytes) {

drivers/crypto/cmh/cmh_kmac.c line 333

Quoted 10 lines
drivers/crypto/cmh/cmh_kmac.c new file +10 -0
+			kfree(chunk);
+			rctx->error = -EINVAL;
+			goto err_free_chunks;
+		}
+	}
+
+	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: High]
Is there an unbounded kernel memory leak here?

The chunks are dynamically allocated on the heap and tied to the TFM's lifetime in tctx->all_chunks. If unprivileged userspace repeatedly creates and abandons requests (e.g. by closing an AF_ALG socket early), does it continuously leak memory until an OOM panic occurs?

Quoted 4 lines
drivers/crypto/cmh/cmh_kmac.c new file +4 -0
+	rctx->num_chunks++;
+	rctx->total_len += req->nbytes;
+
+	return 0;

[ ... ]

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 490

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

[Severity: Medium]
Will this error path destroy all accumulated KMAC chunks if the hardware submission is rejected synchronously?

This breaks the ability to retry on transient errors.

Quoted 1 line

+}

[ ... ]

drivers/crypto/cmh/cmh_kmac.c line 523

Quoted 9 lines
drivers/crypto/cmh/cmh_kmac.c new file +9 -0
+static int cmh_kmac_export(struct ahash_request *req, void *out)
+{
+	return -EOPNOTSUPP;
+}
+
+static int cmh_kmac_import(struct ahash_request *req, const void *in)
+{
+	return -EOPNOTSUPP;
+}

[Severity: Medium]
Do these stub implementations cause the testmgr to fail? The testmgr expects that if export/import function pointers are non-NULL, the feature is supported and will try to exercise it.

[ ... ]

drivers/crypto/cmh/cmh_kmac.c line 547

Quoted 7 lines
drivers/crypto/cmh/cmh_kmac.c new file +7 -0
+static void cmh_kmac_cra_exit(struct crypto_tfm *tfm)
+{
+	struct cmh_kmac_tfm_ctx *tctx = crypto_tfm_ctx(tfm);
+	struct cmh_kmac_chunk *chunk, *tmp;
+
+	/* Free any orphaned chunks (e.g. testmgr export/reimport poison) */
+	spin_lock_bh(&tctx->chunk_lock);

[Severity: High]
Does acquiring this lock with spin_lock_bh() during TFM destruction present the same deadlock risk if hardirq accesses are possible?

drivers/crypto/cmh/cmh_kmac.c line 552

Quoted 5 lines
drivers/crypto/cmh/cmh_kmac.c new file +5 -0
+	list_for_each_entry_safe(chunk, tmp, &tctx->all_chunks, tfm_node) {
+		list_del(&chunk->tfm_node);
+		kfree(chunk);
+	}
+	spin_unlock_bh(&tctx->chunk_lock);

[Severity: High]
Is doing this sweep only at TFM teardown what permits the unbounded memory growth during the TFM's lifetime for abandoned requests?

[ ... ]

Quoted 5 lines
drivers/crypto/cmh/cmh_kmac.c new file +5 -0
+	for (i = 0; i < CMH_KMAC_ALG_COUNT; i++) {
+		const struct cmh_kmac_alg_info *info =
+			&cmh_kmac_algs_info[i];
+		struct cmh_kmac_alg_drv *drv = &cmh_kmac_drvs[i];
+		struct ahash_alg *alg = &drv->alg;

drivers/crypto/cmh/cmh_kmac.c line 590

Quoted 10 lines
drivers/crypto/cmh/cmh_kmac.c new file +10 -0
+
+		drv->info = info;
+
+		alg->init   = cmh_kmac_init;
+		alg->update = cmh_kmac_update;
+		alg->final  = cmh_kmac_final;
+		alg->finup  = cmh_kmac_finup;
+		alg->digest = cmh_kmac_digest;
+		alg->export = cmh_kmac_export;
+		alg->import = cmh_kmac_import;

[Severity: Medium]
Is it problematic to expose these stubs to the crypto API by assigning them here? The unsupported export/import will cause testmgr initialization to fail.

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

PATCH v4 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         | 687 +++++++++++++++++++++++++++
 drivers/crypto/cmh/include/cmh_sm3.h |  27 ++
 4 files changed, 725 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 +687 -0

687 lines not on this page · raw message

drivers/crypto/cmh/include/cmh_sm3.h new file +27 -0
new file mode 100644
index 000000000000..2f73537f9c87
@@ -0,0 +1,27 @@
+/* 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).
+ * Uses the same incremental HW update model as cmh_hash.c:
+ *
+ *   .init()   -> software-only: zero per-request context
+ *   .update() -> holdback partial blocks; submit full blocks via
+ *                SM3_CMD_INIT [+ RESTORE] + UPDATE + SAVE + FLUSH
+ *   .final()  -> SM3_CMD_INIT [+ RESTORE] [+ UPDATE] + FINAL + FLUSH
+ *   .digest() -> INIT + UPDATE + FINAL + FLUSH (single-shot)
+ *   .export() -> software-only: copy checkpoint + holdback
+ *   .import() -> software-only: restore checkpoint + holdback
+ */
+
+#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
#20 lore raw

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

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider: - [High] Deterministic failure on large hash updates due to a single large kmalloc linearization. - [High]…

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

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

crypto: cmh - add SM3 ahash

Register the SM3 ahash algorithm using the CMH SM3 core. Supports incremental update, finup, final, and export/import functionality.

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

[ ... ]

Quoted 7 lines
drivers/crypto/cmh/cmh_sm3.c new file +7 -0
+struct cmh_sm3_reqctx {
+	int    error;
+	u32    hw_started;
+	u32    buf_len;
+	u32    has_checkpoint;
+	u8     checkpoint[SM3_CONTEXT_SIZE]; /* SM3 context from last SAVE */
+	/* DMA state for current async operation */

[ ... ]

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

[ ... ]

drivers/crypto/cmh/cmh_sm3.c line 237

Quoted 8 lines
drivers/crypto/cmh/cmh_sm3.c new file +8 -0
+	/*
+	 * full_len is user-controlled and can exceed KMALLOC_MAX_SIZE for a
+	 * single large update; __GFP_NOWARN avoids splatting the page
+	 * allocator on an oversized request.
+	 */
+	rctx->data_buf = kmalloc(full_len, gfp | __GFP_NOWARN);
+	if (!rctx->data_buf)
+		return -ENOMEM;

[Severity: High]
Is it safe to assume the entire remaining data can be linearized into a single kmalloc buffer? If a caller attempts to hash a large input (e.g., several megabytes) using the ahash API via AF_ALG, this allocation will predictably fail for sizes exceeding KMALLOC_MAX_SIZE or under memory fragmentation, which breaks the API contract.

[ ... ]

drivers/crypto/cmh/cmh_sm3.c line 278

Quoted 5 lines
drivers/crypto/cmh/cmh_sm3.c new file +5 -0
+	rctx->ckpt_dma = DMA_MAPPING_ERROR;
+	if (rctx->has_checkpoint) {
+		rctx->ckpt_dma = cmh_dma_map_single(rctx->checkpoint,
+						    SM3_CONTEXT_SIZE,
+						     DMA_TO_DEVICE);

[Severity: High]
Does mapping this inline checkpoint buffer violate the DMA API?

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

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

[ ... ]

Quoted 14 lines
drivers/crypto/cmh/cmh_sm3.c new file +14 -0
+	ret = cmh_vcq_pack_and_submit_async(cmds, idx, rctx->packed,
+					    CMH_SM3_MAX_PACKED,
+					    d.mbx_idx,
+					    cmh_sm3_update_complete, req,
+					    !!(req->base.flags &
+					       CRYPTO_TFM_REQ_MAY_BACKLOG),
+					    cmh_tm_async_timeout_jiffies());
+	if (ret && ret != -EBUSY)
+		goto err_unmap_ckpt;
+
+	/*
+	 * Submit accepted (in flight or backlogged) -- only now move the tail
+	 * into the holdback.  A synchronous rejection above (e.g. -EAGAIN)
+	 * leaves rctx->buf/buf_len untouched so the caller can retry the

drivers/crypto/cmh/cmh_sm3.c line 325

Quoted 10 lines
drivers/crypto/cmh/cmh_sm3.c new file +10 -0
+	 * identical update.
+	 */
+	if (tail_len > 0) {
+		if (req->base.flags & CRYPTO_AHASH_REQ_VIRT)
+			memcpy(rctx->buf, req->svirt + from_src, tail_len);
+		else
+			scatterwalk_map_and_copy(rctx->buf, req->src,
+						 from_src, tail_len, 0);
+	}
+	rctx->buf_len = tail_len;

[Severity: High]
Is there a race condition here that could lead to a use-after-free or state corruption?

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

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

[ ... ]

Quoted 3 lines
drivers/crypto/cmh/cmh_sm3.c new file +3 -0
+static int cmh_sm3_submit_final(struct ahash_request *req,
+				u8 *data_buf, u32 data_len)
+{

[ ... ]

drivers/crypto/cmh/cmh_sm3.c line 278

Quoted 5 lines
drivers/crypto/cmh/cmh_sm3.c new file +5 -0
+	rctx->ckpt_dma = DMA_MAPPING_ERROR;
+	if (rctx->has_checkpoint) {
+		rctx->ckpt_dma = cmh_dma_map_single(rctx->checkpoint,
+						    SM3_CONTEXT_SIZE,
+						     DMA_TO_DEVICE);

[Severity: High]
Similarly, in the finalization stage, can mapping this embedded inline buffer cause DMA API violations or kernel panics on vmap stacks?

[ ... ]

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 546

Quoted 6 lines
drivers/crypto/cmh/cmh_sm3.c new file +6 -0
+	gfp = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ?
+	      GFP_KERNEL : GFP_ATOMIC;
+
+	data_buf = kmalloc(data_len, gfp | __GFP_NOWARN);
+	if (!data_buf)
+		return -ENOMEM;

[Severity: High]
Does this finup path have the same issue with large inputs?

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

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

PATCH v4 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    |  709 ++++++++++++++++++
 drivers/crypto/cmh/cmh_main.c        |   25 +
 drivers/crypto/cmh/include/cmh_aes.h |   24 +
 6 files changed, 2530 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 +709 -0

709 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
#22 lore raw

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

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider: - [High] Aborted or re-initialized `cmac(aes)` ahash requests leak accumulated dynamically allocated chunks…

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] Aborted or re-initialized cmac(aes) ahash requests leak accumulated dynamically allocated chunks until TFM destruction, allowing trivial kernel memory exhaustion (OOM).
- [High] Incorrect IV state update in cmh_aes_update_iv for AES-CFB mode with partial blocks breaks cipher chaining.
- [Medium] The skcipher driver attempts to kmalloc up to 32MB for input/output buffers, deterministically failing for valid large requests.
--

commit 0ec57ce28ce08fa19d032fb79fd5650db5f53a75
Author: Alex Ousherovitch <[email protected]>
Subject: crypto: cmh - add AES skcipher/aead/cmac

This commit registers AES algorithms using the CMH AES core for skcipher, aead, and ahash interfaces. It handles key management, context setup, and VCQ command sequencing for encryption and authentication.

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

[ ... ]

Quoted 7 lines
drivers/crypto/cmh/cmh_aes.c new file +7 -0
+static void cmh_aes_update_iv(struct skcipher_request *req, u32 mode,
+			      u32 op, const u8 *in_buf, const u8 *out_buf)
+{
+	u32 bs = CMH_AES_BLOCK_SIZE;
+	u32 nblocks;
+
+	switch (mode) {

[ ... ]

Quoted 11 lines
drivers/crypto/cmh/cmh_aes.c new file +11 -0
+	case AES_MODE_CFB:
+		/*
+		 * CFB-128 chains on the last ciphertext block.  On encrypt,
+		 * that is out_buf; on decrypt, it is in_buf.
+		 *
+		 * For sub-block requests (cryptlen < 16), there is no
+		 * complete ciphertext block to chain, so the IV is left
+		 * unchanged -- CFB-128 has no defined chaining semantic
+		 * for partial blocks (shift-register CFB-n is a different
+		 * mode).  Without this guard the pointer arithmetic
+		 * underflows and reads before the buffer.

drivers/crypto/cmh/cmh_aes.c line 228

Quoted 10 lines
drivers/crypto/cmh/cmh_aes.c new file +10 -0
+		 */
+		if (req->cryptlen >= bs) {
+			if (op == AES_OP_ENCRYPT)
+				memcpy(req->iv, out_buf + req->cryptlen - bs,
+				       bs);
+			else
+				memcpy(req->iv, in_buf + req->cryptlen - bs,
+				       bs);
+		}
+		break;

[Severity: High]
When dealing with partial blocks in CFB mode where req->cryptlen is not a multiple of the block size, will the offset calculation (req->cryptlen - bs) point to an unaligned offset rather than the last full block boundary? The next operation in a chained CFB stream requires the last full ciphertext block for the chaining IV, so could this break the cipher chaining by copying the wrong bytes?

[ ... ]

Quoted 1 line

+#define CMH_AES_MAX_CRYPTLEN SZ_32M

[ ... ]

Quoted 2 lines
drivers/crypto/cmh/cmh_aes.c new file +2 -0
+static int cmh_aes_crypt(struct skcipher_request *req, u32 aes_op)
+{

[ ... ]

Quoted 2 lines
drivers/crypto/cmh/cmh_aes.c new file +2 -0
+	if (req->cryptlen > CMH_AES_MAX_CRYPTLEN)
+		return -EINVAL;

[ ... ]

drivers/crypto/cmh/cmh_aes.c line 476

Quoted 9 lines
drivers/crypto/cmh/cmh_aes.c new file +9 -0
+	/*
+	 * Linearise input from scatterlist.  cryptlen is user-controlled up
+	 * to CMH_AES_MAX_CRYPTLEN (well above KMALLOC_MAX_SIZE), so use
+	 * __GFP_NOWARN: an oversized request fails cleanly with -ENOMEM
+	 * instead of splatting the page allocator.
+	 */
+	rctx->in_buf = kmalloc(req->cryptlen, gfp | __GFP_NOWARN);
+	if (!rctx->in_buf)
+		return -ENOMEM;

[Severity: Medium]
Does this driver attempt to allocate up to 32MB of physically contiguous memory via kmalloc() for the input and output buffers? While the __GFP_NOWARN flag ensures a clean failure, any valid request larger than KMALLOC_MAX_SIZE (typically 4MB or 8MB) will deterministically fail with -ENOMEM. Would it be better to cap the maximum length to KMALLOC_MAX_SIZE instead of 32MB, or process the buffers in smaller chunks?

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

[ ... ]

drivers/crypto/cmh/cmh_aes_cmac.c line 230

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]
If a user opens an AF_ALG socket, accumulates data by calling crypto_ahash_update(), and then calls crypto_ahash_init() to reset the hash state, won't this memset() clear the rctx->chunks list head and leak the dynamically allocated chunks? The orphaned chunks would remain on tctx->all_chunks indefinitely until the long-lived TFM is destroyed, which could allow unprivileged userspace to easily exhaust kernel memory.

[ ... ]

Quoted 7 lines
drivers/crypto/cmh/cmh_aes_cmac.c new file +7 -0
+static int cmh_aes_cmac_import(struct ahash_request *req, const void *in)
+{
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+	struct cmh_aes_cmac_tfm_ctx *tctx = crypto_ahash_ctx(tfm);
+	struct cmh_aes_cmac_reqctx *rctx = ahash_request_ctx(req);
+	const struct cmh_aes_cmac_export_state *state = in;
+	struct cmh_aes_cmac_chunk *chunk;

drivers/crypto/cmh/cmh_aes_cmac.c line 540

Quoted 10 lines
drivers/crypto/cmh/cmh_aes_cmac.c new file +10 -0
+
+	/*
+	 * Do NOT call free_chunks() here: the crypto API does not
+	 * guarantee the request context is in a valid state before
+	 * import(), so the list pointers may be stale or invalid.
+	 * Re-initialize from scratch instead.  Any pre-existing chunks
+	 * are tracked on tctx->all_chunks and freed in exit_tfm.
+	 */
+	memset(rctx, 0, sizeof(*rctx));
+	INIT_LIST_HEAD(&rctx->chunks);

[Severity: High]
Similarly, if a caller performs a state import over a request that has already accumulated data in its own chunk list, doesn't this memset() also strand any previously allocated chunks?

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

PATCH v4 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     | 935 ++++++++++++++++++++++++++
 drivers/crypto/cmh/cmh_sm4_skcipher.c | 709 +++++++++++++++++++
 drivers/crypto/cmh/include/cmh_sm4.h  |  24 +
 6 files changed, 2581 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 +935 -0

935 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
#24 lore raw

Re: [PATCH v4 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] Unbounded kernel memory leak (OOM DoS) in SM4 MAC algorithms because dynamically allocated chunks…

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Unbounded kernel memory leak (OOM DoS) in SM4 MAC algorithms because dynamically allocated chunks are orphaned during request abortion or reuse, accumulating indefinitely on the TFM. --

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

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

This commit registers SM4 algorithms using the CMH SM4 core. It adds support for various skcipher, aead, and ahash (CMAC and XCBC) operations.

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

[ ... ]

drivers/crypto/cmh/cmh_sm4_cmac.c line 311

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

[Severity: High]
Does this code leak cmh_sm4_mac_chunk structures if a request is reused?

By clearing rctx without freeing pre-existing chunks, it appears those chunks become permanently stranded on the tctx->all_chunks list until the entire TFM is destroyed.

[ ... ]

Quoted 6 lines
drivers/crypto/cmh/cmh_sm4_cmac.c new file +6 -0
+static int cmh_sm4_mac_update(struct ahash_request *req)
+{
+	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);
+	struct cmh_sm4_mac_chunk *chunk;

[ ... ]

drivers/crypto/cmh/cmh_sm4_cmac.c line 360

Quoted 12 lines
drivers/crypto/cmh/cmh_sm4_cmac.c new file +12 -0
+	chunk->len = req->nbytes;
+	if (req->base.flags & CRYPTO_AHASH_REQ_VIRT)
+		memcpy(chunk->data, req->svirt, req->nbytes);
+	else
+		scatterwalk_map_and_copy(chunk->data, req->src,
+					 0, req->nbytes, 0);
+	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);
+	rctx->total_len += req->nbytes;
+	return 0;

[Severity: High]
Can this lead to an unbounded memory leak and subsequent kernel OOM if a user creates an AF_ALG socket, streams data via cmh_sm4_mac_update(), and then closes the socket without calling final?

Since the dynamically allocated chunks are tied to the TFM's lifetime on tctx->all_chunks and the crypto API destroys the request without calling a driver cleanup callback, an unprivileged local user could potentially trigger this accumulation indefinitely, causing a denial of service.

[ ... ]

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 718

Quoted 10 lines
drivers/crypto/cmh/cmh_sm4_cmac.c new file +10 -0
+
+	/*
+	 * Do NOT call free_chunks() here: the crypto API does not
+	 * guarantee the request context is in a valid state before
+	 * import(), so the list pointers may be stale or invalid.
+	 * Re-initialize from scratch instead.  Any pre-existing chunks
+	 * are tracked on tctx->all_chunks and freed in exit_tfm.
+	 */
+	memset(rctx, 0, sizeof(*rctx));
+	INIT_LIST_HEAD(&rctx->chunks);

[Severity: High]
Is it safe to intentionally strand previous chunks here?

Because they are only cleaned up in exit_tfm instead of when the request state is replaced, a rapid sequence of export and import operations on the same request could quickly exhaust kernel memory.

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

PATCH v4 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    | 700 +++++++++++++++++++++++++++
 drivers/crypto/cmh/cmh_main.c        |  25 +
 drivers/crypto/cmh/include/cmh_ccp.h |  24 +
 6 files changed, 1715 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 +700 -0

700 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
#26 lore raw

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

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider: - [High] Unbounded memory leak of dynamically allocated Poly1305 chunks (`struct cmh_poly_chunk`) when an…

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] Unbounded memory leak of dynamically allocated Poly1305 chunks (struct cmh_poly_chunk) when an ahash_request is re-initialized or abandoned, due to missing cleanup.
- [High] The driver linearizes arbitrary-length skcipher and AEAD requests into large contiguous kmalloc buffers (up to 1MB), which is highly prone to allocation failures and violates API contracts.
- [Medium] Mapping an unaligned structure member for DMA violates DMA API constraints and causes cacheline sharing issues.
--

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

This commit registers the ChaCha20-Poly1305 AEAD, ChaCha20 skcipher, and Poly1305 ahash algorithms using the CMH CCP core. It introduces VCQ transaction handling for hardware operations while accumulating data in memory for arbitrary-length poly1305 requests.

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

[ ... ]

Quoted 2 lines
drivers/crypto/cmh/cmh_ccp.c new file +2 -0
+static int cmh_ccp_crypt(struct skcipher_request *req, u32 ccp_op)
+{

[ ... ]

drivers/crypto/cmh/cmh_ccp.c line 207

Quoted 12 lines
drivers/crypto/cmh/cmh_ccp.c new file +12 -0
+	/* Limit linearisation buffers to avoid large allocations. */
+	if (req->cryptlen > SZ_1M)
+		return -EINVAL;
+
+	gfp = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ?
+	      GFP_KERNEL : GFP_ATOMIC;
+
+	memset(rctx, 0, sizeof(*rctx));
+	rctx->cryptlen = req->cryptlen;
+
+	/* Linearise input from scatterlist */
+	rctx->in_buf = kmalloc(req->cryptlen, gfp | __GFP_NOWARN);

[Severity: High]
Does this code linearize the entire payload into a large contiguous buffer? Allocating up to 1MB of contiguous physical memory via kmalloc (especially with GFP_ATOMIC) is extremely prone to failure under memory fragmentation.

Also, returning -EINVAL for requests larger than 1MB breaks the crypto API contract, which expects support for arbitrary payload sizes. Could this cause unpredictable failures for subsystems like IPsec?

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

[ ... ]

Quoted 2 lines
drivers/crypto/cmh/cmh_ccp_aead.c new file +2 -0
+static int cmh_ccp_aead_crypt(struct aead_request *req, u32 ccp_op)
+{

[ ... ]

Quoted 2 lines
drivers/crypto/cmh/cmh_ccp_aead.c new file +2 -0
+	if ((u64)cryptlen + req->assoclen > SZ_1M)
+		return -EINVAL;

[ ... ]

drivers/crypto/cmh/cmh_ccp_aead.c line 323

Quoted 3 lines
drivers/crypto/cmh/cmh_ccp_aead.c new file +3 -0
+	/* Linearise input */
+	if (cryptlen > 0) {
+		rctx->in_buf = kmalloc(cryptlen, gfp | __GFP_NOWARN);

[Severity: High]
Does this AEAD implementation suffer from the same limitation? Using kmalloc for large contiguous buffers (up to 1MB) can easily fail under memory pressure, and rejecting requests larger than this size violates the expected behavior of the crypto API. Can this be reworked to use scatterlists directly or handle chunks iteratively?

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

[ ... ]

Quoted 3 lines
drivers/crypto/cmh/cmh_ccp_poly.c new file +3 -0
+static int cmh_poly_setkey(struct crypto_ahash *tfm, const u8 *key,
+			   unsigned int keylen)
+{

[ ... ]

drivers/crypto/cmh/cmh_ccp_poly.c line 183

Quoted 3 lines
drivers/crypto/cmh/cmh_ccp_poly.c new file +3 -0
+	tctx->skey_dma = cmh_dma_map_single(tctx->key + CCP_POLY_KEY_SIZE,
+					    CCP_POLY_KEY_SIZE,
+					     DMA_TO_DEVICE);

[Severity: Medium]
Are we mapping a structure member that is not cacheline aligned for DMA? Mapping an inner offset of the tctx->key array for DMA violates the DMA API constraints and can cause cacheline sharing issues with surrounding fields (like tctx->chunk_lock) on non-coherent architectures. Should this use a separately allocated buffer instead?

[ ... ]

drivers/crypto/cmh/cmh_ccp_poly.c line 278

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

[Severity: High]
Does this unconditionally overwrite the request context without cleaning up previously allocated chunks?

If a user re-initializes a request (e.g. via crypto_ahash_init), any chunks currently linked to rctx->chunks are abandoned here. Since the crypto framework provides no request destructor, this leads to an unbounded memory leak.

[ ... ]

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

[ ... ]

Quoted 7 lines
drivers/crypto/cmh/cmh_ccp_poly.c new file +7 -0
+	chunk = kmalloc(sizeof(*chunk) + req->nbytes, gfp);
+	if (!chunk) {
+		ret = -ENOMEM;
+		goto err_free_chunks;
+	}
+
+	chunk->len = req->nbytes;

[ ... ]

drivers/crypto/cmh/cmh_ccp_poly.c line 328

Quoted 4 lines
drivers/crypto/cmh/cmh_ccp_poly.c new file +4 -0
+	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: High]
Is this where the leaked chunks are accumulated?

Chunks allocated here are added to both the request list and the global transform list. If the user abandons the request (like closing an AF_ALG socket), the chunks remain permanently orphaned in tctx->all_chunks until the parent transform is destroyed.

[ ... ]

drivers/crypto/cmh/cmh_ccp_poly.c line 554

Quoted 10 lines
drivers/crypto/cmh/cmh_ccp_poly.c new file +10 -0
+static int cmh_poly_import(struct ahash_request *req, const void *in)
+{
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+	struct cmh_poly_tfm_ctx *tctx = crypto_ahash_ctx(tfm);
+	struct cmh_poly_reqctx *rctx = ahash_request_ctx(req);
+	const struct cmh_poly_export_state *state = in;
+	struct cmh_poly_chunk *chunk;
+
+	memset(rctx, 0, sizeof(*rctx));
+	INIT_LIST_HEAD(&rctx->chunks);

[Severity: High]
Does this zeroing of the request context cause the same leak as cmh_poly_init?

Any existing chunks attached to the request before the import will be abandoned and remain orphaned in the global transform list.

[ ... ]

drivers/crypto/cmh/cmh_ccp_poly.c line 628

Quoted 12 lines
drivers/crypto/cmh/cmh_ccp_poly.c new file +12 -0
+static void cmh_poly_exit_tfm(struct crypto_ahash *tfm)
+{
+	struct cmh_poly_tfm_ctx *tctx = crypto_ahash_ctx(tfm);
+	struct cmh_poly_chunk *c, *tmp;
+
+	/* Free any orphaned chunks (e.g. testmgr export/reimport poison) */
+	spin_lock_bh(&tctx->chunk_lock);
+	list_for_each_entry_safe(c, tmp, &tctx->all_chunks, tfm_node) {
+		list_del(&c->tfm_node);
+		kfree_sensitive(c);
+	}
+	spin_unlock_bh(&tctx->chunk_lock);

[Severity: High]
Does this cleanup step confirm the accumulation of orphaned chunks?

The fact that chunks must be freed here during transform destruction verifies that abandoned requests leave their chunks permanently stranded in tctx->all_chunks throughout the lifetime of the transform, providing an easy path for a local denial of service.

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

PATCH v4 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
#28 lore raw

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

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider: - [High] Missing hardware presence check in `cmh_rng_register` causes indefinite spinning if DRBG is…

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] Missing hardware presence check in cmh_rng_register causes indefinite spinning if DRBG is absent.
- [High] Module unload frees in-flight DRBG DMA buffers without stopping the hardware, causing a DMA use-after-free.
- [Medium] Small kmalloc buffer mapped for DMA risks cacheline sharing and memory corruption. --

commit 888e90a741e40c8e3f25d31a12ecb6c6108685b4
Author: Alex Ousherovitch <[email protected]>

crypto: cmh - add DRBG hwrng

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.

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

[ ... ]

Quoted 8 lines
drivers/crypto/cmh/cmh_rng.c new file +8 -0
+static int cmh_rng_read(struct hwrng *rng, void *data, size_t max, bool wait)
+{
+	struct cmh_dma_orphan *orphan;
+	struct vcq_cmd vcq[DRBG_READ_VCQ_CMDS];
+	dma_addr_t dma_addr;
+	void *dmabuf;
+	size_t nbytes;
+	int ret;

[ ... ]

drivers/crypto/cmh/cmh_rng.c line 105

Quoted 13 lines
drivers/crypto/cmh/cmh_rng.c new file +13 -0
+	nbytes = min_t(size_t, max, CMH_DRBG_MAX_GENERATE);
+
+	orphan = kmalloc_obj(*orphan, GFP_KERNEL);
+	if (!orphan)
+		return -ENOMEM;
+
+	dmabuf = kmalloc(nbytes, GFP_KERNEL);
+	if (!dmabuf) {
+		kfree(orphan);
+		return -ENOMEM;
+	}
+
+	dma_addr = cmh_dma_map_single(dmabuf, nbytes, DMA_FROM_DEVICE);

[Severity: Medium]
Since dmabuf is a small allocation (up to 32 bytes) from the generic kmalloc cache, does mapping it for DMA risk cacheline sharing and memory corruption?

On architectures without SWIOTLB bounce-buffering for unaligned kmallocs, this violates DMA API requirements for cacheline alignment and risks adjacent object corruption upon unmap or invalidate.

[ ... ]

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);

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: High]
Does this code introduce a DMA use-after-free during module unload?

If cmh_rng_read() returns 0 on a timeout (-EINPROGRESS), the hardware continues executing and an orphan callback (cmh_dma_orphan_free) is set. During module unload, cmh_tm_cleanup() forcefully completes timed-out transactions to drain the queues, triggering the orphan callback which unmaps and frees the DMA buffer:

drivers/crypto/cmh/cmh_dma.c:cmh_dma_orphan_free() {
    cmh_dma_unmap_single(o->addr, o->len, o->dir);
    kfree_sensitive(o->buf);
}

Because the hardware lacks a stop primitive and is still running, when it finally completes, will it write random bytes into the freed physical memory?

[ ... ]

Quoted 11 lines
drivers/crypto/cmh/cmh_rng.c new file +11 -0
+int cmh_rng_register(struct platform_device *pdev)
+{
+	struct vcq_cmd cfg_vcq[DRBG_CONFIG_VCQ_CMDS];
+	int ret;
+
+	/*
+	 * The hwrng core elevates a zero quality to full trust (1024) for
+	 * a hardware RNG, so cmh_hwrng.quality is left at 0.  Set it in the
+	 * hwrng initializer to lower the entropy estimate if a platform
+	 * requires it.
+	 *

drivers/crypto/cmh/cmh_rng.c line 234

Quoted 10 lines
drivers/crypto/cmh/cmh_rng.c new file +10 -0
+	 * DRBG CONFIG is a management-host operation.  Attempt it: it
+	 * succeeds in stateless mode (any host) or when we are the
+	 * management host.  On -EPERM (not the management host) continue
+	 * without error -- GENERATE works once the management host has
+	 * configured the DRBG.
+	 */
+	vcq_set_header(&cfg_vcq[0], DRBG_CONFIG_VCQ_CMDS);
+	vcq_add_drbg_reset(&cfg_vcq[1]);
+	vcq_add_drbg_config(&cfg_vcq[2], CMH_DRBG_ENTROPY_RATIO,
+			    CMH_DRBG_SECURITY_STRENGTH);

[Severity: High]
Is it intentional to interact with the DRBG hardware here without checking if the DRBG core is actually present?

Other CMH registration functions seem to use cmh_core_present(CMH_CORE_DRBG) to guard against absent hardware. If the DRBG core is not present, commands could time out. The function ignores the -ETIMEDOUT error, warns, and registers the device anyway.

If a local process then reads from /dev/hwrng, cmh_rng_read() will time out and return 0, which could force the hwrng core into an infinite retry loop, causing readers to spin indefinitely.

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

PATCH v4 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
#30 lore raw

PATCH v4 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
#31 lore raw

PATCH v4 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 | 802 ++++++++++++++++++++++++++++++
 3 files changed, 812 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 +802 -0

802 lines not on this page · raw message

Signature · 1 line
2.43.7
#32 lore raw

Re: [PATCH v4 14/19] crypto: cmh - add ECDH/X25519 kpp

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider: - [High] Lack of synchronization in `cmh_ecdh_scratch_free` causes a data race and…

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] Lack of synchronization in cmh_ecdh_scratch_free causes a data race and Use-After-Free/NULL-dereference with active TFMs.
- [High] Async PKE operations directly reference ctx->key.raw.dma without taking a reference, leading to a DMA Use-After-Free if set_secret is called concurrently. --

commit 9c7dc04a32751847394f5938e43b1f3fa2bfd7c8
Author: Alex Ousherovitch <[email protected]>

crypto: cmh - add ECDH/X25519 kpp

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

Quoted 5 lines
drivers/crypto/cmh/cmh_pke_ecdh.c new file +0 -0
new file mode 100644
index 0000000000000..2264fea1facbb

[ ... ]

Quoted 2 lines
drivers/crypto/cmh/cmh_pke_ecdh.c new file +2 -0
+static int cmh_ecdh_generate_public_key(struct kpp_request *req)
+{

[ ... ]

drivers/crypto/cmh/cmh_pke_ecdh.c line 336

Quoted 3 lines
drivers/crypto/cmh/cmh_pke_ecdh.c new file +3 -0
+	vcq_add_sys_write(&vcq[idx], SYS_REF_TEMP, ctx->key.raw.dma,
+			  SYS_REF_NONE, ctx->key.raw.len,
+			  ctx->key.raw.sys_type);

[Severity: High]
Does this code risk a DMA use-after-free if the key is updated concurrently?

This queues an asynchronous hardware command using the transform's key DMA address (ctx->key.raw.dma) as the data source, and then returns -EINPROGRESS. However, the kernel crypto API does not serialize set_secret against in-flight asynchronous operations.

If set_secret is called concurrently, cmh_ecdh_commit_key() delegates to cmh_key_setkey_raw(), which destroys the key:

drivers/crypto/cmh/cmh_key.c:cmh_key_destroy() {
	if (ctx->mode == CMH_KEY_RAW && ctx->raw.data) {
		cmh_dma_unmap_single(ctx->raw.dma, ctx->raw.len,
				     DMA_TO_DEVICE);
		kfree_sensitive(ctx->raw.data);
	...
}

This immediately executes cmh_dma_unmap_single() and kfree_sensitive() on the key material without waiting for pending operations to complete. Could this allow the hardware to read from unmapped or freed memory?

[ ... ]

Quoted 15 lines
drivers/crypto/cmh/cmh_pke_ecdh.c new file +15 -0
+static void cmh_ecdh_scratch_free(void)
+{
+	u32 i;
+
+	if (!cmh_ecdh_key_scratch)
+		return;
+
+	for (i = 0; i < cmh_ecdh_scratch_count; i++) {
+		struct vcq_cmd vcq[3];
+
+		if (!cmh_ecdh_key_scratch[i])
+			continue;
+
+		vcq_set_header(&vcq[0], 3);
+		vcq_add_sys_grant(&vcq[1], cmh_ecdh_key_scratch[i], 0, 0, 0);

drivers/crypto/cmh/cmh_pke_ecdh.c line 667

Quoted 10 lines
drivers/crypto/cmh/cmh_pke_ecdh.c new file +10 -0
+		vcq_add_sys_flush(&vcq[2]);
+		cmh_tm_submit_sync_mbx(vcq, 3, 1, (s32)i);
+		cmh_ecdh_key_scratch[i] = 0;
+	}
+
+	kfree(cmh_ecdh_key_scratch);
+	cmh_ecdh_key_scratch = NULL;
+	cmh_ecdh_scratch_count = 0;
+	cmh_ecdh_scratch_ready = false;
+}

[Severity: High]
Does this cleanup path safely handle active TFMs?

This function frees the cmh_ecdh_key_scratch array without holding the cmh_ecdh_scratch_lock mutex and without waiting for active TFMs to be destroyed.

If the device is unbound (e.g., via sysfs unbind) while a user holds an active AF_ALG socket, the remove path calls cmh_remove() -> cmh_pke_ecdh_unregister() -> cmh_ecdh_scratch_free().

If the user submits a request via the active socket concurrently:

drivers/crypto/cmh/cmh_pke_ecdh.c:cmh_ecdh_compute_shared_secret() {
	...
	if (dd.mbx_idx < 0 || (u32)dd.mbx_idx >= cmh_ecdh_scratch_count ||
	    !cmh_ecdh_key_scratch[dd.mbx_idx]) {
		ret = -EIO;
		goto out_unmap;
	}
	...
}

This locklessly accesses cmh_ecdh_key_scratch, leading to a NULL pointer dereference or reading unmapped memory.

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

PATCH v4 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 | 389 +++++++++++++++++++++++++++++
 drivers/crypto/cmh/cmh_pqc_sizes.c |  39 +++
 drivers/crypto/cmh/cmh_qse.c       | 211 ++++++++++++++++
 5 files changed, 652 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 +389 -0

389 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
#34 lore raw

Re: [PATCH v4 15/19] crypto: cmh - add ML-KEM/ML-DSA (QSE)

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [High] ML-DSA implementation incorrectly rejects 0-length messages, preventing signing and verification…

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] ML-DSA implementation incorrectly rejects 0-length messages, preventing signing and verification of empty messages. --

commit 69ecf7bfc1b6bb507d086ddc8d892b5e6791e35f
Author: Alex Ousherovitch <[email protected]>

crypto: cmh - add ML-KEM/ML-DSA (QSE)

Register ML-KEM (Kyber) and ML-DSA (Dilithium) algorithms using the CMH QSE core (core ID 0x09).

Quoted 6 lines
drivers/crypto/cmh/cmh_pqc_mldsa.c new file +0 -0
new file mode 100644
index 0000000000000..cbaba7d63b437
@@ -0,0 +1,389 @@

[ ... ]

Quoted 4 lines
drivers/crypto/cmh/cmh_pqc_mldsa.c new file +4 -0
+static int cmh_mldsa_sign(struct crypto_sig *tfm,
+			  const void *src, unsigned int slen,
+			  void *dst, unsigned int dlen)
+{

[ ... ]

drivers/crypto/cmh/cmh_pqc_mldsa.c line 76

Quoted 6 lines
drivers/crypto/cmh/cmh_pqc_mldsa.c new file +6 -0
+	if (ctx->key.mode != CMH_KEY_RAW)
+		return -EINVAL;
+	if (dlen < sig_size)
+		return -EINVAL;
+	if (!slen || slen > ML_DSA_MAX_MLEN)
+		return -EINVAL;

[Severity: High]
Does this incorrectly reject valid 0-length messages?

Because this driver overrides the kernel's fallback implementation with a higher priority (5001), system-wide empty message signing operations could unconditionally fail with -EINVAL, violating the FIPS 204 specification.

[ ... ]

Quoted 4 lines
drivers/crypto/cmh/cmh_pqc_mldsa.c new file +4 -0
+static int cmh_mldsa_verify(struct crypto_sig *tfm,
+			    const void *src, unsigned int slen,
+			    const void *digest, unsigned int dlen)
+{

[ ... ]

drivers/crypto/cmh/cmh_pqc_mldsa.c line 160

Quoted 6 lines
drivers/crypto/cmh/cmh_pqc_mldsa.c new file +6 -0
+	if (!ctx->pub_key)
+		return -EINVAL;
+	if (slen != sig_size)
+		return -EINVAL;
+	if (!dlen || dlen > ML_DSA_MAX_MLEN)
+		return -EINVAL;

[Severity: High]
Does this also incorrectly reject valid 0-length messages for verification?

Similar to signing, this could block drop-in compatibility for userspace or kernel components verifying an empty payload.

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

PATCH v4 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 | 383 ++++++++++++++++++++++++++++
 drivers/crypto/cmh/cmh_pqc_xmss.c   | 244 ++++++++++++++++++
 6 files changed, 1213 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 +383 -0

383 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 · 1 line
2.43.7
#36 lore raw

Re: [PATCH v4 16/19] crypto: cmh - add SLH-DSA/LMS/XMSS (HCQ)

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Low] Mixed declarations and code violate strict declaration-after-statement coding style --

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] Mixed declarations and code violate strict declaration-after-statement coding style --

commit 0ef415a044191dc8d92f6871f0f86042ccf5c94f
Author: Alex Ousherovitch <[email protected]>

crypto: cmh - add SLH-DSA/LMS/XMSS (HCQ)

This commit registers SLH-DSA, LMS, LMS-HSS, XMSS, and XMSS-MT algorithms using the CMH HCQ core. SLH-DSA is registered with sign and verify support, while the others are exposed as verify-only algorithms since their stateful semantics are not modeled by the kernel crypto API.

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

[ ... ]

Quoted 4 lines
drivers/crypto/cmh/cmh_pqc_slhdsa.c new file +4 -0
+static int cmh_slhdsa_sign(struct crypto_sig *tfm,
+			   const void *src, unsigned int slen,
+			   void *dst, unsigned int dlen)
+{

[ ... ]

drivers/crypto/cmh/cmh_pqc_slhdsa.c line 96

Quoted 11 lines
drivers/crypto/cmh/cmh_pqc_slhdsa.c new file +11 -0
+	m_dma = cmh_dma_map_single(m_buf, slen, DMA_TO_DEVICE);
+	sig_dma = cmh_dma_map_single(sig_buf, sig_sz, DMA_FROM_DEVICE);
+	if (cmh_dma_map_error(m_dma) || cmh_dma_map_error(sig_dma)) {
+		ret = -ENOMEM;
+		goto out_unmap;
+	}
+
+	sk_dma = DMA_MAPPING_ERROR;
+	idx = 0;
+
+	struct core_dispatch d;

[Severity: Low]
This isn't a bug, but could this variable declaration be moved to the start of the block? The kernel coding style historically expects variables to be declared before executable statements. Mixing declarations and code here can trigger warnings on older toolchains or depending on subsystem Makefile flags.

Quoted 2 lines
drivers/crypto/cmh/cmh_pqc_slhdsa.c new file +2 -0
+
+	d = cmh_core_select_instance(CMH_CORE_HCQ);

[ ... ]

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

PATCH v4 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 3f0ef1e27eb0..83fd74b6f396 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
#38 lore raw

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

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [High] The patch introduces a massive vendor-specific UAPI for standard cryptographic algorithms (RSA…

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] The patch introduces a massive vendor-specific UAPI for standard cryptographic algorithms (RSA, ECDSA, ML-KEM, ML-DSA, etc.) and key management, bypassing the standard Linux kernel Crypto API and Keys subsystems. --

commit 46b4cfa2c3a26b48cc446eeae37ca79f94c3f4db
Author: Alex Ousherovitch <[email protected]>

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

This commit adds documentation for the Rambus CryptoManager Hub (CMH) ioctl interface, covering key management and cryptographic operations. It also registers the 'J' ioctl magic number for the driver.

Quoted 5 lines
Documentation/userspace-api/ioctl/cmh_mgmt.rst new file +0 -0
new file mode 100644
index 0000000000000..c02bac1287874

[ ... ]

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

Quoted 8 lines
Documentation/userspace-api/ioctl/cmh_mgmt.rst new file +8 -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)
+key, identified only by a ``ref`` or CID, whose raw bytes the CPU never
+sees.  The standard crypto API cannot express this -- every

[Severity: High]
Does introducing a bespoke ioctl interface for standard cryptographic algorithms (RSA, ECDSA, ML-KEM, ML-DSA, etc.) fracture the kernel UAPI ecosystem?

Instead of integrating hardware-bound keys into the existing Key Retention Service and Crypto API/AF_ALG, which allows user-space tools to transparently support new hardware, this locks the kernel into maintaining an immutable, vendor-specific ABI forever.

Is it possible to integrate these operations using existing core kernel abstractions rather than creating a massive vendor-specific UAPI?

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

PATCH v4 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 8d4db2241cc2..fe0b3a5b9769 100644
@@ -17,6 +17,7 @@ TARGETS += damon
 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
#40 lore raw

PATCH v4 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 d1dbf2f07104..4af6412323e5 100644
@@ -22489,6 +22489,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