Skip to content

SPARC Application Data Integrity

SPARC M7+ üzerinde her 64-byte block'u ve ona ulaşmak için kullanılan pointer'ları tag'leyen, bir load/store'un pointer version'ı target memory'nin version'ı ile uyuşmadığında trap üreten hardware memory-versioning.

Mechanism

Note

Kavramsal: NEDEN çalışır, invariant/teori.

Silicon Secured Memory olarak da pazarlanan Application Data Integrity (ADI), SPARC M7, M8, S7, T7 ve T8 processor'larında implemente edilmiştir. Aynı anda iki şeye küçük bir version number iliştirir: physical memory'ye (her 64-byte ADI block başına — bir cacheline ile aynı boyut) ve o memory'ye ulaşmak için kullanılan virtual address'in üst bitlerine. Her load ve store'da MMU, pointer'da encode edilen version'ı target block için saklanan version ile karşılaştırır; uyuşmazlıkta bir exception üretir.

Invariant şudur: "memory'yi yalnızca doğru color'ı taşıyan bir pointer üzerinden dereference edebilirsin." Bu, çoğu memory-corruption exploit'inin altında yatan iki bug sınıfını doğrudan yakalar:

  • Linear buffer overflow'lar: bitişik allocation'lar farklı version'larla color'lanır, böylece bir buffer'ın sonunu aşıp bir sonrakine giren bir write yanlış version ile dereference edilir ve trap'ler.
  • Stray / dangling pointer dereference (use-after-free): memory free edilip yeniden color'landığında, bayat bir pointer hâlâ eski version'ı taşır ve kullanımda trap'ler.

SPARC M7'de version tag, virtual address'in bit 63-60'ını işgal eder (4 bit → 16 değer). İki değer reserve'dür: 0x0 ve 0xf herhangi bir target version ile eşleşir ve bu yüzden asla bir uyuşmazlık üretmez — herhangi-color'lı memory'ye meşru şekilde dokunabilen bir "wildcard" pointer için kullanışlı. Bir task açıkça opt-in yapmalıdır: kernel, versioning etkili olmadan önce task için PSTATE.mcde'yi (MCD enable) ve ilgili TLB entry'lerinde TTE.mcd'yi set eder.

İki trap çeşidi vardır. Bir precise exception (MCDPERR=1) senkron olarak ateşlenir ve si_code = SEGV_ADIPERR ile SIGSEGV teslim eder; bir disrupting exception asenkrondur (suçlu erişimden biraz sonra ortaya çıkabilir) ve si_code = SEGV_ADIDERR ile SIGSEGV teslim eder.

Walkthrough

Linux kernel'i ADI parametrelerini auxiliary vector'lar üzerinden sunar, böylece bir program granule ve tag width'ini hardcode etmek yerine runtime'da keşfedebilir:

#include <sys/auxv.h>
#include <stdio.h>

int main(void) {
    unsigned long blksz = getauxval(AT_ADI_BLKSZ);  /* ADI block size, bytes */
    unsigned long nbits = getauxval(AT_ADI_NBITS);  /* number of version bits */
    printf("ADI block size = %lu bytes, version bits = %lu\n", blksz, nbits);
    return 0;
}

ADI-capable bir M7-sınıfı makinede beklenen:

ADI block size = 64 bytes, version bits = 4

Bir bölgeyi enable etme ve tag'leme (Linux modeli):

  1. Mapping'i mprotect(addr, len, PROT_READ | PROT_WRITE | PROT_ADI) ile ADI-capable işaretleyin. Kernel, task için PSTATE.mcde'yi ve TLB entry'lerinde TTE.mcd'yi set eder.
  2. Aralıktaki her ADI block üzerinde iterate ederek, ASI ASI_MCD_PRIMARY (veya ASI_MCD_ST_BLKINIT_PRIMARY) ile stxa store'unu kullanarak her 64-byte block'u seçilen bir version ile damgalayın.
  3. Memory'ye, bit 63-60'ı o aynı version'ı encode eden bir virtual address üzerinden erişin (ör. version 0xa → top nibble'ında 0xa olan adresler).

Solaris'te eşdeğer kontroller library/syscall tabanlıdır: memcntl(2) / mmap(2) page'lerde ADI'yi enable eder, meminfo(2) ADI durumunu sorgular, pmap(1) hangi mapping'lerin ADI açık olduğunu raporlar ve libadimalloc, her malloc() chunk'ını otomatik olarak color'layan ADI-aware bir allocator'dır. Data-transfer syscall'ları (read(), write(), copyin()/copyout(), uiomove(), …) de version'ları onurlandırır ve uyuşmazlıkta hata döner.

Warning

Wildcard version'ları 0x0 ve 0xf, hassas bir pointer bir wildcard color'da bırakılırsa korumayı yener ve 4-bit tag yalnızca 14 ayırt edilebilir non-wildcard color demektir — bitişik allocation'lar şans eseri bir version'da çakışabilir, bu yüzden ADI spatial safety için probabilistiktir, sert bir bounds check değil.

Detection

Bir version uyuşmazlığı, process'e si_code == SEGV_ADIPERR (precise) veya SEGV_ADIDERR (disrupting) ile SIGSEGV olarak ortaya çıkar; bir fault handler veya fuzzer harness'i, crash'i sıradan bir page fault yerine ADI'ye atfetmek için siginfo'yu inceleyebilir.

References