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

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

การนำอุปกรณ์

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

เรียกใช้ในโหมดอนุญาต

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

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

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

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

adb shell getenforce

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

บังคับใช้ก่อน

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

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

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

ระบุที่อยู่การปฏิเสธบริการหลัก

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

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 ไม่ต้องการการอนุญาตเพิ่มเติมเนื่องจากเซิร์ฟเวอร์มีเดีย มีสิทธิ์ที่จำเป็น ในนโยบายหลักเพื่อเข้าถึง 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 builds เช่น adb root และ adb shell setenforce 0

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

การขยายขนาดนโยบาย

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

นโยบายขนาดใหญ่ที่ไม่จำเป็น:

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

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

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

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

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

ให้ความสามารถ dac_override

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