| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | |||||
| 3 | 4 | 5 | 6 | 7 | 8 | 9 |
| 10 | 11 | 12 | 13 | 14 | 15 | 16 |
| 17 | 18 | 19 | 20 | 21 | 22 | 23 |
| 24 | 25 | 26 | 27 | 28 | 29 | 30 |
| 31 |
- System Management Mode
- tp link
- hardware hakcing
- Slab free list poisoning
- SMM
- openwrt
- memory
- ROP
- 커널
- kernel exploit
- 공유기
- UART
- Cross-cache attack
- exit handler overwrite
- 라우터
- mips
- Pwnable
- mr 100
- protection ring
- Kernel
- tl mr 100
- exploit
- linux ring 권한 구조
- 익스플로잇
- fini array
- physmap
- e
- Router
- Today
- Total
haehet
[Linux kernel] 물리 메모리 구조와 PCI driver 본문
워게임 혹은 CTF 문제를 풀다 보면 취약한 PCI drvier를 주고 qemu를 escape하는 형식의 pwnable문제가 간혹 나온다. 이번 글에서는 PCI driver 환경에서 qemu escape를 하기 위해서 알아야 하는 MMIO와 PCI driver interface 등을 정리해보겠다.
1. ZONE

리눅스 커널은 물리 메모리 전체를 ZONE이라는 단위로 나눠서 관리한다. 이는 하드웨어, 장치 제약, DMA 가능성 같은 기준에 따라 물리 메모리를 구분하기 위해서이다.
● ZONE_DMA, ZONE_DMA32: DMA 주소 폭 제약(16MiB/4GiB) 때문에 커널이 장치가 접근 가능한 저주소 RAM에서만 DMA 버퍼를 할당하도록 분리해 둔 메모리 존이다.
● ZONE_NORMAL: 커널이 항상 직접 접근 할 수 있는 메모리이다.
● ZONE_HIGHMEM: 커널이 직접 가상 주소로 매핑하지 않는 물리 메모리이다. (일부 32-bit에서만 활성화 된다.)
2. DMA (Direct Memory Access)와 MMIO (Memory Mapped I/O)
DMA란 디바이스가 물리 메모리 주소를 입력으로 받아 그 주소 범위의 RAM을 직접 read/write 하는 데이터 전송 경로다.
MMIO란 디바이스의 레지스터(명령/설정/상태 등)를 특정 메모리에 매핑 해두고 접근해서 그 디바이스를 제어하는 것을 말한다. MMIO를 하기 위해서는 BAR(Base Address Register)로 할당된 주소를 매핑하고 해당 주소에 쓰기, 읽기 동작을 하면 된다.
3. PCI driver
PCI (Peripheral Component Interconnect)란 컴퓨터에 다양한 주변장치를 연결하기 위한 규격을 말한다. PCI driver란 PCI 규격의 하드웨어를 컴퓨터와 연결하고 정상적으로 작동하게 해주는 소프트웨어이다.
4. CTF helper
위 내용을 바탕으로 PCI driver 문제를 풀 때 쓸만한 helper 함수를 적어두겠다.
1. vrit_to_phys
uint64_t virt_to_phys(uint64_t vaddr){
uint64_t entry;
int pagemap = open("/proc/self/pagemap", O_RDONLY);
off_t offset = (vaddr / 0x1000ULL) * 8;
lseek(pagemap, offset, SEEK_SET);
read(pagemap, &entry, 8);
close(pagemap);
if (!(entry & (1ULL << 63))) { fprintf(stderr, "Page not present check the mapping\n"); exit(1); }
uint64_t pfn = entry & ((1ULL << 55) -1);
return (pfn * 0x1000ULL) + (vaddr & 0xfff); // return physical address
}
현재 프로세스의 가상주소를 넣으면 물리주소로 변환해주는 함수이다. 주로 디바이스에게 물리주소를 전달할 때 사용할 수 있다.
2. map_resource
#define PCI_MMIO_RESOURCE "/sys/bus/pci/devices/0000:00:02.0/resource0"
#define MMIO_SIZE 0x1000
volatile uint8_t *mmio;
void map_resource() {
int fd = open(PCI_MMIO_RESOURCE, O_RDWR | O_SYNC);
if (fd < 0) { perror("Error while open resource"); exit(1); }
mmio = (volatile uint8_t *)mmap(NULL, MMIO_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (mmio == (void *)MAP_FAILED) { perror("Failed mmap for mmio"); exit(1); }
close(fd);
}
mmio 할 주소를 매핑 후 page fault를 일으켜둔다.
5. Typical vulnerabilities
CTF에는 주로 mmio에서 note 같은 system을 구현해두고 uaf나 heap overflow 취약점등을 넣어둔다. 혹은 dma 만의 취약점 (DMA reentrancy)등을 넣을 수도 있다. 보통 익스는 heap 취약점을 이용해 ops필드를 덮거나 혹은 qemu에 있는 TCG(Tiny Code Generator)영역을 shellcode로 overwrite 하면된다.
이번 글에서는 PCI driver 기반 CTF에서 자주 마주치는 ZONE/DMA/MMIO 개념이랑 실전에서 바로 써먹을 수 있는 helper(virt_to_phys, map_resource)를 정리했다. 이 글에서 설명한 것 외에도 qemu 관련된 trick(rep stosb 재귀 참조)이 많으니 찾아서 공부해보도록하자.
reference: https://docs.kernel.org/mm/physical_memory.html
https://mchehab.fedorapeople.org/kernel_docs/driver-api/device-io.html
https://en.wikipedia.org/wiki/Memory-mapped_I/O_and_port-mapped_I/O
https://unix.stackexchange.com/questions/5143/zone-normal-and-its-association-with-kernel-user-pages
'Linux kernel' 카테고리의 다른 글
| [Linux Kernel] 메모리 관리 2편: Page Allocator (PCP & Buddy System) (0) | 2026.01.09 |
|---|---|
| [Linux Kernel] 메모리 관리 1편: TLB와 Page Table Walk: Multi Level paging 동작 원리 (0) | 2026.01.08 |
| [Linux kernel] 링 권한 구조와 SMM(System Management Mode) (0) | 2026.01.06 |
| [Linux kernel] memory map 정리 (0) | 2025.12.31 |
| [Linux kernel] 보안 기법 정리 (0) | 2025.12.30 |
