GrapheneOS พบความเสียหายของหน่วยความจำ Bluetooth ด้วย ARM MTE
(grapheneos.social)- การรองรับ hardware memory tagging ของ Pixel 8 และ Pixel 8 Pro เผยให้เห็นบั๊กความเสียหายของหน่วยความจำใน Bluetooth LE ที่เพิ่งเข้ามาใน Android 14 QPR2
- สาเหตุได้รับการยืนยันว่าเป็นบั๊ก upstream use-after-free ใน Bluetooth LE และ GrapheneOS ได้ทำแพตช์แก้ไขแล้ว โดยมีแผนจะรวมไว้ในรีลีสใหม่
- ผู้ใช้ที่จำลองปัญหาได้ในโหมด Bluetooth LE ของ Samsung Galaxy Buds2 Pro ยืนยันว่าการแก้ไขทำงานได้ และ stock Pixel OS ก็ได้รับผลกระทบเช่นกัน
- GrapheneOS มองว่า Bluetooth เป็น attack surface ขนาดใหญ่ ดังนั้นวิธีเลี่ยงด้วยการปิด memory tagging ของโปรเซสนี้จึงไม่เหมาะสม แม้ในระยะสั้น
- โค้ด Bluetooth บางส่วนของ Android ถูกพอร์ตไปเป็น Rust แล้ว แต่ยังต้องพอร์ตโค้ดที่เหลือต่อ และต้องทดสอบบิลด์ HWASan·MTE บนอุปกรณ์จริงมากขึ้น
บั๊ก Bluetooth LE ใน Android 14 QPR2 และการแก้ไข
- GrapheneOS พบ bug ความเสียหายของหน่วยความจำ Bluetooth LE ใน Android 14 QPR2 จากการรองรับ hardware memory tagging ของ Pixel 8 และ Pixel 8 Pro
- ไม่ใช่ปัญหาที่เกิดกับอุปกรณ์ Bluetooth ทั้งหมด แต่จำลองได้เฉพาะกับ อุปกรณ์ Bluetooth LE บางรุ่นเท่านั้น
- GrapheneOS กำลังตรวจสอบวิธีแก้ไขฟีเจอร์ที่เพิ่งเพิ่มเข้ามา หรือปิดใช้งานชั่วคราว
- สาเหตุได้รับการยืนยันว่าเป็นบั๊ก upstream use-after-free ใน Bluetooth LE และ GrapheneOS ได้พัฒนาแพตช์แล้ว
- สิ่งสำคัญลำดับแรกคือการปล่อยรีลีส GrapheneOS ที่มีการแก้ไขนี้อย่างรวดเร็ว
- มีแผนจะรายงานเป็นบั๊กความปลอดภัยของ Android
- การแก้ไขนี้น่าจะแก้ regression ของ BLE audio ด้วย
- ผู้ใช้ที่จำลองปัญหาได้โดยใช้ Samsung Galaxy Buds2 Pro ใน โหมด Bluetooth LE ยืนยันว่าการแก้ไขทำงานได้
- ปัญหาเดียวกันนี้ส่งผลต่อ stock Pixel OS ด้วย
- GrapheneOS ตรวจพบปัญหานี้ด้วยการรองรับ memory tagging ของ hardened_malloc และเพิ่ม การแจ้งเตือน MTE crash ที่มีรายงานให้คัดลอกได้
วิธีใช้ MTE และโจทย์ของโค้ด Android Bluetooth
- GrapheneOS มองว่าวิธีเลี่ยงด้วยการปิด memory tagging ในโปรเซสนี้ไม่เหมาะสม แม้ในระยะสั้น
- Bluetooth เป็น attack surface ขนาดใหญ่ ไม่ว่าบั๊กนี้จะถูกนำไปโจมตีได้จริงหรือไม่ก็ตาม
- Android ได้พอร์ตโค้ด Bluetooth ไปเป็น Rust เป็นจำนวนมากแล้ว แต่ยังต้องใช้ทรัพยากรมากขึ้นในการพอร์ตโค้ดส่วนที่เหลือ
- ในสภาพแวดล้อมจริง ยังจำเป็นต้องทดสอบบิลด์ HWASan และ MTE กับอุปกรณ์ Bluetooth ที่หลากหลายมากขึ้น
- อุปกรณ์ Pixel มี MTE ซึ่งเป็นฟีเจอร์ความปลอดภัยฮาร์ดแวร์ขนาดใหญ่ แต่ OS พื้นฐานไม่ได้เปิดใช้งาน โดยให้เหตุผลว่าช่วยลดการใช้หน่วยความจำและแคชได้ 3.125%
- การคำนวณอิงจาก แท็ก 4 บิต ต่อหน่วยความจำที่ถูกแท็กทุก 16 ไบต์
- heap MTE ในโหมดอะซิงโครนัส (async mode) มี overhead ด้านประสิทธิภาพแทบใกล้ 0% และใน asymmetric mode มีต้นทุนต่ำกว่ามาตรการลดผลกระทบเดิมอย่าง SSP
- GrapheneOS เปิดใช้ MTE เป็นค่าเริ่มต้นให้กับแอปที่ผู้ใช้ติดตั้งและทราบว่าเข้ากันได้กับ OS พื้นฐาน
- สามารถเปิดแบบ opt-in สำหรับแอปที่ผู้ใช้ติดตั้งทั้งหมดได้ที่ Settings > Security
- มีการแจ้งเตือนที่คัดลอก crash report ได้ และมี toggle แยกต่อแอป
- การใช้งาน MTE ของ hardened_malloc ใน GrapheneOS ใช้แท็กสุ่มมาตรฐานและแท็ก free เฉพาะ และตัดแท็กก่อนหน้ารวมถึงแท็กข้างเคียงปัจจุบันหรือก่อนหน้าออกแบบไดนามิก
- การผสานรวมกับ Chromium ได้รับการแก้ไขแล้ว และมีแผนจะปรับปรุง PartitionAlloc ด้วย
1 ความคิดเห็น
ความเห็นจาก Hacker News
เป็นเรื่องแปลกที่ Pixels ใส่ฟีเจอร์ความปลอดภัยฮาร์ดแวร์ขนาดใหญ่อย่าง MTE มาแล้ว แต่ใน OS กลับไม่เปิดใช้เพราะอยากประหยัดการใช้หน่วยความจำ/แคช 3.125%
อยากเห็นจริง ๆ ว่าทีม Pixel อธิบายการตัดสินใจนี้อย่างไร และอยากรู้กระบวนความคิดที่ยอมปิดฟีเจอร์ความปลอดภัยสำคัญขนาดนี้เพื่อแลกกับประสิทธิภาพที่เพิ่มขึ้นเพียงเล็กน้อย
อย่างไรก็ตาม GrapheneOS เป็นโปรเจ็กต์ที่ยอดเยี่ยม แต่มีอุปกรณ์ที่รองรับราว 11 รุ่นเท่านั้น ขณะที่การเปลี่ยนแปลงใน AOSP ต้องคำนึงถึงระบบนิเวศ OEM ที่ใหญ่กว่ามาก
เราพยายามหาวิธีทำให้ Android ดีขึ้นอยู่เสมอ แต่การวิจารณ์การเปิดตัวฟีเจอร์หนึ่งโดยมองข้ามระบบนิเวศ OEM ที่ใหญ่กว่านั้นก็ดูค่อนข้างมองแคบ
มีโอกาสน้อยมากที่เหตุผลที่ยังไม่เปิดใช้ฟีเจอร์นี้จะเป็นเพราะหน่วยความจำ/แคช 3% และน่าจะมีปัจจัยอื่นประกอบ
เวลาตัดสินใจว่าจะเปิดฟีเจอร์นี้หรือไม่ ปัจจัยนี้น่าจะสำคัญกว่า
มีการบอกว่า OS อื่น ๆ เองก็ยัง ไม่ได้ออกมาพร้อม MTE ที่เปิดใช้งาน ดังนั้นการจะเปิดหรือไม่เปิดน่าจะเป็นการตัดสินใจที่ซับซ้อนกว่านั้น
คนฝั่ง Google เป็นฝ่ายผลักดัน hardware MTE ตั้งแต่แรก และเริ่มจากทีมที่เกี่ยวข้องกับ ASAN, syzkaller ฯลฯ
แม้ทีมจะไม่ได้สังกัด Android โดยตรง แต่ก็มีความช่วยเหลือและการสนับสนุนจากฝั่ง Android และแน่นอนว่ามีความร่วมมือกับ ARM เป็นต้น
ตอนนั้นผมอยู่ในตำแหน่งที่ดูแลทีมเหล่านั้น จึงเข้าใจจุดแลกเปลี่ยนดี และมันไม่ได้มีแค่ปัญหาเรื่องหน่วยความจำหรือแคช
จริงอยู่ที่ MTE ถูกออกแบบมาให้เปิดปิดแบบไดนามิกได้ และให้ต้นทุนด้านประสิทธิภาพใกล้ศูนย์มาก แต่การใช้งานหลักในตอนนั้นคือการค้นหาบั๊กแบบอาศัยการสุ่มตัวอย่าง
ถ้าเปิดเพียง 1% ของเวลากับทั้งกลุ่มอุปกรณ์ ก็ถือว่าใหญ่พอจะพบบั๊กได้เร็วมาก และยังใช้ในการทดสอบภายในได้ด้วย
กล่าวคือ เป้าหมายคือทำให้สามารถเปิดปิด ฟังก์ชันระดับใกล้เคียง ASAN ได้เมื่อต้องการ
การใช้เป็นมาตรการลดความเสี่ยงด้านความปลอดภัยที่เปิดไว้ตลอดเป็นเพียงความเป็นไปได้รอง และยังมีปัญหาอื่นนอกเหนือจากโอเวอร์เฮดด้านหน่วยความจำ
ตัวอย่างเช่น จู่ ๆ ก็อาจมีการแครชที่ผู้ใช้มองเห็นได้จำนวนมาก โดยบนโทรศัพท์ที่มี MTE จะเกิดแครช แต่บนรุ่นที่ไม่มีจะไม่เกิด ทำให้ขาดความสม่ำเสมอ
ในมุมของนักพัฒนาเองก็คงไม่ชอบ หากต้องบังคับให้ทุกคนทดสอบบนโทรศัพท์รุ่นเดียวที่แทบเป็นรุ่นเดียวที่เปิดใช้ MTE ได้
มันสามารถป้องกันการโจมตีแบบเอ็กซ์พลอยต์ได้ และทำให้เกิดแครชแทนการถูกนำไปใช้โจมตี
มันยังจับบั๊กที่ไม่เป็นอันตรายได้ด้วย
แต่ตามที่กล่าวไป ผมจะไม่สมมติว่าไม่ได้ใช้เลย เพียงแต่น่าจะไม่ใช่สิ่งที่เปิดไว้ตลอดเวลาในโปรดักชัน
ถ้าเป็นคนที่มีประสบการณ์กับการนำฟีเจอร์ฮาร์ดแวร์แบบนี้มาใช้ จะบอกว่าการที่ระบบบูตและทำงานได้ และแครชเฉพาะบางพฤติกรรมภายใต้ MTE นั้น กลับเป็นสัญญาณที่ดีว่าใช้งานมันอยู่แล้ว
ถ้าไม่ได้ใช้เลย ก็น่าจะแครชไปเป็นล้านครั้งแล้ว
เสริมอีกนิดว่า ก็ยังไม่ชัดเจนว่ามันเป็นตัวเลือกที่ดีที่สุดในฐานะมาตรการป้องกันขณะรันจริงหรือไม่
Pixel รุ่นปกติอาจไม่ได้เปิดให้ผู้ใช้ปลายทางใช้งานเป็นค่าเริ่มต้น แต่ถ้าต้องการ ใคร ๆ ก็สามารถเปิด Memory Tagging Extensions ได้จากตัวเลือกนักพัฒนา
จะเปิดค้างไว้จนกว่าจะปิดเอง หรือเปิดแค่หนึ่งเซสชันเพื่อทดสอบบางแอปก็ได้
การเปิดการรองรับ memory tagging จากตัวเลือกนักพัฒนาบน Pixel OS ปกติเพียงแค่ทำให้ระบบพร้อมใช้งาน แต่ไม่ได้ใช้งานจริง
ต้องเปิด heap memory tagging ด้วย
setpropใน Android Debug Bridge (ADB) shell เพิ่มเติมถ้าไม่มีการติดแท็กให้ allocation ต่อให้เปิดไว้ก็ไม่มีประโยชน์
สามารถเปิด user space heap MTE เต็มรูปแบบบน OS ปกติผ่าน Scudo ซึ่งเป็น allocator เริ่มต้นได้ แต่ตอนนี้ยังไม่ใช่อิมพลีเมนเทชันที่เสริมความแข็งแกร่งเป็นพิเศษ
KASan ที่ใช้ MTE backend ก็เปิดใช้ได้ด้วย
setpropเช่นกัน แต่ตอนนี้ไม่ได้ออกแบบมาเพื่อการ hardening และอนาคตจะเป็นแบบนั้นหรือไม่ก็ยังไม่ชัดเจนในเคอร์เนลน่าจะต้องมีอิมพลีเมนเทชัน MTE แยกต่างหาก ไม่ใช่แค่บางส่วนของ KASan และ GrapheneOS เองก็ยังไม่ได้ทำ ดังนั้นการ hardening ด้วย MTE ในปัจจุบันจึงเป็นฟีเจอร์ของ user space
GrapheneOS ใช้อิมพลีเมนเทชัน hardware memory tagging ของตัวเองสำหรับ hardened_malloc และมีคุณสมบัติด้านความปลอดภัยที่แข็งแกร่งกว่า
หากจะเปิดเป็นค่าเริ่มต้นใน OS ปกติ จำเป็นต้องแก้หรือหาทางเลี่ยงปัญหาหลายอย่างรวมถึงประเด็นนี้
แทนที่จะใช้ asynchronous MTE บนคอร์หลัก มันใช้โหมด asymmetric บนทุกคอร์
โหมด asymmetric จะเป็น asynchronous สำหรับการเขียน แต่ synchronous สำหรับการอ่าน จึงไม่เปิดช่องเวลาให้เอ็กซ์พลอยต์สำเร็จและสามารถบล็อกได้อย่างเหมาะสม
มีการตรวจสอบที่ system call และ
io_uringซึ่งอาจเป็นอีกช่องทางเลี่ยงหนึ่ง ก็ถูกอนุญาตใน Android ให้ใช้ได้เฉพาะ 2 โปรเซสระบบหลักด้วยข้อจำกัดของ SELinuxfastbootdใช้เฉพาะระหว่างการติดตั้ง และsnapuserdใช้ใน OS หลักหลังจากนำอัปเดตไปใช้GrapheneOS ใช้ heap MTE เสมอกับแอปที่ยืนยันแล้วว่าเข้ากันได้กับ OS ปกติ
สำหรับแอปที่ผู้ใช้ติดตั้งเองซึ่งไม่มีอยู่ในฐานข้อมูลความเข้ากันได้และไม่ได้ประกาศว่าเข้ากันได้ด้วยตัวเอง จะมีตัวสลับ MTE แยกเป็นรายแอป
ผู้ใช้ยังสามารถตั้งให้บังคับใช้ MTE กับแอปที่ติดตั้งเองทั้งหมดเป็นค่าเริ่มต้น และยกเว้นเฉพาะแอปที่ไม่เข้ากันได้ก็ได้
เพื่อให้ใช้งานสิ่งนี้ได้จริง จำเป็นต้องมีระบบรายงานการแครชที่ผู้ใช้มองเห็นได้ และได้ทำให้สามารถคัดลอกส่งรายงานการแครชที่เป็นประโยชน์ต่อผู้พัฒนาได้อย่างง่ายดาย
พอค้นหา Memory Tagging Extensions ในการตั้งค่าก็เห็นเหมือนมีอยู่ เลยนึกว่าถูกซ่อนไว้ที่ไหนสักแห่ง แต่กลายเป็นว่ามีเฉพาะในโทรศัพท์ Pixel 8: https://news.ycombinator.com/item?id=38125379
GrapheneOS นำหน้าอย่างมากในด้านความปลอดภัยจนทำให้รู้สึกว่าน่าสงสัยที่จะเลือกอย่างอื่นที่ไม่ใช่ฮาร์ดแวร์ Pixel
แต่ก็อยากได้ แบตเตอรี่แบบถอดเปลี่ยนได้ จริง ๆ
ไม่รู้ว่าทำไมทุกอย่างทุกวันนี้ถึงแย่แบบนี้
อุปกรณ์ Android อื่น ๆ ยังเทียบไม่ติด
การรองรับ hardware memory tagging เป็นหนึ่งในข้อได้เปรียบด้านความปลอดภัยใหญ่หลายข้อของ Pixel
รายการข้อกำหนดฮาร์ดแวร์อย่างเป็นทางการอยู่ที่นี่: https://grapheneos.org/faq#future-devices
ข้อกำหนดเหล่านี้ถูกตอบครบถ้วนใน Pixel รุ่นที่ 8
Pixel รุ่นที่ 6/7 ขาดเพียง MTE, BTI และ PAC โดย MTE เป็นฟีเจอร์ที่มีคุณค่ามากที่สุดในรายการข้อกำหนดฮาร์ดแวร์
การมี security patch ที่เหมาะสมสำคัญกว่า และนอก Pixel ก็ไม่ได้ให้มาในรูปแบบเดียวกัน
Android มีการออกรุ่นรายเดือน รายไตรมาส และรายปี
Android OEM รายอื่นให้ monthly security backport ครบเฉพาะการแก้ไขระดับความรุนแรง Critical/High ส่วนการแก้ไขระดับ Moderate/Low ซึ่งรวมถึงการแก้ไขด้านความเป็นส่วนตัวส่วนใหญ่ มักไม่ได้ให้ครบ
การใช้ OS ทางเลือกเพื่อให้ได้แพตช์เหล่านี้ช่วยบรรเทาได้บางส่วน แต่ OS ทางเลือกสำหรับอุปกรณ์เหล่านั้นมักทำให้ความปลอดภัยถอยหลังในหลายด้าน
เฟิร์มแวร์และโค้ดรองรับอุปกรณ์จำนวนมากจริง ๆ แล้วมาจาก OEM
สามารถนำ Android 14 QPR2 มารันบนเคอร์เนล/ไดรเวอร์ของ Android 12 ได้ แต่จะทำให้พลาดการปรับปรุงความปลอดภัยในส่วนใหญ่ของ OS
แบตเตอรี่ Pixel ไม่ได้เปลี่ยนง่ายแบบไม่เสี่ยงทำให้อุปกรณ์เสียหาย แต่มีการรองรับอย่างเป็นทางการและมีอะไหล่อย่างเป็นทางการ: https://www.ifixit.com/Device/Google_Pixel
เราไม่สามารถรองรับอุปกรณ์ที่ไม่ปลอดภัยและขาดแม้แต่พื้นฐานได้
ในรายการข้อกำหนดฮาร์ดแวร์ของเรามีทั้งสิ่งพื้นฐานมาก ๆ ที่ Android OEM ส่วนใหญ่ไม่ให้มา และฟีเจอร์ขั้นสูงอย่าง MTE ที่ตอนนี้เรามองว่าเป็นข้อกำหนดพื้นฐานของความปลอดภัยที่เหมาะสม
เราอยากรองรับอุปกรณ์อื่นด้วย แต่เครื่องเหล่านั้นต้องผ่านข้อกำหนดเหล่านี้
memory tagging เป็นฟีเจอร์พื้นฐานที่คอร์มาตรฐาน Cortex ARMv9 รองรับ
น่าเสียดายที่ Qualcomm ไม่ได้นำมันมาใช้ และ OEM ที่ใช้ SoC ที่รองรับสิ่งนี้ก็ไม่ได้เปิดใช้เช่นกัน
เป็นเรื่องน่าเศร้าที่ตัวสถาปัตยกรรม CPU มีฟีเจอร์นี้อยู่ แต่กลับใช้งานไม่ได้เพราะ SoC หรือ OEM
อย่างน้อย Pixel 8 ก็มีกำหนดรองรับ 7 ปี ซึ่งถือว่าดี
ทั้ง Apple และ Samsung ก็ไว้ใจได้ยาก และ Google กลายเป็นตัวเลือกที่ดีที่สุดไปแล้ว
อยากให้คนที่ใช้ GrapheneOS มาตอบหน่อย
แต่ล่าสุดตอนที่ผมไป Orlando, Florida กับภรรยาเพื่อเที่ยว Disney World และ Universal Studios แม้ว่าแอปส่วนใหญ่จะทำงานได้ด้วย Google Play Services แบบ sandboxed แต่ก็มีปัญหาน่ารำคาญอยู่
แอป My Disney Experience มีปัญหาเกี่ยวกับตำแหน่งค่อนข้างบ่อย และบางครั้งขึ้นว่าต้องอยู่ในสหรัฐฯ หรือแคนาดาจึงจะทำงานสำคัญบางอย่างได้ ทำให้ผมต้องใช้โทรศัพท์ของภรรยาเป็นทางออกชั่วคราว
ส่วนแอป Universal ล็อกอินเข้าบัญชีไม่ได้ ทั้งที่บน Samsung Galaxy มาตรฐานของภรรยากลับใช้ได้ จึงดูเหมือนเป็นปัญหาของ GrapheneOS
อีกอย่าง ถ้าจะใช้ Google Wallet เพื่อจ่ายเงินด้วยบัตรเครดิต จะไม่รองรับ เพราะ Google ไม่รับรอง GrapheneOS
แต่ฟังก์ชันอื่นของ Wallet ใช้งานได้
Uber ใช้งานได้ไม่มีปัญหา
นอกเหนือจากนั้น ผมไม่ได้ใช้แอป proprietary
ถ้าคุณตั้งใจจะใช้แอปเสรี/โอเพนซอร์สเป็นหลัก ก็น่าจะไม่มีปัญหา
แอป proprietary ส่วนใหญ่ใช้งานได้กับ Google Play Services แบบ sandboxed แต่ถ้ามีแอปสำคัญต่อการทำงานจริง ๆ ก็อาจเจอปัญหาน่ารำคาญแบบที่ผมเจอกับ Universal Studio และ My Disney Experience ได้
ผมใช้สาย USB ปกติกับ
adbบน command line ของ Linux แต่วิธีที่แนะนำคือใช้ WebUSB ของ Chromium ซึ่งน่าจะง่ายกว่าสำหรับคนที่ไม่ใช่สายเทคนิคแต่กรณีของผมมันใช้งานไม่ได้ดีนัก
มี Google Play Services แบบ sandboxed ทำให้สามารถติดตั้งแอป proprietary ทั้งหลายที่ช่วยให้ใช้ชีวิตยุคนี้ได้ โดยที่ Google Play ก็ยังเข้าไม่ถึงทั้งเครื่องแบบไร้ขีดจำกัด จึงได้ข้อดีทั้งสองด้าน
ถ้าอยากแยกให้มากขึ้น ก็สามารถสร้างผู้ใช้แยกแล้วให้รันรายการที่เกี่ยวกับ Google Play ในบัญชีนั้นได้
ผมเคยลองแป๊บหนึ่ง แต่ส่วนตัวรู้สึกว่าการสลับผู้ใช้ทุกครั้งมันน่ารำคาญ
โทรศัพท์ไม่เคยแครชเลย และแอปธนาคารก็ใช้งานได้
อุปกรณ์คือ Pixel 6a
จะซื้อเครื่องที่ติดตั้งไว้แล้วก็ได้ แต่แทบทุกคนใช้ตัวติดตั้งผ่านเว็บได้
บน Android, ChromeOS และ macOS จะง่ายเป็นพิเศษ ส่วน Windows จะยุ่งยากขึ้นเล็กน้อยเพราะต้องติดตั้งไดรเวอร์
เดสก์ท็อป Linux ต้องติดตั้งกฎ
udevและบางดิสโทรที่ตรึงเวอร์ชันซอฟต์แวร์ไว้มีบริการที่มีบั๊กซึ่งมาขัดขวางคนที่ไม่ใช่สายเทคนิคก็ทำได้ ขอแค่มีเบราว์เซอร์ที่รองรับ WebUSB
ไม่ต้องใช้ซอฟต์แวร์พิเศษ
สำหรับการใช้งานประจำวัน ถ้าใช้ Google Play แบบ sandboxed ก็แทบไม่ต่างจาก Pixel OS เดิม และความเข้ากันได้กับแอปก็แทบพอ ๆ กัน
โอกาสที่จะเจอแครชมากขึ้นอย่างมีนัยสำคัญมีน้อย
มีระบบรายงานแครชฝั่งผู้ใช้ที่ใน OS เดิมไม่มี จึงอาจทำให้คุณสังเกตเห็นแครชที่ปกติคงไม่รู้ตัว
แอปที่มีบั๊กมากและมี memory corruption อาจแครชได้จนกว่าจะเปิดโหมดความเข้ากันได้รายแอป โดยเฉพาะถ้าคุณเลือกบังคับใช้ MTE กับทุกแอปที่ผู้ใช้ติดตั้ง
แอปธนาคารจะใช้งานได้ถ้าธนาคารยอมให้ใช้ OS ที่ไม่ได้รับการรับรองจาก Google ซึ่งตอนนี้ส่วนใหญ่ยังยอมอยู่
แต่ธนาคารกำลังค่อย ๆ บล็อก OS ที่ไม่ได้รับการรับรองจาก Google มากขึ้น ซึ่งโดยเนื้อแท้แล้วควรถูกจัดการในฐานะประเด็นกำกับดูแลด้านการผูกขาดการแข่งขัน
ระหว่างนี้ก็กำลังพยายามโน้มน้าวให้ธนาคารใช้ https://grapheneos.org/articles/attestation-compatibility-guide
ฟีเจอร์ความปลอดภัยเพิ่มเติม การตั้งค่า sandboxing และ hardened memory allocator ทำให้มีความช้าลงเล็กน้อย และยุ่งยากกว่าการใช้ Android เดิม ๆ แล้วกด OK กับทุกคำขอเข้าถึงข้อมูล
ตอนตั้งค่าเริ่มต้น รวมถึงการทำความเข้าใจว่า GrapheneOS ต่างจากอะไรอย่างไร และจะใช้ฟีเจอร์ความปลอดภัยอย่างไร ก็ต้องใช้เวลาอยู่บ้าง
ตลอด 4 ปีที่ใช้มาไม่เคยมีแครช
อย่างน้อยก็ไม่เคยมีการแครชทั้งระบบ และจากประสบการณ์ก็ไม่ค่อยเกิดแครชที่ต้องมานั่งดีบักหลายวัน เพราะฮาร์ดแวร์กับซอฟต์แวร์ของ Pixel เข้ากันได้ดี
แอปธนาคารขึ้นอยู่กับแต่ละแอป
บางแอปทำงานได้โดยไม่ต้องมี Play Services ส่วนใหญ่ทำงานได้กับ Play Services แบบ sandboxed และมีเพียงส่วนน้อยมากที่ใช้ไม่ได้เลย
ถ้าคุณบอกว่าคุณใช้ธนาคารไหน ก็อาจมีผู้ใช้อื่นช่วยเช็กให้ได้ว่าใช้งานได้ไหม
แม้แต่วิธีติดตั้งที่ยากกว่าก็แค่ต่อโทรศัพท์ผ่าน USB กดปุ่มพาวเวอร์/ปรับเสียงเล็กน้อย แล้วคัดลอกวางคำสั่งในเทอร์มินัลสักสองสามคำสั่ง
วิธีง่ายคือแค่ต่อโทรศัพท์เข้ากับคอมพิวเตอร์ แล้วกด ปุ่มติดตั้งแบบคลิกเดียว ที่ทำงานในเบราว์เซอร์ Chrome
ผมใช้มันเป็น OS ประจำวันแทบตลอดตั้งแต่ Pixel 6 ออกใหม่ ๆ และไม่เคยแครชเลยสักครั้ง
ไม่เคยมีบั๊กหรือมีอะไรที่ต้องดีบัก แก้ไข หรือบำรุงรักษา
ทุกแอปที่ผมลองใช้ทำงานได้เหมือน Android เดิม ๆ แบบใช้งานได้เลย และพูดตามตรงแทบไม่รู้สึกถึงความต่าง
บางทีก็ลืมไปด้วยซ้ำว่านี่ไม่ใช่ OS ที่ติดมากับโทรศัพท์ตั้งแต่แรก
ส่วนตัวแอปธนาคาร Discover ใช้งานได้ แต่แอปอื่น ๆ ผมไม่แน่ใจ
อย่างไรก็ดี มี Google Play services และหลังติดตั้งแล้ว bootloader จะถูกล็อกกลับ ดังนั้นแอปส่วนใหญ่น่าจะใช้ได้
ในปี 2024 เราต้องการ ระบบปฏิบัติการ แอปพลิเคชัน และเครื่องมือที่ผ่านการพิสูจน์เชิงรูปแบบ ซึ่งสืบทอดแนวคิดของ seL4 แต่เข้มงวดยิ่งกว่า
การเอา codebase ที่ออกแบบเกินความจำเป็นแต่ทดสอบมาแบบผิวเผิน กับภาษาที่เปราะบางและอันตราย มาต่อ ๆ กันในยุคแบบนี้ คือการเปิดทางให้ผู้ไม่หวังดีจากต่างชาติเจาะระบบจนผู้ใช้อาจเสียชีวิตได้ และยังสร้างทั้งบั๊กน่ารำคาญ มัลแวร์ และพื้นผิวการโจมตีจากการแฮ็กจำนวนมาก
และบนสิ่งนั้นก็ยังต้องมอบประสบการณ์ผู้ใช้ที่สะอาดและเป็นหนึ่งเดียว รวมถึงฟังก์ชันที่ใช้งานได้จริงด้วย ไม่เช่นนั้นงานวิศวกรรมทั้งหมดก็สูญเปล่า
ดู Qubes OS ได้เลย
มีคอมพิวเตอร์บอร์ดเดี่ยวที่ใช้ได้ดีตัวไหนบ้างที่รองรับ Arm MTE? พวกอย่าง Raspberry Pi รุ่นใหม่ ๆ น่ะ
RasPi 5 เป็นควอด A76 และใช้ส่วนขยาย v8.2 ส่วน MTE อยู่ใน v8.5
ถ้าเทียบกับ CHERI แล้ว MTE เป็นอย่างไร?
MTE มีไว้เพื่อค้นหาบั๊กด้านความปลอดภัยที่อาจเกิดขึ้น ไม่ใช่การป้องกันจริงเต็มรูปแบบ
แท็กมีเพียง 4 บิต และแอปพลิเคชันก็ปลอมแปลงได้ ดังนั้นถ้าผู้โจมตีต้องเดาแท็กให้ถูก ต่อให้สุ่มก็ยังมีโอกาสถูก 1/16
แนวคิดของ MTE คือทำให้ตรวจจับการเข้าถึงผิดพลาดที่อาจเกิดขึ้นเป็นครั้งคราวแม้ไม่ใช่ฝีมือผู้โจมตี และอาจยังไม่ก่อผลเสียจริงได้
ถ้านึกถึงบัฟเฟอร์โอเวอร์โฟลว์แบบทั่วไป คำถัดจากท้ายบัฟเฟอร์อาจยังไม่ได้ถูกใช้เพื่อวัตถุประสงค์อื่น ทำให้ในทางปฏิบัติโค้ดยังทำงานต่อได้
MTE จะตรวจจับการเข้าถึงแบบนี้ และทำให้สามารถสืบสวนกับแพตช์ได้ก่อนจะถูกทำให้เป็น exploit ที่ใช้โจมตีได้จริง
อย่างไรก็ตาม มันสามารถให้คุณสมบัติความปลอดภัยแบบกำหนดแน่นอนได้ผ่าน reserved tags
สิ่งที่ไม่ถูกแท็กจะมีแท็กเป็น 0 และสิ่งที่ถูกแท็กโดยปกติจะมีแท็กที่ไม่ใช่ 0 เพราะมีการยกเว้นค่าเริ่มต้น
แท็กอื่น ๆ ก็สามารถถูกยกเว้นแบบคงที่หรือแบบไดนามิกได้ผ่านคำสั่ง แต่ถ้าใช้แท็ก 0 กับวัตถุประสงค์ภายในอย่างหน่วยความจำที่ถูก free แล้ว ก็อาศัยข้อเท็จจริงได้ว่าพอยน์เตอร์ที่มีแท็กใด ๆ จะเข้าถึงมันไม่ได้
ใน hardened_malloc จะมีการยกเว้นแท็กของสลอตที่จัดสรรซึ่งอยู่ติดกันและแท็กที่เคยใช้ก่อนหน้าแบบไดนามิก
ทำให้ได้การป้องกันแบบกำหนดแน่นอนต่อ linear overflow และ overflow ขนาดเล็ก
ในกรณี use-after-free พอยน์เตอร์ที่ชี้ไปยังการจัดสรรที่ถูก free แล้วจะเข้าถึงไม่ได้ในช่วงที่มันยังถูก free อยู่หรือทันทีหลังถูกจัดสรรใหม่ และต้องรอจนกว่าจะถูกนำกลับมาใช้อีกครั้ง โดยตอนนั้นโอกาสที่จะมีแท็กถูกต้องคือ 1/15
สิ่งนี้ทำงานร่วมกับคุณสมบัติความปลอดภัยอื่น ๆ ของ hardened_malloc ได้ดี
มีการใช้โซนแยกแบบ FIFO/สุ่มสำหรับการจัดสรรแบบ slab และหน่วยความจำเสมือน เพื่อหน่วงการนำกลับมาใช้และทำให้ไม่เป็นแบบกำหนดแน่ชัดมากขึ้น
จนกว่าจะเกิน 128k จะไม่มีการนำตำแหน่งหน่วยความจำกลับมาใช้ข้ามคลาสขนาดการจัดสรรที่ต่างกันเลย และแต่ละคลาสจะอยู่กันคนละบริเวณ ขณะที่เมทาดาทาทั้งหมดก็อยู่ในพื้นที่สำรองอีกส่วนหนึ่ง
โดยทั่วไป MTE ตอนนี้มีแค่ 4 บิต จึงมีโอกาสหลบเลี่ยงได้ราว 1/15
มันขยายให้รองรับการใช้ 8 บิตได้ไม่ยาก และถ้าไม่ใช้ PAC ก็ยังมีบิตว่างอื่นอีก
ในทางทฤษฎี บนพื้นที่แอดเดรส 39 บิตทั่วไป มันสามารถรองรับ MTE ได้สูงสุด 16 บิตสำหรับพื้นที่แอดเดรส 48 บิตขึ้นไป
ตอนนี้มันถูกตรึงไว้ที่ 4 บิต และเคยได้ยินมาว่าเลือกแบบนี้แทน 8 บิตเพื่อให้สามารถเก็บบิตเพิ่มไว้ในหน่วยความจำแบบ ECC parity ได้
แต่ตรวจจับได้ไม่น่าเชื่อถือเท่า CHERI
ไม่มีการป้องกันตัวแท็กเอง และพื้นที่แท็กก็เล็ก (2^4)
รอวันที่ฮาร์ดแวร์กระแสหลักจะตาม memory tagging architectures ของ Solaris SPARC ปี 2015 หรือเก่ากว่านั้นได้ทัน และสุดท้ายเราจะควบคุมปัญหา memory corruption ได้
แน่นอนว่าปัญหาเหล่านั้นมักถูกมองปัดว่าเป็นเรื่องที่มีแต่คนเขียนโค้ดไม่เก่งเท่านั้นที่สร้างขึ้น
นี่ไม่ใช่ปัญหาของ “นักพัฒนาที่ไม่เก่ง” แต่เป็นปัญหาของทุกคน
memory corruption แทบจะเป็นฟีเจอร์ของภาษา C/C++ อยู่แล้ว
ไม่ควรเผยแพร่ความเชื่อว่ามันเกิดจากคนโง่
แทบไม่มีใครคิดว่าตัวเองโง่ และผมก็เคยเห็นโค้ดเดอร์เก่งมาก ๆ ทำบั๊กหน่วยความจำแบบน่าขันเหมือนกัน
มันเป็นส่วนหนึ่งของโลกของภาษาพวกนั้น และไม่ใช่คำถามว่า “จะเกิดไหม” แต่เป็น “เมื่อไร”
ชอบที่มีการสอดประโยคเข้ามาเนียน ๆ ว่านี่แสดงให้เห็นเหตุผลที่ Android ย้ายโค้ด Bluetooth ไปเป็น Rust ไปมากแล้ว และควรทุ่มทรัพยากรเพิ่มเพื่อย้ายส่วนที่เหลือไปเป็น Rust ด้วย
ผมใช้ C และ C++ มาหลายปี แต่ไม่มีประสบการณ์กับ Rust เลย เลยสงสัยว่าการพอร์ตจาก C ไป Rust ต้องรีแฟกเตอร์มากแค่ไหน
ถ้าแยกคำถามออกมาเป็น 1. C แปลตรงไปเป็น Rust ได้มากน้อยแค่ไหน? Rust บังคับให้ต้องจัดโครงสร้างใหม่หรือรีแฟกเตอร์หรือไม่?
2. Google เข้าหาเรื่องนี้อย่างไร? เขาพยายาม “แปล” ให้ใกล้เคียงที่สุด หรือมองเป็นโอกาสสำหรับการเขียนใหม่และรีแฟกเตอร์ครั้งใหญ่?
และก็สงสัยด้วยว่าสแต็ก Android Bluetooth จะใช้บนระบบเดสก์ท็อป Linux distro ทั่วไปได้ในสักวันไหม
เพราะมี circular reference เยอะมาก โครงสร้างเลยเป็นแบบที่โมดูลสื่อสารกันผ่าน “signal bus” ที่มี callback และรู้สึกเหมือนต้องสู้กับ Rust มากกว่าที่มันจะช่วย
หลายจุดต้องใช้ Box ซึ่งเป็น heap pointer แม้ใน C++ จะเก็บข้อมูลแบบ inline ได้
สรุปคือถ้าเป็นเครื่องมือบรรทัดคำสั่งง่าย ๆ หรือโครงสร้างแบบ request-response การพอร์ตไป Rust ก็น่าจะง่าย
โดยทั่วไปแล้ว ถ้าโครงสร้างโค้ดเข้ากับ arena allocation ได้ดี การย้ายไปใช้การอ้างอิงที่มี lifetime annotation ก็ไม่ได้เป็นปัญหาใหญ่
แต่ถ้าคุณเขียนโค้ดแบบโปรแกรมเมอร์ C ที่มี circular reference เต็มไปหมด ซึ่งยอมรับว่าไม่สวย Rust จะให้ความรู้สึกเหมือนทางชันและไม่ใช่จุดที่ควรเริ่มต้น
ควรเปลี่ยนโครงสร้างโค้ด C++ ก่อน ย้าย ownership ไปไว้ที่ parent กลางร่วมกัน
แบบนั้นน่าจะดีขึ้น
ผมตั้งใจจะค่อย ๆ เรียนรู้ Rust เพิ่มไปเรื่อย ๆ แต่จะยังทำงานใน C++ ต่อจนกว่าโค้ดจะเข้ากับ Rust ได้ดีขึ้น
คุณคงต้องทำสถาปัตยกรรมใหม่ให้กับส่วนใหญ่ของสิ่งที่กำลังเขียนอยู่
หลีกเลี่ยงไม่ได้เพราะวิธีที่ Rust ใช้เพื่อรับประกัน memory safety