#siamstr
quoting
naddr1qv…uq4nแนวคิดอันนี้เกิดขึ้นหลังจากที่ผมได้รู้จัก LFS หรือ Log- structure File System มันทำให้ผมเกิดความคิดว่าในเมื่อมันสามารถที่จะเก็บ file และทุก log ของการเปลี่ยนแปลงในแต่ละไฟล์ งั้นแปลว่าในกรณีที่ file โดน encrypt มันก็น่าจะสามารถกู้คืนมาได้สิ เอ้ะแต่ถ้าเครื่องนั้นโดน ransomware ไปรอบนึงแล้วกู้คืนมาแล้วมันก็โดนอีกอยู่ดีมั้ย เลยเกิดไอเดียใหม่ว่าแล้วถ้าเราหา SSD อีกลูกมาเก็บ backup ถ้าโดน ransomware ก็ถอดไปเสียบเครื่องใหม่ก็จบ ตะตะแต่ว่า LFS เนี่ย ดั้นนนใช้ไม่ได้กับ windows หรือ Mac เอาละ ปัญหาใหม่มาอีกละ งั้นต้องทำไงล่ะ ? หึเก็บไว้บอกท้ายบทความละกัน มาทำความเข้าใจโปรเจคนี้กันทีละขั้นตอนกันดีกว่า
Log-structure File System (LFS)
เป็น File system รูปแบบหนึ่งที่จะทำการเก็บข้อมูลเป็น log และสามารถย้อนกลับได้ทุกการกระทำ นอกจากมีความถี่ในการสร้าง snapshot ที่สูงมาก จริง ๆ แล้วเหมาะกับงานประเภทที่ต้องการความต่อเนื่องหากดบัไปต้องกู้คืนได้มากที่สุดเท่าที่เป็นไปได้ แต่เพราะไอความสามารถตรงนั้นของมันนี่แหละ ที่ผมมองว่ามันน่าจะหยิบมาใช้กับการกู้คืน file หลังจากโดน ransomware ได้แน่ ๆ โดยในครั้งนี้ผมเลือกใช้เป็น NILFS2 เนื่องจากดูแล้วน่าจะเหลือตัวเดียวที่ยังพอมีการพัฒนาอยู่ 5555 รูปแบบการเก็บข้อมูลจะเหมือนกับภาพด้านล่างนี้
ตัวอย่าง: เดิมที file A: “AAAAA” จากนั้นผมได้ทำการอัพเดตข้อมูลใน file A เป็น “BBBBB” ด้วยความสามารถของ LFS มันสามารถที่จะดึง file A เวอร์ชันที่เป็น “AAAAA” กลับมาได้
นี่เป็นปัจจัยสำคัญที่ทำให้ผมมองว่า LFS เหมาะสมที่จะมาเป็นระบบไฟล์ที่ใช้ในการสำรองข้อมูล แต่อยากที่ได้กล่าวไว้ข้างต้นว่าปัญหาของระบบไฟล์นี้คือมันใช้พื้นที่เก็บข้อมูลค่อนข้างสูง และมี write speed ที่ค่อนข้างช้า ถ้าเทียบกับระบบไฟล์อื่น ๆ ในกรณีที่ความเร็วของ SSD เท่ากัน เลยมองว่าถ้าจะใช้เป็นระบบหลักในการเก็บข้อมูลทุกอย่างคงจะไม่เหมาะ เลยนำไปสู่การทำระบบโดยใช้ระบบไฟล์สองแบบที่แตกต่างกัน
System Design
อย่างที่ได้พูดถึงข้อเสียของ NILFS2 ไปข้างต้น แปลว่าถ้าอยากจะให้คอมพิวเตอร์ทำงานได้อย่างมีประสิทธิภาพคงเดิมและสามารถป้องกัน ransomware ได้ด้วยก็จำเป็นต้องมีระบบไฟล์ที่ใช้กันทั่วไปอย่าง FAT32 หรือ ext4 และใช้ SSD อีกลูกหนึ่งที่ format เป็น NILFS2 และเขียนโปรแกรมให้คอยมอนิเตอร์ทุก ๆ กิจกรรมบน user space และทุกครั้งที่เกิดการเขียนไฟล์ขึ้นให้เขียนลงใน SSD ที่เป็น NILFS2 ด้วย ดังภาพที่แสดงด้านล่างนี้
แล้วทำไมไฟล์ในลูกที่เก็บสำรองข้อมูลถึงไม่เท่ากับจำนวนไฟล์ในที่เก็บข้อมูลหลักล่ะ ? เนื่องด้วยความเร็วในการเขียนที่ค่อนข้างแตกต่างกันของทั้งสอง ผมเลยมองว่าถ้าเราเก็บในรูปแบบบล๊อกจะทำให้เก็บข้อมูลได้ไวกว่า อย่างตัวอย่างในรูป สมมุติว่าไฟล์ A มีขนาดประมาณ 3 บล๊อกใน SSD ที่เป็น nilfs2 ก็จะมี 3 ไฟล์และต้องใช้ทั้งสามไฟล์เพื่อที่จะคืนค่าไฟล์ A กลับมา ถ้าอ่านมาถึงตรงนี้อาจจะเกิดข้อสงสัยว่า แล้วจะทำให้มันยุ่งยากทำไม คัดลอกไฟล์มาใส่ก็จบแล้วมั้ย ? ก็ใช่แหละและจริง ๆ ผมคิดว่าทำแบบนั้นก็เพียงพอ แต่ว่าอย่างที่บอกไปข้างต้น ผมอยากได้ระบบที่ป้องกันได้ 100% ผมเลยเลือกที่จะมอนิเตอร์ kernel เอาไว้และเมื่อมีการเขียนไฟล์เกิดขึ้นผมต้องการดึงข้อมูลมาจากตรงนั้นเลย ไม่อยากรอถูกเขียนลงในพื้นที่เก็บข้อมูลหลักก่อนแล้วค่อยคัดลอกมา จริง ๆ ก็ด้วยเหตุผลด้านประสิทธิภาพด้วย
แล้วจะมอนิเตอร์ kernel อย่างไร ??
ในครั้งนี้ผมเลือกที่จะใช้เป็น eBPF (extended Berkeley Packet Filter) จริงแล้วเจ้า eBPF เนี่ยใช้งานได้หลากหลายเลยแหละ เรียกได้ว่าประโยชน์รอบด้านสุด ๆ ตามรูปที่แนบด้านล่างเลย
แต่ในครั้งนี้เราจะยุ่งกับมันเพียงแค่การใช้งานเพื่อสอดส่อง kernel เท่านั้น
ภาพด้านบนนี้แสดงให้เห็นจุดที่เราสามารถใช้ eBPF ในการดึงข้อมูลได้ นั่นเลยเป็นเหตุผลหลักที่ผมเลือกใช้ โดยวางการทำงานทั้งหมดของการมอนิเตอร์ไว้ดังนี้
- ใช้ eBPF เพื่อคอยเช็คว่ามีการเขียนเกิดขึ้นมั้ยโดยการอ่านค่า flag จาก NVMe ว่ามีค่าเป็นอะไรจากนั้นนำค่าที่ได้มา XOR ด้วย mask ถ้าค่าออกมาเป็น 1 แปลว่านั่นคือ write_operation (อาจแตกต่างกันแล้วแต่ version)
- เมื่อเช็คค่าแล้วเป็น write_operation จากนั้นก็ให้ทำการอ่านเลข sector, และขนาดของข้อมูลที่ต้องการจะเขียน
- จากนั้นเข้าไปอ่านต่อใน Bio ลงไปยัง Bio_vec และไป Bv_page ตามลำดับ เพื่ออ่านข้อมูลทั้งหมดที่มาจากคำสั่งในการเขียนครั้งนั้น ๆ
*ภาพประกอบเพิ่มเติมเพื่อใครงงว่า Bio คืออะไรข้อมูลเวลาเราเขียนจะอยู่บน page
- ส่งข้อมูลที่ได้ทั้งหมดออกมา
เพียงเท่านี้เราก็ทำการดึงข้อมูลทุกครั้งที่เราเขียนได้แล้ว และจะนำมันเข้าสู่ขั้นตอนต่อไปในการเก็บข้อมูลลง SSD
เก็บข้อมูลและส่งไป SSD ที่เป็น nilfs2
เมื่อได้ข้อมูลมาจากการทำงานที่ได้กล่าวไว้ข้างบนแล้ว ก็จะได้ชุดข้อมูลมาชุดหนึ่ง ส่งออกมันมาจาก ebpf(C program) มาสู่ Python ต่อโดยมีขั้นตอนดังนี้
- นำเลข sector ที่ได้มาทำการคูณด้วยขนาดของ sector เพื่อให้เราได้ logical address มา จากนั้นให้นำ logical address หารด้วยขนาดของบล๊อกเพื่อให้ได้เลขบล๊อก
- นำข้อมูลในแต่ละ sector มาเรียงลงในบล๊อกที่มันอยู่ละบันทึกลงไปใน SSD
ตัวอย่างเพื่อให้เห็นภาพมากขึ้น สมมุติว่าข้อมูลที่ส่งกลับมาขนาด 4097 B และเริ่มเขียนที่ sector 0 (กำหนดให้ 1 sector มีขนาด 512B และ 1 Block มี 8 sector)
4097⁄512 = 8.xx ก็แปลว่าข้อมูลนี้ต้องเก็บใน 9 sector คือ sector 0 ถึง 8 และ 8 sector รวมเป็น 1 block แปลว่าข้อมูลใน sector 0-7จะอยู่ใน block 0 และ sector 8 จะอยู่ใน block 1 แปลว่าโปรแกรมของผมจะสร้างมาสองไฟล์คือ 0,1 จากนั้นจะทำการเติม 0 ท้ายไฟล์ 1 จนมีขนาด 4096 B เท่ากับขนาดของ block
สำหรับคนที่งงว่า sector บล๊อกคืออะไร
ให้ดูตรงรูปกลม ๆ ทางซ้ายมือจะเห็นได้ว่ามันเป็นหน่วยความจำในจานหมุน ซึ่ง sector คือหน่วยย่อยสุด และ sector รวม ๆ กันหลาย ๆ sector จะเป็น cluter บางที่ก็เรียก Tracks บางที่ก็ Block ซึ่งนี่แหละคือบล๊อกที่ผมหมายถึง
เพียงเท่านี้เราก็ได้ระบบที่สามารถป้องกัน ransomware ได้แล้ว เพราะเนื่องจากเมื่อเราโดน ransomware และไฟล์เราถูก encrypt เราก็เพียงใช้ความความสามารถของ SSD ลูกที่เป็น nilfs2 เพื่อนำไฟล์ดั้งเดิมก่อนจะถูก encrypt กับมาได้ดังรูปประกอบด้านล่างนี้
ส่งท้าย
จริง ๆ แล้วที่ผมเก็บเป็นไฟล์ block เพราะผมอยากให้ backup file สามารถเข้ากันได้กับทุกระบบไฟล์เพื่อให้สามารถใช้งานได้กับทุกระบบ ถึงจะยังทำไม่ได้ก็เหอะ 55555