Skip to content

CommBuffer / SMM pointer not-in-SMRAM (confused deputy)

CommBuffer'ı — ya da içindeki nested bir pointer'ı — SMRAM'e karşı doğrulamayan bir SMI handler, ring-0 kodun handler'ı kendi korunan belleğini okumaya ya da yazmaya zorlamasına izin verir; bu da SMM'i bir confused deputy'ye dönüştürür.

Mechanism

Neden çalışır — SMM, saldırgan kontrolündeki bellekte yaşayan bir pointer'a güvenir

System Management Mode (SMM), en privilege'li x86 execution context'idir. Kodu ve verisi SMRAM'de oturur, OS'tan kilitlenmiş halde. OS'tan iş kabul etmek için bir SMI handler, tasarım gereği SMRAM dışında, OS'un erişebildiği bellekte yaşayan paylaşımlı bir Communication Buffer (CommBuffer) okur.

Platform invariant'ı şudur: bir SMI handler, SMRAM'e yönelen OS-tarafından-verilmiş bir pointer'ı asla dereference etmemelidir. EDK2 bunu zorunlu kılmak için SmmIsBufferOutsideSmmValid(Address, Size) sağlar. Klasik confused-deputy bug'ı şudur: handler dış CommBuffer'ı doğrular ama sonra içindeki bir alanı pointer olarak ele alır (bir nested pointer, örn. CommBuffer->BufferSize uzunluğundaki CommBuffer->BufferPtr) ve o pointer'ı SMRAM'e karşı doğrulamadan dereference eder. Saldırgan o alanı basitçe SMRAM'in içine gösterir. Handler "çıktısını yazdığında" SMRAM'in üzerine yazar — en privilege'li context'e arbitrary write — ve "girdisini okuduğunda" SMRAM içeriğini geri sızdırır.

Açıklanmış bug'larda iki incelik görülür. Birincisi, mevcut bir kontrol bile yanlış olabilir: bir size alanını (beklenen sabit bir değer yerine) yalnızca sıfıra karşı doğrulamak hâlâ oversized write'lara izin verir. İkincisi, doğrulama dış buffer'ı değil, alanların local copy'sini kullanmalıdır: bir TOCTOU varyantında saldırgan, kontrol ile kullanım arasında CommBuffer'ı mutate eder. Defansif kural aynıdır: copy in, kopyayı doğrula, sonra yalnızca kopya üzerinde işlem yap.

Walkthrough

Aşağıdaki örnekleyici pattern, public EDK2/firmware analizini (NCC Group, SentinelOne) izler. Doğru kontrolü ve temsili bir eksik nested kontrolü gösterir — silahlandırılmış bir handler değildir.

Bir handler önce dış buffer'ı doğrular:

// Correct: outer CommBuffer is checked before any use
if (!SmmIsBufferOutsideSmmValid ((UINTN)CommBuffer, TempCommBufferSize)) {
  return EFI_SUCCESS;   // refuse: buffer overlaps SMRAM
}

Bug, bir nested pointer kontrolsüz dereference edildiğinde ortaya çıkar:

typedef struct {
  UINTN   OpCode;
  UINT8  *BufferPtr;   // attacker-controlled, points anywhere
  UINTN   BufferSize;  // attacker-controlled
} SMM_REQUEST;

SMM_REQUEST *Req = (SMM_REQUEST *)CommBuffer;   // outer buffer was validated

// MISSING: SmmIsBufferOutsideSmmValid((UINTN)Req->BufferPtr, Req->BufferSize)
CopyMem (Req->BufferPtr, InternalSmramSecret, Req->BufferSize);  // leaks/overwrites SMRAM

Beklenen saldırgan sonucu: BufferPtr'ı SMRAM'in içine ayarlayarak CopyMem, kopya yönüne bağlı olarak arbitrary bir SMRAM read ya da write primitive'ine dönüşür — yani ring 0'dan SMM privilege escalation.

Sağlam biçim, her pointer'ı beklenen size ile doğrular ve local bir snapshot üzerinde çalışır:

SMM_REQUEST Local;
CopyMem (&Local, CommBuffer, sizeof (Local));            // snapshot
if (!SmmIsBufferOutsideSmmValid ((UINTN)Local.BufferPtr, Local.BufferSize)) {
  return EFI_SUCCESS;                                     // refuse nested overlap
}
if (Local.BufferSize != EXPECTED_SIZE) return EFI_SUCCESS; // size must match, not just != 0

Detection

  • Firmware'ın static analizi. SMM driver'larını disassemble et (örn. IDA + HexRaysCodeXplorer / HexRaysPyTools ile) ve bir CommBuffer alanını, o nested pointer üzerinde karşılık gelen bir SmmIsBufferOutsideSmmValid() çağrısı olmadan pointer olarak dereference eden SMI handler'ları işaretle.
  • CHIPSEC. SMRAM/TSEG DMA korumasını doğrulamak için smm_dma modülünü; SMI pointer argümanlarını fuzz'layıp olmaması gereken yerde fault üreten ya da yazan handler'ları yüzeye çıkarmak için smm / smm_ptr modüllerini kullan.
  • WSMT flag'i. Windows SMM Security Mitigation Table'ında COMM_BUFFER_NESTED_PTR_PROTECTION'ı kontrol et; yokluğunu bir risk sinyali olarak değerlendir (varlığı tek başına bir garanti değildir).

Mitigation

Her pointer'ın local copy'sini, beklenen size ile doğrula

  • Herhangi bir dereference'tan önce, kontrol ettiğin bir uzunluk kullanarak dış CommBuffer ve her nested pointer üzerinde SmmIsBufferOutsideSmmValid() çağır.
  • Önce CommBuffer'ı SMRAM'e kopyala, sonra yalnızca local copy'yi doğrula ve kullan — bu hem nested-pointer hem de TOCTOU pencerelerini kapatır.
  • Size alanlarını yalnızca sıfıra karşı değil, beklenen sabit değere karşı karşılaştır.
  • AMI firmware'ında, tutarlı kontroller için platform'un AMI_SMM_BUFFER_VALIDATION_PROTOCOL'ünü tercih et; vendor BIOS güncellemelerini uygula (örn. ilgili SMM CommBuffer düzeltmeleri için INTEL-SA-00688 / CVE-2022-21198 gibi Intel advisory'leri).

Ayrıca bkz.: komşu SMM trust-boundary hataları için Binarly SMM callout class.

References