เขียนนโยบาย SELinux

โครงการโอเพนซอร์ส Android (AOSP) มีนโยบายพื้นฐานที่มั่นคงสำหรับแอปและบริการที่ใช้ร่วมกันในอุปกรณ์ Android ทั้งหมด ผู้มีส่วนร่วมใน AOSP จะปรับแต่งนโยบายนี้เป็นประจำ นโยบายหลักคาดว่าจะคิดเป็นสัดส่วนประมาณ 90-95% ของนโยบายในอุปกรณ์ขั้นสุดท้าย โดยมีการปรับแต่งเฉพาะอุปกรณ์คิดเป็นสัดส่วน 5-10% ที่เหลือ บทความนี้มุ่งเน้นไปที่การปรับแต่งเฉพาะอุปกรณ์เหล่านี้ วิธีเขียนนโยบายเฉพาะอุปกรณ์ และข้อผิดพลาดที่ควรหลีกเลี่ยง

การเปิดใช้งานอุปกรณ์

ขณะเขียนนโยบายเฉพาะอุปกรณ์ ให้ทำตามขั้นตอนต่อไปนี้

ทำงานในโหมดไม่เข้มงวด

เมื่ออุปกรณ์อยู่ในโหมดอนุญาต ระบบจะบันทึกการปฏิเสธ แต่ไม่บังคับใช้ โหมดอนุญาตมีความสำคัญเนื่องจากเหตุผล 2 ประการ ดังนี้

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

วิธีที่ง่ายที่สุดในการเปลี่ยนอุปกรณ์เป็นโหมดอนุญาตคือการใช้บรรทัดคำสั่งเคอร์เนล คุณสามารถเพิ่มข้อมูลนี้ลงในไฟล์ BoardConfig.mk ของอุปกรณ์ได้ platform/device/<vendor>/<target>/BoardConfig.mk หลังจากแก้ไขบรรทัดคำสั่งแล้ว ให้กด make clean แล้วกด make bootimage แล้วแฟลชอิมเมจการบูตใหม่

หลังจากนั้น ให้ยืนยันโหมดอนุญาตด้วย

adb shell getenforce

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

บังคับใช้ตั้งแต่เนิ่นๆ

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

นำนโยบายที่มีอยู่ออกหรือลบ

มีเหตุผลหลายประการที่ควรสร้างนโยบายเฉพาะอุปกรณ์ตั้งแต่ต้นในอุปกรณ์เครื่องใหม่ ดังนี้

จัดการการปฏิเสธบริการหลัก

โดยปกติแล้ว การปฏิเสธที่เกิดจากบริการหลักจะได้รับการแก้ไขด้วยการติดป้ายกำกับไฟล์ เช่น

avc: denied { open } for pid=1003 comm=”mediaserver” path="/dev/kgsl-3d0”
dev="tmpfs" scontext=u:r:mediaserver:s0 tcontext=u:object_r:device:s0
tclass=chr_file permissive=1
avc: denied { read write } for pid=1003 name="kgsl-3d0" dev="tmpfs"
scontext=u:r:mediaserver:s0
tcontext=u:object_r:device:s0 tclass=chr_file permissive=1

ได้รับการแก้ไขอย่างสมบูรณ์แล้วโดยการติดป้ายกํากับ /dev/kgsl-3d0 อย่างถูกต้อง ในตัวอย่างนี้ tcontext คือ device รายการนี้แสดงบริบทเริ่มต้นที่ทุกอย่างใน /dev จะได้รับป้ายกํากับ " device" เว้นแต่จะมีการกําหนดป้ายกํากับที่เฉพาะเจาะจงมากขึ้น การยอมรับเอาต์พุตจาก audit2allow ที่นี่เพียงอย่างเดียวจะทำให้ได้กฎที่ไม่ถูกต้องและอนุญาตมากเกินไป

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

ไฟล์อื่นๆ สำหรับอุปกรณ์ที่เฉพาะเจาะจงซึ่งควรติดป้ายกำกับด้วยประเภทที่กำหนดไว้ล่วงหน้าในนโยบายหลัก

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

ติดป้ายกำกับบริการใหม่และแก้ไขการปฏิเสธ

บริการที่เริ่มต้นด้วย Init ต้องทำงานในโดเมน SELinux ของตนเอง ตัวอย่างต่อไปนี้จะใส่บริการ "foo" ไว้ในโดเมน SELinux ของตัวเองและมอบสิทธิ์ให้

บริการจะเปิดขึ้นในไฟล์ init.device.rc ของอุปกรณ์ ดังนี้

service foo /system/bin/foo
    class core
  1. สร้างโดเมนใหม่ "foo"

    สร้างไฟล์ device/manufacturer/device-name/sepolicy/foo.te ที่มีเนื้อหาต่อไปนี้

    # foo service
    type foo, domain;
    type foo_exec, exec_type, file_type;
    
    init_daemon_domain(foo)
    

    นี่คือเทมเพลตเริ่มต้นสำหรับโดเมน SELinux ของ foo ซึ่งคุณสามารถเพิ่มกฎตามการดำเนินการที่เฉพาะเจาะจงซึ่งไฟล์ปฏิบัติการนั้นดำเนินการได้

  2. ป้ายกำกับ /system/bin/foo

    เพิ่มข้อมูลต่อไปนี้ลงใน device/manufacturer/device-name/sepolicy/file_contexts

    /system/bin/foo   u:object_r:foo_exec:s0
    

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

  3. สร้างและแฟลชอิมเมจการบูตและระบบ
  4. ปรับแต่งกฎ SELinux สำหรับโดเมน

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

เปลี่ยนกลับไปใช้โหมดบังคับใช้

การแก้ปัญหาในโหมดที่อนุญาตนั้นทำได้ แต่ให้เปลี่ยนไปใช้โหมดบังคับใช้โดยเร็วที่สุดและพยายามใช้โหมดนี้ต่อไป

ความผิดพลาดที่พบบ่อย

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

การใช้การปฏิเสธมากเกินไป

ตัวอย่างกฎต่อไปนี้เปรียบเสมือนการล็อกประตูหน้าแต่เปิดหน้าต่างไว้

allow { domain -untrusted_app } scary_debug_device:chr_file rw_file_perms

เจตนานั้นชัดเจนว่าทุกคนยกเว้นแอปของบุคคลที่สามจะมีสิทธิ์เข้าถึงอุปกรณ์แก้ไขข้อบกพร่อง

กฎมีข้อบกพร่องในหลายประการ การยกเว้น untrusted_app นั้นแก้ไขได้ง่าย เนื่องจากแอปทั้งหมดอาจเลือกที่จะเรียกใช้บริการในโดเมน isolated_app ได้ ในทำนองเดียวกัน หากเพิ่มโดเมนใหม่สำหรับแอปของบุคคลที่สามลงใน AOSP แอปเหล่านั้นจะมีสิทธิ์เข้าถึง scary_debug_device ด้วย กฎให้สิทธิ์มากเกินไป โดเมนส่วนใหญ่จะไม่ได้รับประโยชน์จากการมีสิทธิ์เข้าถึงเครื่องมือแก้ไขข้อบกพร่องนี้ กฎควรเขียนขึ้นเพื่ออนุญาตเฉพาะโดเมนที่ต้องเข้าถึง

แก้ไขข้อบกพร่องของฟีเจอร์ในเวอร์ชันที่ใช้งานจริง

ฟีเจอร์แก้ไขข้อบกพร่องไม่ควรอยู่ในบิลด์เวอร์ชันที่ใช้งานจริง รวมถึงนโยบายของฟีเจอร์ดังกล่าว

ทางเลือกที่ง่ายที่สุดคือการอนุญาตให้ใช้ฟีเจอร์แก้ไขข้อบกพร่องเฉพาะเมื่อปิดใช้ SELinux ในรุ่น eng/userdebug เช่น adb root และ adb shell setenforce 0

อีกทางเลือกหนึ่งที่ปลอดภัยคือการใส่สิทธิ์แก้ไขข้อบกพร่องไว้ในคำสั่ง userdebug_or_eng

นโยบายที่เพิ่มขึ้นอย่างรวดเร็ว

การระบุลักษณะนโยบาย SEAndroid ในการใช้งานจริงอธิบายแนวโน้มที่น่ากังวลเกี่ยวกับการเติบโตของการปรับเปลี่ยนนโยบายอุปกรณ์ นโยบายเฉพาะอุปกรณ์ควรคิดเป็นสัดส่วน 5-10% ของนโยบายโดยรวมที่ทำงานในอุปกรณ์ การปรับแต่งในช่วง 20%ขึ้นไปมีโดเมนที่มีสิทธิ์มากเกินไปและนโยบายที่ใช้งานไม่ได้เกือบแน่นอน

นโยบายที่มีขนาดใหญ่เกินความจำเป็น

  • ใช้หน่วยความจํา 2 เท่าเนื่องจากนโยบายอยู่ใน RAMdisk และโหลดลงในหน่วยความจําเคอร์เนลด้วย
  • สิ้นเปลืองพื้นที่ในดิสก์เนื่องจากต้องใช้บูตอิมเมจขนาดใหญ่ขึ้น
  • ส่งผลต่อเวลาในการค้นหานโยบายรันไทม์

ตัวอย่างต่อไปนี้แสดงอุปกรณ์ 2 เครื่องที่นโยบายเฉพาะผู้ผลิตคิดเป็นสัดส่วน 50% และ 40% ของนโยบายในอุปกรณ์ การเขียนนโยบายขึ้นใหม่ทำให้มีการปรับปรุงด้านความปลอดภัยอย่างมากโดยไม่สูญเสียฟังก์ชันการทำงาน ดังที่แสดงด้านล่าง (รวมอุปกรณ์ AOSP Shamu และ Flounder ไว้เพื่อการเปรียบเทียบ)

รูปที่ 1: การเปรียบเทียบขนาดนโยบายเฉพาะอุปกรณ์หลังการตรวจสอบความปลอดภัย

รูปที่ 1 การเปรียบเทียบขนาดนโยบายเฉพาะอุปกรณ์หลังจากการตรวจสอบความปลอดภัย

นโยบายทั้ง 2 ฉบับนี้มีขนาดและจำนวนสิทธิ์ลดลงอย่างมาก ขนาดนโยบายที่ลดลงเกือบทั้งหมดเกิดจากการนําสิทธิ์ที่ไม่จําเป็นออก ซึ่งส่วนใหญ่เป็นกฎที่ audit2allow สร้างขึ้นและเพิ่มลงในนโยบายโดยไม่คํานึงถึง โดเมนที่ใช้งานไม่ได้ก็เป็นปัญหาสำหรับทั้ง 2 อุปกรณ์ด้วย

ให้สิทธิ์ dac_override

การปฏิเสธ dac_override หมายความว่ากระบวนการที่ละเมิดกำลังพยายามเข้าถึงไฟล์ที่มีสิทธิ์ผู้ใช้/กลุ่ม/โลก Unix ไม่ถูกต้อง แทบจะไม่เคยมีโซลูชันที่เหมาะสมในการให้สิทธิ์ dac_override แต่ให้ измените права Unix на файл или процесс โดเมนบางรายการ เช่น init, vold และ installd จำเป็นต้องมีความสามารถในการลบล้างสิทธิ์เข้าถึงไฟล์ Unix เพื่อเข้าถึงไฟล์ของกระบวนการอื่นๆ ดูคำอธิบายโดยละเอียดเพิ่มเติมได้ที่บล็อกของ Dan Walsh