new file mode 100644
@@ -0,0 +1,604 @@
+From 73a34808912e3cfea8d88f0a2c08fc0ed107a9d8 Mon Sep 17 00:00:00 2001
+From: Markus Theil <markus.theil@secunet.com>
+Date: Fri, 3 Apr 2026 15:06:53 +0200
+Subject: [PATCH] fixes found by analysis with LLM
+
+Signed-off-by: Markus Theil <markus.theil@secunet.com>
+Signed-off-by: Stephan Mueller <smueller@chronox.de>
+(cherry picked from commit e8396c28c2cd2b81f69fc68500fcb2ec7163b4fd)
+
+CVE: CVE-2026-71226
+Upstream-Status: Backport [https://github.com/smuellerDD/libkcapi/commit/e8396c28c2cd2b81f69fc68500fcb2ec7163b4fd]
+Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
+---
+ apps/app-internal.c | 15 +++++++++---
+ apps/kcapi-dgst.c | 11 ++++++---
+ apps/kcapi-enc.c | 9 ++++---
+ apps/kcapi-hasher.c | 12 ++++++---
+ apps/kcapi-rng.c | 24 ++++++++++++------
+ configure.ac | 3 ++-
+ lib/kcapi-aead.c | 12 +++++++--
+ lib/kcapi-kdf.c | 6 +++--
+ lib/kcapi-kernel-if.c | 57 +++++++++++++++++++++++++++++--------------
+ lib/kcapi-kpp.c | 4 +--
+ lib/kcapi-md.c | 2 +-
+ lib/kcapi-sym.c | 6 +++++
+ lib/kcapi-utils.c | 7 ++++--
+ 13 files changed, 118 insertions(+), 50 deletions(-)
+
+diff --git a/apps/app-internal.c b/apps/app-internal.c
+index 7e01dd7..724b0b1 100644
+--- a/apps/app-internal.c
++++ b/apps/app-internal.c
+@@ -173,18 +173,24 @@ static uint8_t bin_char(char hex)
+ void hex2bin(const char *hex, uint32_t hexlen, uint8_t *bin, uint32_t binlen)
+ {
+ uint32_t i;
+- uint32_t chars = (binlen > (hexlen / 2)) ? (hexlen / 2) : binlen;
++ uint32_t chars;
+
+ /*
+ * handle odd-length of strings where the first digit is the least
+ * significant nibble
+ */
+ if (hexlen & 1) {
++ if (!binlen)
++ return;
+ bin[0] = bin_char(hex[0]);
+ bin++;
+ hex++;
++ hexlen--;
++ binlen--;
+ }
+
++ chars = (binlen > (hexlen / 2)) ? (hexlen / 2) : binlen;
++
+ for (i = 0; i < chars; i++) {
+ bin[i] = (uint8_t)(bin_char(hex[(i*2)]) << 4);
+ bin[i] |= bin_char(hex[((i*2)+1)]);
+@@ -238,13 +244,14 @@ ssize_t read_complete(int fd, uint8_t *buf, size_t buflen)
+ if (0 < ret) {
+ buflen -= (size_t)ret;
+ buf += ret;
++ rc += ret;
+ }
+- rc += ret;
+- if (ret)
+- break;
+ } while ((0 < ret || EINTR == errno || ERESTART == errno)
+ && buflen > 0);
+
++ if (ret < 0)
++ return -errno;
++
+ return rc;
+ }
+
+diff --git a/apps/kcapi-dgst.c b/apps/kcapi-dgst.c
+index 591a7fb..42d099c 100644
+--- a/apps/kcapi-dgst.c
++++ b/apps/kcapi-dgst.c
+@@ -128,6 +128,11 @@ static int cipher_op(struct kcapi_handle *handle, struct opt_data *opts)
+ }
+
+ outlen = kcapi_md_digestsize(handle);
++ if (!outlen) {
++ dolog(KCAPI_LOG_ERR, "Cipher has zero digest size");
++ ret = -EINVAL;
++ goto out;
++ }
+
+ if (opts->hexout)
+ outlen *= 2;
+@@ -285,8 +290,8 @@ static int set_key(struct kcapi_handle *handle, struct opt_data *opts)
+ }
+
+ while (j < saltbuflen) {
+- ret = kcapi_rng_generate(rng, saltbuf,
+- (size_t)saltbuflen);
++ ret = kcapi_rng_generate(rng, saltbuf + j,
++ (size_t)(saltbuflen - j));
+ if (ret < 0) {
+ kcapi_rng_destroy(rng);
+ free(saltbuf);
+@@ -320,7 +325,7 @@ static int set_key(struct kcapi_handle *handle, struct opt_data *opts)
+ if (opts->key_fd != -1) {
+ ret = read_complete(opts->key_fd, keybuf, sizeof(keybuf));
+ if (ret < 0)
+- return (int)ret;
++ goto out;
+
+ have_key = 1;
+ keybuflen = (uint32_t)ret;
+diff --git a/apps/kcapi-enc.c b/apps/kcapi-enc.c
+index 68cf2f7..e7aa9db 100644
+--- a/apps/kcapi-enc.c
++++ b/apps/kcapi-enc.c
+@@ -218,7 +218,7 @@ static ssize_t return_data_fd(struct kcapi_handle *handle,
+ }
+
+ out:
+- munmap(outmem, outsize);
++ munmap(outmem, outsize + offset);
+ return (ret < 0) ? ret : generated_bytes;
+ }
+
+@@ -609,7 +609,7 @@ static int cipher_op(struct kcapi_handle *handle, struct opt_data *opts)
+ }
+
+ /* Get data from file. */
+- } else {
++ } else if (insb.st_size) {
+ uint32_t sent_data = 0;
+
+ inmem = mmap(NULL, (size_t)insb.st_size, PROT_READ, MAP_SHARED,
+@@ -636,6 +636,7 @@ static int cipher_op(struct kcapi_handle *handle, struct opt_data *opts)
+ * we will not apply padding.
+ */
+ if (!opts->decrypt &&
++ insb.st_size >= 2 &&
+ !(insb.st_size % opts->func_blocksize(handle)) &&
+ (uint32_t)padbyte < opts->func_blocksize(handle)) {
+ uint32_t i;
+@@ -803,8 +804,8 @@ static int set_key(struct kcapi_handle *handle, struct opt_data *opts)
+ }
+
+ while (j < saltbuflen) {
+- ret = kcapi_rng_generate(rng, saltbuf,
+- saltbuflen);
++ ret = kcapi_rng_generate(rng, saltbuf + j,
++ saltbuflen - j);
+ if (ret < 0) {
+ kcapi_rng_destroy(rng);
+ free(saltbuf);
+diff --git a/apps/kcapi-hasher.c b/apps/kcapi-hasher.c
+index 217f59d..90dc34d 100644
+--- a/apps/kcapi-hasher.c
++++ b/apps/kcapi-hasher.c
+@@ -271,7 +271,7 @@ static int load_file(const char *filename, uint8_t **memory, off_t *size)
+ fprintf(stderr, "Key longer than UINT32_MAX\n");
+ ret = -ERANGE;
+ goto out;
+- } else if (buffer_size * 2 < buffer_size)
++ } else if (buffer_size > UINT32_MAX / 2)
+ buffer_size = UINT32_MAX;
+ else
+ buffer_size *= 2;
+@@ -340,7 +340,7 @@ static int hasher(struct kcapi_handle *handle, const struct hash_params *params,
+ } while (left);
+ munmap(memblock, mapped);
+ offset = offset + (off_t)mapped;
+- } while (offset ^ size);
++ } while (offset != size);
+ } else {
+ uint8_t tmpbuf[TMPBUFLEN] __aligned(KCAPI_APP_ALIGN);
+ uint32_t bufsize;
+@@ -647,11 +647,17 @@ static int process_checkfile(const struct hash_params *params,
+ hexhash = buf;
+
+ if (bsd_style) {
++ if (bsd_style > linelen) {
++ fprintf(stderr, "Invalid checkfile format\n");
++ ret = 1;
++ goto out;
++ }
++
+ /* Hash starts after separator */
+ hexhashlen = linelen - bsd_style + 1;
+
+ /* remove closing parenthesis behind filename */
+- if (buf[(bsd_style - 4)] == ')')
++ if (bsd_style >= 4 && buf[(bsd_style - 4)] == ')')
+ buf[(bsd_style - 4)] = '\0';
+ }
+
+diff --git a/apps/kcapi-rng.c b/apps/kcapi-rng.c
+index 9e025cd..46dab02 100644
+--- a/apps/kcapi-rng.c
++++ b/apps/kcapi-rng.c
+@@ -282,16 +282,18 @@ int main(int argc, char *argv[])
+ seedsize);
+
+ if (!isatty(0) && (errno == EINVAL || errno == ENOTTY)) {
+- while (fgets((char *)seedbuf, (int)seedsize, stdin)) {
+- ret = kcapi_rng_seed(rng, seedbuf, seedsize);
++ ssize_t rret;
++
++ while ((rret = read(STDIN_FILENO, seedbuf, seedsize)) > 0) {
++ ret = kcapi_rng_seed(rng, seedbuf, (uint32_t)rret);
+ if (ret)
+ dolog(KCAPI_LOG_WARN,
+- "User-provided seed of %lu bytes not accepted by DRNG (error: %ld)",
+- (unsigned long)sizeof(buf), ret);
++ "User-provided seed of %zd bytes not accepted by DRNG (error: %ld)",
++ rret, ret);
+ else
+ dolog(KCAPI_LOG_DEBUG,
+- "User-provided seed of %u bytes",
+- seedsize);
++ "User-provided seed of %zd bytes",
++ rret);
+ }
+ }
+
+@@ -312,9 +314,15 @@ int main(int argc, char *argv[])
+ char hexbuf[2 * KCAPI_RNG_BUFSIZE];
+
+ bin2hex(buf, (size_t)ret, hexbuf, sizeof(hexbuf), 0);
+- fwrite(hexbuf, 2 * (size_t)ret, 1, stdout);
++ if (fwrite(hexbuf, 2 * (size_t)ret, 1, stdout) != 1) {
++ ret = -EIO;
++ goto out;
++ }
+ } else {
+- fwrite(buf, (size_t)ret, 1, stdout);
++ if (fwrite(buf, (size_t)ret, 1, stdout) != 1) {
++ ret = -EIO;
++ goto out;
++ }
+ }
+
+ outlen -= (size_t)ret;
+diff --git a/configure.ac b/configure.ac
+index fbae4f9..446b8a8 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -14,16 +14,17 @@ m4_define([__KCAPI_MINVERSION], [5])
+ m4_define([__KCAPI_PATCHLEVEL], [0])
+ m4_define([KCAPI_VERSION], [__KCAPI_MAJVERSION.__KCAPI_MINVERSION.__KCAPI_PATCHLEVEL])
+
++AC_PREREQ([2.69])
+ AC_INIT([libkcapi], [KCAPI_VERSION])
+ AC_DEFINE([KCAPI_MAJVERSION], [__KCAPI_MAJVERSION])
+ AC_DEFINE([KCAPI_MINVERSION], [__KCAPI_MINVERSION])
+ AC_DEFINE([KCAPI_PATCHLEVEL], [__KCAPI_PATCHLEVEL])
++AC_CONFIG_MACRO_DIRS([m4])
+ AM_INIT_AUTOMAKE([foreign])
+ LT_INIT([pic-only])
+ AC_SUBST([LIBTOOL_DEPS])
+ AC_PROG_CC
+ AC_CONFIG_FILES([Makefile])
+-AC_CONFIG_MACRO_DIR([m4])
+ AX_PROG_CC_FOR_BUILD
+ AX_CHECK_PIE
+
+diff --git a/lib/kcapi-aead.c b/lib/kcapi-aead.c
+index b52dda0..3a7d711 100644
+--- a/lib/kcapi-aead.c
++++ b/lib/kcapi-aead.c
+@@ -566,7 +566,11 @@ size_t impl_aead_outbuflen_enc(struct kcapi_handle *handle,
+ {
+ struct kcapi_handle_tfm *tfm = handle->tfm;
+ uint32_t bs = tfm->info.blocksize;
+- size_t outlen = (inlen + bs - 1) / bs * bs + taglen + assoclen;
++ size_t outlen;
++
++ if (!bs)
++ return 0;
++ outlen = (inlen + bs - 1) / bs * bs + taglen + assoclen;
+
+ /* the kernel does not like zero length output buffers */
+ if (!outlen)
+@@ -591,7 +595,11 @@ size_t impl_aead_outbuflen_dec(struct kcapi_handle *handle,
+ {
+ struct kcapi_handle_tfm *tfm = handle->tfm;
+ uint32_t bs = tfm->info.blocksize;
+- size_t outlen = (inlen + bs - 1) / bs * bs + assoclen;
++ size_t outlen;
++
++ if (!bs)
++ return 0;
++ outlen = (inlen + bs - 1) / bs * bs + assoclen;
+
+ if (!handle->flags.ge_v4_9 == true)
+ outlen += taglen;
+diff --git a/lib/kcapi-kdf.c b/lib/kcapi-kdf.c
+index 54dc1ec..5f389b6 100644
+--- a/lib/kcapi-kdf.c
++++ b/lib/kcapi-kdf.c
+@@ -54,6 +54,8 @@
+ #include "kcapi.h"
+ #include "internal.h"
+
++#define MAX_DIGESTSIZE 64
++
+ #ifndef __has_builtin
+ # define __has_builtin(x) 0
+ #endif
+@@ -101,7 +103,7 @@ ssize_t impl_kdf_dpi(struct kcapi_handle *handle,
+ ssize_t err = 0;
+ uint8_t *dst_orig = dst;
+ size_t dlen_orig = dlen;
+- uint8_t Ai[h];
++ uint8_t Ai[MAX_DIGESTSIZE];
+ uint32_t i = 1;
+
+ if (dlen > INT_MAX)
+@@ -448,7 +450,7 @@ static inline uint64_t kcapi_get_time(void)
+ {
+ struct timespec time;
+
+- if (clock_gettime(CLOCK_REALTIME, &time) == 0)
++ if (clock_gettime(CLOCK_MONOTONIC, &time) == 0)
+ return (uint64_t)time.tv_nsec;
+
+ return 0;
+diff --git a/lib/kcapi-kernel-if.c b/lib/kcapi-kernel-if.c
+index 835e45a..b37f0dc 100644
+--- a/lib/kcapi-kernel-if.c
++++ b/lib/kcapi-kernel-if.c
+@@ -216,7 +216,7 @@ ssize_t _kcapi_common_send_meta(struct kcapi_handle *handle,
+ }
+ header->cmsg_level = SOL_ALG;
+ header->cmsg_type = ALG_SET_IV;
+- header->cmsg_len = kcapi_downcast_socklen_t(iv_msg_size);
++ header->cmsg_len = CMSG_LEN(iv_msg_size);
+ alg_iv = (void*)CMSG_DATA(header);
+ alg_iv->ivlen = tfm->info.ivsize;
+ memcpy(alg_iv->iv, handle->cipher.iv, tfm->info.ivsize);
+@@ -409,8 +409,10 @@ ssize_t _kcapi_common_vmsplice_chunk(struct kcapi_handle *handle,
+ "AF_ALG: splice syscall returned %zd", ret);
+ }
+
++ if (ret == 0)
++ return -EPIPE;
+ processed += ret;
+- inlen -= (uint32_t)ret;
++ inlen -= (size_t)ret;
+ }
+
+ return processed;
+@@ -434,14 +436,17 @@ int _kcapi_aio_read_all(struct kcapi_handle *handle, size_t toread,
+
+ for (i = 0; i < rc; i++) {
+ struct iocb *cb;
++ unsigned int idx = (unsigned int)events[i].data;
++
++ if (idx >= KCAPI_AIO_CONCURRENT)
++ return -EOVERFLOW;
+
+ /*
+ * If one cipher operation fails, so will the entire
+ * AIO operation
+ */
+ if (events[i].res < 0) {
+- handle->aio.iocb_ret[events[i].data] =
+- events[i].res;
++ handle->aio.iocb_ret[idx] = events[i].res;
+ return (int)events[i].res;
+ }
+
+@@ -452,16 +457,15 @@ int _kcapi_aio_read_all(struct kcapi_handle *handle, size_t toread,
+ * return code.
+ */
+ if (events[i].res > 0) {
+- handle->aio.iocb_ret[events[i].data] =
+- events[i].res;
++ handle->aio.iocb_ret[idx] = events[i].res;
+ } else {
+- handle->aio.iocb_ret[events[i].data] =
++ handle->aio.iocb_ret[idx] =
+ (__s64)cb->aio_nbytes;
+ }
+
+ cb->aio_fildes = 0;
+ }
+- toread -= (uint32_t)rc;
++ toread -= (size_t)rc;
+ }
+
+ return 0;
+@@ -613,7 +617,7 @@ ssize_t _kcapi_common_read_data(struct kcapi_handle *handle,
+ ret = read(*_kcapi_get_opfd(handle), out, outlen);
+ if (ret > 0) {
+ out += ret;
+- outlen -= (uint32_t)ret;
++ outlen -= (size_t)ret;
+ totallen += ret;
+ }
+ kcapi_dolog(KCAPI_LOG_DEBUG,
+@@ -722,13 +726,13 @@ static int __kcapi_common_getinfo(struct kcapi_handle *handle,
+ goto out;
+ }
+ if (addr_len != sizeof(nl)) {
+- ret = -errno;
++ ret = -EPROTO;
+ kcapi_dolog(KCAPI_LOG_ERR,
+ "Netlink error: wrong address length %d", addr_len);
+ goto out;
+ }
+ if (nl.nl_family != AF_NETLINK) {
+- ret = -errno;
++ ret = -EPROTO;
+ kcapi_dolog(KCAPI_LOG_ERR,
+ "Netlink error: wrong address family %d",
+ nl.nl_family);
+@@ -764,12 +768,12 @@ static int __kcapi_common_getinfo(struct kcapi_handle *handle,
+ goto out;
+ }
+ if (rc == 0) {
+- ret = -errno;
++ ret = -ENODATA;
+ kcapi_dolog(KCAPI_LOG_ERR, "Netlink error: no data");
+ goto out;
+ }
+ if (rc > (ssize_t)sizeof(buf)) {
+- ret = -errno;
++ ret = -EOVERFLOW;
+ kcapi_dolog(KCAPI_LOG_ERR,
+ "Netlink error: received too much data");
+ goto out;
+@@ -779,6 +783,12 @@ static int __kcapi_common_getinfo(struct kcapi_handle *handle,
+
+ ret = -EFAULT;
+ res_len = res_n->nlmsg_len;
++ if (res_len > sizeof(buf)) {
++ kcapi_dolog(KCAPI_LOG_ERR,
++ "Netlink error: nlmsg_len %lu exceeds buffer",
++ res_len);
++ goto out;
++ }
+ if (res_n->nlmsg_type == NLMSG_ERROR) {
+ /*
+ * return -EAGAIN -- this error will occur if we received a
+@@ -819,6 +829,9 @@ static int __kcapi_common_getinfo(struct kcapi_handle *handle,
+
+ if (tb[CRYPTOCFGA_REPORT_HASH]) {
+ struct rtattr *rta = tb[CRYPTOCFGA_REPORT_HASH];
++
++ if (RTA_PAYLOAD(rta) < sizeof(struct crypto_report_hash))
++ goto out;
+ struct crypto_report_hash *rsh =
+ (struct crypto_report_hash *) RTA_DATA(rta);
+ tfm->info.hash_digestsize = rsh->digestsize;
+@@ -831,6 +844,9 @@ static int __kcapi_common_getinfo(struct kcapi_handle *handle,
+ }
+ if (tb[CRYPTOCFGA_REPORT_BLKCIPHER]) {
+ struct rtattr *rta = tb[CRYPTOCFGA_REPORT_BLKCIPHER];
++
++ if (RTA_PAYLOAD(rta) < sizeof(struct crypto_report_blkcipher))
++ goto out;
+ struct crypto_report_blkcipher *rblk =
+ (struct crypto_report_blkcipher *) RTA_DATA(rta);
+ tfm->info.blocksize = rblk->blocksize;
+@@ -845,6 +861,9 @@ static int __kcapi_common_getinfo(struct kcapi_handle *handle,
+ }
+ if (tb[CRYPTOCFGA_REPORT_AEAD]) {
+ struct rtattr *rta = tb[CRYPTOCFGA_REPORT_AEAD];
++
++ if (RTA_PAYLOAD(rta) < sizeof(struct crypto_report_aead))
++ goto out;
+ struct crypto_report_aead *raead =
+ (struct crypto_report_aead *) RTA_DATA(rta);
+ tfm->info.blocksize = raead->blocksize;
+@@ -858,6 +877,9 @@ static int __kcapi_common_getinfo(struct kcapi_handle *handle,
+ }
+ if (tb[CRYPTOCFGA_REPORT_RNG]) {
+ struct rtattr *rta = tb[CRYPTOCFGA_REPORT_RNG];
++
++ if (RTA_PAYLOAD(rta) < sizeof(struct crypto_report_rng))
++ goto out;
+ struct crypto_report_rng *rrng =
+ (struct crypto_report_rng *) RTA_DATA(rta);
+ tfm->info.rng_seedsize = rrng->seedsize;
+@@ -981,19 +1003,19 @@ static int _kcapi_get_kernver(struct kcapi_handle *handle)
+ /* 3.15.0 */
+ res = strtok_r(kernel.release, ".", &saveptr);
+ if (!res) {
+- printf("Could not parse kernel version");
++ kcapi_dolog(KCAPI_LOG_ERR, "Could not parse kernel version");
+ return -EFAULT;
+ }
+ tfm->sysinfo.kernel_maj = strtoul(res, NULL, 10);
+ res = strtok_r(NULL, ".", &saveptr);
+ if (!res) {
+- printf("Could not parse kernel version");
++ kcapi_dolog(KCAPI_LOG_ERR, "Could not parse kernel version");
+ return -EFAULT;
+ }
+ tfm->sysinfo.kernel_minor = strtoul(res, NULL, 10);
+ res = strtok_r(NULL, ".", &saveptr);
+ if (!res) {
+- printf("Could not parse kernel version");
++ kcapi_dolog(KCAPI_LOG_ERR, "Could not parse kernel version");
+ return -EFAULT;
+ }
+ tfm->sysinfo.kernel_patchlevel = strtoul(res, NULL, 10);
+@@ -1217,7 +1239,6 @@ static int _kcapi_handle_init_tfm(struct kcapi_handle *handle, const char *type,
+
+ ret = _kcapi_common_getinfo(handle, ciphername);
+ if (ret) {
+- ret = -errno;
+ kcapi_dolog(KCAPI_LOG_ERR, "NETLINK_CRYPTO: cannot obtain cipher information for %s (is required crypto_user.c patch missing? see documentation)",
+ ciphername);
+ return ret;
+@@ -1368,7 +1389,7 @@ ssize_t _kcapi_cipher_crypt_chunk(struct kcapi_handle *handle,
+ in += inprocess;
+ inlen -= inprocess;
+ out += ret;
+- outlen -= (uint32_t)ret;
++ outlen -= (size_t)ret;
+ }
+
+ return totallen;
+diff --git a/lib/kcapi-kpp.c b/lib/kcapi-kpp.c
+index 814485a..d0383d6 100644
+--- a/lib/kcapi-kpp.c
++++ b/lib/kcapi-kpp.c
+@@ -52,12 +52,12 @@ int kcapi_kpp_ecdh_setcurve(struct kcapi_handle *handle,
+ unsigned long curve_id)
+ {
+ struct kcapi_handle_tfm *tfm = handle->tfm;
+- char curve_id_str[sizeof(unsigned long)];
++ char curve_id_str[24];
+ int ret = 0;
+
+ snprintf(curve_id_str, sizeof(curve_id_str), "%lu", curve_id);
+ ret = setsockopt(tfm->tfmfd, SOL_ALG, ALG_SET_ECDH_CURVE,
+- curve_id_str, sizeof(curve_id_str));
++ curve_id_str, (socklen_t)strlen(curve_id_str));
+ return (ret >= 0) ? ret : -errno;
+ }
+
+diff --git a/lib/kcapi-md.c b/lib/kcapi-md.c
+index bddd76b..5f493eb 100644
+--- a/lib/kcapi-md.c
++++ b/lib/kcapi-md.c
+@@ -196,7 +196,7 @@ ssize_t impl_md_sha256(const uint8_t *in, size_t inlen,
+ }
+
+ ORIG_SYMVER(md_sha256, "1.0.0")
+-ssize_t orig_md_sha256(const uint8_t *in, uint32_t inlen,
++int32_t orig_md_sha256(const uint8_t *in, uint32_t inlen,
+ uint8_t *out, uint32_t outlen)
+ {
+ return (int32_t)kcapi_md_conv_common("sha256", in, inlen, out, outlen);
+diff --git a/lib/kcapi-sym.c b/lib/kcapi-sym.c
+index 911ec1e..d500061 100644
+--- a/lib/kcapi-sym.c
++++ b/lib/kcapi-sym.c
+@@ -47,6 +47,9 @@ ssize_t impl_cipher_encrypt(struct kcapi_handle *handle,
+ struct kcapi_handle_tfm *tfm = handle->tfm;
+ uint32_t bs = tfm->info.blocksize;
+
++ if (!bs)
++ return -EINVAL;
++
+ /* require properly sized output data size */
+ if (outlen < ((inlen + bs - 1) / bs * bs))
+ kcapi_dolog(KCAPI_LOG_WARN,
+@@ -120,6 +123,9 @@ ssize_t impl_cipher_decrypt(struct kcapi_handle *handle,
+ {
+ struct kcapi_handle_tfm *tfm = handle->tfm;
+
++ if (!tfm->info.blocksize)
++ return -EINVAL;
++
+ /* require properly sized output data size */
+ if (inlen % tfm->info.blocksize)
+ kcapi_dolog(KCAPI_LOG_WARN,
+diff --git a/lib/kcapi-utils.c b/lib/kcapi-utils.c
+index 46fd330..e801d29 100644
+--- a/lib/kcapi-utils.c
++++ b/lib/kcapi-utils.c
+@@ -96,7 +96,7 @@ err:
+ } else {
+ kcapi_dolog(KCAPI_LOG_WARN,
+ "AF_ALG: setting maximum splice pipe size to %u failed: %s",
+- size, strerror(ret));
++ size, strerror(-ret));
+ }
+ return ret;
+ }
+@@ -109,7 +109,10 @@ int kcapi_get_maxsplicesize(struct kcapi_handle *handle)
+ return -EINVAL;
+
+ /* Both pipe endpoints should have the same pipe size */
+- handle->pipesize = (unsigned int)fcntl(handle->pipes[0], F_GETPIPE_SZ);
++ int ret = fcntl(handle->pipes[0], F_GETPIPE_SZ);
++ if (ret < 0)
++ return -errno;
++ handle->pipesize = (unsigned int)ret;
+
+ /*
+ * For vmsplice to allow the maximum number of 16 pages, we need to
new file mode 100644
@@ -0,0 +1,55 @@
+From 79198067bdf027f5d4d5e2804b086a0a37b277ec Mon Sep 17 00:00:00 2001
+From: Stephan Mueller <smueller@chronox.de>
+Date: Fri, 3 Apr 2026 17:43:05 +0200
+Subject: [PATCH] fix kernel invocation
+
+Signed-off-by: Stephan Mueller <smueller@chronox.de>
+(cherry picked from commit d9f16d5fbcf8270110a8f6f35523525f345ca311)
+
+CVE: CVE-2026-71226
+Upstream-Status: Backport [https://github.com/smuellerDD/libkcapi/commit/d9f16d5fbcf8270110a8f6f35523525f345ca311]
+Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
+---
+ lib/kcapi-kernel-if.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/lib/kcapi-kernel-if.c b/lib/kcapi-kernel-if.c
+index b37f0dc..5d3b352 100644
+--- a/lib/kcapi-kernel-if.c
++++ b/lib/kcapi-kernel-if.c
+@@ -216,7 +216,7 @@ ssize_t _kcapi_common_send_meta(struct kcapi_handle *handle,
+ }
+ header->cmsg_level = SOL_ALG;
+ header->cmsg_type = ALG_SET_IV;
+- header->cmsg_len = CMSG_LEN(iv_msg_size);
++ header->cmsg_len = kcapi_downcast_socklen_t(iv_msg_size);
+ alg_iv = (void*)CMSG_DATA(header);
+ alg_iv->ivlen = tfm->info.ivsize;
+ memcpy(alg_iv->iv, handle->cipher.iv, tfm->info.ivsize);
+@@ -411,6 +411,7 @@ ssize_t _kcapi_common_vmsplice_chunk(struct kcapi_handle *handle,
+
+ if (ret == 0)
+ return -EPIPE;
++
+ processed += ret;
+ inlen -= (size_t)ret;
+ }
+@@ -436,7 +437,7 @@ int _kcapi_aio_read_all(struct kcapi_handle *handle, size_t toread,
+
+ for (i = 0; i < rc; i++) {
+ struct iocb *cb;
+- unsigned int idx = (unsigned int)events[i].data;
++ uint64_t idx = events[i].data;
+
+ if (idx >= KCAPI_AIO_CONCURRENT)
+ return -EOVERFLOW;
+@@ -459,8 +460,7 @@ int _kcapi_aio_read_all(struct kcapi_handle *handle, size_t toread,
+ if (events[i].res > 0) {
+ handle->aio.iocb_ret[idx] = events[i].res;
+ } else {
+- handle->aio.iocb_ret[idx] =
+- (__s64)cb->aio_nbytes;
++ handle->aio.iocb_ret[idx] = (__s64)cb->aio_nbytes;
+ }
+
+ cb->aio_fildes = 0;
new file mode 100644
@@ -0,0 +1,93 @@
+From 8ab3c8939276848ec8f43156a7658f7c5dae4026 Mon Sep 17 00:00:00 2001
+From: Stephan Mueller <smueller@chronox.de>
+Date: Thu, 30 Jul 2026 08:36:32 +0200
+Subject: [PATCH] fix memory corruption
+
+Signed-off-by: Zoltan Fridrich <zfridric@redhat.com>
+Signed-off-by: Stephan Mueller <smueller@chronox.de>
+
+CVE: CVE-2026-71226
+Upstream-Status: Backport [https://github.com/smuellerDD/libkcapi/commit/cd966ffa08cf605ae5853d2f9a42fdd2b6df8bb4]
+
+Dropped changes to the CHANGES.md file.
+
+Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
+---
+ lib/kcapi-kernel-if.c | 33 ++++++++++++++-------------------
+ 1 file changed, 14 insertions(+), 19 deletions(-)
+
+diff --git a/lib/kcapi-kernel-if.c b/lib/kcapi-kernel-if.c
+index 5d3b352..8a12c09 100644
+--- a/lib/kcapi-kernel-if.c
++++ b/lib/kcapi-kernel-if.c
+@@ -423,6 +423,8 @@ ssize_t _kcapi_common_vmsplice_chunk(struct kcapi_handle *handle,
+ int _kcapi_aio_read_all(struct kcapi_handle *handle, size_t toread,
+ struct timespec *timeout)
+ {
++ int err = 0;
++
+ if (toread > KCAPI_AIO_CONCURRENT)
+ return -EINVAL;
+
+@@ -433,34 +435,26 @@ int _kcapi_aio_read_all(struct kcapi_handle *handle, size_t toread,
+ events, timeout);
+
+ if (rc < 0)
+- return rc;
++ return err == 0 ? rc : err;
+
+ for (i = 0; i < rc; i++) {
+ struct iocb *cb;
+ uint64_t idx = events[i].data;
+
+- if (idx >= KCAPI_AIO_CONCURRENT)
+- return -EOVERFLOW;
+-
+- /*
+- * If one cipher operation fails, so will the entire
+- * AIO operation
+- */
+- if (events[i].res < 0) {
+- handle->aio.iocb_ret[idx] = events[i].res;
+- return (int)events[i].res;
++ if (idx >= KCAPI_AIO_CONCURRENT) {
++ if (err == 0)
++ err = -EOVERFLOW;
++ continue;
+ }
+
+ cb = (struct iocb *)(uintptr_t)events[i].obj;
+
+- /*
+- * Older symmetric AIO implementations used a wrong
+- * return code.
+- */
+- if (events[i].res > 0) {
+- handle->aio.iocb_ret[idx] = events[i].res;
+- } else {
++ if (events[i].res == 0) {
+ handle->aio.iocb_ret[idx] = (__s64)cb->aio_nbytes;
++ } else {
++ handle->aio.iocb_ret[idx] = events[i].res;
++ if (events[i].res < 0 && err == 0)
++ err = (int)events[i].res;
+ }
+
+ cb->aio_fildes = 0;
+@@ -468,7 +462,7 @@ int _kcapi_aio_read_all(struct kcapi_handle *handle, size_t toread,
+ toread -= (size_t)rc;
+ }
+
+- return 0;
++ return err;
+ }
+
+ int _kcapi_aio_send_iov(struct kcapi_handle *handle, struct iovec *iov,
+@@ -544,6 +538,7 @@ int _kcapi_aio_read_iov(struct kcapi_handle *handle,
+ } else {
+ kcapi_dolog(KCAPI_LOG_ERR,
+ "Could not sumbit AIO read\n");
++ _kcapi_aio_read_all(handle, (size_t)ret, NULL);
+ return -EIO;
+ }
+ }
@@ -5,6 +5,9 @@ LIC_FILES_CHKSUM = "file://COPYING;md5=3d8a091d797491204567185a6efce70f"
SRCREV = "fc937358e71253a6efaa3ba74885364976b040ea"
SRC_URI = "git://github.com/smuellerDD/libkcapi.git;branch=master;protocol=https \
+ file://CVE-2026-71226-1.patch \
+ file://CVE-2026-71226-2.patch \
+ file://CVE-2026-71226-3.patch \
"
inherit autotools