ผู้ให้บริการ init

กระบวนการเริ่มต้นมีสิทธิ์ที่แทบไม่มีการจำกัด และใช้สคริปต์อินพุตจากทั้งพาร์ติชันของระบบและของผู้ให้บริการเพื่อเริ่มต้นระบบระหว่างการเปิดเครื่อง การเข้าถึงนี้ทำให้เกิดช่องโหว่ขนาดใหญ่ในการแยกระบบ/ผู้ให้บริการของ Treble เนื่องจากสคริปต์ของผู้ให้บริการอาจสั่งให้ init เข้าถึงไฟล์ พร็อพเพอร์ตี้ ฯลฯ ที่ไม่ได้เป็นส่วนหนึ่งของอินเทอร์เฟซไบนารีของแอปพลิเคชัน (ABI) ของผู้ให้บริการระบบที่เสถียร

Vendor init ได้รับการออกแบบมาเพื่อปิดช่องโหว่นี้โดยใช้โดเมน vendor_init ของ Linux (SELinux) ที่เพิ่มความปลอดภัยแยกต่างหากเพื่อเรียกใช้คำสั่งที่พบใน /vendor ด้วยสิทธิ์เฉพาะของผู้ให้บริการ

กลไก

ผู้ให้บริการเริ่มแยกกระบวนการย่อยของ init ในช่วงต้นของขั้นตอนการเปิดเครื่องด้วยบริบท SELinux u:r:vendor_init:s0 บริบท SELinux นี้มีสิทธิ์น้อยกว่าบริบท init เริ่มต้นมาก และการเข้าถึงจะจำกัดอยู่ที่ไฟล์ พร็อพเพอร์ตี้ ฯลฯ ที่เป็นของผู้ให้บริการรายใดรายหนึ่งหรือเป็นส่วนหนึ่งของ ABI ของผู้ให้บริการระบบที่เสถียร

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

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

ลูปการประมวลผลหลักของ init จะมีการตรวจสอบว่าหากมีการกำกับเนื้อหาคำสั่งให้ทำงานในกระบวนการย่อยของผู้ให้บริการและมาจากสคริปต์ของผู้ให้บริการ ระบบจะส่งคำสั่งนั้นผ่านการสื่อสารระหว่างกระบวนการ (IPC) ไปยังกระบวนการย่อย init ของผู้ให้บริการ ซึ่งจะเรียกใช้คำสั่งและส่งผลลัพธ์กลับไปยัง init

ใช้ init ของผู้ให้บริการ

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

อย่างไรก็ตาม หากคําสั่งในสคริปต์ของผู้ให้บริการละเมิดข้อจํากัดของผู้ให้บริการในการเริ่มต้นใช้งาน คําสั่งดังกล่าวจะไม่ทํางาน คำสั่งที่ล้มเหลวจะมีบรรทัดในบันทึกของเคอร์เนล (มองเห็นได้ด้วย dmesg) จาก init ที่ระบุว่าล้มเหลว การตรวจสอบ SELinux จะแสดงพร้อมกับคำสั่งที่ดำเนินการไม่สำเร็จเนื่องจากนโยบาย SELinux ตัวอย่างของข้อผิดพลาดที่รวมถึงการตรวจสอบ SELinux

type=1400 audit(1511821362.996:9): avc: denied { search } for pid=540 comm="init" name="nfc" dev="sda45" ino=1310721 scontext=u:r:vendor_init:s0 tcontext=u:object_r:nfc_data_file:s0 tclass=dir permissive=0
init: Command 'write /data/nfc/bad_file_access 1234' action=boot (/vendor/etc/init/hw/init.walleye.rc:422) took 2ms and failed: Unable to write to file '/data/nfc/bad_file_access': open() failed: Permission denied

หากคำสั่งไม่สำเร็จ จะมี 2 ตัวเลือกดังนี้

  • หากคำสั่งไม่สำเร็จเนื่องจากข้อจำกัดที่ต้องการ (เช่น หากคำสั่งเข้าถึงไฟล์หรือพร็อพเพอร์ตี้ของระบบ) คุณต้องติดตั้งใช้งานคำสั่งอีกครั้งในลักษณะที่รองรับ Treble โดยผ่านอินเทอร์เฟซที่เสถียรเท่านั้น กฎ "ไม่อนุญาต" จะป้องกันไม่ให้เพิ่มสิทธิ์เข้าถึงไฟล์ระบบที่ไม่ได้อยู่ใน ABI ที่เสถียรของผู้ให้บริการระบบ
  • หากป้ายกำกับ SELinux เป็นป้ายกำกับใหม่และยังไม่ได้ให้สิทธิ์ในvendor_init.teของระบบหรือยกเว้นสิทธิ์ผ่านกฎ neverallow ป้ายกำกับใหม่อาจได้รับสิทธิ์ในvendor_init.teเฉพาะอุปกรณ์

สําหรับอุปกรณ์ที่เปิดตัวก่อน Android 9 ระบบอาจข้ามกฎ neverallows โดยการเพิ่มแอตทริบิวต์ประเภท data_between_core_and_vendor_violators ลงในไฟล์ vendor_init.te สําหรับอุปกรณ์นั้นๆ

ตําแหน่งโค้ด

ตรรกะส่วนใหญ่สําหรับ IPC ของ init ของผู้ให้บริการอยู่ใน system/core/init/subcontext.cpp

ตารางคำสั่งอยู่ในคลาส BuiltinFunctionMap ใน system/core/init/builtins.cpp และมีการกำกับเนื้อหาที่ระบุว่าคำสั่งต้องทำงานในพาร์ทเนอร์ init ย่อยหรือไม่

SEPolicy สําหรับ init ของผู้ให้บริการจะแยกอยู่ในไดเรกทอรีส่วนตัว (system/sepolicy/private/vendor_init.te) และสาธารณะ (system/sepolicy/public/vendor_init.te) ใน system/sepolicy