핵심 인사이트 (3줄 요약)
- 본질: 가드 페이지 (Guard Page)는 스레드 스택 끝에 배치된 매핑되지 않은(unmapped) 메모리 페이지로, 스택이 한계를 초과하여 확장될 때 하드웨어 예외(SIGSEGV)를 발생시켜 조용한 메모리 손상을 방지한다.
- 가치: 스택 오버플로우는 버퍼 오버플로우 공격의 주요 공격 벡터이며, 가드 페이지 없이는 인접 메모리를 덮어써 보안 취약점을 유발한다.
- 융합: 메모리 관리 유닛(MMU)의 페이지 보호 메커니즘을 활용하며, 컴파일러의 스택 프로브(stack probe) 기법과 결합하여 확장 가능한 스택을 구현한다.
Ⅰ. 개요 및 필요성
-
개념: 각 스레드는 독립적인 스택을 가지며, 스택 크기는 고정되어 있다(기본 1~8MB). 가드 페이지는 스택 영역의 끝에 위치한 매핑되지 않은 페이지로, 스택 포인터가 이 영역을 침범하면 CPU가 페이지 폴트를 발생시킨다.
-
필요성: 스택 오버플로우가 발생하면 스택 포인터가 인접 메모리(힙, 다른 스레드의 스택 등)를 덮어쓰다. 이는 재현이 어려운 잠재적 메모리 오류로 이어지며, 보안 관점에서는 공격자가 return 주소를 조작하여 임의 코드를 실행할 수 있는 스택 스매싱(Stack Smashing) 공격의 토대가 된다.
-
💡 비유: 가드 페이지는 "스키장 너머 경고선"과 같다. 스키장을 넘어가려 하면 경보가 욨려 사고를 막아준다.
┌──────────────────────────────────────────────────────────┐
│ 스레드 스택 메모리 레이아웃 │
├──────────────────────────────────────────────────────────┤
│ │
│ 높은 주소 │
│ ┌──────────────────┐ │
│ │ │ │
│ │ 스택 영역 │ ← 함수 호출 시 아래로 확장 │
│ │ (mapped) │ (SP가 낮은 주소로 이동) │
│ │ │ │
│ │ 지역 변수 │ │
│ │ 매개변수 │ │
│ │ 반환 주소 │ │
│ │ │ │
│ ├──────────────────┤ ← 스택 포인터(SP) │
│ │ ████████████████ │ ← 가드 페이지 (unmapped) │
│ │ (Guard Page) │ 접근 시 SIGSEGV 발생 │
│ ├──────────────────┤ │
│ │ 힙 / 다른 메모리 │ │
│ └──────────────────┘ │
│ 낮은 주소 │
│ │
│ 스택 확장 방향: 높은 주소 → 낮은 주소 │
└──────────────────────────────────────────────────────────┘
[다이어그램 해설] 스택은 높은 주소에서 낮은 주소 방향으로 확장된다. 함수가 호출될 때마다 스택 포인터(SP)가 낮아지며, 로컬 변수와 반환 주소가 스택에 저장된다. 가드 페이지는 이 확장 경로의 끝에 위치한 unmapped 페이지로, SP가 가드 페이지에 도달하면 CPU가 페이지 폴트를 생성하고 커널이 SIGSEGV 시그널을 전송한다. Linux에서는 pthread_attr_setguardsize()로 가드 페이지 크기를 설정할 수 있으며(기본 보통 1페이지=4KB), 여러 페이지를 할당하여 더 넓은 오버플로우 감지 범위를 확보할 수 있다.
- 📢 섹션 요약 비유: 가드 페이지는 "엘리베이터의 바닥 센서"와 같습니다. 바닥에 닿으면 엘리베이터가 정지하여 추락을 막아주죠.
Ⅱ. 아키텍처 및 핵심 원리
구현 메커니즘
| 요소명 | 역할 | 특징 |
|---|---|---|
| mmap PROT_NONE | 가드 페이지 생성 | 매핑되지 않은 페이지로 물리 메모리 소모 없음 |
| SIGSEGV | 오버플로우 시그널 | 스택 오버플로우 시 커널이 프로세스에 전송 |
| pthread_attr_setstacksize | 스택 크기 설정 | 기본 8MB(RHEL), 2MB(Windows) |
| pthread_attr_setguardsize | 가드 크기 설정 | 기본 보통 4KB(1페이지) |
| 스택 프로브 (Stack Probe) | 확장 가능 스택 | 컴파일러가 스택 한계 근처에서 probe를 삽입 |
- 📢 섹션 요약 비유: 가드 페이지는 전기 퓨즈의 "과부하 차단기"와 같습니다. 정격을 초과하면 회로를 보호하기 위해 자동으로 차단됩니다.
Ⅲ. 융합 비교 및 다각도 분석
| 비교 항목 | 가드 페이지 | 스택 카나리 (Canary) |
|---|---|---|
| 감지 방식 | 하드웨어 페이지 폴트 | 소프트웨어 무결성 검사 |
| 위치 | 스택 끝(하위 주소) | 반환 주소 앞(상위 주소) |
| 방어 방향 | 스택이 아래로 커질 때 감지 | 위로 덮어쓰는 공격 감지 |
| 성능 영향 | 없음 (페이지 폴트 시에만) | 함수 진입/퇴장마다 검사 |
- 📢 섹션 요약 비유: 가드 페이지는 스택의 "바닥 경보", 스택 카나리는 "천장 경보"입니다. 두 가지를 모두 사용하면 위아래 모든 방향의 공격을 감지할 수 있습니다.
Ⅳ. 실무 적용 및 기술사적 판단
안티패턴
-
스택 크기 과소 추정: 재귀 함수나 대규모 로컬 배열 사용 시 기본 스택 크기로 부족할 수 있다. ulimit -s로 확인하고 pthread_attr_setstacksize()로 조정해야 한다.
-
가드 페이지 생략: 임베디드 메모리가 극소적인 환경에서 가드 페이지를 생략하면 스택 오버플로우가 인접 메모리를 조용히 파괴한다.
-
📢 섹션 요약 비유: 스택 크기를 모를 때는 항상 "최악의 경우"를 고려해야 합니다. 평소에는 작은 스택이라도 예외 처리 경로에서 갑자기 커질 수 있거든요.
Ⅴ. 기대효과 및 결론
- 📢 섹션 요약 비유: 가드 페이지는 저렴한 보험료로 큰 재해를 막는 "최소 안전장치"입니다. 4KB의 빈 페이지 하나가 시스템 전체의 붕괴를 막을 수 있습니다.
📌 관련 개념 맵 (Knowledge Graph)
| 개념 명칭 | 관계 및 시너지 설명 |
|---|---|
| 스레드 스택 (Stack) | 가드 페이지가 보호하는 대상. 독립적인 메모리 영역 |
| SIGSEGV | 가드 페이지 접근 시 발생하는 시그널 |
| 스택 카나리 (Canary) | 스택 버퍼 오버플로우 검출을 위한 다른 방어 기법 |
| 버퍼 오버플로우 | 가드 페이지가 방어하는 주요 공격 유형 |
👶 어린이를 위한 3줄 비유 설명
- 가드 페이지는 "스키장 바닥의 경고선"이에요. 스키장을 너무 깊이 파려고 하면 바닥에 도달해서 굴러떨어지는 것을 막아줘요.
- 컴퓨터에서도 프로그램이 자기 할당된 공간을 넘어가려 하면, 가드 페이지라는 빈 공간이 있어서 여기서 멈춰요. 넘어가면 안 되니까요!
- 이게 없으면 옆 친구의 공간을 침범해서 엉망진 데이터가 되거나, 나쁜 사람이 이것을 이용해서 장난칠 수도 있대요.