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

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

การเรียกอุปกรณ์

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

เรียกใช้ในโหมดไม่เข้มงวด

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

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

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

หลังจากนั้นให้ยืนยันโหมดอนุญาตด้วยการตั้งค่าต่อไปนี้

adb shell getenforce

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

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

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

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

มีเหตุผลหลายประการในการสร้างนโยบายเฉพาะอุปกรณ์ ขูดบนอุปกรณ์ใหม่ ซึ่งรวมถึง

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

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

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 ได้รับ " อุปกรณ์" เว้นแต่จะมีการกำหนดป้ายกำกับที่เฉพาะเจาะจงมากกว่า เพียงแค่ยอมรับ เอาต์พุตจาก audit2allow จะทำให้เกิดกฎที่ไม่ถูกต้องและอนุญาตมากเกินไป

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

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

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

ติดป้ายกำกับบริการและที่อยู่ใหม่ การปฏิเสธ

บริการเริ่มต้นจะต้องทำงานในโดเมน 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)
    

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

  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 เครื่องที่ นโยบายประกอบด้วย 50% และ 40% ของนโยบายในอุปกรณ์ นโยบายที่เขียนใหม่ ให้ประสิทธิภาพในการรักษาความปลอดภัยที่ดีขึ้น โดยไม่สูญเสียฟังก์ชันการทำงาน ดังที่แสดงด้านล่าง (มีอุปกรณ์ AOSP Shamu และ Flounder รวมอยู่ด้วยเพื่อใช้เปรียบเทียบ)

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

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

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

การให้สิทธิ์ dac_override

การปฏิเสธ dac_override หมายความว่ากระบวนการที่ไม่เหมาะสมคือ มีการพยายามเข้าถึงไฟล์ที่มีสิทธิ์ของผู้ใช้/กลุ่ม/โลก Unix ที่ไม่ถูกต้อง โซลูชันที่เหมาะสมแทบจะไม่ต้องให้สิทธิ์ dac_override เลย แทน เปลี่ยนสิทธิ์ Unix ในไฟล์หรือกระบวนการ ตัวอย่างโดเมน เช่น ต้องการ init vold และ installd จริงๆ ความสามารถในการลบล้างสิทธิ์ของไฟล์ Unix เพื่อเข้าถึงไฟล์ของกระบวนการอื่นๆ ดูบล็อกของ Dan Walsh เพื่อดูคำอธิบายที่ละเอียดยิ่งขึ้น