Bug 2462011 (CVE-2026-71225) - CVE-2026-71225 libkcapi: IV reuse in libkcapi one-shot symmetric cipher chunking causes cipher state reset across chunk boundaries
Summary: CVE-2026-71225 libkcapi: IV reuse in libkcapi one-shot symmetric cipher chunk...
Keywords:
Status: NEW
Alias: CVE-2026-71225
Product: Security Response
Classification: Other
Component: vulnerability
Version: unspecified
Hardware: All
OS: Linux
medium
medium
Target Milestone: ---
Assignee: Product Security DevOps Team
QA Contact:
URL:
Whiteboard:
Depends On: 2511445
Blocks:
TreeView+ depends on / blocked
 
Reported: 2026-04-26 18:00 UTC by OSIDB Bzimport
Modified: 2026-08-31 13:34 UTC (History)
18 users (show)

Fixed In Version:
Clone Of:
Environment:
Last Closed:
Embargoed:


Attachments (Terms of Use)

Description OSIDB Bzimport 2026-04-26 18:00:55 UTC
AI_ONLY_REPORT
package: libkcapi-1.5.0-3.el10
------
Summary: IV Reuse in Symmetric Cipher Chunking: large one-shot symmetric  
cipher operations can resend the original IV for each internal chunk,  
restarting cipher state and breaking expected continuous-message behavior.
Requirements to exploit: An attacker must be able to make an application  
using `libkcapi-1.5.0-3.el10` call the one-shot symmetric cipher APIs on  
data larger than `sysconf(_SC_PAGESIZE) * ALG_MAX_PAGES` (typically 64 KiB)  
in an affected stateful mode such as `ctr` or `cbc`, and observe the  
resulting ciphertext or decryption behavior. Reachability depends on the  
consuming application; the available evidence does not establish that every  
deployment exposes this path.
Component affected: `libkcapi-1.5.0-3.el10`, `lib/kcapi-sym.c`,  
`lib/kcapi-kernel-if.c`, one-shot symmetric cipher path  
(`kcapi_cipher_encrypt`, `kcapi_cipher_decrypt`,  
`_kcapi_cipher_crypt_chunk`, `_kcapi_common_send_meta`)
Version affected: `libkcapi-1.5.0-3.el10`
Patch available: no released package fix established; proposed patch  
included below
Version fixed: unknown
Upstream coordination: Not notified.
CVSS: CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:L/A:N - 6.8 (MEDIUM)
AV:N - In the worst-case deployment, a remote caller can trigger the  
affected one-shot API through a network-facing application that uses this  
library for large-buffer encryption or decryption.
AC:H - Exploitation depends on specific application behavior: the  
one-shot path must be used, the input must cross the internal chunk  
threshold, and the mode must be one whose security depends on continuous  
IV/chaining state.
PR:N - No privileges are inherent to the flaw itself.
UI:N - No user interaction is required once the application processes  
the crafted large input.
S:U - The impact remains within the vulnerable cryptographic operation  
and does not cross a separate security boundary.
C:H - For `ctr`, restarting the keystream at chunk boundaries can  
expose plaintext relationships and materially weaken confidentiality.
I:L - Resetting state across chunk boundaries can cause applications to  
process data with different cryptographic semantics than a continuous  
message, which can affect integrity expectations in some uses.
A:N - No direct availability impact is established from the available  
evidence.
Impact: Moderate. Based on Red Hat severity guidance, this flaw can cause a  
meaningful confidentiality loss or cryptographic semantic break in  
applications that use the affected large-buffer one-shot path, but  
exploitation depends on specific API usage patterns and affected modes  
rather than presenting an easily exploitable default remote compromise path  
in this SRPM package.
Embargo: no
Reason: The currently supported impact is use-dependent, practical  
mitigations exist, and the available evidence does not show an easily  
weaponized default exposure that would normally justify embargo handling.
Acknowledgement: Aisle Research
Vulnerability Details: The one-shot symmetric cipher entry points store the  
caller-provided IV once and then pass the request into  
`_kcapi_cipher_crypt_chunk()`. For inputs larger than `handle->pagesize *  
ALG_MAX_PAGES`, `_kcapi_cipher_crypt_chunk()` splits the request into  
multiple chunks and calls `_kcapi_cipher_crypt()` for each chunk. Each  
`_kcapi_cipher_crypt()` call sends fresh operation metadata, and  
`_kcapi_common_send_meta()` copies `handle->cipher.iv` into `ALG_SET_IV`  
every time. No IV advancement is visible between chunks, so each chunk is  
processed as a new operation with the same IV instead of as a continuation  
of one message.
```c
handle->cipher.iv = iv;
return _kcapi_cipher_crypt_chunk(handle, in, inlen, out, outlen, access,  
ALG_OP_ENCRYPT /* or DECRYPT */);
```
```c
while (inlen && outlen) {
...
ret = _kcapi_cipher_crypt(handle, in, inprocess, out, outprocess,  
access, enc);
...
}
```
```c
if (handle->cipher.iv) {
...
memcpy(alg_iv->iv, handle->cipher.iv, tfm->info.ivsize);
}
```
For `ctr`, this restarts the keystream at each chunk boundary and can  
expose plaintext relationships across chunks. For `cbc`, the chaining  
value is reset at each boundary, so large one-shot processing no longer  
matches the behavior of one continuous CBC message. Based on the available  
evidence, this report is limited to the one-shot symmetric cipher path  
described above.
Steps to reproduce:
1. Initialize a `ctr(aes)` handle and set the key.
2. Prepare `131072` bytes of plaintext, with block `0` identical to the  
block at offset `65536`.
3. Encrypt the buffer with the one-shot API `kcapi_cipher_encrypt()` using  
a fixed IV.
4. Encrypt the same plaintext as one continuous message using  
`kcapi_cipher_stream_init_enc()`, repeated `kcapi_cipher_stream_update()`,  
`kcapi_cipher_stream_update_last()`, and `kcapi_cipher_stream_op()`.
5. Compare the outputs. The observed condition is `out_oneshot !=  
out_stream`, even though both operations are intended to represent the same  
continuous-message semantics.
6. For `ctr(aes)`, verify that `out_oneshot[0:16] ==  
out_oneshot[65536:65552]` when the corresponding plaintext blocks are  
equal. This indicates keystream restart at the chunk boundary.
7. Repeat with `cbc(aes)` and observe a mismatch versus the  
continuous-stream result at the chunk boundary.
Mitigation: Until a fix is available, avoid using the one-shot symmetric  
cipher APIs for inputs larger than `sysconf(_SC_PAGESIZE) * ALG_MAX_PAGES`  
when continuous-message semantics matter. Prefer the streaming interface  
for long messages, or keep one-shot inputs below the internal chunking  
threshold so the IV is applied only once per operation.
Proposed Fix: Send operation metadata and IV only for the first internal  
chunk, then keep the AF_ALG operation open and send only data for  
subsequent chunks so cipher state is preserved across the full message.
```diff
diff --git a/lib/kcapi-kernel-if.c b/lib/kcapi-kernel-if.c
@@
ssize_t _kcapi_cipher_crypt_chunk(struct kcapi_handle *handle,
const uint8_t *in, size_t inlen,
uint8_t *out, size_t outlen,
int access, unsigned int enc)
{
+    bool first = true;
ssize_t totallen = 0;
@@
while (inlen && outlen) {
size_t inprocess = inlen;
size_t outprocess = outlen;
+        bool last;
+        struct iovec iov;
@@
if (inlen > maxprocess)
inprocess = maxprocess;
if (outlen > maxprocess)
outprocess = maxprocess;
+        last = (inlen <= maxprocess);
       ret = _kcapi_cipher_crypt(handle, in, inprocess, out, outprocess,  
access, enc);
+        if (first) {
+            if ((access == KCAPI_ACCESS_HEURISTIC && inprocess <= (1<<13))  
||
+                access == KCAPI_ACCESS_SENDMSG) {
+                iov.iov_base = (void *)(uintptr_t)in;
+                iov.iov_len = inprocess;
+                ret = _kcapi_common_send_meta(handle, &iov, 1, enc, last ?  
0 : MSG_MORE);
+            } else {
+                ret = _kcapi_common_send_meta(handle, NULL, 0, enc,  
MSG_MORE);
+                if (ret >= 0)
+                    ret = _kcapi_common_vmsplice_chunk(handle, in,  
inprocess,
+                                                       last ? 0 :  
SPLICE_F_MORE);
+            }
+            first = false;
+        } else {
+            if ((access == KCAPI_ACCESS_HEURISTIC && inprocess <= (1<<13))  
||
+                access == KCAPI_ACCESS_SENDMSG) {
+                iov.iov_base = (void *)(uintptr_t)in;
+                iov.iov_len = inprocess;
+                ret = _kcapi_common_send_data(handle, &iov, 1, last ? 0 :  
MSG_MORE);
+            } else {
+                ret = _kcapi_common_vmsplice_chunk(handle, in, inprocess,
+                                                   last ? 0 :  
SPLICE_F_MORE);
+            }
+        }
          if (ret < 0)
              return ret;
+        ret = _kcapi_common_read_data(handle, out, outprocess);
+        if (ret < 0)
+            return ret;
@@
      }
      return totallen;
  }
```


------
This report was generated using AI technology. Always review AI-generated  
content prior to use


Note You need to log in before you can comment on or make changes to this bug.