๐Ÿ›ก๏ธ CONFIG_HARDENED_USERCOPY Architecture Simulator Linux Kernel 6.12 Hardening Lab

๋ฐฐ์†:
ํ…Œ์ŠคํŠธ ๋ฒกํ„ฐ:
ACTIVE: __check_object_size() ์ธํ„ฐ์…‰ํ„ฐ ๋Ÿฐํƒ€์ž„ ๊ฐ์‹œ ์ค‘
โŒ Baseline (ํ•˜๋“œ๋‹ ๋น„ํ™œ์„ฑํ™”)
VULNERABLE (CWE-125 / Info Leak)
RING 0 : Kernel Space (EL1) SLUB Allocator & copy_to_user() Without Hardened Usercopy SLUB Chunk A: 64B kmalloc "PUBLIC_DATA_HEADER_CHUNK_A..." Adjacent Chunk B / Metadata "CONFIDENTIAL_KEY_9999..." copy_to_user(u_buf, chunk_a, 128) check_object_size() == no-op (๋นˆ ํ•จ์ˆ˜) ์Šฌ๋žฉ ๊ฒฝ๊ณ„(64B) ๋ฌด์‹œ: 128B ์—ฐ์† ์œ ์ถœ ํ—ˆ์šฉ โš ๏ธ ๋ฌด๋ฐฉ๋น„ ์ปค๋„ ๊ฒฝ๊ณ„์„  RING 3 : User Space (EL0) Unprivileged Attacker Process (/bin/exploit_hardened_usercopy) User Memory Buffer (128 Bytes Received): [00-63B] PUBLIC_DATA_HEADER_CHUNK_A... [64-127B] ๐Ÿšจ CONFIDENTIAL_KEY_IN_CHUNK_B_9999 (LEAKED!)
๐Ÿ›ก๏ธ Hardened (CONFIG_HARDENED_USERCOPY=y)
PROTECTED (SLUB Bounds Clamped)
RING 0 : Kernel Space (EL1) Active In-flight Interception (__check_object_size & SLUB Clamping) SLUB Chunk A (s->usersize=64) "PUBLIC_DATA_HEADER_CHUNK_A..." LIMIT: 64B Adjacent Chunk B (SHIELDED) "CONFIDENTIAL_KEY_9999..." __check_object_size(chunk_a, 128, to_user=true) โšก __check_heap_object: (offset 0 + len 128) > s->usersize (64)! ๐Ÿ’ฅ usercopy_abort("SLUB object", "kmalloc-64") -> BUG() ๐Ÿ”’ ์™„์ „ ๋ด‰์‡„: ๋ฐ์ดํ„ฐ ์ „์†ก ์ฆ‰์‹œ ์ฐจ๋‹จ RING 3 : User Space (EL0) Rogue Exploit Thread Terminated via Kernel SIGKILL User Buffer Status (0 Bytes Transferred): โœ… 0 Bytes Leaked! No Adjacent Chunk Data Reached User Memory. Process Status: Killed with SIGSEGV/SIGKILL before copy completed
๐Ÿ“ฆ 1. ์Šฌ๋žฉ ๋ฒ„ํผ ๊ฒฝ๊ณ„ ๊ฒ€์ฆ (__check_heap_object)
`copy_to_user` ํ˜ธ์ถœ ์‹œ SLUB ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ(`s->usersize`, `s->useroffset`)๋ฅผ ์กฐํšŒํ•˜์—ฌ, ์š”์ฒญ๋œ ๋ณต์‚ฌ ๋ฒ”์œ„๊ฐ€ ๋‹จ์ผ ํ• ๋‹น ๊ฐ์ฒด์˜ ๊ฒฝ๊ณ„๋ฅผ ๋ฒ—์–ด๋‚˜๋Š”์ง€ ๊ฒ€์ฆํ•จ. ์ธ์ ‘ ๊ฐ์ฒด ์˜ค๋ฒ„๋ฆฌ๋“œ ๋ฐฉ์–ด.
if (offset + n > s->usersize) usercopy_abort();
๐Ÿ“œ 2. ์ปค๋„ ์‹คํ–‰ ์ฝ”๋“œ ๋ณดํ˜ธ (check_kernel_text_object)
์ปค๋„์˜ ์‹คํ–‰ ์ฝ”๋“œ ์˜์—ญ(`[_stext, _etext]`)์—์„œ ์œ ์ € ๊ณต๊ฐ„์œผ๋กœ์˜ ์ง์ ‘ ๋ณต์‚ฌ๋ฅผ ์—„๊ฒฉ ์ฐจ๋‹จํ•จ. ์ปค๋„ ํ•จ์ˆ˜ ๋ฐ”์ดํŠธ์ฝ”๋“œ ๋…ธ์ถœ ๋ฐ ROP ๊ฐ€์ ฏ ์ฃผ์†Œ ์œ ์ถœ์„ ๋ฐฉ์–ดํ•˜์—ฌ KASLR ๋ณดํ˜ธ.
if (overlaps(ptr, n, _stext, _etext)) BUG();
๐Ÿ“š 3. ์Šคํƒ ํ”„๋ ˆ์ž„ ์ดํƒˆ ๋ฐฉ์–ด (check_stack_object)
๋ณต์‚ฌ ์†Œ์Šค ๋˜๋Š” ๋Œ€์ƒ ์ฃผ์†Œ๊ฐ€ ํ”„๋กœ์„ธ์Šค ์ปค๋„ ์Šคํƒ(`task_stack_page`) ๋‚ด์— ์œ„์น˜ํ•  ๋•Œ, ํ˜„์žฌ ์Šคํƒ ํ”„๋ ˆ์ž„ ๊ฒฝ๊ณ„๋ฅผ ์ดˆ๊ณผํ•˜์—ฌ ๋ณต์‚ฌํ•˜๋Š” ํ–‰์œ„๋ฅผ ์ฐจ๋‹จํ•จ. ์Šคํƒ ์ž”๋ฅ˜ ์ •๋ณด ๋…ธ์ถœ ๋ฐฉ์–ด.
check_stack_object(ptr, n) -> valid_stack