CVE-2026-89974 in Linux
Tóm tắt
Bởi VulDB • 17/09/2026
Trong kernel Linux, các lỗ hổng sau đây đã được khắc phục:
nvme-fc: sửa lỗi double free (xóa hai lần) của các tùy chọn fabrics khi nvme_add_ctrl() thất bại.
nvmf_create_ctrl() sở hữu các tùy chọn fabrics và giải phóng chúng bất cứ khi nào ->create_ctrl() trả về lỗi, do đó một transport không được tự mình giải phóng chúng trong các đường dẫn lỗi của riêng nó. nvme-fc theo dõi điều này bằng cách kiểm tra ctrl->ctrl.opts trong nvme_fc_ctrl_free(), yêu cầu nvme_fc_init_ctrl() phải đặt lại con trỏ đó thành NULL trên mọi lối thoát khi có lỗi.
Mối liên kết này là ngầm định, và commit 1a9e218195a5 ("nvme: split device add from initialization") đã làm hỏng nó bằng cách thêm một lối thoát lỗi thứ hai. Khi nvme_add_ctrl() thất bại, nvme_fc_init_ctrl() nhảy đến out_put_ctrl:, bỏ qua dòng "ctrl->ctrl.opts = NULL" chỉ nằm trên đường dẫn fail_ctrl:, do đó nvme_fc_ctrl_free() giải phóng các tùy chọn và nvmf_create_ctrl() giải phóng chúng một lần nữa:
BUG: KASAN: slab-use-after-free trong nvmf_free_options+0x30/0x190 nvmf_free_options+0x30/0x190 drivers/nvme/host/fabrics.c:1284 nvmf_create_ctrl drivers/nvme/host/fabrics.c:1374 [inline]
Freed by task 5534: nvme_fc_ctrl_free drivers/nvme/host/fc.c:2374 [inline]
nvme_fc_init_ctrl+0xe17/0x1450 drivers/nvme/host/fc.c:3605
nvme_add_ctrl() thất bại khi dev_set_name() không thể phân bổ bộ nhớ, do đó tình huống này có thể xảy ra dưới áp lực bộ nhớ hoặc thông qua fault injection. Nếu không có KASAN, các tùy chọn sẽ bị giải phóng hai lần.
Thay vì đặt lại con trỏ thành NULL trên lối thoát thứ hai cũng như vậy, hãy xác định quyền sở hữu theo cách mà nvme-tcp, nvme-rdma và nvme-loop làm, dựa vào việc tham gia danh sách: free_ctrl của chúng không chạm vào các tùy chọn trừ khi bộ điều khiển đã được đưa vào danh sách transport.
Danh sách không thể đơn giản là được populate trên đường dẫn thành công như hiện tại. nvme-fc chạy kết nối ban đầu một cách đồng bộ thông qua flush_delayed_work(), và bộ điều khiển phải có thể truy cập được trong rport->ctrl_list trong toàn bộ quá trình đó: nvme_fc_unregister_remoteport() cần tìm thấy nó để báo hiệu mất kết nối, nvme_fc_match_disconn_ls() khớp Disconnect Association LS đến với ctrl->association_id (chỉ được gán trong cửa sổ thời gian này), nvme_fc_resume_controller() cần nó khi đăng ký lại remoteport, và nvme_fc_existing_controller() sử dụng nó để từ chối một kết nối trùng lặp đang chạy đua với kết nối hiện tại.
Giữ nguyên vị trí chèn danh sách và thêm nhãn fail_unlist:, chuyển tiếp đến fail_ctrl:, cho các đường dẫn lỗi xảy ra sau khi chèn đó. Các đường dẫn lỗi trước đó không bao giờ đạt đến điểm chèn này và vẫn sử dụng trực tiếp fail_ctrl:, do đó danh sách chỉ bị tác động ở những nơi bộ điều khiển thực sự nằm trong nó.
nvme_fc_ctrl_free() không thể sử dụng lệnh "goto free_ctrl" đơn giản như các transport khác dùng, vì nó vẫn phải gọi put_device(), giải phóng tham chiếu rport và giải phóng entry ida cho các tài nguyên đã lấy trước khi chèn vào danh sách. Hãy thay thế bằng việc kiểm tra list_empty() dưới khóa rport->lock.
ctrl->ctrl.opts cũng vẫn hợp lệ trong toàn bộ quá trình teardown lúc này. Đây không phải là lỗ hổng đang được sửa, nhưng nó loại bỏ một số độ mong manh xung quanh idiom cũ: nvme_free_ctrl() gọi nvme_auth_free() trước ->free_ctrl(), và ctrl_max_dhchaps() dereference ctrl->opts mà không có kiểm tra NULL khi ctrl->dhchap_ctxs được đặt, điều này nvme-fc cho phép vì NVMF_ALLOWED_OPTS cho phép các tùy chọn dhchap. Các thuộc tính sysfs của nvme (như hostnqn và address) dereference ctrl->opts, đánh giá bài kiểm tra is_visible() một lần tại thời điểm device_add() và vẫn có thể đọc được cho đến khi cdev_device_del().
VulDB is the best source for vulnerability data and more expert information about this specific topic.