Bug 2511484

Summary: CVE-2026-71226 libkcapi: Memory corruption via uncanceled AIO requests on error in libkcapi's one-shot AIO path [fedora-all]
Product: [Fedora] Fedora Reporter: Vladimir Vasilev <vvasilev>
Component: libkcapiAssignee: Ondrej Mosnáček <omosnacek>
Status: CLOSED ERRATA QA Contact: Fedora Extras Quality Assurance <extras-qa>
Severity: medium Docs Contact:
Priority: medium    
Version: 45CC: besser82, crypto-team, omosnacek, shebburn
Target Milestone: ---Keywords: Security, SecurityTracking
Target Release: ---Flags: fedora-admin-xmlrpc: mirror+
Hardware: Unspecified   
OS: Unspecified   
Whiteboard: {"flaws": ["a41e9ad2-0d7c-47ef-b776-466879e4d1ee"]}
Fixed In Version: libkcapi-1.5.1-2.fc45 libkcapi-1.5.1-2.fc46 Doc Type: ---
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2026-08-20 17:35:28 UTC Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Bug Depends On:    
Bug Blocks: 2462114    

Description Vladimir Vasilev 2026-08-05 12:24:41 UTC
Disclaimer: Community trackers are created by Red Hat Product Security team on a best effort basis. Package maintainers are required to ascertain if the flaw indeed affects their package, before starting the update process.

AI_ONLY_REPORT
package: libkcapi-1.5.0-3.el10
------
Summary: Memory Corruption via Uncanceled AIO Requests on Error: libkcapi's  
one-shot AIO path can return an error before all submitted IOCBs are  
drained, allowing later kernel writes into caller-owned output buffers.
Requirements to exploit: A consumer must use the one-shot AIO interfaces  
with `KCAPI_INIT_AIO` so the real AIO backend is active, hit an error after  
one or more IOCBs have been submitted or completed, and then free or reuse  
the referenced `outiov` buffers before all kernel completions finish.
Component affected: `libkcapi-1.5.0-3.el10`, `lib/kcapi-kernel-if.c`,  
`_kcapi_aio_read_all()`, `_kcapi_aio_read_iov()`,  
`_kcapi_cipher_crypt_aio()` in the one-shot AIO path
Version affected: `libkcapi-1.5.0-3.el10` when the handle is initialized  
with `KCAPI_INIT_AIO` and libkcapi enables its real kernel AIO backend
Patch available: no released package fix established; proposed patch  
included below
Version fixed: unknown
Upstream coordination: Unknown.
CVSS: CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:H - 6.8 (MEDIUM)
AV:L - exploitation is local to the process using libkcapi.
AC:L - once the real AIO path is active, the unsafe behavior is reached  
directly through documented error paths after request submission.
PR:N - no elevated privileges are required beyond the ability to  
exercise the affected API in the local process.
UI:N - no separate user interaction is required.
S:U - the impact stays within the security scope of the calling process.
C:L - late writes into reused buffers can expose limited process data.
I:L - late kernel writes can alter caller memory after the library has  
reported failure.
A:H - heap corruption or process termination is a realistic outcome.
Impact: Moderate. This flaw can cause real process memory corruption, but  
it depends on an opt-in AIO configuration, kernel AIO availability, and an  
error path after submission rather than a default or easily reachable  
execution path. Under Red Hat's severity guidance, that is more consistent  
with Moderate impact than Important or Critical.
Embargo: no
Reason: the issue is local and configuration-dependent, requires  
explicit AIO use plus an error-path trigger, and does not present a  
straightforward remote compromise scenario.
Acknowledgement: Aisle Research
Vulnerability Details: In the affected one-shot AIO path, libkcapi can  
return failure before all submitted kernel requests are drained.  
`_kcapi_aio_read_all()` returns immediately on the first negative  
completion result, and `_kcapi_aio_read_iov()` returns immediately on a  
short `io_submit()` result even if some IOCBs were already submitted.  
`_kcapi_cipher_crypt_aio()` then propagates that error directly to the  
caller. If the caller treats the operation as failed and promptly frees or  
reuses `outiov[*].iov_base`, later kernel completions may still write into  
those buffers.
```c
if (events[i].res < 0) {
handle->aio.iocb_ret[events[i].data] =
events[i].res;
return (int)events[i].res;
}
...
ret = io_submit(handle->aio.aio_ctx, (long)iovlen, handle->aio.ciopp);
if ((uint32_t)ret != iovlen) {
if (ret < 0) {
ret = -errno;
kcapi_dolog(KCAPI_LOG_ERR, "io_read Error: %d\n", ret);
return ret;
} else {
kcapi_dolog(KCAPI_LOG_ERR,
"Could not sumbit AIO read\n");
return -EIO;
}
}
```
```c
ret = _kcapi_aio_read_iov(handle, outiov, process);
if (ret < 0)
return ret;
```
The issue is not established for the default synchronous path. Reachability  
depends on the caller enabling `KCAPI_INIT_AIO` so libkcapi uses the real  
kernel AIO backend.
Steps to reproduce:
1. Build an ASAN-enabled harness that calls `kcapi_cipher_encrypt_aio()` or  
`kcapi_aead_decrypt_aio()` with multiple output `iovec` entries.
2. Initialize the handle with `KCAPI_INIT_AIO` so the real AIO path is  
active.
3. Force a deterministic short-submit path with an `LD_PRELOAD` wrapper  
around `syscall(__NR_io_submit, ...)` that returns `0 < ret < iovlen` after  
forwarding only the first `N` IOCBs.
4. Optionally fault-inject `io_getevents()` so one returned event has `res  
< 0` before all completions are consumed.
5. When the API returns an error, immediately free or reallocate the  
`outiov[*].iov_base` buffers.
6. Observe delayed writes into freed or reused memory, for example as an  
ASAN use-after-free, heap corruption, or a canary mismatch.
Mitigation: Until a fix is available, avoid initializing affected handles  
with `KCAPI_INIT_AIO` and prefer the synchronous interfaces. If the real  
AIO path must remain enabled, applications should not immediately free or  
reuse `outiov` buffers after an error return.
Proposed Fix: Drain all submitted requests before returning an error. A  
minimal approach is to record the first completion error, continue draining  
outstanding completions, and drain any successfully submitted subset after  
a short `io_submit()` result.
```diff
diff --git a/lib/kcapi-kernel-if.c b/lib/kcapi-kernel-if.c
— a/lib/kcapi-kernel-if.c
+++ b/lib/kcapi-kernel-if.c
@@ -420,6 +420,7 @@ int _kcapi_aio_read_all(struct kcapi_handle *handle,  
size_t toread,
struct timespec *timeout)
{
+	int first_err = 0;
if (toread > KCAPI_AIO_CONCURRENT)
return -EINVAL;
@@ -440,8 +441,10 @@ int _kcapi_aio_read_all(struct kcapi_handle *handle,  
size_t toread,
if (events[i].res < 0) {
handle->aio.iocb_ret[events[i].data] =
events[i].res;
-				return (int)events[i].res;
+				if (!first_err)
+					first_err = (int)events[i].res;
+				continue;
}
@@ -467,7 +470,7 @@ int _kcapi_aio_read_all(struct kcapi_handle *handle,  
size_t toread,
toread -= (uint32_t)rc;
}
-	return 0;
+	return first_err;
}
@@ -534,15 +537,20 @@ int _kcapi_aio_read_iov(struct kcapi_handle *handle,
ret = io_submit(handle->aio.aio_ctx, (long)iovlen, handle->aio.ciopp);
if ((uint32_t)ret != iovlen) {
+		size_t submitted = (ret > 0) ? (size_t)ret : 0;
+		int submit_err = (ret < 0) ? -errno : -EIO;
if (ret < 0) {
-			ret = -errno;
kcapi_dolog(KCAPI_LOG_ERR, "io_read Error: %d\n", ret);
-			return ret;
} else {
kcapi_dolog(KCAPI_LOG_ERR,
"Could not sumbit AIO read\n");
-			return -EIO;
}
+		if (submitted) {
+			int drain = _kcapi_aio_read_all(handle, submitted, NULL);
+			if (submit_err == 0 && drain < 0)
+				submit_err = drain;
+		}
+		return submit_err;
}
```
(Equivalent fix using `io_cancel` + confirmed drain is also acceptable.)
------
This report was generated using AI technology. Always review AI-generated  
content prior to use

Comment 1 Aoife Moloney 2026-08-17 15:46:45 UTC
This bug appears to have been reported against 'rawhide' during the Fedora Linux 45 development cycle.
Changing version to 45.

Comment 2 Fedora Update System 2026-08-18 18:53:18 UTC
FEDORA-2026-4ba4b4f139 (libkcapi-1.5.1-1.fc45) has been submitted as an update to Fedora 45.
https://bodhi.fedoraproject.org/updates/FEDORA-2026-4ba4b4f139

Comment 3 Fedora Update System 2026-08-18 18:54:35 UTC
FEDORA-2026-6a1526575a (libkcapi-1.5.1-1.fc46) has been submitted as an update to Fedora 46.
https://bodhi.fedoraproject.org/updates/FEDORA-2026-6a1526575a

Comment 4 Fedora Update System 2026-08-20 13:05:02 UTC
FEDORA-2026-1a1eac3dfb (libkcapi-1.5.1-2.fc45) has been submitted as an update to Fedora 45.
https://bodhi.fedoraproject.org/updates/FEDORA-2026-1a1eac3dfb

Comment 5 Fedora Update System 2026-08-20 13:06:00 UTC
FEDORA-2026-e3ee465ab3 (libkcapi-1.5.1-2.fc46) has been submitted as an update to Fedora 46.
https://bodhi.fedoraproject.org/updates/FEDORA-2026-e3ee465ab3

Comment 6 Fedora Update System 2026-08-20 17:35:28 UTC
FEDORA-2026-1a1eac3dfb (libkcapi-1.5.1-2.fc45) has been pushed to the Fedora 45 stable repository.
If problem still persists, please make note of it in this bug report.

Comment 7 Fedora Update System 2026-08-21 03:05:48 UTC
FEDORA-2026-e3ee465ab3 (libkcapi-1.5.1-2.fc46) has been pushed to the Fedora 46 stable repository.
If problem still persists, please make note of it in this bug report.