CONFIG_INIT_STACK_ALL_ZERO / STRUCTLEAK Simulator Category 6: Structure Hardening

Interactive Visualization of Kernel Stack Alignment Padding & Structure Zero-Initialization

배속:
INIT_STACK_ALL_ZERO Active: Stack Frame & Padding Holes 100% Zeroed
KERNEL SPACE (Ring 0 / EL1) - Function Call Stack Frame USER SPACE (Ring 3 / EL0) - Target App Buffer copy_to_user() Boundary 이전 호출자 스택 프레임 (Caller Stack Frame) 잔여 데이터: 0x53544b5f4c45414b ("STK_LEAK") 현재 함수 스택 프레임 (vuln_structleak) Return Address / FP (0xffff800008...) Stack Canary (0xdeadbeef1337cafe) struct demo_padding_leak (32B on Stack) uint32_t header [4B] (명시적 대입) 0x44454d4f ("DEMO") ⚠️ [ALIGNMENT PADDING HOLE] [4B] 0x00000000 (컴파일러 자동 0 초기화) uint64_t timestamp [8B] (명시적 대입) 0x1122334455667788 char msg[16] [16B] (명시적 대입) "STRUCT_PADDING!" 🛡️ Compiler Stack Zeroing ARM64: stp xzr, xzr, [sp] x86: xorps %xmm0, %xmm0 movaps %xmm0, (%rsp) 함수 진입(Prologue) 시 32바이트 전체를 0x00으로 소거하여 패딩 누출 차단 Exploit Process Memory (read() 결과) user_buf.header [Offset 0..3] 0x44454d4f ("DEMO") - 정상 수신 🛡️ user_buf.padding [Offset 4..7] 0x00 0x00 0x00 0x00 (CLEAN) 안전: 커널 스택 정보 누출 없음 user_buf.timestamp [Offset 8..15] 0x1122334455667788 user_buf.msg [Offset 16..31] "STRUCT_PADDING!" ✅ PoC 결과: SECURE 패딩 홀 0x00 유지 확인 잔여 스택 토큰 추출 실패 CONFIG_INIT_STACK_ALL_ZERO=y 커널 주소/카나리 탈취 원천 차단

🧩 구조체 정렬 패딩(Alignment Padding)의 맹점

C 언어에서 64비트 아키텍처는 데이터 정렬을 위해 4바이트 멤버 뒤에 4바이트 패딩 홀을 삽입합니다.

struct demo { uint32_t a; /* 4B hole */ uint64_t b; }; demo.a = 1; demo.b = 2; // 패딩 홀은 초기화되지 않음!

개발자가 구조체의 모든 멤버를 할당하더라도, 컴파일러가 생성한 패딩 공간에는 이전 스택 프레임의 데이터(카나리, 포인터)가 남아 그대로 유저 공간에 복사됩니다.

🛡️ CONFIG_INIT_STACK_ALL_ZERO 방어 원리

컴파일러(-ftrivial-auto-var-init=zero)가 함수 프롤로그에서 스택 프레임 전체를 0x00으로 소거합니다.

  • ARM64: stp xzr, xzr, [sp] 명령어로 16바이트 단위 초고속 0 초기화.
  • x86_64: SIMD xorps/movaps 또는 rep stosq를 통한 즉각 소거.
  • 효과: 패딩 홀과 미초기화 구조체 필드가 100% 0x00으로 정화되어 정보 누출 원천 봉쇄.

🔄 STRUCTLEAK 플러그인과의 역사적 관계

과거 GCC 11 이전에는 GCC 플러그인인 CONFIG_GCC_PLUGIN_STRUCTLEAK이 이 역할을 담당했습니다.

  • STRUCTLEAK_USER: __user 속성 구조체만 초기화.
  • STRUCTLEAK_BYREF_ALL: 참조 전달되는 모든 변수 초기화.
  • 현대 리눅스 (6.x LTS): GCC 12+ 및 Clang 12+의 네이티브 INIT_STACK_ALL_ZERO가 플러그인을 완전히 대체하여 프로덕션 표준으로 안착함.