]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ksmbd: fix use-after-free from async crypto on Qualcomm crypto engine
authorJoshua Klinesmith <joshuaklinesmith@gmail.com>
Tue, 7 Apr 2026 02:31:12 +0000 (22:31 -0400)
committerSteve French <stfrench@microsoft.com>
Sun, 12 Apr 2026 23:07:55 +0000 (18:07 -0500)
ksmbd_crypt_message() sets a NULL completion callback on AEAD requests
and does not handle the -EINPROGRESS return code from async hardware
crypto engines like the Qualcomm Crypto Engine (QCE). When QCE returns
-EINPROGRESS, ksmbd treats it as an error and immediately frees the
request while the hardware DMA operation is still in flight. The DMA
completion callback then dereferences freed memory, causing a NULL
pointer crash:

  pc : qce_skcipher_done+0x24/0x174
  lr : vchan_complete+0x230/0x27c
  ...
  el1h_64_irq+0x68/0x6c
  ksmbd_free_work_struct+0x20/0x118 [ksmbd]
  ksmbd_exit_file_cache+0x694/0xa4c [ksmbd]

Use the standard crypto_wait_req() pattern with crypto_req_done() as
the completion callback, matching the approach used by the SMB client
in fs/smb/client/smb2ops.c. This properly handles both synchronous
engines (immediate return) and async engines (-EINPROGRESS followed
by callback notification).

Fixes: e2f34481b24d ("cifsd: add server-side procedures for SMB3")
Link: https://github.com/openwrt/openwrt/issues/21822
Signed-off-by: Joshua Klinesmith <joshuaklinesmith@gmail.com>
Acked-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/smb/server/auth.c

index af5f4030433171e2523833259dbead30dc881c42..7d0691f7263fe2d0080563df3c75ccce618e6317 100644 (file)
@@ -827,6 +827,7 @@ int ksmbd_crypt_message(struct ksmbd_work *work, struct kvec *iov,
        struct smb2_transform_hdr *tr_hdr = smb_get_msg(iov[0].iov_base);
        unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20;
        int rc;
+       DECLARE_CRYPTO_WAIT(wait);
        struct scatterlist *sg;
        u8 sign[SMB2_SIGNATURE_SIZE] = {};
        u8 key[SMB3_ENC_DEC_KEY_SIZE];
@@ -913,12 +914,12 @@ int ksmbd_crypt_message(struct ksmbd_work *work, struct kvec *iov,
 
        aead_request_set_crypt(req, sg, sg, crypt_len, iv);
        aead_request_set_ad(req, assoc_data_len);
-       aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL);
+       aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG |
+                                 CRYPTO_TFM_REQ_MAY_SLEEP,
+                                 crypto_req_done, &wait);
 
-       if (enc)
-               rc = crypto_aead_encrypt(req);
-       else
-               rc = crypto_aead_decrypt(req);
+       rc = crypto_wait_req(enc ? crypto_aead_encrypt(req) :
+                            crypto_aead_decrypt(req), &wait);
        if (rc)
                goto free_iv;