David Weston หัวหน้าฝ่ายความปลอดภัยระบบปฏิบัติการของ Windows ไปพูดในงานสัมมนาความปลอดภัย BlueHat IL 2023 ที่อิสราเอล เปิดเผยว่าไมโครซอฟท์เริ่มใช้ภาษา Rust เขียนบางส่วนของ Windows เพื่อแก้ปัญหาช่องโหว่หน่วยความจำแล้ว
Weston เล่าว่าช่องโหว่ด้านหน่วยความจำ มีสัดส่วนเป็น 70% ของช่องโหว่ทั้งหมดของ Windows ทำให้ไมโครซอฟท์ต้องหาวิธีแก้ไขที่ยั่งยืนในระยะยาว โดยวิธีการหนึ่งคือใช้ภาษาโปรแกรมที่ป้องกันเรื่องนี้ตั้งแต่ระดับของตัวภาษาเลย
แต่ความซับซ้อนของ Windows ทำให้ไมโครซอฟท์ต้องค่อยๆ ลองเปลี่ยนโค้ดจาก C++ มาเป็น Rust อย่างช้าๆ โดยเริ่มจากชิ้นส่วนที่ไม่ค่อยมี dependency กับส่วนอื่นมากนัก คือ DWrite เอนจินสำหรับวิเคราะห์และเรนเดอร์ข้อความบนหน้าจอ ไมโครซอฟท์เขียนมันใหม่ด้วย Rust เป็น DWriteCore ในปี 2020 ตอนนี้มีโค้ดที่เป็น Rust ราว 152,000 บรรทัดแล้ว เหลือส่วนที่เป็น C++ ราว 96,000 บรรทัด และนอกจากความปลอดภัยที่ดีขึ้นแล้ว ไมโครซอฟท์ยังพบว่าประสิทธิภาพดีขึ้นด้วย 5-15% ถือเป็นผลพลอยได้จาก Rust
ถัดมา ไมโครซอฟท์เริ่มเขียน Win32k GDI ไลบรารีส่วนที่ใช้วาด UI ขอบหน้าต่างแบบเก่าที่ใช้มาตั้งแต่ยุค 80s/90s ตอนนี้มีโค้ด Rust ราว 36,000 บรรทัด และ Win32k GDI ตัวใหม่ถูกผนวกเข้ามาใน Windows 11 รุ่นภายในแล้ว บูตผ่านแล้ว เทสต์ผ่านด้วย แต่ยังปิดการใช้งานเป็นค่าดีฟอลต์อยู่
Weston ยังเผยข้อมูลว่าตอนนี้ไมโครซอฟท์เริ่มเขียน SysCall ของเคอร์เนล Windows ด้วย Rust บ้างแล้วเช่นกัน แต่ยังไม่บอกรายละเอียดเหมือน 2 โครงการข้างต้น
ความนิยมใน Rust เพิ่มขึ้นเรื่อยๆ ในช่วงหลัง นอกจากไมโครซอฟท์แล้ว อีกองค์กรที่เริ่มใช้ Rust อย่างจริงจังคือ กูเกิลที่เขียนบางส่วนของ Android เป็น Rust รวมถึง Chrome
My presentation slides for "Windows 11: security by-default" from @BlueHatIL covering:Rust in win32k, Adminless Windows, Token Binding, Sandboxing win32, and more! posted here: https://t.co/mfOcOh8f84 pic.twitter.com/WDAbbIjaEv
— David Weston (DWIZZZLE) (@dwizzzleMSFT) April 18, 2023
ที่มา - The Register
Comments
สงสัยต้องไปศึกษาบ้างแล้ว
นึกถึงช่วงที่ บ ผมย้ายจาก php มา NodeJS ทั้งทีมแทบกระอักเหมือนกัน
ผมก็กำลังศึกษา Rust สิ่งที่ชอบมากๆคือการดีลกับ error แบบไม่ใช้ throw exception
..: เรื่อยไป
การ throw exception ทำให้ 1 function มีมากกว่า 1 ทางออกทำให้ความซับซ้อนสูง และบางภาษามี runtime exception จะทำให้ handle ยาก เพราะมีโอกาสเกิดขึ้นได้แต่คนเขียนต้องรู้เอาเองว่ามีโอกาสเกิดขึ้นแล้วต้อง handle เอง ต่างกับภาษาที่มีแต่ exception และบังคับ handle ตั้งแต่ตอนพัฒนาโปรแกรมเลยก็จะ safe กว่า
ผมเดาว่าภาษาใหม่ ๆ พยายามหนีคำว่า exception เพราะกลัวคนจะเพิกเฉย ละเลย ไม่ใส่ใจ ด้วยการเปลี่ยนเป็น error แล้วสร้าง practice ใหม่ว่าต้อง handle แทน
การไม่ใช่ exception มันก็มีข้อเสียอยู่เหมือนกันตรงที่มันดูรก และจุดที่ต้องระวังคือการที่คนใช้ไม่ handle error code ไปเลย
ถ้าใช้ exception อย่างน้อย ๆ เวลาเกิดแล้วไม่ไป handle มัน โปรแกรมมันก็จะพังแบบขึ้น unhandled exception error แต่ถ้าเป็น error code แล้วไม่ handle โปรแกรมอาจจะทำงานเพี้ยนแบบไม่ทราบสาเหตุจนถึงขั้นหยุดทำงานได้
ในปัจจุบันมีการใช้ lint tool มากขึ้นทำให้ปัญหานี้เกิดน้อยลงมากครับ แต่ก็จะเจอว่าเดฟรำคาญแทน จะเตือนอะไรกันนักกันหนา
แล้วก็ runtime exception จริง ๆ ภาษาที่ออกแบบมาดี ปัญหานี้จะเป็นพวก unrecoverable error เช่น memory หมด พวกนี้มีหน้าที่แค่เอาไว้แจ้งผู้ใช้ว่ามีปัญหานะ แล้วปิดโปรแกรมไป ส่วนพวกภาษาอื่น ๆ ก็อาจจะมี runtime บางตัวที่แบบ เอะอะอะไรก็นับเป็น runtime exception หมด ทำให้ dev แยกไม่ได้ว่าอันไหน recover ได้ (เช่น connection timeout) อันไหน recover ไม่ได้
แล้วก็ runtime exception จริง ๆ ภาษาที่ออกแบบมาดี
อันนี้ไม่น่าเกี่ยวกับภาษาที่ใช้น่ะครับ อยู่ที่คนออกแบบ API/library มากกว่า ในภาษาเดียวกันผมเจอคนใช้ exception แบบแย่ๆ - ดีๆ ก็มีปนกันไป
ตอนเรียน dev ส่วนมากน่าจะเรียนมาแค่ exception มีไว้ catch เพื่อให้ program ทำงานต่อไป
แต่พอผมมีประสบสารณ์สักหน่อย กลับคิดว่า exception มีไว้เพื่อให้ dev กลับไปแก้โปรแกรมให้มันไม่ throw มากกว่า
มันมีประโยชน์เรื่องการพัฒนาโปรแกรมมากกว่า
เวลาเขียนโปรแกรมแรกๆ เราอาจจะนึก case ของสิ่งที่จะเกิด error ทั้งหมดไม่ออก ก็ throw ไว้ให้ program มันหยุดทำงานไปก่อน ดีกว่าให้มัน run ทั้งที่เจอสิ่งผิดปกติ
ก็ใช่ครับ พอดีใช้แต่ภาษาที่ runtime spec ส่วนหนึ่งระบุอยู่ในตัวภาษาเลย 555
ขอบคุณทุกท่านที่มาเสวนากันครับ
..: เรื่อยไป
ทุกบริษัท ติด code legacy หมดแหละครับ ระบบคุณจ้างใครมา dev ให้หลัก 10-100 ล้านสมัย 15-20 ปีก่อน คุณไม่เปลี่ยนแบบสั่งเขียนใหม่ทั้งตัวหลอกครับ ถ้ามันไม่ถึงจุดที่มันไม่ไหวแล้วจริงๆ
โปรแกรมที่ดีสามารถถอดประกอบได้ ไม่จำเป็นต้องเขียนใหม่ทั้งหมด จริง ๆ โปรแกรมมันคุยกันด้วย message อยู่แล้ว เช่น text (CLI, HTTP (REST), csv), binary (RPC, stream buffer, DB) แยกส่วนมันได้ ก็เขียนใหม่ทีละส่วนไม่ยาก แต่มันจะมีเวลาที่ใช้ในการสร้าง แบก ซ่อม เลื่อนที่ต่างกัน ขึ้นอยู่กับว่าเราออกแบบปฎิสัมพันธ์ระหว่างโปรแกรมว่ามันยึดผูกติดหรือหลวม ๆ กันแค่ไหน
ผมว่ากรณีนี้เค้าเป็นแค่ dll ตัวนึงที่ติดต่อกับคนอื่นผ่าน C API
ถ้าเค้าไม่ break ABI ก็ไม่น่ามีปัญหาอะไรครับ
edit เสริมนิดนึง
คือถ้าเป็นซอฟต์แวร์ธุรกิจ ถ้าเขียนด้วย C++ ก็บอกเลยว่า แทบจะโละทิ้งทำใหม่ ส่วนหนึ่งเพราะ C++ ไม่มี Standard ABI ดังนั้นถ้าโค๊ดไม่ได้เขียนให้สร้าง C ABI ตั้งแต่แรก มันก็จะต่อกันได้เฉพาะ C++ ด้วยกันเองเท่านั้น แล้วการเขียนโค๊ด C++ โดยให้คง ABI Compatibility อยู่เป็นงานหินมาก ยกเว้นแต่ถ้าเราโฟกัสกันที่ C ABI อย่างเดียว public interface แต่ละตัวเป็น C API หมด อันนี้จะย้ายภาษาในบาง component ก็ไม่ได้ยากขนาดนั้น
แต่ก็ใช่แหละคือการสร้าง component ใหม่ทั้งตัวมาแทนของเก่าก็เป็นงานหินและแพงมากครับ
(แล้วก็เห็นด้วยว่าถ้าเขียนระบบใหม่หมดตั้งแต่ 0 โอกาสจะพังมีสูงมาก อย่างคนที่เคยทำงานแถว ๆ สวนลุมบางส่วนอาจจะเคยเจอมาแล้ว -- พอดีคนรู้จักผมทำงานให้ลูกค้าของเจ้านี้ ฮา)
แต่ถ้ามองกลับไปที่ Windows ตัว Win32 แต่เริ่มเดิมทีเป็น C อยู่แล้ว ดังนั้นถ้าเราจะเขียนใหม่ ก็แค่เขียนโค๊ดด้วยภาษาอะไรก็ได้แล้วให้มัน expose C ABI ออกมาก็พอ (ถ้าจำไม่ผิด runtime มันเป็น dynamic link อยู่แล้ว) หรือถ้าเป็น code ที่ใหม่กว่าหน่อย เข้าใจว่าใน MS เองยังใช้ COM (Component Object Model) กันอยู่เลย (.Net Framework ก็เขียนอยู่บนตัวนี้เหมือนกัน สังเกตได้จากพวกฟังก์ชั่น AddRef) ตัวโค๊ดอาจจะเป็น C++ แต่ interface ที่เปิดมาเป็น C ABI ดังนั้นต่อให้ไปเปลี่้ยนดีเทลข้างในก็ไม่กระทบข้างนอกเหมือนกันครับ
ภาษาส่วนใหญ่ ถ้าจะเขียนให้เข้ากับโค๊ดเนทีฟ จะเข้ากันผ่านทาง C ABI เพราะว่าโค๊ดเดิมที่ใช้ ๆ กันมักจะเป็นภาษา C และทุกคนก็ใช้กลยุทธเดียวกับ C++ คือเขียนให้มันเรียก C ได้ แค่ C++ สามารถเรียกใช้ตรง ๆ ได้โดยไม่ต้องเขียน shim อะไรเลยเท่านั้นเองที่เป็นจุดได้เปรียบ
ต้องไปฟังบรรยายของ Michael Kerrisk แล้วจะพบว่า "ไม่ break ABI" นี่ยากจัด เขียนใหม่แล้วบอกว่าให้ "เหมือนเดิมเป๊ะ" เพราะจะมีใครสักคนใช้บางพฤติกรรมของมันนี่ยากมากๆ
lewcpe.com, @wasonliw
เข้าใจว่า การพยายามไม่ break ABI นี่เป็นหัวใจของ COM เลยครับ
แต่การไม่ break ABI นี่ไม่ได้การันตีว่าโปรแกรมจะทำงานเหมือนเดิมนะครับ แค่อินเตอร์เฟซมันเหมือนเดิมเฉยๆ
ทุกบริษัท ติด code legacy หมดแหละครับ ระบบคุณจ้างใครมา dev ให้หลัก 10-100 ล้านสมัย 15-20 ปีก่อน คุณไม่เปลี่ยนแบบสั่งเขียนใหม่ทั้งตัวหลอกครับ ถ้ามันไม่ถึงจุดที่มันไม่ไหวแล้วจริงๆ
win10 หมดโอกาสได้ใช้ในอนาคตสินะครับ
The Last Wizard Of Century.
Upgrade ไป Windows ใหม่กว่าฟรีนี่ครับ
เคยฟังคนที่ผลักดัน Rust ที่ MS พูดในงาน talk
คือเค้าไม่ใช่แค่ศึกษาแล้วเอามาใช้แบบบริษัท it ปกติ
แต่ต้องสร้าง compiler ใหม่ของ MS เองเลย แล้วถึงทำ poc เพื่อพิสูจน์ว่ามันดีกว่า โค๊ดเดิมและปลอดภัยจากช่องโหว่อื่นๆ ในระดับ compiler เลย
MS ก็ดัน Rust อยู่นะ คอสเรียนฟรีของ ms ก็มีสอน
Microsoft Contribute ของดี ๆ เยอะมากยุคนี้
VS Code, TypeScript, Playwright, etc.
ถามว่าทำไมต้องทำ
ผมมองว่าในโลกของ product เราไม่ควรแข่งกันที่ software หรือ tools มันควรแข่งกันที่โปรดักว่าของใครทำอะไรได้บ้าง แล้วการจะได้มาใน 1 product ขั้นตอนกระบวนการวิธี และสิ่งที่ต้องกังวลหรือแก้ไขมันเยอะมากเช่น ความเป็นส่วนตัว ความปลอกภัย เวลาในการพัฒนา ทำงานได้มั้ย กฎหมายแต่ละประเทศ localization, internationalization, การรองรับคนพิการประเภทต่าง ๆ
ถ้าของดีไม่ช่วยกันดันไม่อยู่ใน main stream มันจะเจออาการว่า internal framework, internal tools ถึงเวลามันจะ outdate ไม่มีคนช่วย contributes คนที่เข้าใจออก คนที่ไม่เข้าใจเข้า จะรู้จักได้ต้องเป็นคนในก่อน คนเดิม ๆ ที่ไปทำเรื่องใหม่ ๆ ถ้าเขามีไฟเขาก็คงไม่อยากโดนดอง โดนครอบด้วยวิธีการทำงานแบบเดิม เครื่องมือเดิม ๆ แถมถ้า products เดิมที่เหมือนกำลังจะตาย หรือทำเงินไม่ได้ แต่ปิดก็ไม่ได้มันเหมือนโดนแช่แข็งเลยสำหรับผม
บางทีผมก็คิดอยู่นะว่า ตาลุงในเสื้อฮาวาย น่าจะเริ่มร้อน ๆ หนาว ๆ ละว่าจะโดนเลย์ออฟหรือเปล่า (ฮา)
ปล. ผมแซวคุณลุง Herb Sutter ที่เป็น WG21 Convener และทำงานที่ Microsoft ครับ คนนี้เป็นหัวหอกคนนึงของ C++ ใน Microsoft เลย แต่หลังๆ ดูแผ่ว ๆ เพราะ MS หลัง ๆ ไม่ค่อยแคร์โปรดักท์ C++ (หรือให้พูดตรง ๆ ก็ Visual Studio ทั้งชุด) สักเท่าไหร่ละ
ถ้าโปรแกรม A เขียนด้วย OOP ทั้งดุ้น แล้วจะเขียนใหม่ด้วย Rust ที่ไม่รองรับ OOP แบบนี้ต้องทำไง
ผมรู้จัก Rust แค่ผิวเผินนะครับ สำหรับเคสนี้ผมว่าทำอะไรไม่ได้นอกจาก design ใหม่ล่ะครับ คือถ้าในลักษณของ class, interface ผมว่า struct, trait เองก็ทำงานในลักษณะที่มองของเป็น object ได้ แต่ถ้าใช้คุณบัติของ OOP แบบเต็มออพชั่น 555 ผมว่าคิดใหม่ทำใหม่อย่างเดียว
..: เรื่อยไป
เปลี่ยนตั้งแต่กระบวนการคิดของ Programmer เลย แต่โดยปกติแล้วโปรแกรมเมอร์ที่ดีจะไม่ยัด Business Logic เข้าไปในโปรแกรมตั้งแต่แรก เน้นใช้ OO เฉพาะส่วนของการสืบทอดและ In-Module Messaging (ไม่ส่ง Message ข้ามไปมาระหว่าง Module) ตอนถอดออกมาใส่ภาษาที่ไม่ใช่ OO ก็จะง่ายลงไปเยอะ
OOP คือวีธีคิดครับ
ต่อให้ภาษาไม่มี class, method, inherit ก็ยังคิดแบบ OOP ได้ครับ
เท่าที่ดูคือ Rust มัน strict ไป ทำให้ต้องเรียนรู้ idiom ของมันเพิ่ม เขียนตรงๆ ขวานผ่าซากไม่ได้
ขนาด goto ยังไม่มีให้ใช้เลย