1 คะแนน โดย GN⁺ 2024-03-23 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • 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 ได้
    • บน CPU m3 การตั้งค่า DIT bit จะปิดใช้งาน DMP ได้อย่างมีประสิทธิภาพ
    • ใช้ไม่ได้กับ m1 และ m2
    • บน Intel Raptor Lake สามารถปิดใช้งาน DMP ได้ด้วย DOIT bit
  • ในเดือนเมษายน 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 ที่ไม่ถูกต้อง

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

 
GN⁺ 2024-03-23
ความคิดเห็นบน Hacker News
  • ถ้าเราอยู่ในยุคที่มีอย่างคอร์ประหยัดพลังงาน สถาปัตยกรรมสมัยใหม่ก็อาจจำเป็นต้องมี คอร์เข้ารหัส ด้วยก็ได้
    คอร์แบบนี้ควรให้การรับประกันที่เกี่ยวข้องกับอัลกอริทึมแบบเวลาคงที่อย่างชัดเจน และไม่ทำอะไรอย่างการดึงข้อมูลล่วงหน้าหรือการทำนายสาขา
    คล้าย Itanium แต่ถ้าจำกัดให้เป็น “โปรเซสเซอร์เข้ารหัส” ฟีเจอร์ที่ตัดออกไปก็คงเยอะ ดังนั้นโดยหลักการแล้วพื้นที่ซิลิคอนของตัวคอร์เองก็น่าจะไม่ใหญ่
    ในมุมของคนที่ต้องเขียนโค้ดเข้ารหัส ปัญหาแบบนี้คงหนักจนอยากดื่มเหล้า แม้ในสถานการณ์ที่ดีที่สุดก็เป็นศึกที่ยากอยู่แล้ว ต่อให้ implement ถูกต้องทั้งหมด ฟีเจอร์มากมายของโปรเซสเซอร์ทั้งในปัจจุบันและอนาคตก็อาจทำให้โค้ดพังได้ทุกเมื่อ

    • ในมุมของผู้ implement งานเข้ารหัส ปัญหาแบบนี้ทำให้แทบบ้าได้จริง ๆ
      แต่ ตัวประมวลผลร่วมสำหรับงานเข้ารหัส เป็นทางแก้ที่รุนแรงเกินไป ต้องสร้างโครงสร้างพื้นฐานกองโต ทั้งการสลับไปคอร์นั้นแล้วกลับมา การแชร์หน่วยความจำ และอื่น ๆ
      ที่หนักกว่านั้นคือไม่ใช่ว่าย้ายเฉพาะการคูณ RSA ไปคอร์นั้นแล้วจบ คีย์คงถูก parse มาจากที่ไหนสักแห่ง แล้ว parser ต้องรันบนคอร์เข้ารหัสด้วยไหม? ถ้ามาจากเครือข่ายล่ะ? ต่อให้ปกป้องคีย์ทั้งหมดได้ แต่ถ้า side-channel ของ CPU ทำให้ข้อความที่เข้ารหัสแล้วรั่วไหล แบบนั้นโอเคไหม? มองว่าไม่เป็นไรเพราะไม่ใช่คีย์ได้หรือเปล่า?
      เหตุผลที่การโจมตีแบบนี้ไม่ค่อยเห็นในโค้ดที่ไม่ใช่งานเข้ารหัส คือการหาเป้าหมายแตกต่างกันมากตามแต่ละแอปพลิเคชัน ส่วนในไลบรารีเข้ารหัส ทุกคนเห็นตรงกันว่าคีย์รั่วเป็นเรื่องแย่
      สุดท้ายผู้ออกแบบโปรเซสเซอร์ต้องไม่ทำลายสมมติฐาน และอย่างน้อยก็ควรมาคุยกับเราก่อนทำ
    • ทิศทางที่เป็นไปได้มากกว่าน่าจะเป็น การสลับโหมด ที่ปิดองค์ประกอบเหล่านี้ของ CPU ได้ในช่วงบางส่วนของโค้ดที่กำลังรัน
      หน่วยนามธรรมคงมีแนวโน้มเป็นระดับเธรด
    • นั่นไม่ใช่เหตุผลที่ Secure Enclave มีอยู่หรือ?
      https://support.apple.com/guide/security/secure-enclave-sec5...
    • MMU แบบบัสเข้ารหัสมีมาตั้งแต่ทศวรรษ 1990 แล้ว
      แต่สถาปัตยกรรมคลาวด์ที่ปรับต้นทุนให้ต่ำสุดหันไปพึ่งฮาร์ดแวร์ผู้บริโภคจนกินตลาด CPU ไปแล้ว และตอนนี้แม้แต่แอปพลิเคชันขนาดใหญ่ ทางเลือกที่เป็นจริงได้ก็เหลือแค่ CPU ผู้บริโภค
    • สถาปัตยกรรมสมัยใหม่จำนวนมากมักมี ส่วนขยายการเข้ารหัส ที่เร่งอัลกอริทึมทั่วไปอยู่ไม่กี่แบบ
      หากต้องการให้ใช้อัลกอริทึมใหม่ ๆ ได้ การเพิ่มคำสั่ง primitive ด้านการเข้ารหัสบางอย่างก็อาจเป็นเรื่องดี
  • ตามรายงานระบุว่า “OpenSSL แจ้งว่าการโจมตี side-channel ในเครื่องอยู่นอก threat model และทีม Go Crypto มองว่าความรุนแรงของการโจมตีนี้ต่ำ”

    • อย่างน้อยนักพัฒนางานคริปโตของ Go คนหนึ่งก็เคยแสดงความกังวลต่อสาธารณะเรื่องปัญหานี้โดยตรงตั้งแต่ปี 2021: https://github.com/golang/go/issues/49702
  • บทสรุปสุดท้ายของการโจมตี side-channel แบบนี้ก็คงเป็น CPU ที่ไม่ทำ optimization ใด ๆ เลย และทุกคำสั่งใช้จำนวนไซเคิลเท่ากันในทุกสถานการณ์
    แต่เรื่องแบบนั้นไม่มีทางเกิดขึ้นแน่ ๆ ไม่มีใครอยากได้ CPU ช้า
    ถ้า exploit จากระยะไกลไม่ได้ ผมว่าไม่ใช่เรื่องที่ต้องกังวล แน่นอนว่า virtualization บนคลาวด์แบบหลายผู้เช่า ใช้ไม่ได้

    • โค้ดที่ไม่น่าเชื่อถือทั้งหมดควรถูกโยนไปไว้บน คอร์แบบรันตามลำดับ ที่แย่มาก ๆ
      ไม่มี speculative execution ไม่มี prefetching เป็นคอร์แบบ pipeline 5 ขั้นเหมือนที่เรียนในวิชา Computer Architecture 101 นั่นแหละ
    • เพราะเรื่อง “virtualization บนคลาวด์แบบหลายผู้เช่า” ผมจึงไม่กังวลเท่าช่องโหว่แบบเดียวกันบนชิป Intel เมื่อหลายปีก่อน
      มีผู้ให้บริการคลาวด์อยู่บ้างที่ให้เช่าเวลา 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

    • อ้างอิงว่า ในบรรดาผู้เขียน GoFetch มีสามคนที่เคยร่วมทำ Augury ด้วย
    • ใช่ ในบทความและ FAQ พูดถึงเรื่องนั้นโดยเฉพาะ
  • ทำไม Apple ถึงมีฮาร์ดแวร์แบ็กดอ… บั๊กบริสุทธิ์เยอะแบบนี้?

    • ตั้งแต่แรก แคชจำเป็นตรงไหน? prefetching จำเป็นตรงไหน?
      ตอบทฤษฎีสมคบคิดแบ็กดอร์ไร้สาระนั่นก็คือ ผู้คนต้องการ CPU ที่เร็ว โปรเซสเซอร์จึงมีแคชและความต่างของเวลา คุณไม่สามารถได้ทั้ง เวลาคงที่ และประสิทธิภาพสูงพร้อมกัน และ Apple ก็ไม่ใช่บริษัทเดียวที่มี prefetching
      นี่คือเอกสารที่ Apple บอกวิธีเปิดการทำงานแบบเวลาคงที่สำหรับงานเข้ารหัสไว้ เหมือนกับว่ามันถูกออกแบบไว้ในฮาร์ดแวร์อย่างตั้งใจเลย แปลกดีนะ: https://developer.apple.com/documentation/xcode/writing-arm6...
    • เหตุผลเดียวกับที่ Intel และ AMD มี Meltdown กับ Spectre นั่นแหละ
  • ถ้าจะเขียน routine เข้ารหัส ก็ควรใช้ไลบรารีเข้ารหัสของแพลตฟอร์มหรือทำตามเอกสาร
    https://developer.apple.com/documentation/xcode/writing-arm6...

  • ตอนนี้การตรวจมัลแวร์และ สแกนไวรัส บน Mac กับ iPad ก็เริ่มมีความหมายแล้ว
    ผู้โจมตีต้องกำลังรันอยู่บนฮาร์ดแวร์เดียวกัน