what is SMEP & SMAP
주로 SMEP (Supervisor Mode Execution Prevention) SMAP (Supervisor Mode Access Prevention)
SMEP (Supervisor Mode Execution Prevention)
한 줄 요약: 커널이 유저 페이지에 있는 코드를 실행하려고 하면 CPU가 예외를 터뜨림.
- 무엇을 막나?
- 커널 RIP가 유저 영역(정확히는 페이지 테이블 엔트리의 U/S 비트가 User로 표시된 페이지)에 있는 코드로 점프해서 실행하려는 상황
- 즉 커널에서 jmp 0x7f...(유저 매핑) 같은 식으로 유저에 둔 쉘코드를 실행하려 하면 막힘 → ret2usr 핵심이 여기서 꺾임
- 어떻게 동작하나?
- CPU가 현재 CPL=0(Supervisor) 인 상태에서 instruction fetch가 “User 페이지”에서 일어나면 fault.
- 그래서 “커널 권한 얻었으니 유저 메모리에 둔 shell()로 iretq 복귀해서 실행” 같은 흐름이 막히는 경우가 많음(상황에 따라 #PF/#GP로 보일 수 있음).
- 어디에 켜져 있나?
- x86-64 기준으로 **CR4의 SMEP 비트(일반적으로 bit 20)**가 1이면 활성화.
- 확인 방법(리눅스)
- cat /proc/cpuinfo | grep -Eo 'smep|smap' | sort -u
- 또는 커널 부팅 로그(dmesg)에 “SMEP” 언급이 뜨는 경우도 있음(근데 환경에 따라 권한 제한 있을 수 있음).
SMAP (Supervisor Mode Access Prevention)
한 줄 요약: 커널이 기본적으로 유저 페이지를 읽거나 쓰는 것 자체를 막음. (실행이 아니라 데이터 접근까지)
- 무엇을 막나?
- 커널이 유저 포인터를 그대로 믿고 *user_ptr을 읽거나 쓰는 실수를 했을 때의 피해(정보 유출/임의 쓰기)를 크게 줄임.
- 익스플로잇 관점에서는 “커널 ROP에서 유저 메모리에 만들어 둔 가짜 구조체/ROP 체인/문자열(/bin/sh) 등을 커널이 참조”하는 패턴이 막힘.
- 핵심 포인트: STAC/CLAC
- SMAP이 켜져 있어도 커널은 정상 동작을 해야 하니까,
- STAC: 커널이 “지금부터는 유저 메모리 접근 허용”을 잠깐 켬(AC 플래그 세팅)
- CLAC: 다시 유저 접근을 막음(AC 플래그 클리어)
- 리눅스의 copy_to_user, copy_from_user 같은 경로가 이런 식으로 “짧은 구간만 허용”하도록 구현되는 게 전형적이에요.
- SMAP이 켜져 있어도 커널은 정상 동작을 해야 하니까,
- 어디에 켜져 있나?
- x86-64 기준으로 **CR4의 SMAP 비트(일반적으로 bit 21)**가 1이면 활성화.
ret2usr와의 관계를 딱 정리하면
- SMEP: 커널이 유저land 코드를 실행하는 ret2usr를 직접 타격
- SMAP: 커널이 유저land 데이터/체인/구조체를 참조하는 ret2usr(및 많은 커널 익스플로잇 편법)를 타격
- 그래서 “SMEP+SMAP 둘 다 켜짐”이면 보통
- 커널에서 바로 유저 함수로 점프(실행)도 안 되고(SMEP),
- 커널 ROP가 유저 메모리에 놓인 체인/데이터를 만지는 것도 까다로워져(SMAP),
- 결과적으로 “커널 내부의 정상 코드 경로”를 더 많이 이용해야 하는 방향으로 난이도가 올라가요.
원하면 네가 쓰는 커널(버전/CONFIG, QEMU 옵션) 기준으로 **“지금 실제로 SMEP/SMAP이 켜져 있는지, 켜져 있다면 GDB에서 CR4를 어떻게 읽어서 확인하는지”**까지 딱 디버깅 관점으로 이어서 설명해줄게.
맞아. SMAP만 켜져 있으면(=SMEP는 꺼져 있으면) 커널(CPL=0)이 유저 페이지의 “코드 실행” 자체는 원칙적으로 막지 못해.
SMAP은 “실행(fetch)”이 아니라 유저 페이지에 대한 데이터 접근(load/store) 을 막는 기능이라서 그래.
다만 주의할 점이 2개 있어:
- ret2usr가 의미하는 게 “커널 모드로 유저 페이지 코드를 실행(CPL=0 유지)” 인 경우라면
→ SMAP은 실행은 허용해도, 그 코드가 실행 중에 유저 메모리(자기 코드 옆의 데이터 포함)를 읽거나 쓰려 하면 SMAP 때문에 터질 수 있어(커널이 AC=0 상태면).
- iretq로 CPL=3(유저 모드)로 돌아가서 유저 코드 실행하는 경우는
→ 그건 애초에 커널이 유저 페이지를 실행하는 게 아니라 “유저가 유저 페이지 실행”이라 SMEP/SMAP이 관여할 대상이 아님(둘 다 Supervisor에 대한 제한이라서).
정리:
- 커널 모드에서 유저 코드 실행을 직접 막는 건 SMEP
- 커널 모드에서 유저 메모리 데이터를 못 만지게 하는 건 SMAP (필요할 때만 STAC/CLAC로 잠깐 허용)