Reptar: ช่องโหว่ FSRM/REX ของ CPU Intel
(lock.cmpxchg8b.com)- ในโปรเซสเซอร์ Intel บางรุ่น เมื่อ
rep movsทำงานร่วมกับ prefixrex.rที่ซ้ำซ้อนภายใต้การเพิ่มประสิทธิภาพ FSRM อาจทำให้ CPU เข้าสู่สถานะ “glitch” ที่หลุดจากกฎการทำงานปกติได้ - สาเหตุมาจาก การถอดรหัส prefix ของ x86 ที่ค่อนข้างยืดหยุ่น และในคำสั่งที่ใช้โอเปอแรนด์แบบแฝงอย่าง
movsbนั้น prefixrexซึ่งตามปกติไม่ควรมีความหมาย กลับไปเข้าสู่เส้นทางการเพิ่มประสิทธิภาพบางแบบได้ - ไปป์ไลน์ตรวจสอบของ Google พบผลลัพธ์ที่คาดเดาไม่ได้จากชุดค่าผสมนี้ในเดือนสิงหาคม 2023 และสังเกตเห็นการกระโดดแบบไม่คาดคิด การเพิกเฉยต่อการกระโดดแบบไม่มีเงื่อนไข และความผิดปกติของการบันทึกตัวชี้คำสั่งใน
xsaveและcall - หากหลายคอร์กระตุ้นบั๊กเดียวกันพร้อมกัน อาจเกิด machine check exception และระบบหยุดทำงานได้ และยังสามารถทำซ้ำได้ภายใน guest VM ที่ไม่มีสิทธิพิเศษ จึงสำคัญต่อสภาพแวดล้อมคลาวด์
- Intel เผยแพร่ อัปเดตไมโครโค้ด สำหรับโปรเซสเซอร์ที่ได้รับผลกระทบแล้ว และหากอัปเดตไม่ได้ สามารถปิด fast strings ใน
IA32_MISC_ENABLEได้ แต่จะแลกกับประสิทธิภาพที่ลดลงมาก
prefix ของ x86 และ rep movsb
rep movsbเป็นวิธีการย้ายหน่วยความจำแบบที่ใช้กันทั่วไปใน x86 โดยเมื่อกำหนด source, destination, direction และ count แล้ว โปรเซสเซอร์จะจัดการการคัดลอกซ้ำให้- คำสั่งจริงคือ
movsbและrepคือ prefix ที่เปลี่ยนให้คำสั่งนั้นถูกทำซ้ำหลายครั้ง - การถอดรหัสคำสั่งของ x86 ค่อนข้างยืดหยุ่น ดังนั้นแม้จะมี prefix ที่ไม่มีความหมายหรือขัดแย้งกันแนบมา ก็มักจะถูกเพิกเฉย
- คอมไพเลอร์สามารถใช้ prefix ซ้ำซ้อนเหล่านี้เพื่อ padding คำสั่งเดี่ยวให้พอดีกับขอบเขตการจัดแนวที่ต้องการได้
rex,vex,evexเป็น prefix ที่เปลี่ยนวิธีการถอดรหัสของคำสั่งถัดไป
ชุดค่าผสมที่ rex prefix กลายเป็นปัญหา
- i386 มีรีจิสเตอร์ใช้งานทั่วไป 8 ตัว จึงใช้ 3 บิตเพื่อระบุรีจิสเตอร์ได้ แต่ x86-64 มีรีจิสเตอร์ใช้งานทั่วไป 16 ตัว จึงต้องใช้บิตเพิ่ม
rexprefix ให้บิตพิเศษเพิ่มเติมที่คำสั่งถัดไปสามารถยืมไปใช้ตอนเข้ารหัสโอเปอแรนด์ได้- โดยปกติเขียนเป็น
rex.rxbและสามารถตั้งบิตb,x,r,wได้ตามต้องการ
- โดยปกติเขียนเป็น
movsbมีโอเปอแรนด์ที่ไม่ได้ระบุไว้ในคำสั่งและเป็นแบบแฝงทั้งหมด ดังนั้นบิตrexในrex.rxb rep movsbจึงไม่ควรมีความหมาย- โดยทั่วไปโปรเซสเซอร์จะเพิกเฉยต่อ
rexprefix แบบนี้อย่างเงียบ ๆ แต่ในระบบที่รองรับ fast short repeat move ชุดค่าผสมนี้สามารถนำไปสู่ช่องโหว่ได้
FSRM และโปรเซสเซอร์ที่ได้รับผลกระทบ
- FSRM เป็นฟีเจอร์ที่เริ่มใช้ใน Ice Lake เพื่อแก้ข้อจำกัดด้านการจัดการสตริงสั้นของ ERMS
- ERMS (enhanced repeat move/store) จัดการการจัดแนวบัฟเฟอร์และการเก็บข้อมูลแบบกว้างในไมโครโค้ด ทำให้โค้ด
rep movsbเดิมทำงานได้เร็วขึ้น- แต่มีค่าใช้จ่ายในการตั้งค่าช่วงต้นสูง จึงไม่เหมาะกับสตริงที่สั้นมาก
- FSRM เป็นฟีเจอร์สำหรับจัดการการย้ายข้อมูลสั้น ๆ ขนาด ไม่เกิน 128 ไบต์ ให้เร็วขึ้น
- สามารถตรวจสอบการรองรับได้จาก flag
fsrmในบรรทัดflagsของ/proc/cpuinfo - ตัวอย่างโปรเซสเซอร์ที่มี FSRM ได้แก่
- Ice Lake
- Rocket Lake
- Tiger Lake
- Raptor Lake
- Alder Lake
- Sapphire Rapids
- รายการนี้ไม่ครอบคลุมทั้งหมด และควรดูรายการเต็มจาก advisory ของ Intel หมายเลข INTEL-SA-00950
การค้นพบและการทำซ้ำ
- ไปป์ไลน์ตรวจสอบของ Google ใช้เทคนิค Oracle Serialization โดยรันโปรแกรมที่สร้างแบบสุ่ม 2 รูปแบบ แล้วเปรียบเทียบว่าสถานะสุดท้ายเหมือนกันหรือไม่
- คำอธิบายที่เกี่ยวข้องอยู่ในบทความก่อนหน้า Oracle Serialization
- ในเดือนสิงหาคม 2023 พบว่าการเติม prefix
rex.rที่ซ้ำซ้อนให้กับrep movsที่ถูกเพิ่มประสิทธิภาพด้วย FSRM ทำให้เกิดผลลัพธ์ที่คาดเดาไม่ได้ - พฤติกรรมผิดปกติที่สังเกตได้มีดังนี้
- กระโดดไปยังตำแหน่งที่ไม่คาดคิด
- เพิกเฉยต่อการกระโดดแบบไม่มีเงื่อนไข
- ตัวชี้คำสั่ง (instruction pointer) ถูกบันทึกอย่างไม่ถูกต้องในคำสั่ง
xsaveหรือcall - ดีบักเกอร์รายงานสถานะที่เป็นไปไม่ได้
- หากหลายคอร์กระตุ้นบั๊กเดียวกัน โปรเซสเซอร์อาจรายงาน machine check exception และหยุดทำงานได้
- สามารถทำซ้ำได้แม้อยู่ภายใน guest VM ที่ไม่มีสิทธิพิเศษ จึงเป็นประเด็นด้านความปลอดภัยที่สำคัญสำหรับผู้ให้บริการคลาวด์
- เครื่องมือสำหรับทำซ้ำและข้อมูลวิจัยเผยแพร่ไว้ใน security research repository ของ Google
- มี local mirror ของเครื่องมือ
icebreakให้ด้วยที่ icebreak.tar.gz
- มี local mirror ของเครื่องมือ
icebreakจะพยายามทำซ้ำโดยระบุคู่คอร์ที่ต่างกัน- บนระบบที่ไม่ได้รับผลกระทบ ควรไม่มีเอาต์พุตใด ๆ ราวกับวนลูปไม่สิ้นสุด
- บนระบบที่ได้รับผลกระทบ จะพิมพ์
.ทุกครั้งที่ทำซ้ำสำเร็จ - บนคอร์พี่น้องแบบ SMT อาจสังเกตเห็นการกระโดดแบบสุ่ม
- บนคอร์พี่น้องแบบ SMP ภายในแพ็กเกจเดียวกัน อาจสังเกตเห็น machine check
- หากไม่ได้ระบุสองคอร์ที่ต่างกัน อาจต้องใช้ hammer thread
สาเหตุที่เป็นไปได้และผลกระทบที่สังเกตได้
- การทำงานของไมโครโค้ดในระบบสมัยใหม่ไม่ได้เปิดเผยสู่สาธารณะ ดังนั้นสาเหตุรากแท้จริงจึงอธิบายได้เพียงเป็นทฤษฎีตามสิ่งที่สังเกตพบ
- CPU โดยใหญ่แบ่งเป็น frontend และ backend
- frontend ดึงและถอดรหัสคำสั่งเพื่อสร้าง μops
- backend รันคำสั่งแบบไม่เรียงลำดับ เก็บผลลัพธ์ไว้ใน ROB (reorder buffer) แล้วค่อยจัดระเบียบ
- บั๊กนี้ดูเหมือนจะทำให้ frontend คำนวณขนาดของคำสั่ง
movsbผิด และทำให้รายการ ROB ถัดไปถูกเชื่อมกับแอดเดรสที่ไม่ถูกต้อง - ในสถานะนี้จะเกิดภาวะสับสนที่ตัวชี้คำสั่งถูกคำนวณผิด
- ในท้ายที่สุดระบบสามารถกู้กลับสู่สถานะที่สอดคล้องกันภายในได้ แต่ผลลัพธ์ระหว่างทางอาจผิดพลาด
- หากหลายคอร์แบบ SMT หรือ SMP เข้าสู่สถานะนี้พร้อมกัน อาจเกิดความเสียหายต่อสถานะระดับไมโครสถาปัตยกรรมมากพอที่จะบังคับให้เกิด machine check ได้
- สถานะของระบบอาจเสียหายได้ถึงระดับที่ทำให้เกิด machine check และในการรันโปรเซสที่ถูกจัดตารางบนคอร์พี่น้องแบบ SMT ก็มีการสังเกตเห็นการรบกวนกันระหว่างเธรด
- ยังไม่ยืนยันว่าสามารถควบคุมความเสียหายได้ละเอียดพอสำหรับการยกระดับสิทธิ์หรือไม่
วิธีรับมือ
- Intel เผยแพร่ไมโครโค้ดที่อัปเดตแล้วสำหรับโปรเซสเซอร์ที่ได้รับผลกระทบทั้งหมดที่ INTEL-SA-00950
- ผู้ให้บริการระบบปฏิบัติการหรือ BIOS อาจมีการแจกจ่ายอัปเดตนี้อยู่แล้ว
- หากอัปเดตไม่ได้ สามารถปิดใช้งาน fast strings ผ่านรีจิสเตอร์เฉพาะรุ่น
IA32_MISC_ENABLEได้ - การปิด fast strings จะทำให้ประสิทธิภาพลดลงอย่างมาก จึงไม่ควรใช้เว้นแต่จำเป็นจริง ๆ
เอกสารบั๊ก CPU ที่เกี่ยวข้อง
- Google เผยแพร่บั๊ก CPU ที่ค้นพบ และบางรายการก็น่าอ่านแม้ไม่มีผลกระทบด้านความปลอดภัย
- ตัวอย่างเอกสาร
- movlps just doesn’t work: กรณีที่
movlpsใช้งานไม่ได้ - registers can sometimes roll back: กรณีที่รีจิสเตอร์ย้อนกลับไปเป็นค่าก่อนหน้า
- movlps just doesn’t work: กรณีที่
1 ความคิดเห็น
ความคิดเห็นจาก Hacker News
บทความที่เกี่ยวข้อง: https://cloud.google.com/blog/products/identity-security/goo...
เป็นเนื้อหามาจาก https://news.ycombinator.com/item?id=38268043 แต่คอมเมนต์ถูกรวมไว้ที่นี่
อ่านบทความนี้แล้วทำให้ตระหนักว่าผมไม่รู้อะไรเกี่ยวกับ ฮาร์ดแวร์ ที่ซอฟต์แวร์ของผมทำงานอยู่มากแค่ไหน
เขาบอกว่า “prefix ช่วยให้เปิดหรือปิดฟีเจอร์เพื่อเปลี่ยนพฤติกรรมของคำสั่งได้” เลยสงสัยว่าทำไมการเปิดปิดฟีเจอร์ถึงต้องใช้ “prefix”
มันเอาไว้สลับฟีเจอร์แบบไดนามิกโดยไม่ต้องเข้า BIOS หรือเปล่า?
REP prefix เป็นแบบที่พบบ่อยที่สุด ทำหน้าที่ให้ทำคำสั่งเดิมซ้ำตามจำนวนครั้งที่เปลี่ยนแปลงได้
จำนวนครั้งที่ทำซ้ำจะเอามาจากรีจิสเตอร์ CX และช่วยทำให้ลูปทั่วไปอย่างการย้ายออบเจ็กต์ในหน่วยความจำสั้นมาก
ฟังก์ชัน memcpy มักถูก inline เป็นคำสั่ง REP MOVS คำสั่งเดียว และถ้าจำเป็นก็จะมีคำสั่งคัดลอกค่า count ไปยัง CX เพิ่มเข้ามา
REX prefix ก็พบค่อนข้างบ่อย เพราะโปรแกรม 64 บิตจัดการกับค่าและแอดเดรส 64 บิตอยู่เป็นประจำ
ไม่มี prefix ใดที่ toggle สิ่งที่ตั้งค่าแบบ global ได้ผ่าน BIOS หรืออะไรทำนองนั้น ทั้งหมดเพียงแค่ระบุว่าคำสั่งถัดไปควรทำอะไร
โหมด addressing ที่ใช้น้อยจะมี “segment prefix” เพื่อให้ใช้ segment อื่นที่ไม่ใช่ DS และ “REX” prefix ของ x86_64 ก็เพิ่มบิตให้กับฟิลด์รีจิสเตอร์ ทำให้ใช้ general-purpose register ได้ 16 ตัว
ในทำนองเดียวกัน “LOCK” prefix แม้สเปกเดิมจะไม่ค่อยดีนัก แต่ก็ทำให้การทำงานกับหน่วยความจำบางอย่างเป็น atomic เมื่อเทียบกับส่วนอื่นของระบบ เช่นใช้ “LOCK CMPXCHG” เพื่อทำ compare-and-set
สถาปัตยกรรม CPU อื่นก็แสดง operation แบบนี้ได้เหมือนกัน แต่ปกติมักใส่ไว้ในพื้นที่คำสั่งเดิม ทำให้ต้องใช้บิตมากขึ้นเพื่อแทนคำสั่งทั้งหมด
โดยเฉพาะ “REP” prefix ที่เป็นปัญหาที่นี่ค่อนข้างเป็นข้อยกเว้น เพราะเป็น prefix สำหรับทำซ้ำด้วยไมโครโค้ดที่หลงเหลือมาตั้งแต่ยุคโบราณ
ถึงอย่างนั้นมันก็แทน operation ที่ยังอ่อนไหวต่อประสิทธิภาพในปัจจุบันอย่าง memset/memmove จึงคุ้มที่ผู้ผลิต CPU จะปรับแต่งต่อไป และบั๊กครั้งนี้ก็ดูเหมือนจะเกิดขึ้นในกระบวนการนั้น
ปัญหาใหญ่ที่สุดคือมัน “ใช้ประโยชน์อย่างมีประสิทธิภาพ” จาก พื้นที่ encoding ของคำสั่ง
พอภายหลังมีคำสั่งใหม่ ๆ และที่แย่กว่านั้นคือมีรีจิสเตอร์เพิ่ม ก็ต้องหาทางยัดรูปแบบคำสั่งใหม่เข้าไปให้ได้ และวิธีก็คือการต่อ prefix เข้าไป
ทุกครั้งที่ขยาย instruction set ก็จะขุดพื้นที่ opcode บางส่วนออกมาแล้วยัด prefix ใหม่เข้าไป
ดูจากที่ Intel เสนอวิธีใหม่อีกแบบในปีนี้ แนวโน้มแบบนี้คงจะยังดำเนินต่อไป
กระบวนการวินิจฉัยทำให้นึกถึงตอนที่ qemu เจอกับ repz ret: https://repzret.org/p/repzret/
ตามกฎของ HN ผมว่าควรห้ามชื่อเรื่องแบบนี้
มันไม่บอกเลยว่าลิงก์คืออะไร และ URL กลับทำให้สับสนกว่าเดิม
ถ้าชื่อเรื่องไร้ความหมายแบบนี้ ผมคิดว่าคนโพสต์ควรเพิ่มคำอธิบายสั้น ๆ
ถ้าใส่บริบทลงในชื่อเรื่องให้มากที่สุด คนจะไม่คลิกลิงก์ และเราเคยเห็นแล้วว่าคอมเมนต์จะกลายเป็นที่ที่ผู้คนขัดเกลาแต่ประเด็นที่ตัวเองสนใจ เหมือนตอบสนองต่อทวีต
HN เลือกจุดกึ่งกลางที่กระตุ้น ความอยากรู้อยากเห็นเชิงปัญญา และการคลิกลิงก์
ต่อให้ชื่อเรื่องคลุมเครือจนคุณปฏิเสธจะคลิกลิงก์ อย่างน้อยคุณก็จะตอบคนที่คลิกลิงก์แล้ว ซึ่งผมว่าดีกว่าที่อื่น ๆ บนอินเทอร์เน็ต
โพสต์ที่ไม่มีรางวัลคุ้มพอจะทำให้ชื่อเรื่องที่คลุมเครือและมีไหวพริบดูสมเหตุสมผล ต่างจากโพสต์นี้ มันก็จะตกจากหน้าแรกไปเอง
บทความเขียนได้ดีมาก
แม้ผมแทบไม่รู้เรื่องการเขียนโปรแกรม assembly และชุดคำสั่งของ Intel รวมถึง microarchitecture แต่ก็ยังตามคำอธิบายได้ และรู้สึกว่าพอเข้าใจคร่าว ๆ ว่าเกิดอะไรขึ้นที่นี่
อยากรู้ว่ามีใครทราบไหมว่า CPU ของ AMD ได้รับผลกระทบด้วยหรือเปล่า
ถ้าปัญหาเป็นเรื่องที่โปรเซสเซอร์สับสนเรื่อง ความยาวคำสั่ง จริง ๆ ก็น่าประทับใจที่แก้ด้วยไมโครโค้ดได้โดยไม่ทำให้ประสิทธิภาพตกมาก
สัญชาตญาณของผมอาจผิดสนิทก็ได้ แต่ผมนึกว่าการคำนวณความยาวคำสั่งน่าจะถูก synthesize โดยตรงเป็น logic gate
คิดอีกที uOP decoder อาจไม่ได้มีปัญหาในเชิงฮาร์ดแวร์ และ routine คัดลอกที่ถูกปรับแต่งด้วยไมโครโค้ดอาจกำลังพยายามอนุมานสิ่งที่ไม่จริงเกี่ยวกับสตรีม uOP อยู่
เช่นอาจเป็นทำนองว่า “อ้อ นี่คือ rep mov งั้นย้อนกลับไปสอง uOP เพื่อทำลูปก็น่าจะได้”
ทีม CPU ของ Intel คงไม่น่าจะเปิดเผยรายละเอียดขนาดนั้น
ไม่ค่อยเข้าใจ “ERMS” กับ “FSRM” และใน Google ก็ดูแทบไม่มีข้อมูลดี ๆ เลย
สงสัยว่าสิ่งเหล่านี้เป็นแค่ CPUID flags ที่บอกว่าเราสามารถใช้ rep movsb ได้ด้วยประสิทธิภาพสูงสุดแทนการใช้ implementation ของ SSE memcpy ที่ปรับแต่งมาแล้วหรือไม่ หรือว่าเป็น encoding หรือ prefix พิเศษที่ทำให้ rep movsb เร็วขึ้น
ถ้าเป็นอย่างหลัง ก็ไม่รู้ว่าทำไมถึงจำเป็น และ fsrm ถูกนำไปใช้ประโยชน์อย่างไร
ERMS น่าจะเคยเป็นทางเลือกที่ถูกกว่าของ AVX และ FSRM น่าจะเป็นเวอร์ชันที่ดีกว่าสำหรับบล็อกสั้น ๆ
“Celeron และ Pentium รุ่น Kaby Lake ที่ออกในปี 2017 ซึ่งเป็นรุ่นราคาถูกของโปรเซสเซอร์ยุคหลัง ไม่มี AVX ที่ใช้สำหรับการคัดลอกหน่วยความจำอย่างรวดเร็ว แต่มี Enhanced REP MOVSB
และสถาปัตยกรรม Intel สำหรับมือถือและพลังงานต่ำบางรุ่นที่ออกหลังปี 2018 ไม่ได้อิงจาก SkyLake แต่สามารถคัดลอกไบต์ต่อรอบ CPU ด้วย REP MOVSB ได้มากกว่าไมโครสถาปัตยกรรมรุ่นก่อนหน้าประมาณสองเท่า”
“ก่อน Fast Short REP MOV(FSRM) ในไมโครสถาปัตยกรรม Ice Lake นั้น Enhanced REP MOVSB(ERMSB) จะเร็วกว่า AVX copy หรือการคัดลอกด้วยรีจิสเตอร์ทั่วไปก็ต่อเมื่อขนาดบล็อกอย่างน้อย 256 ไบต์เท่านั้น
สำหรับบล็อกที่เล็กกว่า 64 ไบต์ ต้นทุนเริ่มต้นภายในของ ERMSB สูงราว 35 cycles จึงช้ากว่ามาก และฟีเจอร์ FSRM มีเป้าหมายเพื่อให้บล็อกที่เล็กกว่า 128 ไบต์เร็วขึ้นด้วย”
[1] https://stackoverflow.com/a/43837564
[2] http://www.intel.com/content/dam/www/public/us/en/documents/...
การเลือกคำสั่งและการจัดตารางที่เหมาะที่สุดอาจทำแบบ static ตอน compile time ก็ได้ หรือเลือกหนึ่งในหลาย ๆ ฟังก์ชันไลบรารีตอน runtime หรือทำแบบ dynamic ด้วย JIT ก็ได้
หากต้องการตรวจจับตอน runtime ว่าการจัดตารางคำสั่งแบบใดเหมาะที่สุด ก็ต้องรู้จัก CPU จริงที่ใช้อยู่
จะมีตารางของ CPU model ทั้งหมดก็ได้ แต่ก็สามารถถามระบบปฏิบัติการได้ว่า CPU ที่กำลังรันอยู่นั้น implement การปรับแต่งนั้นหรือไม่
Linux จำเป็นต้องมีแพตช์เพื่อให้ CPU รายงานได้ว่าได้ implement การปรับแต่งนั้นแล้ว
https://www.phoronix.com/news/Intel-5.6-FSRM-Memmove
เห็นว่าในคำแนะนำของ Intel [1] เขียนไว้ดังนี้
Intel กล่าวขอบคุณพนักงานของ Intel ที่ค้นพบปัญหานี้ภายใน และยังขอบคุณพนักงานของ Google ที่รายงานปัญหานี้ด้วย
[1] https://www.intel.com/content/www/us/en/security-center/advi...
คำแนะนำของ Intel ที่มีคำอธิบายผลกระทบก็น่าอ้างอิงเช่นกัน: https://www.intel.com/content/www/us/en/security-center/advi...
“ในโปรเซสเซอร์ Intel(R) บางรุ่น ลำดับคำสั่งของโปรเซสเซอร์อาจทำให้เกิดพฤติกรรมที่ไม่คาดคิด ซึ่งอาจทำให้ผู้ใช้ที่ได้รับการยืนยันตัวตนสามารถยกระดับสิทธิ์ เปิดเผยข้อมูล หรือทำให้เกิดการปฏิเสธการให้บริการผ่านการเข้าถึงภายในเครื่องได้”
Konrad Magnusson จากทีม Victoria 3 ของ Paradox Interactive พบอะไรบางอย่างที่เกี่ยวข้องกับเรื่องนี้และ mimalloc: https://github.com/microsoft/mimalloc/issues/807
ไม่แน่ใจว่าเกี่ยวข้องกันเต็ม ๆ หรือไม่ แต่ก็เป็นไปได้