- Data Memory-Dependent Prefetcher (DMP) ปฏิบัติต่อค่าข้อมูลในโค้ดเข้ารหัสเหมือนเป็นที่อยู่ ทำให้คีย์ลับอาจรั่วได้แม้ในการใช้งานแบบ constant-time
- บน CPU Apple m-series เมื่อค่าที่โหลดจากหน่วยความจำดูเหมือน pointer, DMP จะพยายาม dereference ทำให้สมมติฐานของการเขียนโปรแกรมแบบ constant-time เรื่อง การแยกข้อมูลกับที่อยู่ สั่นคลอน
- นักวิจัยสาธิต การสกัดคีย์แบบ end-to-end บน Apple m1 สำหรับ OpenSSL Diffie-Hellman, การถอดรหัส Go RSA, CRYSTALS-Kyber และ CRYSTALS-Dilithium และยังยืนยันพฤติกรรม DMP ที่คล้ายกันบน m2·m3
- บน m3 DIT bit ปิดใช้งาน DMP ได้อย่างมีประสิทธิภาพ แต่ใช้ไม่ได้กับ m1·m2 และ HID setting bit ที่ค้นพบในเดือนเมษายน 2024 ยังใช้งานได้ยากทันทีเพราะไม่มีการรองรับจากเคอร์เนล macOS
- แนวทางบรรเทารวมถึงการใช้ซอฟต์แวร์เวอร์ชันล่าสุด, การใช้ DIT/DOIT bit บน CPU บางรุ่น, input blinding และการหลีกเลี่ยงการแชร์ฮาร์ดแวร์ ส่วนการประเมินช่องโหว่จำเป็นต้องใช้การวิเคราะห์การเข้ารหัสและการตรวจสอบโค้ด
แก่นสำคัญของการโจมตี GoFetch
- GoFetch คือการโจมตี side-channel ระดับ microarchitecture ที่ใช้ Data Memory-Dependent Prefetcher (DMP)
- สามารถสกัดคีย์ลับได้แม้จาก implementation การเข้ารหัสที่เขียนแบบ constant-time
- เป้าหมายที่นักวิจัยสาธิตมีดังนี้
- OpenSSL Diffie-Hellman Key Exchange
- Go RSA decryption
- CRYSTALS-Kyber
- CRYSTALS-Dilithium
- เอกสารวิจัยและเครื่องมือมีให้ที่ Paper, Tools ตามลำดับ
วิธีที่ DMP ทำลายสมมติฐาน constant-time
- DMP ของ CPU Apple m-series จะทำงานเมื่อข้อมูลที่โหลดจากหน่วยความจำเป็น ค่าที่ดูเหมือน pointer และพยายาม dereference
- การเขียนโปรแกรมแบบ constant-time ต้องแยกข้อมูลกับที่อยู่ออกจากกัน เพื่อไม่ให้ branch, loop, การเข้าถึงหน่วยความจำ หรือ array index เปลี่ยนไปตามค่าลับ
- แม้โค้ดของเหยื่อจะทำตามกฎนี้ แต่ DMP ก็สามารถสร้าง การเข้าถึงหน่วยความจำที่ขึ้นกับความลับ ขึ้นมาแทนได้ในระดับฮาร์ดแวร์
- ผลคือโค้ดที่เดิมควรเป็น constant-time เกิดความแตกต่างของเวลาที่สังเกตได้ และถูกเปิดทางให้โจมตีเพื่อสกัดคีย์
ขั้นตอนการโจมตี
- ผู้โจมตีสร้าง อินพุตที่เลือกได้ สำหรับใส่เข้าไปในการคำนวณเข้ารหัส เพื่อให้ค่าที่ดูเหมือน pointer ปรากฏในสถานะระหว่างทางเฉพาะเมื่อเดาส่วนหนึ่งของคีย์ลับได้ถูกต้องเท่านั้น
- จากนั้นใช้การวิเคราะห์ cache timing เพื่อตรวจสอบว่า DMP ได้ทำการ dereference หรือไม่ และยืนยันว่าการเดาถูกต้องหรือไม่
- เมื่อยืนยันการเดาที่ถูกต้องแล้ว ก็ใช้วิธีเดียวกันเดากลุ่มบิตของคีย์ถัดไป
- ด้วยขั้นตอนนี้ จึงสามารถสกัดคีย์แบบ end-to-end ได้จาก implementation ของการเข้ารหัสแบบคลาสสิกและ post-quantum
โปรเซสเซอร์ที่ได้รับผลกระทบและผลการสังเกต
- การโจมตี GoFetch แบบ end-to-end ดำเนินการบนฮาร์ดแวร์ที่ใช้โปรเซสเซอร์ Apple m1
- CPU m2 และ m3 ก็แสดงรูปแบบการเปิดใช้งาน DMP ที่สามารถถูกใช้โจมตีได้คล้ายกัน
- รุ่นย่อยอื่นของ m-series เช่น m2 Pro ยังไม่ได้ทดสอบ แต่ใช้ microarchitecture เดียวกับรุ่นปกติ จึงมีความเป็นไปได้ว่าจะมี DMP ที่ถูกใช้โจมตีได้
- microarchitecture Raptor Lake รุ่นที่ 13 ของ Intel ก็มี DMP เช่นกัน
- อย่างไรก็ตาม เกณฑ์การเปิดใช้งานจำกัดกว่า จึงทนทานต่อการโจมตี GoFetch
ความแตกต่างจาก Augury
- DMP ของ Apple m-series ถูกค้นพบครั้งแรกโดย Augury
- Augury มองว่า DMP อาจผสมข้อมูลกับที่อยู่ได้ในบางเงื่อนไข
- นักวิจัย GoFetch เห็นว่าเกณฑ์การเปิดใช้งาน DMP ที่ Augury สรุปไว้นั้นจำกัดเกินไป
- ในการทำงานจริง ค่าใดๆ ที่โหลดจากหน่วยความจำก็อาจเป็นตัวเลือกสำหรับ dereference ได้ ทำให้นำไปสู่การโจมตีแบบ end-to-end ต่อโค้ดเข้ารหัส constant-time จริง
พื้นฐานเรื่อง cache และ prefetcher
- โปรเซสเซอร์สมัยใหม่ใช้ cache เพื่อลดความหน่วงของการเข้าถึงหน่วยความจำ
- ข้อมูลที่เคยถูกเข้าถึงจะยังอยู่ใน cache ทำให้การเข้าถึงครั้งถัดไปเร็วขึ้น
- ผู้โจมตีที่รันอยู่บนเครื่องเดียวกันสามารถสังเกตสถานะ cache ที่แชร์กัน เพื่ออนุมานรูปแบบการเข้าถึงของเหยื่อได้
- prefetcher ทั่วไปคาดการณ์ที่อยู่ที่จะถูกเข้าถึงในอนาคตจากการติดตามที่อยู่ของการเข้าถึงหน่วยความจำก่อนหน้า
- DMP พิจารณาไปถึงเนื้อหาในหน่วยความจำเพื่อกำหนดข้อมูลที่จะดึงมา เพื่อจัดการรูปแบบการเข้าถึงที่ไม่สม่ำเสมอ เช่น การไล่ traversal ของ linked list
- พฤติกรรมนี้ผสมข้อมูลกับที่อยู่หน่วยความจำในระดับฮาร์ดแวร์ จึงทำให้ทั้ง stack การคำนวณดูเหมือนเป็น non-constant-time ได้
การ判断ว่ามีช่องโหว่หรือไม่และแนวทางบรรเทา
- หากจะ判断ว่า implementation มีช่องโหว่หรือไม่ ต้องรู้ว่าค่าระหว่างทางสามารถถูกทำให้ดูเหมือน pointer แบบขึ้นกับความลับได้เมื่อใดและอย่างไร
- การประเมินนี้ต้องใช้ การวิเคราะห์การเข้ารหัสและการตรวจสอบโค้ด เป็นงานทำด้วยมือ ใช้เวลาช้า และไม่สามารถตัดความเป็นไปได้ของวิธีโจมตีอื่นออกได้
- ในโปรเซสเซอร์บางรุ่นสามารถปิดใช้งาน DMP ได้
- ในเดือนเมษายน 2024 Hector Martin(marcan) ค้นพบ HID setting bit
SYS_APL_HID11_EL1[30]ที่ปิดใช้งาน DMP บน CPU m1·m2- การตั้งค่า chicken bit นี้ต้องมีการรองรับจากเคอร์เนล
- ปัจจุบัน macOS ไม่มีการรองรับดังกล่าว
- ข้อมูลที่เกี่ยวข้องอยู่ใน โพสต์ของ @marcan
- แนะนำให้ผู้ใช้ใช้ซอฟต์แวร์เวอร์ชันล่าสุดและอัปเดตเป็นประจำ
- นักพัฒนาไลบรารีเข้ารหัสสามารถตั้งค่า DIT/DOIT bit ได้บน CPU ที่รองรับ
- Input blinding อาจช่วยหลีกเลี่ยงค่าระหว่างทางที่ผู้โจมตีควบคุมใน crypto scheme บางประเภทได้
- การหลีกเลี่ยงการแชร์ฮาร์ดแวร์เพื่อไม่ให้ผู้โจมตีวัดการเปิดใช้งาน DMP ได้ จะช่วยเสริมความปลอดภัยของโปรโตคอลเข้ารหัสได้มากขึ้น
การเปิดเผยและอัปเดตต่อเนื่อง
- นักวิจัยเปิดเผยผลลัพธ์ต่อ Apple เมื่อวันที่ 5 ธันวาคม 2023 ซึ่งเป็นเวลา 107 วันก่อนการเผยแพร่สู่สาธารณะ
- ในเดือนสิงหาคม 2024 GoFetch ได้รับรางวัล Pwnie Award 2024 Best Cryptographic Attack
- งานวิจัยต่อเนื่องในเดือนธันวาคม 2024 reverse engineer semantics ของ Intel DMP และแสดงเทคนิคที่สามารถรั่วข้อมูลได้แม้ในกรณีที่ DMP dereference pointer ที่ไม่ถูกต้อง
- เอกสารวิจัยต่อเนื่องคือ Peek-a-Walk: Leaking Secrets via Page Walk Side Channels
- โค้ดอยู่ที่ Peek-a-Walk GitHub repository
1 ความคิดเห็น
ความคิดเห็นบน Hacker News
ถ้าเราอยู่ในยุคที่มีอย่างคอร์ประหยัดพลังงาน สถาปัตยกรรมสมัยใหม่ก็อาจจำเป็นต้องมี คอร์เข้ารหัส ด้วยก็ได้
คอร์แบบนี้ควรให้การรับประกันที่เกี่ยวข้องกับอัลกอริทึมแบบเวลาคงที่อย่างชัดเจน และไม่ทำอะไรอย่างการดึงข้อมูลล่วงหน้าหรือการทำนายสาขา
คล้าย Itanium แต่ถ้าจำกัดให้เป็น “โปรเซสเซอร์เข้ารหัส” ฟีเจอร์ที่ตัดออกไปก็คงเยอะ ดังนั้นโดยหลักการแล้วพื้นที่ซิลิคอนของตัวคอร์เองก็น่าจะไม่ใหญ่
ในมุมของคนที่ต้องเขียนโค้ดเข้ารหัส ปัญหาแบบนี้คงหนักจนอยากดื่มเหล้า แม้ในสถานการณ์ที่ดีที่สุดก็เป็นศึกที่ยากอยู่แล้ว ต่อให้ implement ถูกต้องทั้งหมด ฟีเจอร์มากมายของโปรเซสเซอร์ทั้งในปัจจุบันและอนาคตก็อาจทำให้โค้ดพังได้ทุกเมื่อ
แต่ ตัวประมวลผลร่วมสำหรับงานเข้ารหัส เป็นทางแก้ที่รุนแรงเกินไป ต้องสร้างโครงสร้างพื้นฐานกองโต ทั้งการสลับไปคอร์นั้นแล้วกลับมา การแชร์หน่วยความจำ และอื่น ๆ
ที่หนักกว่านั้นคือไม่ใช่ว่าย้ายเฉพาะการคูณ RSA ไปคอร์นั้นแล้วจบ คีย์คงถูก parse มาจากที่ไหนสักแห่ง แล้ว parser ต้องรันบนคอร์เข้ารหัสด้วยไหม? ถ้ามาจากเครือข่ายล่ะ? ต่อให้ปกป้องคีย์ทั้งหมดได้ แต่ถ้า side-channel ของ CPU ทำให้ข้อความที่เข้ารหัสแล้วรั่วไหล แบบนั้นโอเคไหม? มองว่าไม่เป็นไรเพราะไม่ใช่คีย์ได้หรือเปล่า?
เหตุผลที่การโจมตีแบบนี้ไม่ค่อยเห็นในโค้ดที่ไม่ใช่งานเข้ารหัส คือการหาเป้าหมายแตกต่างกันมากตามแต่ละแอปพลิเคชัน ส่วนในไลบรารีเข้ารหัส ทุกคนเห็นตรงกันว่าคีย์รั่วเป็นเรื่องแย่
สุดท้ายผู้ออกแบบโปรเซสเซอร์ต้องไม่ทำลายสมมติฐาน และอย่างน้อยก็ควรมาคุยกับเราก่อนทำ
หน่วยนามธรรมคงมีแนวโน้มเป็นระดับเธรด
https://support.apple.com/guide/security/secure-enclave-sec5...
แต่สถาปัตยกรรมคลาวด์ที่ปรับต้นทุนให้ต่ำสุดหันไปพึ่งฮาร์ดแวร์ผู้บริโภคจนกินตลาด CPU ไปแล้ว และตอนนี้แม้แต่แอปพลิเคชันขนาดใหญ่ ทางเลือกที่เป็นจริงได้ก็เหลือแค่ CPU ผู้บริโภค
หากต้องการให้ใช้อัลกอริทึมใหม่ ๆ ได้ การเพิ่มคำสั่ง primitive ด้านการเข้ารหัสบางอย่างก็อาจเป็นเรื่องดี
ตามรายงานระบุว่า “OpenSSL แจ้งว่าการโจมตี side-channel ในเครื่องอยู่นอก threat model และทีม Go Crypto มองว่าความรุนแรงของการโจมตีนี้ต่ำ”
บทสรุปสุดท้ายของการโจมตี side-channel แบบนี้ก็คงเป็น CPU ที่ไม่ทำ optimization ใด ๆ เลย และทุกคำสั่งใช้จำนวนไซเคิลเท่ากันในทุกสถานการณ์
แต่เรื่องแบบนั้นไม่มีทางเกิดขึ้นแน่ ๆ ไม่มีใครอยากได้ CPU ช้า
ถ้า exploit จากระยะไกลไม่ได้ ผมว่าไม่ใช่เรื่องที่ต้องกังวล แน่นอนว่า virtualization บนคลาวด์แบบหลายผู้เช่า ใช้ไม่ได้
ไม่มี speculative execution ไม่มี prefetching เป็นคอร์แบบ pipeline 5 ขั้นเหมือนที่เรียนในวิชา Computer Architecture 101 นั่นแหละ
มีผู้ให้บริการคลาวด์อยู่บ้างที่ให้เช่าเวลา compute ของ Mac Mini แบบติดแร็ก แต่มีไม่มาก และถึงมีก็มักใช้กับ workload หรือการ build ที่เฉพาะเจาะจงมาก
มันอาจเป็นปัญหาสำหรับคนที่จ่ายเงินจำนวนมากให้บริการแบบนั้น แต่เครื่อง Apple Silicon ส่วนใหญ่ท่วมท้นจะไม่มีวันไปโฮสต์บริการคลาวด์
ถ้าแยกโค้ดไว้กับคอร์เฉพาะ ภายใต้สมมติฐานว่าทุกอย่างทำงานตามที่ตั้งใจ exploit ก็จะไม่สามารถละเมิดผู้เช่ารายอื่นได้
ในหัวข้อ “ปิดใช้งาน DMP ได้ไหม?” มีคำตอบว่า “ได้ แต่ทำได้เฉพาะในโปรเซสเซอร์บางรุ่นเท่านั้น บน CPU M3 การตั้งบิต DIT จะปิด DMP ได้อย่างมีผล แต่บน M1 และ M2 ไม่เป็นเช่นนั้น”
น่าจะต้องมี chicken bit สำหรับปิดสิ่งนี้อยู่ที่ไหนสักแห่งไม่ใช่หรือ?
ทำใน Swift ได้ไหม หรือต้องใช้ assembly?
อ่านดูแล้ว ไลบรารีอย่าง libsodium น่าจะทำได้แค่ตั้ง บิตปิดใช้งาน ก่อนการทำงานเข้ารหัสที่อ่อนไหวบน M3 ขึ้นไป
อีกอย่าง ดูเหมือนว่าจะต้องรู้บางแง่มุมของคีย์ล่วงหน้าก่อน
เจ๋งมากก็จริง แต่ดูไม่ค่อยใช้งานได้จริงนัก
นึกถึง การโจมตี Augury เมื่อปี 2022 ขึ้นมา อันนั้นก็ใช้ประโยชน์จากการดึงข้อมูลล่วงหน้า DMP ของ CPU Apple Silicon เหมือนกัน
[1]: https://www.prefetchers.info
ทำไม Apple ถึงมีฮาร์ดแวร์แบ็กดอ… บั๊กบริสุทธิ์เยอะแบบนี้?
ตอบทฤษฎีสมคบคิดแบ็กดอร์ไร้สาระนั่นก็คือ ผู้คนต้องการ CPU ที่เร็ว โปรเซสเซอร์จึงมีแคชและความต่างของเวลา คุณไม่สามารถได้ทั้ง เวลาคงที่ และประสิทธิภาพสูงพร้อมกัน และ Apple ก็ไม่ใช่บริษัทเดียวที่มี prefetching
นี่คือเอกสารที่ Apple บอกวิธีเปิดการทำงานแบบเวลาคงที่สำหรับงานเข้ารหัสไว้ เหมือนกับว่ามันถูกออกแบบไว้ในฮาร์ดแวร์อย่างตั้งใจเลย แปลกดีนะ: https://developer.apple.com/documentation/xcode/writing-arm6...
ถ้าจะเขียน routine เข้ารหัส ก็ควรใช้ไลบรารีเข้ารหัสของแพลตฟอร์มหรือทำตามเอกสาร
https://developer.apple.com/documentation/xcode/writing-arm6...
ตอนนี้การตรวจมัลแวร์และ สแกนไวรัส บน Mac กับ iPad ก็เริ่มมีความหมายแล้ว
ผู้โจมตีต้องกำลังรันอยู่บนฮาร์ดแวร์เดียวกัน