From b6dde8a170ced591b6919eef592629b65da1761a Mon Sep 17 00:00:00 2001 From: Alexander Moch Date: Wed, 16 Sep 2026 22:14:20 +0000 Subject: [PATCH] zio_crypt: free the key unwrap uios when decryption fails zio_crypt_key_unwrap() allocates a pair of iovec buffers through zio_crypt_uios_init_os() and releases them with zio_crypt_uios_fini_os() once the keys have been decrypted. When zio_decrypt_os() fails it jumps straight to the error label, which skips that release, so both buffers are leaked. The failure is reachable from userland: any key unwrap that does not authenticate leaks 64 bytes twice, so a loop of "zfs load-key" calls with the wrong passphrase grows kernel memory without bound. It is not Linux specific -- the FreeBSD implementation allocates these buffers as well. Release the uios as soon as the crypto operation returns and check the result afterwards, matching zio_crypt_key_wrap(), which already frees them unconditionally on both paths. The buffers are then released exactly once, and the error label continues to own nothing. Verified with kmemleak on Linux: 200 failed unwraps reported 204 leaked objects from zio_crypt_uios_init_os() before this change and none after, against one object on a control run that performed no unwraps. Reviewed-by: Rob Norris Reviewed-by: Brian Behlendorf Signed-off-by: Alexander Moch Closes #19116 --- module/zfs/zio_crypt.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/module/zfs/zio_crypt.c b/module/zfs/zio_crypt.c index 6032957fd605..40824c4ae645 100644 --- a/module/zfs/zio_crypt.c +++ b/module/zfs/zio_crypt.c @@ -440,11 +440,12 @@ zio_crypt_key_unwrap(crypto_key_t *cwkey, uint64_t crypt, uint64_t version, ret = zio_decrypt_os(ci, cwkey, NULL, &cuio, &puio, ci->ci_keylen + SHA512_HMAC_KEYLEN, iv, (uint8_t *)aad, aad_len, mac); - if (ret != 0) - goto error; zio_crypt_uios_fini_os(&cuio, &puio); + if (ret != 0) + goto error; + /* generate a fresh salt */ ret = random_get_bytes(key->zk_salt, ZIO_DATA_SALT_LEN); if (ret != 0)