Вот как раз "не видит" тут и не сработало. Гостевая машина просит: "а сделай ка мне условный переход, проверив ячейку памяти по такому-то, запрещённому адресу. Если условие выполняется - перейди сюда."
Операция заканчивается отказом от модуля управления памятью. Дескать не положено! И тут ушлый гость раз! И делает обращение по адресу, куда просил, если условие выполняется. И засекает время.
Из-за своей многостадийности, конвейер ядра успевает сделать проверку до того, как адрес будет проверен модулем управления памятью. И успевает прогрузить в кеш адрес перехода по условию.
И хотя выполнение кода гостя получило исключение вместо перехода или не перехода по условию, теперь, по времени доступа, можно угадать, сработало условие (адрес в кеш) или нет (адрес долго читался из памяти).
Теперь, модифицируя условия и повторяя операцию много раз, можно выяснить содержимое ячейки по тестируемому адресу. Таким образом, можно сканировать, читать память хоста по произвольным адресам.
Конечно, на практике очень трудно это сделать - такое "чтение" ненадёжное и долгое, и не зная, где что лежит, можно потратить вечность на поиски. Но сама принципиальная возможность атаки есть и подтверждена экспериментально.