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

โครงการ Android Open Source (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 ของอุปกรณ์ของเรา ไฟล์ 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%+ เกือบจะประกอบด้วยโดเมนที่ได้รับสิทธิพิเศษและนโยบายที่ไม่ทำงาน

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

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

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

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

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

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

การกำหนดความสามารถ dac_override

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