[PATCH] nvmet: auth: validate dhchap id list lengths(KASAN: slab-out-of-bounds)
From: YunJe Shin
Date: Wed Feb 11 2026 - 01:59:48 EST
Validate DH-HMAC-CHAP hash/DH list lengths before indexing the idlist halves to prevent out-of-bounds reads.
KASAN report:
[ 37.160829] Call Trace:
[ 37.160831] <TASK>
[ 37.160832] dump_stack_lvl+0x5f/0x80
[ 37.160837] print_report+0xd1/0x640
[ 37.160842] ? __pfx__raw_spin_lock_irqsave+0x10/0x10
[ 37.160846] ? kfree+0x137/0x390
[ 37.160850] ? kasan_complete_mode_report_info+0x2a/0x200
[ 37.160854] kasan_report+0xe5/0x120
[ 37.160856] ? nvmet_execute_auth_send+0x19a9/0x1f00
[ 37.160860] ? nvmet_execute_auth_send+0x19a9/0x1f00
[ 37.160863] __asan_report_load1_noabort+0x18/0x20
[ 37.160866] nvmet_execute_auth_send+0x19a9/0x1f00
[ 37.160870] nvmet_tcp_io_work+0x17a8/0x2720
[ 37.160874] ? __pfx_nvmet_tcp_io_work+0x10/0x10
[ 37.160877] process_one_work+0x5e9/0x1020
[ 37.160881] ? __kasan_check_write+0x18/0x20
[ 37.160885] worker_thread+0x446/0xc80
[ 37.160889] ? __pfx_worker_thread+0x10/0x10
[ 37.160891] kthread+0x2d7/0x3c0
[ 37.160894] ? __pfx_kthread+0x10/0x10
[ 37.160897] ret_from_fork+0x39f/0x5d0
[ 37.160900] ? __pfx_ret_from_fork+0x10/0x10
[ 37.160903] ? __kasan_check_read+0x15/0x20
[ 37.160906] ? __switch_to+0xb45/0xf90
[ 37.160910] ? __switch_to_asm+0x39/0x70
[ 37.160914] ? __pfx_kthread+0x10/0x10
[ 37.160916] ret_from_fork_asm+0x1a/0x30
[ 37.160920] </TASK>
[ 37.160921]
[ 37.174141] Allocated by task 11:
[ 37.174377] kasan_save_stack+0x3d/0x60
[ 37.174697] kasan_save_track+0x18/0x40
[ 37.175043] kasan_save_alloc_info+0x3b/0x50
[ 37.175420] __kasan_kmalloc+0x9c/0xa0
[ 37.175762] __kmalloc_noprof+0x197/0x480
[ 37.176117] nvmet_execute_auth_send+0x39e/0x1f00
[ 37.176529] nvmet_tcp_io_work+0x17a8/0x2720
[ 37.176912] process_one_work+0x5e9/0x1020
[ 37.177275] worker_thread+0x446/0xc80
[ 37.177616] kthread+0x2d7/0x3c0
[ 37.177906] ret_from_fork+0x39f/0x5d0
[ 37.178238] ret_from_fork_asm+0x1a/0x30
[ 37.178591]
[ 37.178735] The buggy address belongs to the object at ffff88800aecc800
[ 37.178735] which belongs to the cache kmalloc-96 of size 96
[ 37.179790] The buggy address is located 0 bytes to the right of
[ 37.179790] allocated 72-byte region [ffff88800aecc800, ffff88800aecc848)
[ 37.180931]
[ 37.181079] The buggy address belongs to the physical page:
[ 37.181572] page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0xaecc
[ 37.182393] flags: 0x100000000000000(node=0|zone=1)
[ 37.182819] page_type: f5(slab)
[ 37.183080] raw: 0100000000000000 ffff888006c41280 dead000000000122 0000000000000000
[ 37.183730] raw: 0000000000000000 0000000000200020 00000000f5000000 0000000000000000
[ 37.184333] page dumped because: kasan: bad access detected
[ 37.184783]
[ 37.184918] Memory state around the buggy address:
[ 37.185315] ffff88800aecc700: fa fb fb fb fb fb fb fb fb fb fb fb fc fc fc fc
[ 37.185835] ffff88800aecc780: fa fb fb fb fb fb fb fb fb fb fb fb fc fc fc fc
[ 37.186336] >ffff88800aecc800: 00 00 00 00 00 00 00 00 00 fc fc fc fc fc fc fc
[ 37.186839] ^
[ 37.187255] ffff88800aecc880: fa fb fb fb fb fb fb fb fb fb fb fb fc fc fc fc
[ 37.187763] ffff88800aecc900: fa fb fb fb fb fb fb fb fb fb fb fb fc fc fc fc
[ 37.188261] ==================================================================
[ 37.188938] ==================================================================
Fixes: db1312dd95488 ("nvmet: implement basic In-Band Authentication")
Signed-off-by: YunJe Shin <ioerts@xxxxxxxxxxxxx>
---
drivers/nvme/target/fabrics-cmd-auth.c | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/drivers/nvme/target/fabrics-cmd-auth.c b/drivers/nvme/target/fabrics-cmd-auth.c
index 5946681cb0e3..8ad3255aec4a 100644
--- a/drivers/nvme/target/fabrics-cmd-auth.c
+++ b/drivers/nvme/target/fabrics-cmd-auth.c
@@ -36,6 +36,7 @@ static u8 nvmet_auth_negotiate(struct nvmet_req *req, void *d)
struct nvmet_ctrl *ctrl = req->sq->ctrl;
struct nvmf_auth_dhchap_negotiate_data *data = d;
int i, hash_id = 0, fallback_hash_id = 0, dhgid, fallback_dhgid;
+ size_t idlist_half;
pr_debug("%s: ctrl %d qid %d: data sc_d %d napd %d authid %d halen %d dhlen %d\n",
__func__, ctrl->cntlid, req->sq->qid,
@@ -72,6 +73,15 @@ static u8 nvmet_auth_negotiate(struct nvmet_req *req, void *d)
NVME_AUTH_DHCHAP_AUTH_ID)
return NVME_AUTH_DHCHAP_FAILURE_INCORRECT_PAYLOAD;
+ /*
+ * idlist[0..idlist_half-1]: hash IDs
+ * idlist[idlist_half..]: DH group IDs
+ */
+ idlist_half = sizeof(data->auth_protocol[0].dhchap.idlist) / 2;
+ if (data->auth_protocol[0].dhchap.halen > idlist_half ||
+ data->auth_protocol[0].dhchap.dhlen > idlist_half)
+ return NVME_AUTH_DHCHAP_FAILURE_INCORRECT_PAYLOAD;
+
for (i = 0; i < data->auth_protocol[0].dhchap.halen; i++) {
u8 host_hmac_id = data->auth_protocol[0].dhchap.idlist[i];
@@ -98,7 +108,8 @@ static u8 nvmet_auth_negotiate(struct nvmet_req *req, void *d)
dhgid = -1;
fallback_dhgid = -1;
for (i = 0; i < data->auth_protocol[0].dhchap.dhlen; i++) {
- int tmp_dhgid = data->auth_protocol[0].dhchap.idlist[i + 30];
+ int tmp_dhgid =
+ data->auth_protocol[0].dhchap.idlist[i + idlist_half];
if (tmp_dhgid != ctrl->dh_gid) {
dhgid = tmp_dhgid;
--
2.43.0