init_pg_dir 도입 패치 분석
Purpose
해당 패치의 목적은 KSMA(Kernel Space Mirroring Attack)을 어렵게 만드는 것이다.
Patch series
-
arm64/mm: Separate boot-time page tables from swapper_pg_dir
-
arm64/mm: use fixmap to modify swapper_pg_dir
-
arm64/mm: move runtime pgds to rodata
KSMA
해당 공격 기법은 2018 Black hat에서 소개되었다. KSMA는 ARM MMU feature을 이용하고, EL0(user)에서 시스템 콜 없이 커널 이미지에 Read/Write 할 수 있게 된다.
Linux kernel은 아래 그림처럼 여러 단계의 변환을 통해 물리 주소로 변환된다.
ARM MMU의 각 단계의 변환 테이블들은 엔트리를 가지고 있다. 엔트리들은 3가지 타입으로 구성된다.
-
Table descriptor
-
Block descriptor
-
Page descriptor
이 중에서 물리 메모리 주소를 저장하는 엔트리는 Block, Page descriptor이다. 이 두 엔트리들은 매핑된 메모리에 관한 속성들을 아래와 같이 저장한다.
그 중에서 AP 필드는 Read/Write 권한을 저장한다. AP가 가질 수 있는 값들은 아래의 테이블과 같다.
이때 AP가 01일 때, Exception Level 0일 때도 Read/Write 할 수 있다.
따라서, pgd로 사용되는 swapper_pg_dir에 AP가 01로 설정된 block descriptor를 삽입하는 것이 핵심이다.
아래 그림은 swapper_pg_dir에 커널 이미지 영역을 매핑하는 block descriptor을 넣은 모습이다.
물리 메모리 0x3002000에 접근할 때, Direct mapping된 가상 주소나 KSAM을 통한 가상 주소를 통해 접근할 수 있다.
Direct mapping
Virtual Addess: 0xFFFFFFC03002000 -> Physical Address: 0x3002000
EL1에서만 접근가능하다.
KSAM
Virtual Addess: 0xFFFFFFC23002000 -> Physical Address: 0x3002000
EL0에서도 Read/Write 가능하다.
Basic idea
공격의 대상이 되는 swapper_pg_dir을 rodata로 옮기자!
문제 : 불필요한 페이지들도 rodata로 묶인다.
해결 방안 : 부팅 단계의 페이지 테이블과 정규 페이지 테이블로 분리한다.
문제 : swapper_pg_dir에 값을 쓸 방법을 제공해야 한다.
해결 방안 : fixmap에 매핑한 다음 해당 주소를 사용한다.
결과:
1. 부팅 초기 단계에 수행했던 swapper_pg_dir의 역할은 init_pg_dir로 대체된다.
2. swapper_pg_dir은 한 페이지로 축소되며, rodata 섹션에 위치하게 된다.
3. init_pg_dir이 추가되어 page_init에서 새로운 pgd를 할당받지 않아도 된다.
4. swapper_pg_dir에 값을 쓰기 위해서는 fixmap에 매핑해야 한다.
.
감사합니다