ใช้งาน SELinux

SELinux ได้รับการตั้งค่าให้ปฏิเสธโดยค่าเริ่มต้น ซึ่งหมายความว่าการเข้าถึงแต่ละรายการที่มีฮุกในเคอร์เนลต้องได้รับอนุญาตโดยนโยบายอย่างชัดเจน ซึ่งหมายความว่าไฟล์นโยบายประกอบด้วยข้อมูลจำนวนมากเกี่ยวกับกฎ ประเภท คลาส สิทธิ์ และอื่นๆ การพิจารณา SELinux อย่างเต็มรูปแบบอยู่นอกขอบเขตของเอกสารนี้ แต่การทำความเข้าใจวิธีเขียนกฎนโยบายเป็นสิ่งจําเป็นเมื่อเปิดใช้อุปกรณ์ Android เครื่องใหม่ มีข้อมูลเกี่ยวกับ SELinux อยู่มากมายแล้ว ดูแหล่งข้อมูลที่แนะนำในเอกสารประกอบสนับสนุน

ไฟล์คีย์

หากต้องการเปิดใช้ SELinux ให้ผสานรวมเคอร์เนล Android เวอร์ชันล่าสุด แล้วรวมไฟล์ที่พบในไดเรกทอรี system/sepolicy เมื่อคอมไพล์แล้ว ไฟล์เหล่านั้นจะประกอบไปด้วยนโยบายความปลอดภัยเคอร์เนล SELinux และครอบคลุมระบบปฏิบัติการ Android เวอร์ชัน upstream

โดยทั่วไปแล้ว คุณไม่ควรแก้ไขไฟล์ system/sepolicy โดยตรง แต่ให้เพิ่มหรือแก้ไขไฟล์นโยบายเฉพาะอุปกรณ์ของคุณเองในไดเรกทอรี /device/manufacturer/device-name/sepolicy ใน Android 8.0 ขึ้นไป การเปลี่ยนแปลงที่คุณทำกับไฟล์เหล่านี้ควรส่งผลต่อนโยบายในไดเรกทอรีผู้ให้บริการเท่านั้น ดูรายละเอียดเพิ่มเติมเกี่ยวกับการแยกไฟล์นโยบายความปลอดภัยสาธารณะใน Android 8.0 ขึ้นไปได้ที่การปรับแต่ง SEPolicy ใน Android 8.0 ขึ้นไป คุณจะยังคงแก้ไขไฟล์ต่อไปนี้ไม่ว่าจะใช้ Android เวอร์ชันใดก็ตาม

ไฟล์นโยบาย

ไฟล์ที่ลงท้ายด้วย *.te คือไฟล์ต้นทางนโยบาย SELinux ซึ่งจะกำหนดโดเมนและป้ายกำกับของโดเมน คุณอาจต้องสร้างไฟล์นโยบายใหม่ใน /device/manufacturer/device-name/sepolicy แต่ควรพยายามอัปเดตไฟล์ที่มีอยู่หากเป็นไปได้

ไฟล์บริบท

ไฟล์บริบทคือที่ที่คุณระบุป้ายกำกับสำหรับวัตถุ

  • file_contexts กำหนดป้ายกำกับให้กับไฟล์และคอมโพเนนต์ต่างๆ ของพื้นที่ผู้ใช้ใช้ เมื่อสร้างนโยบายใหม่ ให้สร้างหรืออัปเดตไฟล์นี้เพื่อกำหนดป้ายกำกับใหม่ให้กับไฟล์ หากต้องการใช้ file_contexts ใหม่ ให้สร้างอิมเมจระบบไฟล์ใหม่หรือเรียกใช้ restorecon ในไฟล์ที่จะติดป้ายกำกับใหม่ ในการอัปเกรด การเปลี่ยนแปลงใน file_contexts จะมีผลกับพาร์ติชันระบบและพาร์ติชันข้อมูลผู้ใช้โดยอัตโนมัติโดยเป็นส่วนหนึ่งของการอัปเกรด นอกจากนี้ คุณยังใช้การเปลี่ยนแปลงโดยอัตโนมัติในการอัปเกรดไปยังพาร์ติชันอื่นๆ ได้ด้วยการเพิ่มการเรียกใช้ restorecon_recursive ลงในไฟล์ init.board.rc หลังจากที่ระบบได้ต่อเชื่อมพาร์ติชันแบบอ่าน/เขียนแล้ว
  • genfs_contexts กำหนดป้ายกำกับให้กับระบบไฟล์ เช่น proc หรือ vfat ที่ไม่รองรับแอตทริบิวต์แบบขยาย ระบบจะโหลดการกําหนดค่านี้เป็นส่วนหนึ่งของนโยบายเคอร์เนล แต่การเปลี่ยนแปลงอาจไม่มีผลกับอินโนดในเคอร์เนล ซึ่งจะต้องรีบูตหรือยกเลิกการต่อเชื่อมและต่อเชื่อมระบบไฟล์อีกครั้งเพื่อให้การเปลี่ยนแปลงมีผลอย่างสมบูรณ์ นอกจากนี้ คุณยังกำหนดป้ายกำกับที่เจาะจงให้กับการต่อเชื่อมที่เจาะจงได้ด้วย เช่น vfat โดยใช้ตัวเลือก context=mount
  • property_contexts กำหนดป้ายกำกับให้กับพร็อพเพอร์ตี้ของระบบ Android เพื่อควบคุมว่ากระบวนการใดบ้างที่จะตั้งค่าได้ กระบวนการ init จะอ่านการกำหนดค่านี้ระหว่างการเริ่มต้น
  • service_contexts จะกำหนดป้ายกำกับให้กับบริการ Binder ของ Android เพื่อควบคุมว่ากระบวนการใดบ้างที่เพิ่ม (ลงทะเบียน) และค้นหา (ค้นหา) การอ้างอิง Binder สำหรับบริการ กระบวนการ servicemanager จะอ่านการกำหนดค่านี้ระหว่างการเริ่มต้น
  • seapp_contexts กำหนดป้ายกำกับให้กับกระบวนการของแอปและไดเรกทอรี /data/data zygote จะอ่านการกําหนดค่านี้เมื่อเปิดแอปแต่ละครั้ง และ installd จะอ่านระหว่างการเริ่มต้น
  • mac_permissions.xml จะกำหนดแท็ก seinfo ให้กับแอปโดยอิงตามลายเซ็นและแอปพลิเคชันจะระบุชื่อแพ็กเกจหรือไม่ก็ได้ จากนั้นจะใช้แท็ก seinfo เป็นคีย์ในไฟล์ seapp_contexts เพื่อกำหนดป้ายกำกับที่เฉพาะเจาะจงให้กับแอปทั้งหมดที่มีแท็ก seinfo นั้นได้ system_server จะอ่านการกำหนดค่านี้ระหว่างการเริ่มต้น
  • keystore2_key_contexts กำหนดป้ายกำกับให้กับเนมสเปซของ Keystore 2.0 เนมสเปซเหล่านี้บังคับใช้โดยโปรแกรมเดรัม Keystore2 เสมอมา คีย์สโตร์มีเนมสเปซที่อิงตาม UID/AID นอกจากนี้ Keystore 2.0 ยังบังคับใช้เนมสเปซที่กําหนดโดย sepolicy ด้วย ดูคำอธิบายโดยละเอียดเกี่ยวกับรูปแบบและรูปแบบของไฟล์นี้ได้ที่นี่

ไฟล์ Make ของ BoardConfig.mk

หลังจากแก้ไขหรือเพิ่มไฟล์นโยบายและบริบทแล้ว ให้อัปเดตไฟล์ /device/manufacturer/device-name/BoardConfig.mkmakefile เพื่ออ้างอิงไดเรกทอรีย่อย sepolicy และไฟล์นโยบายใหม่แต่ละไฟล์ ดูข้อมูลเพิ่มเติมเกี่ยวกับตัวแปร BOARD_SEPOLICY ได้ที่ ไฟล์ system/sepolicy/README

BOARD_SEPOLICY_DIRS += \
        <root>/device/manufacturer/device-name/sepolicy

BOARD_SEPOLICY_UNION += \
        genfs_contexts \
        file_contexts \
        sepolicy.te

หลังจากสร้างใหม่แล้ว อุปกรณ์จะเปิดใช้ SELinux ตอนนี้คุณสามารถปรับแต่งนโยบาย SELinux เพื่อรองรับการเพิ่มของคุณเองในระบบปฏิบัติการ Android ตามที่อธิบายไว้ในการปรับแต่ง หรือยืนยันการตั้งค่าที่มีอยู่ตามที่อธิบายไว้ในการตรวจสอบ

เมื่อไฟล์นโยบายใหม่และการอัปเดต BoardConfig.mk เสร็จสมบูรณ์แล้ว ระบบจะสร้างการตั้งค่านโยบายใหม่ลงในไฟล์นโยบายเคอร์เนลฉบับสุดท้ายโดยอัตโนมัติ ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีสร้าง sepolicy ในอุปกรณ์ได้ที่หัวข้อการสร้าง sepolicy

การใช้งาน

วิธีเริ่มต้นใช้งาน SELinux

  1. เปิดใช้ SELinux ในเคอร์เนล โดยทำดังนี้ CONFIG_SECURITY_SELINUX=y
  2. เปลี่ยนพารามิเตอร์ kernel_cmdline หรือ bootconfig เพื่อให้มีลักษณะดังนี้
    BOARD_KERNEL_CMDLINE := androidboot.selinux=permissive
    หรือ
    BOARD_BOOTCONFIG := androidboot.selinux=permissive
    การดำเนินการนี้มีไว้สําหรับการพัฒนานโยบายสําหรับอุปกรณ์ในระยะแรกเท่านั้น หลังจากมีนโยบายการบูตเริ่มต้นแล้ว ให้นำพารามิเตอร์นี้ออกเพื่อให้อุปกรณ์บังคับใช้หรือจะทดสอบไม่ผ่าน CTS ก็ได้
  3. บูตระบบในโหมดอนุญาตและดูการปฏิเสธที่พบในการบูต
    ใน Ubuntu 14.04 ขึ้นไป ให้ทำดังนี้
    adb shell su -c dmesg | grep denied | audit2allow -p out/target/product/BOARD/root/sepolicy
    
    ใน Ubuntu 12.04
    adb pull /sys/fs/selinux/policy
    adb logcat -b all | audit2allow -p policy
    
  4. ประเมินผลลัพธ์เพื่อหาคำเตือนที่คล้ายกับinit: Warning! Service name needs a SELinux domain defined; please fix!ดูการตรวจสอบเพื่อดูวิธีการและเครื่องมือ
  5. ระบุอุปกรณ์และไฟล์ใหม่อื่นๆ ที่ต้องติดป้ายกำกับ
  6. ใช้ป้ายกำกับที่มีอยู่หรือป้ายกำกับใหม่สำหรับวัตถุ ดูไฟล์ *_contexts เพื่อดูว่าก่อนหน้านี้มีการติดป้ายกำกับรายการต่างๆ อย่างไร และใช้ความรู้เกี่ยวกับความหมายของป้ายกำกับเพื่อกำหนดป้ายกำกับใหม่ โดยปกติแล้ว ป้ายกำกับนี้ควรเป็นป้ายกำกับที่มีอยู่ซึ่งสอดคล้องกับนโยบาย แต่บางครั้งก็จำเป็นต้องมีป้ายกำกับใหม่และกฎสำหรับการเข้าถึงป้ายกำกับนั้น เพิ่มป้ายกำกับลงในไฟล์บริบทที่เหมาะสม
  7. ระบุโดเมน/กระบวนการที่ควรมีโดเมนความปลอดภัยของตนเอง คุณอาจต้องเขียนนโยบายใหม่ทั้งหมดสำหรับแต่ละรายการ ตัวอย่างเช่น บริการทั้งหมดที่เกิดจาก init ควรมี คำสั่งต่อไปนี้จะช่วยแสดงบริการที่ยังคงทำงานอยู่ (แต่บริการทั้งหมดต้องได้รับการดำเนินการดังกล่าว)
    adb shell su -c ps -Z | grep init
    
    adb shell su -c dmesg | grep 'avc: '
    
  8. ตรวจสอบ init.device.rc เพื่อระบุโดเมนที่ไม่มีประเภทโดเมน กำหนดโดเมนให้แอปตั้งแต่เนิ่นๆ ในกระบวนการพัฒนาเพื่อหลีกเลี่ยงการเพิ่มกฎลงใน init หรือทำให้การเข้าถึง init เกิดความสับสนกับสิทธิ์เข้าถึงที่อยู่ในนโยบายของแอป
  9. ตั้งค่า BOARD_CONFIG.mk ให้ใช้ตัวแปร BOARD_SEPOLICY_* ดูรายละเอียดเกี่ยวกับการตั้งค่านี้ได้ใน README ใน system/sepolicy
  10. ตรวจสอบไฟล์ init.device.rc และ fstab.device และตรวจสอบว่าการใช้ mount ทั้งหมดสอดคล้องกับระบบไฟล์ที่ติดป้ายกำกับอย่างถูกต้อง หรือมีการระบุตัวเลือก context= mount
  11. ตรวจสอบการปฏิเสธแต่ละรายการและสร้างนโยบาย SELinux เพื่อจัดการแต่ละรายการอย่างเหมาะสม ดูตัวอย่างในการปรับแต่ง

คุณควรเริ่มต้นด้วยนโยบายใน AOSP แล้วปรับแต่งตามต้องการ ดูข้อมูลเพิ่มเติมเกี่ยวกับกลยุทธ์ด้านนโยบายและดูรายละเอียดเพิ่มเติมเกี่ยวกับขั้นตอนเหล่านี้ได้ที่การเขียนนโยบาย SELinux

กรณีการใช้งาน

ตัวอย่างที่เฉพาะเจาะจงของการโจมตีที่ควรพิจารณาเมื่อสร้างซอฟต์แวร์ของคุณเองและนโยบาย SELinux ที่เกี่ยวข้องมีดังนี้

Symlink: เนื่องจาก Symlink ปรากฏเป็นไฟล์ ระบบจึงมักอ่าน Symlink เป็นไฟล์ ซึ่งอาจนำไปสู่การแสวงหาประโยชน์ ตัวอย่างเช่น คอมโพเนนต์ที่มีสิทธิ์บางอย่าง เช่น init จะเปลี่ยนสิทธิ์ของไฟล์บางไฟล์ ซึ่งบางครั้งอาจเปิดมากเกินไป

จากนั้นผู้โจมตีอาจแทนที่ไฟล์เหล่านั้นด้วยลิงก์สัญลักษณ์ไปยังโค้ดที่ตนควบคุม ซึ่งจะช่วยให้ผู้โจมตีเขียนทับไฟล์ใดก็ได้ แต่หากทราบว่าแอปของคุณไม่เคยไปยังลิงก์สัญลักษณ์ คุณก็ห้ามไม่ให้แอปดำเนินการดังกล่าวได้โดยใช้ SELinux

ไฟล์ระบบ: พิจารณาคลาสของไฟล์ระบบที่ควรแก้ไขโดยเซิร์ฟเวอร์ระบบเท่านั้น อย่างไรก็ตาม เนื่องจาก netd, init และ vold ทำงานเป็นรูท ไฟล์ระบบเหล่านั้นจึงเข้าถึงได้ ดังนั้นหาก netd มีการบุกรุก ก็อาจทำให้ไฟล์เหล่านั้นและเซิร์ฟเวอร์ระบบเองถูกบุกรุกด้วย

SELinux ช่วยให้คุณระบุไฟล์เหล่านั้นเป็นไฟล์ข้อมูลเซิร์ฟเวอร์ของระบบได้ ดังนั้น โดเมนเดียวที่มีสิทธิ์อ่าน/เขียนในไฟล์ดังกล่าวคือเซิร์ฟเวอร์ระบบ แม้ว่า netd จะถูกบุกรุก แต่ก็จะเปลี่ยนโดเมนเป็นโดเมนเซิร์ฟเวอร์ระบบและเข้าถึงไฟล์ระบบเหล่านั้นไม่ได้ แม้ว่าจะทำงานในฐานะรูทก็ตาม

ข้อมูลแอป: อีกตัวอย่างหนึ่งคือคลาสของฟังก์ชันที่ต้องทำงานในฐานะรูท แต่ไม่ควรเข้าถึงข้อมูลแอป ซึ่งมีประโยชน์อย่างยิ่งเนื่องจากสามารถทำการยืนยันได้หลายอย่าง เช่น โดเมนบางรายการที่ไม่เกี่ยวข้องกับข้อมูลแอปถูกห้ามไม่ให้เข้าถึงอินเทอร์เน็ต

setattr: สำหรับคำสั่ง เช่น chmod และ chown คุณสามารถระบุชุดไฟล์ที่โดเมนที่เกี่ยวข้องสามารถดำเนินการ setattr ได้ ทุกอย่างที่อยู่นอกนั้นอาจไม่ได้รับอนุญาตให้ทำการเปลี่ยนแปลงเหล่านี้ได้ แม้ว่าจะเป็นรูทก็ตาม ดังนั้น แอปอาจทํางานกับ chmod และ chown กับรายการที่ติดป้ายกํากับว่า app_data_files แต่ไม่ทํางานกับ shell_data_files หรือ system_data_files