Skip to content

NVMe-oF/TCP driver vulnerability (CVE-2023-5178)

Linux nvmet-tcp target'ında bozuk bir Initialize Connection Request işlenirken ortaya çıkan bir logic error, free edilmiş bir pointer'ı erişilebilir bırakır ve kmalloc-96 içinde racy bir double-free / use-after-free üretir.

Mechanism

Başarısız bir queue setup neden double-free üretir

nvmet-tcp, TCP transport için kernel tarafındaki NVMe-over-Fabrics target'ıdır (drivers/nvme/target/tcp.c). Uzaktaki bir initiator bağlandığında target socket'i accept eder ve nvmet_tcp_alloc_queue() setup path'ini çalıştırır; bu path queue başına state ayırır ve (in-band crypto/digest'ler negotiate edildiğinde) crypto context'i allocate eder. nvmet_tcp_free_crypto() cleanup helper'ı bu crypto context'i tear down eder.

Bug, NVMe/TCP handshake'inin ilk PDU'su olan bozuk bir Initialize Connection Request (ICReq)'in error-handling'indeki bir logic error'dur. Setup'ın ortasında bir failure olduğunda kod yolu bir struct'ı free eder ama sahip olduğu pointer / state'i tutarlı bir şekilde temizlemez; böylece aynı allocation ikinci kez serbest bırakılabilir — bir kez failure path'inde, bir kez de normal queue-release/teardown path'inde (nvmet_tcp_release_queue_work()).

Connection accept ve queue release farklı work context'lerinden çalıştığı için ikinci free birincisiyle race eder: bu bir racy double-free'dir ve free edilen object genel amaçlı kmalloc-96 slab cache'ine düşer. Küçük ve yoğun trafikli bir kmalloc object'inin double-free'i güçlü bir exploitation primitive'idir — free edilen slot'u saldırgan kontrollü bir object'le reclaim edip ardından stale reference üzerinde işlem yaparak bir use-after-free'e yönlendirilebilir. Red Hat advisory'si etkiyi potansiyel remote code execution (network'ten erişilebilir target) veya local privilege escalation olarak derecelendirir.

Fix'in geri getirdiği invariant basit: bir error path'inde free edilmiş her pointer temizlenmelidir ki sonraki hiçbir teardown path onu tekrar free edemesin.

Walkthrough

Target tarafında nvmet / nvmet-tcp yüklü ve bir TCP port configure edilmiş olmalıdır (default 0.0.0.0:4420); trigger ise kötü niyetli bir initiator'dan gelir.

  1. Bir NVMe/TCP target ayağa kaldır. Modülleri yükle ve configfs üzerinden bir subsystem ile bir TCP port configure et ki target bağlantıları accept etsin.
modprobe nvmet
modprobe nvmet-tcp
# configure a subsystem + namespace, then a tcp port at addr 0.0.0.0:4420
  1. Bağlan ve bozuk bir Initialize Connection Request gönder. Kötü niyetli bir initiator TCP bağlantısını açar ve bir crypto/digest context zaten allocate edilmişken nvmet_tcp_alloc_queue()'yu error path'ine sürmek için hazırlanmış bir malformed ICReq PDU'su gönderir.

  2. İki free'yi race ettir. Error path object'i free eder; queue-release work da onu free eder. İki path örtüşecek şekilde teardown'ı tetiklemek kmalloc-96'da double-free verir. Public PoC (Alon Zahavi / rockrid3r), race'in SLUB freelist davranışı nedeniyle en güvenilir olarak tek CPU'lu bir target'ta çalıştığını not eder.

  3. UAF'e çevir (exploitation). Double-free edilmiş slot'u kontrollü bir object'le reclaim etmek için küçük kmalloc-96 allocation'ları spray et, ardından stale reference'ın onun üzerinde işlem yapmasına izin ver — böylece double-free'i code execution veya privilege escalation için bir use-after-free'e dönüştür.

Public PoC'tan reproduction notları

rockrid3r exploit'i Ubuntu 23.10'u (kernel 6.5.0-9-generic) hedefler, target'ın bir NVMe/TCP port expose etmesini gerektirir ve yalnızca 1-core bir target'ta güvenilir şekilde çalışır — multi-core, race'i kazanmak için ek freelist control gerektirir. Bug, Alon Zahavi tarafından raporlanmıştır.

Detection

  • Malformed ICReq PDU'ları alıp ardından aniden disconnect olan bir NVMe/TCP target bir trigger imzasıdır; nvmet-tcp içindeki beklenmedik handshake parse hatalarını logla.
  • kmalloc-96'nın double/use-after-free'i tipik olarak CONFIG_SLUB_DEBUG / KASAN altında drivers/nvme/target/tcp.c'den kaynaklanan double-free or invalid-free ve use-after-free splat'ları olarak yüzeye çıkar.

Mitigation

  • Upstream fix'i uygula (v6.6-rc7'ye merge edildi; Red Hat RHSA-2023:7370 ve SUSE/Ubuntu güncellemeleri gibi distro errata'ları üzerinden backport edildi). Patch, ICReq error path'inde free edilmiş pointer/state'i temizler, böylece teardown onu tekrar free edemez.
  • NVMe-oF/TCP target'larını güvenilmeyen network'lere expose etme; traddr'ı kısıtla / 4420 port'unu güvenilen initiator'lara firewall'la sınırla.

References