Intel Memory Protection Key

Ahn9807 (토론 | 기여)님의 2023년 2월 3일 (금) 06:28 판 (새 문서: 분류: 하드웨어 기반 보안 == 개요 == Intel MPK는 intel에 의해서 skyylake이후부터 적용되기 시작한 Memory Protection 방식중에 하나로, protection key를 통해서 메모리를 보장하는 방식이다. (기존 방식인 segmentation, Paging에 추가함). MPK는 PTE에 기존에 사용하지 않은 비트 PK(32~35)의 4개의 비트를 사용해서 지금 메모리가 어디에 속해있는지 마킹한다. 이떄 이러한 마킹은...)
(차이) ← 이전 판 | 최신판 (차이) | 다음 판 → (차이)


개요

Intel MPK는 intel에 의해서 skyylake이후부터 적용되기 시작한 Memory Protection 방식중에 하나로, protection key를 통해서 메모리를 보장하는 방식이다. (기존 방식인 segmentation, Paging에 추가함). MPK는 PTE에 기존에 사용하지 않은 비트 PK(32~35)의 4개의 비트를 사용해서 지금 메모리가 어디에 속해있는지 마킹한다. 이떄 이러한 마킹은 kernel mode로 이루어져야 한다. 이러한 변경은 pkey_mprotect란 시스템콜을 이용하여 이루어진다.

MPK는 각각의 키들이 어떤 Protection group에 속해있는지 표기하기 위해서 PKRU레지스터를 사용한다. PKRU 레지스터는 u32로 표현되며 각각의 2비트가 해당하는 키에 대한 permission을 나타낸다. 각 비트는 (AD_access disable, WD_write disable)로 나타내지며,

  • read/write: (0,0)
  • read only: (0,1)
  • no access: (1,x) (만약 mprotect가 execute 로 되어 있다면, 이 부분의 메모리 영역은 execution only 영역이 된다.)

로 permission을 구별한다.

WRPKRU는 PKRU의 permission정보를 업데이트 하며, RDPKRU명령어는 현재 PKRU레지스터의 permission정보를 읽어 온다. 이를 위해서 EAX레지스터로 정보를 소통하며 특히 ECX, EDX레지스터를 0으로 초기화 하여 넘겨주어야 한다. RDPKRU/WRPKRU는 이 3개의 레지스터를 사용하여 PKRU에 접근하고 permission을 수정한다.

MPK

Memory protectino key방식은 physical memory를 여러 특정한 크기의 청크로 나누고, 각각의 청크에 지정된 키를 제공함으로써 주어진 키에 대한 access permision을 변경하는 방식으로 메모리 접근을 조절할 수 있다. Intel MPK는 메모리 페이지 마다 protection key를 4개의 비트를 사용함으로써 즉 16개의 구분되는 키로 페이지들을 구분한다. 같은 키에 소속된 페이지들은 같은 page group에 소속된다고 볼 수 있으며 WRPKRU를 통해서 키에 대한 permission을 설정하고 WRPKRU를 통해서 키에 대한 permission을 읽어온다.

MPK in Linux

리눅스 시스템콜은 pkey_mprotect, pkey_alloc, pkey_free의 3가지 시스템콜을 통해서 MPK기능을 제공한다. (kernel version > 4.6 libc > 2.27 부터 제공함)

시스템 콜

int pkey_alloc(unsigned long flags, unsigned long ini_access_rights);
pkey alloc은 주어진 flag와 access right에 대한 key를 발급받는다.
int pkey_free(int pkey);
key를 등록 해제 한다.
int pkey_mprotect(unsigned long start, size_t len, unsigned long protection, int pkey);
주어진 key에 대하여 memory protection을 설정한다. 

libc

int pkey_set (int key, unsigned int rights)
현재 스레드의 key에 대한 access right을 설정한다. (pkey_alloc으로 할당된 키를 사용해야 한다.)
int pkey_get (int key)
현재 스레드의 key의 permission을 가져온다. 

성능

  • RDPKRU는 일반적인 register접근과 비슷한 성능
  • WDPKRU는 pipeline flushing과 같은 serialization을 수행하기 때문에 out-of-order수행을 저지함. 즉 성능 하락이 있음.
  • pkey_mprotect와 mprotect는 내부적으로 동일한 로직을 사용하기 때문에 성능이 비슷함.
  • pkey_alloc과 pkey_free의 로직은 단순함. 즉 kernel context swtiching cost가 대부분의 성능하락의 원인임.
  • mprotect와 다르게 pkey는 내부 커널 VMA (virtual memory area)구조체의 파편화에 영향을 받지 않음. 따라서 pages크기가 증가함에 따라 linear하게 성능이 하락하는 mprotect와는 다르게 constant한 성능하락을 보여줌.

참고

  1. https://charlycst.github.io/posts/mpk/
  2. https://www.gnu.org/software/libc/manual/html_node/Memory-Protection.html
  3. LibMPK: Software abstraction for intel memory protection keys (Intel MPK)