Dirty Pagetable 기법에 대해 알아보자.
간략하게 설명하면, cross-cache attack을 이용해서 pagetable을 원하는 victim object가 속한 page로 할당이 되도록 하는 방법이다.
이렇게 되면, victim object를 이용해서 pagetable을 임의의 physical address의 값을 가리키게 하여 그 physical address의 값을 원하는 값으로 수정할 수 있게 된다.
cross-cache attack을 사용하기에 앞서서 하나 추가로 알아야 할 내용이 있다.
우선 buddy allocator에 대해 간단히 설명하고 넘어간다.
buddy allocator에서는 free pages를 order 별로 나누어 list 형태로 관리한다. 즉, page_size * 2^(order)
가 크기에 해당한다.
struct zone {
...
/* free areas of different sizes */
struct free_area free_area[MAX_ORDER]; // here! x86 MAX_ORDER = 11
/* zone flags, see below */
unsigned long flags;
/* Primarily protects free_area */
spinlock_t lock;
/* Write-intensive fields used by compaction and vmstats. */
ZONE_PADDING(_pad2_)
...
} ____cacheline_internodealigned_in_smp;
struct free_area
구조체를 통해서 free_area의 list가 저장된다.
page alloc을 하면 이 list의 맞는 order에서 꺼내와 할당하고, order에 맞는 크기가 없으면 더 큰 order에서 메모리를 반으로 나누어 그 중 하나를 할당받고 하는 식으로 동작한다.
buddy system에 대해서는 나중에 자세하게 정리해 볼 예정이다.
하지만, 여기서 추가로 알아야 할 점이 있다.
struct free_area {
struct list_head free_list[MIGRATE_TYPES];
unsigned long nr_free;
};
바로 struct free_area
구조체인데, 자세히 보면 list가 멤버변수로 있는 것은 맞지만 MIGRATE_TYPES
크기의 배열로 list가 생성되어 있는 것을 확인할 수 있다.
buddy allocator에서 메모리를 관리할 때, 모두 하나의 전체적인 메모리에서 할당하는 것이 아니라, migrate types에 따라 관리되는 영역을 나눠놓고, 페이지 할당 시 요청한 migrate types를 확인한 후, 해당 type에 맞는 영역에서 페이지를 할당해 주는 방식으로 동작한다.
그래서 여기서 알 수 있는 점은, cross-cache attack의 경우 slab을 free 시켜서 page allocator로 이동시킨 후 다시 재할당을 하는 원리를 이용하는 것인데, 만약 free한 page와 alloc할 page의 migrate type이 다르게 되면 의도한 대로 재할당이 되지 않을 것이다.
물론, 무조건 한 migrate type 내에서만 할당되는 것이 아니긴 하다.
만약 하나의 type에서의 남은 메모리가 없는 경우, 다른 type에서 메모리를 할당 받는 경우도 존재한다.
-> 나중에 buddy allocator를 정리하면서 같이 다루어 볼 예정이다.
cross-cache attack을 통해 victim object가 포함된 pagetable을 만드는 방법에 대해 설명한다.
우선, victim object가 포함된 page는 free 되었다는 상황을 전제로 한다.
이 상태에서 mmap을 통해 spray를 진행하게 되면 여러 pagetable이 할당되는 과정에서 victim object가 포함된 pagetable이 할당되게 된다.
물론 mmap은 memory를 할당할 때가 아니라 메모리에 접근할 때 실제 메모리가 매핑되므로 이 점을 고려해야 한다.
여기서 한 가지 의문이 들 수 있는게,
mmap을 통한 spray를 통해 pagetable을 할당을 하는데, 그러면은 victim object가 속한 page가 pagetable로 할당될 확률과 실제 mmap을 통해 매핑된 page로 할당될 확률을 비교해 보면, 당연히 후자의 확률이 높다는 것을 알 수 있을 것이다.
그러면 dirty pagetable 기법은 확률에 의존 (심지어 별로 높지도 않음) 한 기법인 걸까?
여기서 앞서 설명했던 migrate type이라는 개념이 쓰이게 된다.
간단하게만 설명하겠다.
pagetable의 경우 MIGRATE_UNMOVABLE
type이고, 실제 할당된 page는 MIGRATE_MOVABLE
type에 해당한다.
또한, 일반적인 kmalloc-xx
형태의 kmem_cache
의 경우, 그리고 여러 dedicated kmem_cache의 경우에도 MIGRATE_UNMOVABLE
에 해당한다.
위 내용을 바탕으로 할당받은 page가 아닌, pagetable이 victim object를 포함하게끔 된다는 것이 설명된다.
또한, 기본적인 cross-cache attack이 가능했던 이유도 같이 살펴보자면 kmalloc-xx
와 dedicated kmem_cache 둘 다 MIGRATE_UNMOVABLE
에 해당했기 때문이다.
https://ptr-yudai.hatenablog.com/entry/2023/12/08/093606
https://hyeyoo.com/155
https://jeongzero.oopy.io/5ab007c6-ae0a-4a26-a0cc-b88a8fcfd732
https://blog.csdn.net/qq_61670993/article/details/136115905
https://tooson.tistory.com/m/2