2 คะแนน โดย GN⁺ 2024-10-27 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • mseal ใน Linux 6.10 เป็น syscall สำหรับลดทอนการ exploit โดยปิดผนึกพื้นที่หน่วยความจำเสมือนขณะรัน ทำให้ผู้โจมตีที่ได้สิทธิ์รันโค้ดแล้วเปลี่ยนสิทธิ์หรือการจัดวางของ VMA ในภายหลังได้ยากขึ้น
  • mseal(start, len, flags) จะติด VM_SEALED ให้กับช่วง VMA ที่จัดแนวตามหน้าเพจแล้ว และเคอร์เนลจะปฏิเสธการเปลี่ยนแปลงในเส้นทาง mprotect, munmap, mmap(MAP_FIXED), mremap และ madvise บางกรณีที่มีผลทำลาย
  • หาก memfd_create หรือ memfd_secret เดิมใกล้เคียงกับการควบคุมการเข้าถึงไฟล์นิรนามบน RAM และหน่วยความจำลับ mseal จะเน้นการป้องกันการเปลี่ยนสิทธิ์ การ unmap และการ remap หลังผู้โจมตีระยะไกลรันโค้ดได้แล้ว
  • เป้าหมายการป้องกันหลักคือการโจมตีที่ใช้ mprotect(PROT_EXEC) เพื่อเลี่ยง NX แล้วรัน shellcode และ data-only exploit ที่ใช้ munmap/การ remap เจาะรูในหน่วยความจำแล้วเติมข้อมูลของผู้โจมตีลงไป
  • อาจถูกรวมเข้า glibc ตั้งแต่ 2.41 เป็นต้นไป แต่ stack และ heap ไม่ใช่เป้าหมายที่จะปิดผนึกอัตโนมัติเนื่องจากมีการขยาย/หดใน runtime ดังนั้นนักพัฒนาต้องกำหนดเวลาและช่วงที่จะใช้งานอย่างรอบคอบ

การป้องกันที่ mseal มอบให้

  • memory sealing คือความสามารถที่ทำให้ช่วง VMA ขณะรันแทบจะไม่เปลี่ยนแปลงได้จากการแก้ไขอันตรายในภายหลัง
  • แม้ผู้โจมตีจะได้ primitive สำหรับรันโค้ดแล้ว ใน VMA ที่ถูกปิดผนึกก็ยังเปลี่ยนสิทธิ์หรือจัดวางให้ได้เปรียบผ่านการดำเนินการกับหน่วยความจำเสมือนได้ยาก
  • ทีม Chrome Security นำ syscall นี้มาใช้เพื่อรองรับ กลยุทธ์ V8 CFI บน ChromeOS ที่ใช้ Linux
  • หลังผ่านการอภิปรายและเขียนใหม่หลายรอบ ฟีเจอร์นี้ก็เข้าไปอยู่ในเคอร์เนล Linux และขอบเขตการใช้งานอาจขยายออกไปนอกเบราว์เซอร์ผ่าน การผนวกรวมกับ glibc

ความแตกต่างจากตระกูล memfd

  • memfd_create และ memfd_secret ใกล้เคียงกับตระกูล file sealing
    • สามารถสร้างไฟล์นิรนามบน RAM ได้
    • memfd_secret ทำให้เฉพาะโปรเซสที่มี file descriptor เท่านั้นที่เข้าถึงพื้นที่หน่วยความจำนั้นได้
    • สามารถใช้กับ mapping ฝั่ง user space แบบ “secure enclave” เพื่อปกป้องข้อมูลละเอียดอ่อนในหน่วยความจำ
  • mseal เป็น syscall ที่ออกแบบให้เป็นการลดทอน exploit ต่อ ผู้โจมตีระยะไกล ที่มุ่งรันโค้ด มากกว่าผู้โจมตีภายในเครื่องที่มุ่งรั่วไหลข้อมูลละเอียดอ่อน

การทำงานภายในเคอร์เนล

  • signature ของ syscall คือ int mseal(unsigned long start, size_t len, unsigned long flags)
    • start และ len ระบุจุดเริ่มต้นและความยาวของ VMA ที่ถูกต้องที่จะปิดผนึก
    • len ต้องจัดแนวตามหน้าเพจอย่างถูกต้อง
    • ปัจจุบัน flags ยังไม่ถูกใช้และต้องเป็น 0
  • การ implement ณ Linux 6.12 เรียก do_mseal
    • current->mm ชี้ไปยัง mm_struct ซึ่งเป็น address space หน่วยความจำเสมือนทั้งหมดของโปรเซสที่เรียก
    • mmap ของ mm_struct เก็บรายการ vm_area_struct ซึ่งเป็นพื้นที่หน่วยความจำต่อเนื่องที่สร้างด้วย mmap
    • พื้นที่อย่าง stack หรือ VDSO ก็อาจถูกแทนเป็น VMA หนึ่งรายการได้
  • do_mseal คำนวณที่อยู่ปลายช่วง จากนั้นล็อกพื้นที่หน่วยความจำด้วย mmap_write_lock_killable
  • check_mm_seal วนผ่าน VMA แต่ละรายการในช่วงเป้าหมายและตรวจสอบ ความถูกต้องของขอบเขต ก่อน
    • หากมีหน่วยความจำที่ไม่ได้ allocate อยู่กลางช่วง จะคืนค่า -ENOMEM
    • การตรวจรอบแรกนี้เป็นขั้นตอนเพื่อหลีกเลี่ยงสถานการณ์ที่มีเพียง VMA บางส่วนถูกปิดผนึกเมื่อเกิดข้อผิดพลาด
  • apply_mm_seal วนผ่านช่วงเดียวกันอีกครั้ง และเพิ่ม flag VM_SEALED ให้ VMA เป้าหมายผ่าน mseal_fixup

การดำเนินการกับหน่วยความจำที่ถูกห้ามหลังปิดผนึก

  • patchset ของเคอร์เนลเพิ่มการตรวจ VM_SEALED ใน mm/madvise.c, mm/mmap.c, mm/mprotect.c, mm/mremap.c, mm/mseal.c
  • mprotect และ pkey_mprotect เรียก can_modify_vma ภายใน mprotect_fixup และหาก VMA ถูกปิดผนึกจะคืนค่า -EPERM
  • ใน VMA ที่ถูกปิดผนึก จะไม่อนุญาตการดำเนินการต่อไปนี้
    • การเปลี่ยนบิตสิทธิ์ ผ่าน mprotect, pkey_mprotect
    • การ unmap ผ่าน munmap
    • การแทนที่ mapping ที่ถูกปิดผนึกด้วย mapping ที่เปลี่ยนแปลงได้และไม่ถูกปิดผนึกผ่าน mmap(MAP_FIXED)
    • การขยายหรือย่อขนาดผ่าน mremap
    • การย้ายไปยังปลายทางใหม่ผ่าน mremap(MREMAP_MAYMOVE | MREMAP_FIXED)
    • madvise ที่ใช้ flag บางแบบซึ่งมีผลทำลาย
  • ในการย้ายด้วย mremap จะตรวจการปิดผนึกทั้ง VMA ต้นทางและปลายทาง
  • หากไม่มี MREMAP_DONTUNMAP จะมีการ unmap VMA ต้นทาง และกรณีนี้ก็ต้องผ่านการตรวจการปิดผนึกของ munmap ด้วย
  • ตั้งแต่ Linux 6.10 ขึ้นไป สามารถใช้ mseal ด้วยการเรียก syscall โดยตรงได้ และ wrapper ตัวอย่างใช้หมายเลข syscall 462 กับ flags=0

บล็อกการรัน shellcode ด้วยการเสริมความแข็งแรงให้ NX

  • ผู้โจมตีอาจยังชอบ การรัน shellcode แม้จะมีเทคนิค reuse โค้ดอย่าง ROP
    • โปรย shellcode ลงใน stack หรือ heap ที่รันไม่ได้
    • ใช้ช่องโหว่เพื่อรัน ROP chain เริ่มต้น
    • ปิดบิต NX ของพื้นที่ที่มี shellcode ด้วย mprotect(PROT_EXEC)
    • กระโดดไปยังพื้นที่นั้นเพื่อรัน shellcode
  • การโจมตี MikroTik RouterOS SMB daemon ที่ใช้ CVE-2018-7445 เป็นตัวอย่างของ flow นี้
    • โปรย shellcode แบบใช้ socket ลงใน heap ที่รันไม่ได้
    • ROP chain ที่สร้างจาก stack overflow เปลี่ยนสิทธิ์หน่วยความจำของ heap
    • จากนั้นรัน shellcode
  • หากปิดผนึก VMA นั้นด้วย mseal การตรวจ can_modify_vma จะขัดขวางการเปลี่ยนสิทธิ์เมื่อเรียก mprotect
  • ในโค้ดตัวอย่าง หากไม่ปิดผนึกหน้าเพจของ shellcode บน stack ก็สามารถรันได้หลัง mprotect(PROT_READ|PROT_WRITE|PROT_EXEC)
  • หากปิดผนึกหน้าเดียวกันด้วย mseal แล้ว mprotect จะเปลี่ยนสิทธิ์จริงไม่ได้ และเมื่อรัน shellcode จะเกิด segmentation fault

ข้อจำกัดในการใช้กับ stack และ heap

  • หากมีการนำ mseal เข้ามาตั้งแต่ glibc 2.41 เป็นต้นไป dynamic loader จะปิดผนึกชุด VMA ที่กำหนดไว้ล่วงหน้า
  • ตามแผนปัจจุบัน stack และ heap จะไม่ถูกปิดผนึกอัตโนมัติ
  • stack และ heap สามารถขยายได้ระหว่าง runtime ดังนั้นการปิดผนึกอัตโนมัติอาจทำให้แอปพลิเคชันทำงานผิดพลาด
    • heap allocator อาจเรียก syscall brk เพื่อคืนพื้นที่
    • ในเส้นทางนี้อาจเกิดการย่อผ่าน arch_unmap และ do_vmi_unmap
    • เมื่ออยู่ในสถานะปิดผนึก การ unmap แบบนี้จะไม่ได้รับอนุญาต ทำให้ dynamic memory allocation พังได้
  • นักพัฒนาต้องตัดสินตามบริบทของแอปพลิเคชันว่าควรใช้การปิดผนึกกับช่วงเวลาและพื้นที่ใดได้บ้าง
  • macro ตัวอย่างจะปิดผนึกหน้าเพจของ stack frame ที่เลือกไว้ ซึ่งอาจมีข้อมูลที่ไม่น่าเชื่อถือ อยู่ซ้ำ ๆ
  • หากเรียก mseal ซ้ำกับ VMA ที่ถูกปิดผนึกแล้ว จะถูกจัดการเป็น no-op และไม่เกิดข้อผิดพลาด
  • ฟีเจอร์อย่างการขยาย stack อัตโนมัติหรือ stack splitting ต้องระวังเป็นพิเศษ
  • หากผู้โจมตียังยืนกรานใช้ shellcode ก็อาจ mmap พื้นที่ใหม่ที่รันได้ แล้วคัดลอก payload จากพื้นที่ที่อ่านได้ แต่ขั้นตอนจะยุ่งยากขึ้น

ลดทอน data-only exploit ที่อาศัยการ unmap

  • การบล็อก mprotect ยังป้องกันไม่ให้พื้นที่ที่ถูกปิดผนึกเปลี่ยนเป็นสถานะเขียนได้ จึงช่วยปกป้องตัวแปรข้อมูลที่หากถูกแก้ไขแล้วอาจเพิ่มความสามารถของ exploit primitive ได้
  • ผู้ดูแล Chrome พิจารณาเทคนิคที่ส่ง pointer ที่เสียหายไปยัง syscall สำหรับ unmap/remap เพื่อ เจาะรู ในหน่วยความจำ แล้วเติมข้อมูลที่ผู้โจมตีควบคุมกลับเข้าไป
  • วิธีนี้ไม่เปลี่ยนการถ่ายโอน control flow อย่าง return address บน stack หรือ function pointer โดยตรง จึงอาจเลี่ยงการรับประกัน CFI ทั้ง forward-edge และ backward-edge ได้
  • ในเบราว์เซอร์ที่ implement JIT compiler เทคนิคนี้อาจมีประโยชน์เป็นพิเศษ
    • Turbofan ของ V8 สามารถสร้างพื้นที่ที่สลับระหว่าง RW และ RX ได้
    • ผู้โจมตีสามารถทำให้กระบวนการ JIT compile สร้างโค้ดรันจาก JavaScript แบบ hot-path ได้
    • เติมพื้นที่ที่ถูก unmap เพื่อเขียนทับข้อมูลสำคัญ แล้วสร้างการเปลี่ยนแปลงที่นำไปสู่การรันโค้ดได้
  • นี่คือ data-only exploit ที่ไม่ต้องยึด control flow โดยตรงหรือบังคับให้มี pointer leak แต่จัดการข้อมูลบางจุดในหน่วยความจำเพื่อส่งผลต่อ control flow
  • mseal สามารถบล็อกการ unmap และ remap เพื่อกันสถานการณ์ hole-punching แบบนี้ได้

กรณี House of Muney

  • House of Muney ใช้เทคนิคที่อาศัยการ unmap คล้ายกันใน exploit heap ฝั่ง user space
  • Qualys ใช้เทคนิคนี้ใน exploit จริง สำหรับบั๊ก Qmail เก่า
  • เทคนิคนี้อาศัยคุณสมบัติที่เมื่อ chunk ขนาดใหญ่มีขนาดมากกว่า M_MAP_THRESHOLD แล้ว malloc และ free จะเรียก mmap และ munmap โดยตรงตามลำดับ
  • chunk ขนาดใหญ่ไม่มี freelist cache ขั้นกลาง ทำให้ขั้นตอน exploit ง่ายขึ้น
  • เมื่อแก้ metadata ขนาดที่ด้านบนของ chunk ที่ allocate ให้เป็นขนาดหน้าเพจอื่นแล้ว free ก็อาจเกิด munmap กับพื้นที่หน่วยความจำที่อยู่ติดกับ chunk นั้นได้
  • ตัวอย่างของ Dulin เล็งพื้นที่ .gnu.hash และ .dynsym ด้วย munmap ตามอำเภอใจ
    • จากนั้นเติมกลับด้วย chunk mmap ที่ใหญ่กว่า
    • ทำให้เขียนทับ PLT entry หนึ่งรายการที่ยังไม่ได้ resolve ได้
    • ทำให้การโจมตีสไตล์ GOT overwrite กลับมาใช้ได้
  • PoC แบบย่อ allocate chunk ขนาดใหญ่สองก้อน, ปรับแต่งฟิลด์ size ของ top[-1], จากนั้น free(top) เพื่อ unmap ไปจนถึงพื้นที่ข้างเคียง และ allocate ก้อนที่ใหญ่กว่าเพื่อเติมข้อมูล X กลับเข้าไป
  • เทคนิคนี้สามารถทำงานได้แม้มี CFI และไม่ต้องมี ASLR leak ล่วงหน้า
  • การปิดผนึกชุด VMA ที่วางแผนไว้ในการผนวกรวม mseal ของ glibc คาดว่าจะปกป้องโค้ดไบนารีและไลบรารีไดนามิกที่ถูก map ไว้จากกลเม็ด unmap/remap และลดทอนการโจมตีนี้โดยอัตโนมัติ
  • นักพัฒนาที่ต้องการเสริมความแข็งแรงเพิ่มเติมสามารถเลือกปิดผนึก allocation จาก mmap ที่จะไม่ขยายหรือถูก unmap ตลอดอายุของโปรแกรมได้

ขอบเขตการใช้งานในอนาคต

  • mseal เป็นฟีเจอร์ลดทอนความเสี่ยงที่ค่อนข้างใหม่ของเคอร์เนล Linux และอาจยังมีกรณีการใช้งานที่ไม่ได้กล่าวถึงอีก
  • เมื่อการผนวกรวมกับ glibc เสร็จสมบูรณ์และเติบโตเต็มที่ อาจมีการปรับปรุงให้สอดคล้องกับข้อกำหนดของ syscall ต่อไป
  • พารามิเตอร์ flags ที่ยังไม่ได้ใช้ในปัจจุบันก็อาจมีการกำหนด用途เฉพาะในอนาคต
  • เมื่อใช้งานกับซอฟต์แวร์จริง ต้องประเมินอายุการใช้งานของหน่วยความจำที่จะปิดผนึกควบคู่กับความจำเป็นในการเปลี่ยนแปลงด้วย

1 ความคิดเห็น

 
GN⁺ 2024-10-27
ความคิดเห็นใน Hacker News
  • ถ้ามีคนวงในช่วยสรุปได้ว่ามีการคัดค้านและความกังวลอะไรบ้างในการถกเถียงอย่างดุเดือดบน mailing list ของเคอร์เนลก็คงดี
    ตัว mailing list เองบางทีก็เผ็ดเกินไป เลยค่อนข้างหลีกเลี่ยง และตอนนี้ก็ปวดหัวมากพออยู่แล้ว
    กลไกเองดูสมเหตุสมผล แต่ก็น่าแปลกใจที่ฟีเจอร์แบบนี้ยังไม่มีอยู่ในเคอร์เนลมาก่อน

    • ไม่รู้ว่านอกจากเธรดที่ลิงก์ไว้แล้วยังมีอีกไหม แต่โดยรวมเป็นความตรงแบบ Linus
      ในบรรดาแฟล็กที่เสนอ มีอันหนึ่งที่ทำให้สามารถละเว้น seal ได้ และ Linus ก็ตอบทำนองว่า “จะไม่ให้ munmap ทำงานในที่หนึ่ง แต่ในอีกที่หนึ่งจะให้ละเว้น seal อย่างนั้นเหรอ”
      ต่อมาพูดแรงขึ้นว่า “เมื่อ seal แล้วก็คือ seal แล้ว” และจะทำแบบ “บางที่เคารพ seal ส่วนที่อื่นตามใจกลับไม่เคารพ” ไม่ได้
      ภายหลังถึงขั้นบอกว่า seal ไม่สามารถละเว้นได้และไม่ใช่เรื่องต่อรอง ถ้ายังเสนอแฟล็กให้ละเว้น seal อีกก็จะเอาเข้า ignore list
    • https://lwn.net/ml/linux-kernel/7071.1697661373@cvs.openbsd....
      ในอีเมลที่ Theo de Raadt ส่งถึง Jeff Xu หลังจาก Jeff บอกว่าแนวทางของ mimmutable() กับ mseal() แตกต่างกัน แต่ทั้งคู่มีเป้าหมายเพื่อ seal หน่วยความจำจากผู้โจมตีและทำให้แอปพลิเคชัน Linux ปลอดภัยขึ้น Theo ตอบว่า “ดูเหมือนคุณกำลังทำ mseal เพื่อ Chrome เท่านั้น
      เขามองว่ามันคงไม่เหมาะกับแอปพลิเคชันโดยรวม โดยให้เหตุผลว่ามันซับซ้อนเกินไป และจากประสบการณ์ของ mimmutable() สุดท้ายแอปพลิเคชันจะไม่ได้จัดการเอง แต่จะเป็นหน้าที่ของ execve(), การเริ่มต้นของ libc และ ld.so
    • Matthew Wilcox ก็ตอบ Jeff Xu อย่างแรงทำนองว่า “ขอบคุณที่แสดงให้เห็นว่าคุณไม่รู้ว่าต้องป้องกันอะไร”
      เขาเห็นด้วยกับ Theo และ Linus โดยมองว่าแนวคิดพื้นฐานของ mimmutable() นั้นดี แต่วิธีที่แยกย่อยและนำไป implement นั้นแย่มาก
    • บทความนี้อาจช่วยได้: https://lwn.net/Articles/948129/
  • สงสัยว่าจะใช้ system call นี้อย่างไร
    Chrome ต้องการมันก็จริง แต่เพราะผู้โจมตีสามารถ map ใหม่ด้วยแฟล็กอื่นได้ หน้าเพจที่ถูก seal แล้วจึงไม่สามารถ unmap ได้
    ถ้าอย่างนั้น หน้าเพจที่จัดสรรตอน runtime ก็แทบจะใช้ไม่ได้ เว้นแต่ตั้งใจจะเก็บไว้ตลอดอายุของโปรเซสหรือเปล่า
    ถ้าเป็นแบบนั้น จะเอาไปใช้กับเป้าหมายที่น่าดึงดูดมากอย่างหน่วยความจำของ JS sandboxได้ยากไม่ใช่หรือ?
    เลยสงสัยว่างานลักษณะนี้แก้ด้วยการรันในโปรเซสแยก seal หน่วยความจำ แล้วพอเสร็จก็ kill โปรเซสหรือไม่
    ไม่ค่อยรู้วิธีจัดการหน่วยความจำและโปรเซสของ Chrome เลยไม่แน่ใจว่าทำไมมันไม่เป็นปัญหา และก็สงสัยว่านี่เป็นเหตุผลที่มักอธิบายกันว่าฟีเจอร์นี้ไม่ค่อยมีประโยชน์กับโปรแกรมส่วนใหญ่หรือเปล่า

    • ในกรณีนี้ หลายโปรเซสอาจเป็นทางเลือกได้
      เท่าที่รู้ Chrome ใช้วิธีนี้อย่างกว้างขวางอยู่แล้ว และด้วยเหตุผลอย่างการแยกกันด้วย namespace ก็จำเป็นต้องมีโปรเซสแยกอยู่ดี จึงอาจเป็นแนวทางนั้น
  • การอภิปรายหลัง mseal() วันที่ 20 ตุลาคม 2023: https://lwn.net/Articles/948129/
    mseal() ใกล้เข้ามาแล้ว วันที่ 19 มกราคม 2024: https://lwn.net/Articles/958438/
    การ seal หน่วยความจำสำหรับ GNU C Library วันที่ 12 มิถุนายน 2024: https://lwn.net/Articles/978010/

  • น่าเสียดายที่แม้สถาปัตยกรรม x86_64 สมัยใหม่จะมีฟีเจอร์มากมายที่ช่วยด้านการเขียนโปรแกรมและการประมวลผลอย่างปลอดภัย แต่ระบบปฏิบัติการก็ยังต้อง implement call แบบนี้
    มองว่าท่าทีที่พยายามซ่อมระบบเก่าซึ่งสร้างอยู่บนมรดกและวิธีคิดล้าสมัย รวมถึง paradigm ที่ไม่สอดคล้องกับโลกและความรู้ในปัจจุบัน กำลังทำให้ความก้าวหน้าของคอมพิวติ้งช้าลง และทำให้ผู้คนนับพันล้านตกอยู่ในความเสี่ยงอย่างแท้จริง
    แน่นอนว่าไม่ได้จะบอกว่าการเปลี่ยนแปลงนี้ไม่ใช่ก้าวไปในทิศทางที่ถูกต้อง แต่หากเลิกยึดติดกับอุดมคติเดิมว่าระบบปฏิบัติการควรทำงานอย่างไร แล้วพิจารณาระบบและความรู้ปัจจุบัน รวมถึงสิ่งที่ผู้คนต้องการจากระบบ ก็สามารถจินตนาการถึงระบบที่หลุดพ้นจากภาระและความเสี่ยงที่ตกอยู่กับนักพัฒนาและผู้ใช้ในวันนี้ได้
    จริงอยู่ที่มีบั๊กในสถาปัตยกรรม แต่ซอฟต์แวร์เองก็ยังใช้ฟีเจอร์ที่มีในปัจจุบันได้ไม่เต็มที่ ดังนั้นการยกบั๊กของสถาปัตยกรรมมาโต้แย้งจึงพลาดประเด็น
    หากสร้างอยู่บนฐานที่สั่นคลอน ก็จะมีวิธีเจาะที่ถูกกว่าเสมอ

    • อยากรู้ว่าใน x86_64 มีฟีเจอร์ความปลอดภัยที่ไม่ได้ใช้หรือใช้น้อยอะไรบ้างที่ใช้งานได้โดยไม่ต้องมีวิธีให้ระบบปฏิบัติการใช้หรือเปิดใช้งาน
      และอยากรู้ด้วยว่าทำไมถึงมองว่า mseal ไม่มีเหตุผลรองรับ และอะไรที่ดีกว่าแทน
  • จะสามารถใช้ทริก LD_PRELOAD เพื่อเขียนทับหรือปิดใช้งาน system call mseal ได้หรือไม่?

    • mseal เป็น system call ที่ต่างจากวิธีป้องกันหน่วยความจำแบบเดิมของ Linux โดยมุ่งไปที่ การบรรเทาการโจมตีแบบรันโค้ดจากระยะไกล มากกว่าผู้โจมตีในเครื่องที่พยายามดึงความลับสำคัญออกจากหน่วยความจำ
      หากผู้โจมตีจากระยะไกลสามารถเปลี่ยนสภาพแวดล้อมภายในเครื่องได้ ก็ควรมองว่าได้เจาะเข้าระบบแล้ว
    • คาดว่าใช้ LD_PRELOAD คงทำไม่ได้
      เพื่อให้ได้ผล มันต้องเป็นฟังก์ชันที่ถูกนำเข้า แต่ system call แบบดิบไม่สามารถถูกดักจับด้วยวิธีนั้นได้
      การอภิปรายเรื่องการดักจับ system call ของ Linux: https://stackoverflow.com/questions/69859/how-could-i-interc...
      วิธีที่ง่ายที่สุดในการ “ปิดใช้งาน” ฟีเจอร์นี้อาจเป็นการสร้างเคอร์เนลที่แพตช์เองให้แสร้งว่า mseal ทำงาน
      อย่างไรก็ตาม โปรแกรมที่ใช้ mseal สามารถตรวจสอบได้ว่ามันทำงานจริงหรือไม่ ดังนั้นเคอร์เนลที่ถูกแก้ไขจึงยังต้องมีวิธีปิด mseal แบบลับ ๆ เพื่อป้องกันการตรวจสอบของแอปหลังนำไปใช้
    • หากมีสิทธิ์ควบคุมตั้งแต่ช่วงต้นของโปรเซส ก็มีวิธีเขียนทับได้ค่อนข้างมาก
      เช่น สามารถติดตามไฟล์รันด้วย ptrace เพื่อเฝ้าดู system call แล้วข้าม mseal(2) ไปได้
      system call นี้ไม่ได้ออกแบบมาสำหรับ threat model ที่ว่า “ผู้โจมตีมีสิทธิ์เข้าถึงอยู่แล้วก่อนการเริ่มต้นโปรเซส”
    • wrapper สำหรับการเรียก mseal สามารถเขียนทับได้ แต่ ตัว system call เอง เขียนทับไม่ได้
      จากที่ลองค้นดู วิธีเขียนทับ system call แบบ preload ทั้งหมดเป็นการเปลี่ยน wrapper และหากเรียก system call โดยตรงก็น่าจะเขียนทับไม่ได้
      ในเชิงเทคนิค อาจเป็นไปได้ที่จะเขียนทับตัวฟังก์ชัน syscall เอง
    • ตาม https://lwn.net/Articles/978010/ จะมีการเพิ่ม glibc tunable เข้ามา
  • เมตา: ต้นแบบของ mseal() ในบทความต้องแก้ไข
    อาร์กิวเมนต์แรกแสดงเป็น unsigned start addr แต่ที่ถูกน่าจะเป็น unsigned long start_addr

    • ตอนนี้ดูเหมือนใช้ได้แล้ว: int mseal(unsigned long start, size_t len, unsigned long flags)
  • เคยมีการถกกันมาก่อนแล้วว่า CPython ควรรองรับ system call mseal() อย่างไร ใน “Memory Sealing ‘Mseal’ System Call Merged for Linux 6.10” (2024) https://news.ycombinator.com/item?id=40474510#40474551

  • OpenBSD มีฟีเจอร์นี้มาตั้งนานแล้ว https://man.openbsd.org/mimmutable.2
    สงสัยว่าทำไมฟีเจอร์ที่ดูชัดเจนแบบนี้เพิ่งจะเข้ามาใน Linux ตอนนี้

    • mimmutable ของ OpenBSD ถูกนำมาใช้ใน OpenBSD 7.3 ซึ่งเผยแพร่เมื่อวันที่ 10 เมษายน 2023 ดังนั้นจึงไม่ใช่ “มีมาตั้งนานแล้ว”
      ในทางกลับกัน Linux และ FreeBSD มี memfd_create มาตั้งนานแล้ว ส่วน OpenBSD ไม่มีไฟล์นิรนาม จึงต้องพึ่ง shm_open