ใช้งาน SELinux

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

ไฟล์สำคัญ

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

โดยทั่วไป คุณไม่ควรแก้ไขไฟล์ system/sepolicy โดยตรง แต่ให้เพิ่มหรือแก้ไขไฟล์นโยบายเฉพาะอุปกรณ์ของคุณเองใน /device/manufacturer/device-name/sepolicy ไดเรกทอรี ใน Android 8.0 ขึ้นไป การเปลี่ยนแปลงที่คุณทำกับไฟล์เหล่านี้ควรส่งผลต่อนโยบายในไดเรกทอรีของผู้ให้บริการเท่านั้น ดูรายละเอียดเพิ่มเติมเกี่ยวกับการแยก sepolicy สาธารณะใน 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 ที่ไม่รองรับแอตทริบิวต์แบบขยาย การกำหนดค่านี้จะโหลดเป็นส่วนหนึ่งของนโยบายเคอร์เนล แต่ การเปลี่ยนแปลงอาจไม่มีผลกับ inodes ในเคอร์เนล ซึ่งต้องรีบูตหรือ ยกเลิกการติดตั้งและติดตั้งระบบไฟล์ใหม่เพื่อให้การเปลี่ยนแปลงมีผลอย่างสมบูรณ์ นอกจากนี้ คุณยังกำหนดป้ายกำกับที่เฉพาะเจาะจงให้กับจุดติดตั้งที่เฉพาะเจาะจงได้ด้วย เช่น 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 daemon keystore2 จะบังคับใช้เนมสเปซเหล่านี้ Keystore มีเนมสเปซที่อิงตาม UID/AID มาโดยตลอด นอกจากนี้ Keystore 2 ยังบังคับใช้เนมสเปซที่กำหนดโดย sepolicy ด้วย คุณสามารถดูคำอธิบายโดยละเอียดเกี่ยวกับรูปแบบและข้อกำหนดของไฟล์นี้ได้ที่นี่ ที่นี่

ไฟล์ makefile ของ BoardConfig.mk

หลังจากแก้ไขหรือเพิ่มไฟล์นโยบายและไฟล์บริบทแล้ว ให้อัปเดตไฟล์ makefile ของ /device/manufacturer/device-name/BoardConfig.mk เพื่ออ้างอิงไดเรกทอรีย่อย 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. ระบุโดเมน/กระบวนการที่ควรมีโดเมนความปลอดภัยของตัวเอง คุณอาจต้องเขียนนโยบายใหม่ทั้งหมดสำหรับแต่ละโดเมน/กระบวนการ ตัวอย่างเช่น บริ101}การทั้งหมดที่สร้างจาก 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 แล้วสร้างนโยบายเพิ่มเติมสำหรับการปรับแต่งของคุณเอง ดูข้อมูลเพิ่มเติมเกี่ยวกับกลยุทธ์นโยบายและa ดูขั้นตอนบางขั้นตอนเหล่านี้อย่างละเอียดได้ที่ การเขียนนโยบาย SELinux

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

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

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

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

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

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

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

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