Skip to content

/proc/PID/pagemap physical address leak

/proc/PID/pagemap içindeki page başına 64-bit girişleri okuyarak bir virtual address'i physical frame number'ına çevir ve userspace'e bir virtual→physical oracle ver.

Mechanism

Note

/proc/PID/pagemap, virtual page başına bir 64-bit giriş açığa çıkarır. Present bir page için bit 63 set'lidir ve bit 0–54 page frame number'ı (PFN) tutar. Dosyayı (vaddr / PAGE_SIZE) * 8 konumunda indekslemek vaddr için girişi verir ve physical address phys = (PFN << PAGE_SHIFT) | (vaddr & (PAGE_SIZE - 1))'dir. Bu, userspace bir process'e bir virtual→physical translation oracle'ı sunar — tam olarak physical-memory saldırılarının (Rowhammer templating, DMA, cache eviction-set kurma) ihtiyaç duyduğu şey.

Giriş bit layout'u (present page):

Bits 0-54   page frame number (PFN) if present
Bit  55     pte is soft-dirty
Bit  56     page exclusively mapped (since 4.2)
Bits 57-60  zero
Bit  61     page is file-page or shared-anon (since 3.5)
Bit  62     page swapped
Bit  63     page present

Swapped page: bit 0–4 = swap type, bit 5–54 = swap offset.

Walkthrough

Kendi process'inde bir vaddr virtual address'i için PFN'i çöz:

uint64_t entry, pfn, phys;
int fd = open("/proc/self/pagemap", O_RDONLY);
off_t off = (vaddr / 0x1000) * sizeof(uint64_t);
pread(fd, &entry, sizeof(entry), off);

if (entry & (1ULL << 63)) {                 /* present */
    pfn  = entry & ((1ULL << 55) - 1);      /* bits 0-54 */
    phys = (pfn << 12) | (vaddr & 0xfff);
}

Warning

Kernel >= 4.2'de CAP_SYS_ADMIN olmadan PFN alanı 0 olarak geri okunur — dosya yine açılır, ama entry & ((1ULL<<55)-1) sıfırdır, dolayısıyla translation başarısız olur. Bit 63'ü set yapmak için önce page'e dokun (yaz), aksi hâlde present olmaz.

Detection

/proc/self/pagemap'i açıp sıfır olmayan PFN'ler okuyan izlenen bir process'in CAP_SYS_ADMIN taşıdığı anlaşılır; unprivileged context'lerden gelen pagemap okumalarını denetlemek bir phys-map oracle kurma girişimlerini işaretler.

Mitigation

Kernel pagemap dokümantasyonundan:

  • Linux 4.0'dan beri yalnızca CAP_SYS_ADMIN'e sahip user'lar PFN edinebilir.
  • 4.0 ve 4.1'de unprivileged open() -EPERM ile başarısız olur.
  • 4.2'den beri dosya açılır ama CAP_SYS_ADMIN'i olmayan caller'lar için PFN alanı sıfırlanır.

Belirtilen gerekçe: "PFN'ler hakkındaki bilgi Rowhammer'ı exploit etmeye yardımcı olur."

References