Supponendo che il sistema operativo assegni le pagine in modo completamente casuale, il mio calcolo migliore dice che c'è una probabilità dell'11% che ogni dato indirizzo della vittima abbia almeno 12 pagine corrispondenti nel buffer da 4MB. Non è molto probabile, e certamente non concorda con il tasso di successo del 70% che hai visto.
Tuttavia, ci sono buone ragioni per un sistema operativo per evitare di mappare le pagine in modo casuale, e invece di fare del suo meglio per mappare le pagine contigue. Una delle ragioni è che a volte il sistema operativo deve allocare buffer contigui di grandi dimensioni (per supportare pagine enormi o buffer DMA di grandi dimensioni, ad esempio) e l'assegnazione casuale di pagine fisiche renderebbe davvero difficile trovare un'area sufficientemente ampia. Questo è noto come frammentazione della memoria.
Ma nel contesto di questa discussione, un vantaggio più interessante dell'allocazione contigua è (abbastanza ironicamente) la prestazione della cache di livello 3. Se si sta eseguendo un algoritmo che utilizza un buffer di memoria di grandi dimensioni, il modo migliore per ottenere le prestazioni è allocare memoria fisica contigua, in modo che le singole pagine non si escludano a vicenda dalla cache. Se il sistema operativo riesce a massimizzare le prestazioni in questo modo, riuscirà anche a massimizzare l'efficacia dell'attacco: il tuo buffer da 4 MB coprirà l'intera cache e avrai il 100% di possibilità di sfrattare una pagina della vittima. Quindi il tasso di successo osservato del 70% è meno una misura del caso, e più una misura approssimativa di quanto sia efficace il sistema operativo nell'allocare le pagine per ottenere buone prestazioni della cache.
Se vuoi vedere un esempio di un sistema operativo che funziona in questo modo, leggi su Linux allocatore di amici . Inizia interrompendo la memoria in un insieme di grandi blocchi liberi. Quindi, se vuole allocare una pagina, prende uno di quei grandi blocchi e lo divide a metà. Prende quindi una delle metà e la divide nuovamente a metà e continua fino a quando non ha un blocco di 1 pagina - a quel punto ha anche un blocco di 2 pagine, uno di 4 dimensioni, uno 8-sized, ecc. Le prime due allocazioni saranno quei due blocchi di 1 pagina, che sono uno accanto all'altro perché sono il risultato della rottura di un blocco di 2 pagine a metà. La terza allocazione spezzerà l'altro blocco di 2 pagine a metà, che sarà di nuovo prossimo agli altri due per gli stessi motivi.
Quindi ogni volta che ha bisogno di una nuova pagina, l'allocatore prende il blocco più piccolo che riesce a trovare e lo scompone finché non ha una singola pagina. Infine, quando una pagina viene liberata, l'allocatore verifica se c'è una pagina libera proprio accanto ad essa, in modo che possa ridistribuire quelle due pagine in un blocco più grande. L'effetto netto è di mantenere le allocazioni approssimativamente contigue quando possibile.