หน้านี้อธิบายวิธีที่ Android จัดการปัญหาความเข้ากันได้ของนโยบายกับการอัปเดตแพลตฟอร์มแบบ Over-The-Air (OTA) ซึ่งการตั้งค่า SELinux ของแพลตฟอร์มใหม่อาจแตกต่างจากการตั้งค่า SELinux ของผู้จำหน่ายแบบเก่า
การเป็นเจ้าของและการติดป้ายกำกับออบเจ็กต์
ต้องกำหนดความเป็นเจ้าของของแต่ละออบเจ็กต์อย่างชัดเจนเพื่อแยกนโยบายของแพลตฟอร์มและผู้ให้บริการออกจากกัน
ตัวอย่างเช่น หากป้ายกำกับนโยบายของผู้ให้บริการ /dev/foo
และป้ายกำกับนโยบายของแพลตฟอร์ม /dev/foo ใน OTA ที่ตามมา จะมีลักษณะการทำงานที่ไม่แน่นอน เช่น การปฏิเสธที่ไม่คาดคิด หรือที่ร้ายแรงกว่านั้นคือการบูตล้มเหลว
สำหรับ SELinux ปัญหานี้จะแสดงเป็นการติดป้ายกำกับที่ซ้ำกัน โหนดอุปกรณ์
มีได้เพียงป้ายกำกับเดียวซึ่งจะแสดงป้ายกำกับที่ใช้ล่าสุด
ผลที่เกิดขึ้นมีดังนี้
- กระบวนการที่ต้องเข้าถึงป้ายกำกับที่ใช้ไม่สำเร็จ จะเสียสิทธิ์เข้าถึงทรัพยากร
- กระบวนการที่ได้รับสิทธิ์เข้าถึงไฟล์อาจหยุดทำงานเนื่องจาก สร้างโหนดอุปกรณ์ที่ไม่ถูกต้อง
การชนกันระหว่างป้ายกำกับของแพลตฟอร์มและผู้ให้บริการอาจเกิดขึ้นกับออบเจ็กต์ใดก็ได้ที่มีป้ายกำกับ SELinux ซึ่งรวมถึงพร็อพเพอร์ตี้ บริการ กระบวนการ ไฟล์ และซ็อกเก็ต หากต้องการหลีกเลี่ยงปัญหาเหล่านี้ ให้กำหนดความเป็นเจ้าของออบเจ็กต์เหล่านี้อย่างชัดเจน
การกำหนดเนมสเปซของประเภท/ชื่อแอตทริบิวต์
นอกเหนือจากการทับซ้อนของป้ายกำกับแล้ว ชื่อประเภทและแอตทริบิวต์ของ SELinux ยังอาจทับซ้อนกันได้ด้วย
SELinux ไม่อนุญาตให้ประกาศประเภทและ
แอตทริบิวต์เดียวกันหลายครั้ง นโยบายที่มีการประกาศซ้ำจะคอมไพล์ไม่สำเร็จ ขอแนะนำอย่างยิ่งให้ประกาศของผู้ให้บริการทั้งหมดเริ่มต้นด้วยคำนำหน้า vendor_ เพื่อหลีกเลี่ยงการชนกันของประเภท
และชื่อแอตทริบิวต์ เช่น ผู้ขายควรใช้ type vendor_foo, domain; แทน type foo, domain;
การเป็นเจ้าของไฟล์
การป้องกันการชนกันของไฟล์เป็นเรื่องที่ท้าทายเนื่องจากนโยบายของทั้งแพลตฟอร์มและผู้ให้บริการ มักจะระบุป้ายกำกับสำหรับระบบไฟล์ทั้งหมด การตั้งชื่อไฟล์ตามเนมสเปซไม่สามารถทำได้เนื่องจากเคอร์เนลเป็นผู้สร้างไฟล์จำนวนมาก ซึ่งแตกต่างจากการตั้งชื่อประเภท หากต้องการป้องกันการชนกันเหล่านี้ ให้ทำตามคำแนะนำในการตั้งชื่อสำหรับระบบไฟล์ ในส่วนนี้ สำหรับ Android 8.0 คำแนะนำเหล่านี้ไม่มีการบังคับใช้ทางเทคนิค ในอนาคต Vendor Test Suite (VTS) จะบังคับใช้คำแนะนำเหล่านี้
ระบบ (/system)
เฉพาะอิมเมจระบบเท่านั้นที่ต้องระบุป้ายกำกับสำหรับคอมโพเนนต์ /system
ถึง file_contexts, service_contexts ฯลฯ หากมีการเพิ่มป้ายกำกับ
สำหรับคอมโพเนนต์ /system ในนโยบายของผู้ให้บริการ การอัปเดต OTA เฉพาะเฟรมเวิร์กอาจเป็นไปไม่ได้
ผู้ให้บริการ (/vendor)
นโยบาย SELinux ของ AOSP ติดป้ายกำกับส่วนต่างๆ ของvendor
พาร์ติชันที่แพลตฟอร์มโต้ตอบด้วยอยู่แล้ว ซึ่งช่วยให้เขียนกฎ SELinux สำหรับ
กระบวนการของแพลตฟอร์มเพื่อให้สามารถพูดคุยหรือเข้าถึงส่วนต่างๆ ของvendor
พาร์ติชันได้ ตัวอย่าง
| /เส้นทางของผู้ให้บริการ | ป้ายกำกับที่แพลตฟอร์มระบุ | กระบวนการของแพลตฟอร์มขึ้นอยู่กับป้ายกำกับ |
|---|---|---|
/vendor(/.*)?
|
vendor_file
|
ไคลเอ็นต์ HAL ทั้งหมดในเฟรมเวิร์ก ueventd ฯลฯ
|
/vendor/framework(/.*)?
|
vendor_framework_file
|
dex2oat, appdomain ฯลฯ
|
/vendor/app(/.*)?
|
vendor_app_file
|
dex2oat, installd, idmap ฯลฯ
|
/vendor/overlay(/.*)
|
vendor_overlay_file
|
system_server, zygote, idmap ฯลฯ
|
ดังนั้น คุณต้องปฏิบัติตามกฎที่เฉพาะเจาะจง (บังคับใช้ผ่าน
neverallows) เมื่อติดป้ายกำกับไฟล์เพิ่มเติมในพาร์ติชัน
vendor
vendor_fileต้องเป็นป้ายกำกับเริ่มต้นสำหรับไฟล์ทั้งหมดใน พาร์ติชันvendorนโยบายแพลตฟอร์มกำหนดให้ต้องทำเช่นนี้เพื่อ เข้าถึงการติดตั้งใช้งาน HAL แบบส่งผ่านexec_typesใหม่ทั้งหมดที่เพิ่มในพาร์ติชันvendorผ่านนโยบายของผู้ให้บริการต้องมีแอตทริบิวต์vendor_file_typeซึ่งบังคับใช้ผ่าน neverallows- เพื่อหลีกเลี่ยงการขัดแย้งกับการอัปเดตแพลตฟอร์ม/เฟรมเวิร์กในอนาคต ให้หลีกเลี่ยงการติดป้ายกำกับ
ไฟล์อื่นๆ นอกเหนือจาก
exec_typesในพาร์ติชันvendor - การขึ้นต่อกันของไลบรารีทั้งหมดสำหรับ HAL ของกระบวนการเดียวกันที่ AOSP ระบุต้องมีป้ายกำกับเป็น
same_process_hal_file.
Procfs (/proc)
ไฟล์ใน /proc อาจติดป้ายกำกับได้โดยใช้ป้ายกำกับ genfscon
เท่านั้น ใน Android 7.0 ทั้งนโยบายแพลตฟอร์มและนโยบายผู้ให้บริการใช้ genfscon เพื่อติดป้ายกำกับไฟล์ใน procfs
คำแนะนำ: ป้ายกำกับนโยบายแพลตฟอร์มเท่านั้น /proc
หากกระบวนการของผู้ให้บริการต้องเข้าถึงไฟล์ใน /proc ที่ปัจจุบันมีป้ายกำกับเริ่มต้น (proc) นโยบายของผู้ให้บริการไม่ควรติดป้ายกำกับอย่างชัดเจน แต่ควรใช้ประเภท proc ทั่วไปเพื่อเพิ่มกฎสำหรับโดเมนของผู้ให้บริการแทน ซึ่งจะช่วยให้แพลตฟอร์ม
อัปเดตเพื่อรองรับอินเทอร์เฟซเคอร์เนลในอนาคตที่แสดงผ่าน procfs และติดป้ายกำกับอย่างชัดเจนตามที่จำเป็น
Debugfs (/sys/kernel/debug)
Debugfs สามารถติดป้ายกำกับได้ทั้งใน file_contexts และ genfscon ใน Android 7.0 ถึง Android 10 ทั้งแพลตฟอร์มและป้ายกำกับของผู้ให้บริการ
debugfs
ใน Android 11 debugfs จะเข้าถึงหรือติดตั้งในอุปกรณ์ที่ใช้งานจริงไม่ได้ ผู้ผลิตอุปกรณ์ควร
นำ debugfs ออก
Tracefs (/sys/kernel/debug/tracing)
Tracefs สามารถติดป้ายกำกับได้ทั้งใน file_contexts และ genfscon ใน Android 7.0 จะมีเฉพาะป้ายกำกับแพลตฟอร์ม
tracefs
คำแนะนำ: มีเพียงแพลตฟอร์มเท่านั้นที่ติดป้ายกำกับ tracefs ได้
Sysfs (/sys)
ไฟล์ใน /sys อาจติดป้ายกำกับโดยใช้ทั้ง file_contexts
และ genfscon ใน Android 7.0 ทั้งแพลตฟอร์มและผู้ให้บริการใช้
genfscon เพื่อติดป้ายกำกับไฟล์ใน sysfs
คำแนะนำ: แพลตฟอร์มอาจติดป้ายกำกับ sysfs
โหนดที่ไม่เจาะจงอุปกรณ์ มิฉะนั้นจะมีเพียงผู้ให้บริการเท่านั้นที่ติดป้ายกำกับไฟล์ได้
tmpfs (/dev)
ไฟล์ใน /dev อาจมีป้ายกำกับใน file_contexts ใน
Android 7.0 ทั้งแพลตฟอร์มและไฟล์ป้ายกำกับของผู้ให้บริการจะอยู่ที่นี่
คำแนะนำ: ผู้ให้บริการอาจติดป้ายกำกับเฉพาะไฟล์ใน
/dev/vendor (เช่น /dev/vendor/foo
/dev/vendor/socket/bar)
Rootfs (/)
ไฟล์ใน / อาจมีป้ายกำกับใน file_contexts ใน Android
7.0 ทั้งไฟล์ป้ายกำกับของแพลตฟอร์มและผู้ให้บริการจะอยู่ที่นี่
คำแนะนำ: มีเพียงระบบเท่านั้นที่ติดป้ายกำกับไฟล์ใน / ได้
ข้อมูล (/data)
ระบบจะติดป้ายกำกับข้อมูลผ่านการผสมผสานระหว่าง file_contexts และ seapp_contexts
คำแนะนำ: ไม่อนุญาตให้ติดป้ายกำกับของผู้ให้บริการภายนอก
/data/vendor มีเพียงแพลตฟอร์มเท่านั้นที่ติดป้ายกำกับส่วนอื่นๆ ของ
/data
เวอร์ชันป้ายกำกับ Genfs
ตั้งแต่ระดับ API ของผู้ให้บริการ 202504 เป็นต้นไป ป้ายกำกับ SELinux
ใหม่ที่กำหนดด้วย genfscon ใน
system/sepolicy/compat/plat_sepolicy_genfs_ver.cil จะ
เป็นตัวเลือกสำหรับพาร์ติชัน vendor รุ่นเก่า ซึ่งช่วยให้พาร์ติชันรุ่นเก่าvendorยังคงใช้การติดตั้งใช้งาน SEPolicy ที่มีอยู่ได้
ซึ่งควบคุมโดยตัวแปร Makefile BOARD_GENFS_LABELS_VERSION
ซึ่งจัดเก็บไว้ใน /vendor/etc/selinux/genfs_labels_version.txt
ตัวอย่าง
-
ในระดับ API 202404 ของผู้ให้บริการ ระบบจะติดป้ายกำกับโหนด
/sys/class/udcเป็นsysfsโดยค่าเริ่มต้น -
ตั้งแต่ระดับ API 202504 ของผู้ให้บริการเป็นต้นไป
/sys/class/udcจะมีป้ายกำกับเป็นsysfs_udc
อย่างไรก็ตาม /sys/class/udc อาจใช้งานโดยvendor พาร์ติชันที่ใช้ระดับ API 202404 โดยใช้ป้ายกำกับ sysfs เริ่มต้นหรือป้ายกำกับเฉพาะของผู้ให้บริการ การติดป้ายกำกับ /sys/class/udc เป็น sysfs_udc โดยไม่มีเงื่อนไขอาจทำให้เกิดปัญหาความเข้ากันได้
กับพาร์ติชัน vendor เหล่านี้ การเลือก
BOARD_GENFS_LABELS_VERSIONจะทำให้แพลตฟอร์มใช้ป้ายกำกับและสิทธิ์ก่อนหน้า
ต่อไปสำหรับพาร์ติชัน vendor รุ่นเก่า
BOARD_GENFS_LABELS_VERSION อาจมากกว่าหรือเท่ากับระดับ API ของผู้ให้บริการ เช่น vendorพาร์ติชันที่ใช้ระดับ API 202404 สามารถตั้งค่า
BOARD_GENFS_LABELS_VERSION เป็น 202504 เพื่อใช้ป้ายกำกับใหม่ที่เปิดตัว
ใน 202504 ดูรายการ
ป้ายกำกับ genfs ที่เฉพาะเจาะจงสำหรับ 202504
เมื่อติดป้ายกำกับโหนด genfscon แพลตฟอร์มต้องพิจารณาพาร์ติชันvendorรุ่นเก่าและใช้กลไกการย้อนกลับเพื่อความเข้ากันได้เมื่อจำเป็น แพลตฟอร์มสามารถใช้ไลบรารีเฉพาะแพลตฟอร์มเพื่อค้นหา
เวอร์ชันป้ายกำกับ genfs ได้
-
ในโฆษณาเนทีฟ ให้ใช้
libgenfslabelsversionดูgenfslabelsversion.hสำหรับไฟล์ส่วนหัวของlibgenfslabelsversion -
ใน Java ให้ใช้
android.os.SELinux.getGenfsLabelsVersion()
นโยบายสาธารณะของแพลตฟอร์ม
นโยบาย SELinux ของแพลตฟอร์มแบ่งออกเป็นแบบส่วนตัวและแบบสาธารณะ
นโยบายสาธารณะของแพลตฟอร์มประกอบด้วยประเภทและแอตทริบิวต์ที่พร้อมใช้งานเสมอสำหรับระดับ API ของผู้ให้บริการ
ซึ่งทำหน้าที่เป็น API ระหว่างแพลตฟอร์มและผู้ให้บริการ นโยบายนี้จะแสดงต่อผู้เขียนนโยบายของผู้ให้บริการเพื่อให้ผู้ให้บริการสร้างไฟล์นโยบายของผู้ให้บริการได้ ซึ่งเมื่อรวมกับนโยบายส่วนตัวของแพลตฟอร์มแล้ว จะส่งผลให้นโยบายของอุปกรณ์ทำงานได้อย่างเต็มที่ นโยบายแพลตฟอร์มสาธารณะกำหนดไว้ใน
system/sepolicy/public
เช่น ประเภท vendor_init ซึ่งแสดงถึงกระบวนการเริ่มต้นใน
บริบทของผู้ให้บริการ จะกำหนดไว้ใน
system/sepolicy/public/vendor_init.te ดังนี้
type vendor_init, domain;
ผู้ให้บริการสามารถดูประเภท vendor_init เพื่อเขียนกฎนโยบายที่กำหนดเองได้
# Allow vendor_init to set vendor_audio_prop in vendor's init scripts
set_prop(vendor_init, vendor_audio_prop)แอตทริบิวต์ความเข้ากันได้
นโยบาย SELinux คือการโต้ตอบระหว่างประเภทแหล่งที่มาและเป้าหมายสำหรับคลาสออบเจ็กต์และสิทธิ์ที่เฉพาะเจาะจง ออบเจ็กต์ทุกรายการ (เช่น กระบวนการ ไฟล์) ที่ได้รับผลกระทบจากนโยบาย SELinux จะมีได้เพียงประเภทเดียว แต่ประเภทนั้นอาจมีแอตทริบิวต์หลายรายการ
นโยบายส่วนใหญ่เขียนขึ้นในแง่ของประเภทที่มีอยู่ ในที่นี้ ทั้ง
vendor_init และ debugfs เป็นประเภท
allow vendor_init debugfs:dir { mounton };
ซึ่งเป็นไปได้เนื่องจากนโยบายนี้เขียนขึ้นโดยมีความรู้เกี่ยวกับเนื้อหาทุกประเภท อย่างไรก็ตาม หากนโยบายของผู้ให้บริการและนโยบายของแพลตฟอร์มใช้ประเภทที่เฉพาะเจาะจง และป้ายกำกับของออบเจ็กต์ที่เฉพาะเจาะจงมีการเปลี่ยนแปลงในนโยบายใดนโยบายหนึ่งเท่านั้น อีกนโยบายหนึ่งอาจมีนโยบายที่ได้รับหรือเสียสิทธิ์เข้าถึงที่เคยใช้ก่อนหน้านี้ ตัวอย่างเช่น สมมติว่า
นโยบายแพลตฟอร์มติดป้ายกำกับโหนด sysfs เป็น sysfs
/sys(/.*)? u:object_r:sysfs:s0
นโยบายผู้ให้บริการให้สิทธิ์เข้าถึง /sys/usb ที่มีป้ายกำกับว่า
sysfs ดังนี้
allow vendor_init sysfs:chr_file rw_file_perms;
หากมีการเปลี่ยนแปลงนโยบายแพลตฟอร์มให้ติดป้ายกำกับ /sys/usb เป็น
sysfs_usb นโยบายของผู้ให้บริการจะยังคงเหมือนเดิม แต่
vendor_init จะเสียสิทธิ์เข้าถึง /sys/usb เนื่องจากไม่มี
นโยบายสำหรับ sysfs_usb ประเภทใหม่
/sys/usb u:object_r:sysfs_usb:s0
Android จึงได้นำแนวคิดของแอตทริบิวต์ที่มีการกำหนดเวอร์ชันมาใช้เพื่อแก้ปัญหานี้ ในเวลาคอมไพล์ ระบบบิลด์จะแปลประเภทสาธารณะของแพลตฟอร์มที่ใช้ในนโยบายของผู้ให้บริการเป็นแอตทริบิวต์ที่มีการกำหนดเวอร์ชันเหล่านี้โดยอัตโนมัติ การแปลนี้ ทําได้โดยการแมปไฟล์ที่เชื่อมโยงแอตทริบิวต์ที่มีการควบคุมเวอร์ชันกับประเภทสาธารณะอย่างน้อย 1 ประเภทจากแพลตฟอร์ม
เช่น สมมติว่า /sys/usb มีป้ายกำกับเป็น sysfs
ในนโยบายแพลตฟอร์ม 202504 และนโยบายผู้ขาย 202504 ให้สิทธิ์ vendor_init เข้าถึง /sys/usb
ในกรณีนี้ ให้ทำดังนี้
-
นโยบายผู้ให้บริการเขียนกฎ
allow vendor_init sysfs:chr_file rw_file_perms;เนื่องจาก/sys/usbมีป้ายกำกับเป็นsysfsในนโยบายแพลตฟอร์ม 202504 เมื่อระบบบิลด์คอมไพล์ นโยบายของผู้ให้บริการ ระบบจะแปลกฎเป็นallow vendor_init_202504 sysfs_202504:chr_file rw_file_perms;โดยอัตโนมัติ แอตทริบิวต์vendor_init_202504และsysfs_202504สอดคล้องกับประเภทvendor_initและsysfsซึ่งเป็นประเภทที่แพลตฟอร์มกำหนด -
ระบบบิลด์จะสร้างไฟล์การจับคู่ข้อมูลประจำตัว
/system/etc/selinux/mapping/202504.cilเนื่องจากทั้งพาร์ติชันsystemและvendorใช้ เวอร์ชัน202504เดียวกัน ไฟล์การแมปจึงมีการจับคู่ข้อมูลประจำตัว จากtype_202504ไปยังtypeเช่นvendor_init_202504จับคู่กับvendor_initและsysfs_202504จับคู่กับsysfs(typeattributeset sysfs_202504 (sysfs)) (typeattributeset vendor_init_202504 (vendor_init)) ...
เมื่ออัปเกรดเวอร์ชันจาก 202504 เป็น 202604 ระบบจะสร้างไฟล์แมปใหม่สำหรับพาร์ติชัน 202504
vendor ภายใต้
system/sepolicy/private/compat/202504/202504.cil ซึ่งจะติดตั้งใน /system/etc/selinux/mapping/202504.cil สำหรับพาร์ติชัน 202604
หรือใหม่กว่า system ในตอนแรก ไฟล์การแมปนี้จะมี
การแมปข้อมูลประจำตัวตามที่อธิบายไว้ก่อนหน้านี้ หากมีการเพิ่มป้ายกำกับใหม่ sysfs_usb
สำหรับ /sys/usb ลงในนโยบายแพลตฟอร์ม 202604 ระบบจะอัปเดตไฟล์การแมป
เพื่อแมป sysfs_202504 กับ sysfs_usb ดังนี้
(typeattributeset sysfs_202504 (sysfs sysfs_usb)) (typeattributeset vendor_init_202504 (vendor_init)) ...
การอัปเดตนี้จะช่วยให้กฎนโยบายของผู้ให้บริการที่แปลงแล้ว allow
vendor_init_202504 sysfs_202504:chr_file rw_file_perms; มอบสิทธิ์เข้าถึงประเภท sysfs_usb ใหม่ให้แก่ vendor_init โดยอัตโนมัติ
หากต้องการรักษาความเข้ากันได้กับพาร์ติชัน vendor รุ่นเก่า เมื่อใดก็ตามที่มีการเพิ่มประเภทสาธารณะใหม่ จะต้องแมปประเภทดังกล่าวกับแอตทริบิวต์ที่มีการกำหนดเวอร์ชันอย่างน้อย 1 รายการในไฟล์การแมป system/sepolicy/private/compat/ver/ver.cil
หรือแสดงไว้ในส่วน system/sepolicy/private/compat/ver/ver.ignore.cil
เพื่อระบุว่าไม่มีประเภทที่ตรงกันในเวอร์ชันของผู้ให้บริการก่อนหน้า
การรวมนโยบายแพลตฟอร์ม นโยบายของผู้ให้บริการ และไฟล์การแมป ช่วยให้ระบบอัปเดตได้โดยไม่ต้องอัปเดตนโยบายของผู้ให้บริการ นอกจากนี้ การแปลงเป็นแอตทริบิวต์ที่มีการกำหนดเวอร์ชันจะเกิดขึ้นโดยอัตโนมัติ ดังนั้นนโยบายของผู้ให้บริการจึงไม่จำเป็นต้องดูแลการกำหนดเวอร์ชัน และยังคงใช้ประเภทสาธารณะตามเดิมได้
system_ext public and product public policy
ตั้งแต่ Android 11 เป็นต้นไป system_ext และพาร์ติชัน product
จะได้รับอนุญาตให้ส่งออกประเภทสาธารณะที่กำหนดไปยังพาร์ติชัน vendor
เช่นเดียวกับนโยบายสาธารณะของแพลตฟอร์ม นโยบายของผู้ให้บริการ
จะใช้ประเภทและกฎที่แปลเป็นแอตทริบิวต์ที่มีการควบคุมเวอร์ชันโดยอัตโนมัติ เช่น จาก type เป็น type_ver โดยที่ ver คือระดับ API ของผู้ให้บริการ
ของพาร์ติชัน vendor
เมื่อพาร์ติชัน system_ext และ product อิงตามแพลตฟอร์มเวอร์ชันเดียวกัน ver ระบบบิลด์จะสร้างไฟล์การแมปฐานไปยัง system_ext/etc/selinux/mapping/ver.cil
และ product/etc/selinux/mapping/ver.cil ซึ่งมี
การแมปข้อมูลประจำตัวจาก type ไปยัง type_ver
นโยบายของผู้ให้บริการสามารถเข้าถึง type ด้วยแอตทริบิวต์ที่มีการควบคุมเวอร์ชัน
type_ver
ในกรณีที่อัปเดตเฉพาะพาร์ติชัน system_ext และ product
เช่น ver เป็น ver+1 (หรือหลังจากนั้น) ในขณะที่พาร์ติชัน vendor ยังคงอยู่ที่ ver นโยบายของผู้ให้บริการ
อาจสูญเสียสิทธิ์เข้าถึงประเภทของพาร์ติชัน system_ext และ
product เพื่อป้องกันการหยุดทำงาน พาร์ติชัน
system_ext และ product ควรมี
ไฟล์การแมปจากประเภทที่เฉพาะเจาะจงไปยังแอตทริบิวต์ type_ver พาร์ทเนอร์แต่ละรายมีหน้าที่รับผิดชอบในการดูแลไฟล์การแมป
หากรองรับพาร์ติชัน ver vendor ที่มี
ver+1 (หรือใหม่กว่า) system_ext และพาร์ติชัน product
หากต้องการติดตั้งไฟล์การจับคู่กับพาร์ติชัน system_ext และ product
ผู้ติดตั้งใช้งานอุปกรณ์หรือผู้ให้บริการควรทำดังนี้
- คัดลอกไฟล์การแมปฐานที่สร้างขึ้นจากพาร์ติชัน ver
system_extและproductไปยังโครงสร้างซอร์สโค้ด - แก้ไขไฟล์การแมปตามต้องการ
-
ติดตั้ง
ไฟล์การแมปใน ver+1 (หรือใหม่กว่า)
system_extและ พาร์ติชันproduct
ตัวอย่างเช่น สมมติว่าพาร์ติชัน 202504 system_ext มีประเภทสาธารณะ 1 ประเภทชื่อ foo_type จากนั้น
system_ext/etc/selinux/mapping/202504.cil
ในพาร์ติชัน 202504 system_ext จะมีลักษณะดังนี้
(typeattributeset foo_type_202504 (foo_type)) (expandtypeattribute foo_type_202504 true) (typeattribute foo_type_202504)
หากมีการเพิ่ม bar_type ลงใน 202604 system_ext และหาก
bar_type ควรแมปกับ foo_type สำหรับพาร์ติชัน 202504
vendor คุณจะอัปเดต 202504.cil จาก
(typeattributeset foo_type_202504 (foo_type)) เป็น
(typeattributeset foo_type_202504 (foo_type bar_type))
แล้วติดตั้งลงในพาร์ติชัน 202604 system_ext ได้ พาร์ติชัน 202504
vendor จะยังคงเข้าถึง foo_type และ bar_type ของ 202604
system_ext ได้
การเปลี่ยนแปลงแอตทริบิวต์สำหรับ Android 9
อุปกรณ์ที่อัปเกรดเป็น Android 9 จะใช้แอตทริบิวต์ต่อไปนี้ได้ แต่อุปกรณ์ที่เปิดตัวด้วย Android 9 จะใช้ไม่ได้
แอตทริบิวต์ของผู้ละเมิด
Android 9 มีแอตทริบิวต์ที่เกี่ยวข้องกับโดเมนต่อไปนี้
data_between_core_and_vendor_violatorsแอตทริบิวต์สำหรับโดเมนทั้งหมดที่ละเมิดข้อกำหนดในการไม่แชร์ไฟล์ตาม เส้นทางระหว่างvendorกับcoredomainsกระบวนการของแพลตฟอร์มและ ผู้ให้บริการไม่ควรใช้ไฟล์ในดิสก์เพื่อสื่อสาร (ABI ไม่เสถียร) คำแนะนำ- รหัสผู้ให้บริการควรใช้
/data/vendor - ระบบไม่ควรใช้
/data/vendor
- รหัสผู้ให้บริการควรใช้
system_executes_vendor_violators. แอตทริบิวต์ สำหรับโดเมนระบบทั้งหมด (ยกเว้นinitและshell domains) ที่ละเมิดข้อกำหนดในการไม่เรียกใช้ไบนารีของผู้ให้บริการ การดำเนินการไบนารีของผู้ให้บริการ มี API ที่ไม่เสถียร แพลตฟอร์มไม่ควรเรียกใช้ไบนารีของผู้ให้บริการ โดยตรง คำแนะนำ- การขึ้นต่อกันของแพลตฟอร์มดังกล่าวกับไบนารีของผู้ให้บริการต้องอยู่เบื้องหลัง HIDL HAL
หรือ
coredomainsที่ต้องเข้าถึงไบนารีของผู้ให้บริการควร ย้ายไปที่พาร์ติชันvendorและหยุดเป็นcoredomain
- การขึ้นต่อกันของแพลตฟอร์มดังกล่าวกับไบนารีของผู้ให้บริการต้องอยู่เบื้องหลัง HIDL HAL
แอตทริบิวต์ที่ไม่น่าเชื่อถือ
แอปที่ไม่น่าเชื่อถือซึ่งโฮสต์โค้ดที่กำหนดเองไม่ควรมีสิทธิ์เข้าถึงบริการ HwBinder ยกเว้นบริการที่ถือว่าปลอดภัยเพียงพอสำหรับการเข้าถึงจากแอปดังกล่าว (ดูบริการที่ปลอดภัยด้านล่าง) สาเหตุหลัก 2 ประการที่ทำให้เกิดกรณีนี้ ได้แก่
- เซิร์ฟเวอร์ HwBinder ไม่ได้ทำการตรวจสอบสิทธิ์ไคลเอ็นต์เนื่องจากปัจจุบัน HIDL ไม่ได้แสดงข้อมูล UID ของผู้โทร แม้ว่า HIDL จะเปิดเผยข้อมูลดังกล่าว แต่บริการ HwBinder จำนวนมาก จะทำงานในระดับที่ต่ำกว่าแอป (เช่น HAL) หรือ ต้องไม่ใช้ข้อมูลประจำตัวของแอปเพื่อการให้สิทธิ์ ดังนั้น เพื่อความปลอดภัย สมมติฐานเริ่มต้น คือบริการ HwBinder ทุกบริการจะถือว่าไคลเอ็นต์ทั้งหมดได้รับอนุญาตให้ดำเนินการที่บริการนำเสนอ อย่างเท่าเทียมกัน
- เซิร์ฟเวอร์ HAL (ชุดย่อยของบริการ HwBinder) มีโค้ดที่มีอัตราอุบัติการณ์ของปัญหาด้านความปลอดภัยสูงกว่าคอมโพเนนต์
system/coreและมีสิทธิ์เข้าถึงเลเยอร์ที่ต่ำกว่าของสแต็ก (ลงไปจนถึงฮาร์ดแวร์) จึงเพิ่มโอกาสในการข้ามโมเดลความปลอดภัยของ Android
บริการที่ปลอดภัย
บริการที่ปลอดภัย ได้แก่
same_process_hwserviceบริการเหล่านี้ (ตามคำจำกัดความ) ทำงานใน กระบวนการของไคลเอ็นต์ จึงมีสิทธิ์เข้าถึงเหมือนกับโดเมนไคลเอ็นต์ที่ กระบวนการทำงานcoredomain_hwserviceบริการเหล่านี้ไม่มีความเสี่ยง ที่เกี่ยวข้องกับเหตุผล #2hal_configstore_ISurfaceFlingerConfigsบริการนี้ออกแบบมาเพื่อใช้กับโดเมนใดก็ได้โดยเฉพาะhal_graphics_allocator_hwserviceการดำเนินการเหล่านี้ยัง มีให้บริการโดยบริการsurfaceflingerBinder ซึ่งแอปได้รับอนุญาต ให้เข้าถึงhal_omx_hwserviceนี่คือบริการ Binder เวอร์ชัน HwBindermediacodecซึ่งแอปได้รับอนุญาตให้เข้าถึงhal_codec2_hwserviceนี่คือเวอร์ชันใหม่กว่าของhal_omx_hwservice
แอตทริบิวต์ที่ใช้ได้
hwservicesทั้งหมดที่ระบบไม่ถือว่าปลอดภัยจะมีแอตทริบิวต์
untrusted_app_visible_hwservice เซิร์ฟเวอร์ HAL ที่เกี่ยวข้องมีแอตทริบิวต์ untrusted_app_visible_halserver อุปกรณ์ที่เปิดตัว
พร้อม Android 9 ต้องไม่ใช้
untrusted แอตทริบิวต์
คำแนะนำ
- แอปที่ไม่น่าเชื่อถือควรสื่อสารกับบริการของระบบที่สื่อสารกับ
HAL ของ HIDL ของผู้ให้บริการแทน เช่น แอปสามารถพูดคุยกับ
binderservicedomainจากนั้นmediaserver(ซึ่งเป็นbinderservicedomain) จะพูดคุยกับhal_graphics_allocatorหรือ
- แอปที่ต้องการเข้าถึง
vendorHAL โดยตรงควรมีโดเมน sepolicy ที่กำหนดโดยผู้ให้บริการของตนเอง
การทดสอบแอตทริบิวต์ไฟล์
Android 9 มีการทดสอบเวลาบิลด์ที่ช่วยให้มั่นใจว่าไฟล์ทั้งหมดในตำแหน่งที่เฉพาะเจาะจง
มีแอตทริบิวต์ที่เหมาะสม (เช่น ไฟล์ทั้งหมดใน
sysfs มีแอตทริบิวต์ sysfs_type ที่จำเป็น)
การติดป้ายกำกับบริบท SELinux
เพื่อรองรับความแตกต่างระหว่าง sepolicy ของแพลตฟอร์มและของผู้ให้บริการ ระบบจะสร้างไฟล์บริบท SELinux ในลักษณะที่แตกต่างกันเพื่อให้แยกกัน
บริบทของไฟล์
Android 8.0 ได้นำการเปลี่ยนแปลงต่อไปนี้มาใช้กับ file_contexts
- เพื่อหลีกเลี่ยงค่าใช้จ่ายในการคอมไพล์เพิ่มเติมในอุปกรณ์ระหว่างการบูต
file_contextsจะไม่มีอยู่ในรูปแบบไบนารี แต่จะเป็นไฟล์ข้อความนิพจน์ทั่วไปที่อ่านได้ เช่น{property, service}_contexts(เช่นเดียวกับในเวอร์ชันก่อน 7.0) file_contextsจะแยกออกเป็น 2 ไฟล์ ดังนี้plat_file_contexts- แพลตฟอร์ม Android
file_contextที่ไม่มีป้ายกำกับเฉพาะอุปกรณ์ ยกเว้นการติดป้ายกำกับส่วนของพาร์ติชัน/vendorที่ต้องติดป้ายกำกับอย่างถูกต้องเพื่อให้ไฟล์ sepolicy ทำงานได้อย่างเหมาะสม - ต้องอยู่ในพาร์ติชัน
systemที่/system/etc/selinux/plat_file_contextsในอุปกรณ์และ โหลดโดยinitเมื่อเริ่มต้นพร้อมกับfile_contextของผู้ให้บริการ
- แพลตฟอร์ม Android
vendor_file_contextsfile_contextเฉพาะอุปกรณ์ที่สร้างขึ้นโดยการรวมfile_contextsที่พบในไดเรกทอรีที่ระบุโดยBOARD_SEPOLICY_DIRSในBoardconfig.mkของอุปกรณ์- ต้องติดตั้งที่
/vendor/etc/selinux/vendor_file_contextsในพาร์ติชันvendorและโหลดโดยinitที่ จุดเริ่มต้นพร้อมกับแพลตฟอร์มfile_context
บริบทของพร็อพเพอร์ตี้
ใน Android 8.0 property_contexts จะแยกออกเป็น 2 ไฟล์ดังนี้
plat_property_contexts- แพลตฟอร์ม Android
property_contextที่ไม่มีป้ายกำกับเฉพาะอุปกรณ์ - ต้องอยู่ในพาร์ติชัน
systemที่/system/etc/selinux/plat_property_contextsและโหลดโดยinitที่จุดเริ่มต้นพร้อมกับproperty_contextsของผู้ให้บริการ
- แพลตฟอร์ม Android
vendor_property_contextsproperty_contextเฉพาะอุปกรณ์ที่สร้างขึ้นโดยการรวมproperty_contextsที่พบในไดเรกทอรีที่ระบุโดยBOARD_SEPOLICY_DIRSในBoardconfig.mkของอุปกรณ์- ต้องอยู่ในพาร์ติชัน
vendorที่/vendor/etc/selinux/vendor_property_contextsและ โหลดโดยinitเมื่อเริ่มต้นพร้อมกับแพลตฟอร์มproperty_context
บริบทของบริการ
ใน Android 8.0 service_contexts จะแยกออกเป็นไฟล์ต่อไปนี้
plat_service_contextsservice_contextสำหรับservicemanagerโดยเฉพาะแพลตฟอร์ม Androidservice_contextไม่มีป้ายกำกับเฉพาะอุปกรณ์- ต้องอยู่ในพาร์ติชัน
systemที่/system/etc/selinux/plat_service_contextsและโหลดโดยservicemanagerที่จุดเริ่มต้นพร้อมกับservice_contextsของผู้ให้บริการ
vendor_service_contextsservice_contextเฉพาะอุปกรณ์ที่สร้างขึ้นโดยการรวมservice_contextsที่พบในไดเรกทอรีที่ระบุโดยBOARD_SEPOLICY_DIRSในBoardconfig.mkของอุปกรณ์- ต้องอยู่ในพาร์ติชัน
vendorที่/vendor/etc/selinux/vendor_service_contextsและโหลดโดยservicemanagerเมื่อเริ่มต้นพร้อมกับแพลตฟอร์มservice_contexts - แม้ว่า
servicemanagerจะค้นหาไฟล์นี้ในเวลาที่เปิดเครื่อง แต่สำหรับอุปกรณ์TREBLEที่เป็นไปตามข้อกำหนดอย่างสมบูรณ์vendor_service_contextsจะต้องไม่มีอยู่ เนื่องจาก การโต้ตอบทั้งหมดระหว่างvendorกับsystemต้องผ่านกระบวนการhwservicemanager/hwbinder
plat_hwservice_contexts- แพลตฟอร์ม Android
hwservice_contextสำหรับhwservicemanagerที่ไม่มีป้ายกำกับเฉพาะอุปกรณ์ - ต้องอยู่ในพาร์ติชัน
systemที่/system/etc/selinux/plat_hwservice_contextsและโหลดโดยhwservicemanagerที่จุดเริ่มต้นพร้อมกับvendor_hwservice_contexts
- แพลตฟอร์ม Android
vendor_hwservice_contextshwservice_contextเฉพาะอุปกรณ์ที่สร้างขึ้นโดยการรวมhwservice_contextsที่พบในไดเรกทอรีที่ระบุโดยBOARD_SEPOLICY_DIRSในBoardconfig.mkของอุปกรณ์- ต้องอยู่ในพาร์ติชัน
vendorที่/vendor/etc/selinux/vendor_hwservice_contextsและต้อง โหลดโดยhwservicemanagerที่จุดเริ่มต้นพร้อมกับplat_service_contexts
vndservice_contextsservice_contextเฉพาะอุปกรณ์service_contextสำหรับvndservicemanagerที่สร้างขึ้นโดยการรวมvndservice_contextsที่อยู่ในไดเรกทอรีซึ่งระบุโดยBOARD_SEPOLICY_DIRSในBoardconfig.mkของอุปกรณ์- ไฟล์นี้ต้องอยู่ในพาร์ติชัน
vendorที่/vendor/etc/selinux/vndservice_contextsและโหลดโดยvndservicemanagerเมื่อเริ่มต้น
บริบท Seapp
ใน Android 8.0 seapp_contexts จะแยกออกเป็น 2 ไฟล์ดังนี้
plat_seapp_contexts- แพลตฟอร์ม Android
seapp_contextที่ไม่มีการเปลี่ยนแปลง เฉพาะอุปกรณ์ - ต้องอยู่ในพาร์ติชัน
systemที่/system/etc/selinux/plat_seapp_contexts.
- แพลตฟอร์ม Android
vendor_seapp_contexts- ส่วนขยายเฉพาะอุปกรณ์สำหรับแพลตฟอร์ม
seapp_contextที่สร้างขึ้น โดยการรวมseapp_contextsที่พบในไดเรกทอรี ซึ่งBOARD_SEPOLICY_DIRSชี้ไปยังใน ไฟล์Boardconfig.mkของอุปกรณ์ - ต้องอยู่ในพาร์ติชัน
vendorที่/vendor/etc/selinux/vendor_seapp_contexts
- ส่วนขยายเฉพาะอุปกรณ์สำหรับแพลตฟอร์ม
สิทธิ์ MAC
ใน Android 8.0 mac_permissions.xml จะแยกออกเป็น 2 ไฟล์ดังนี้
- แพลตฟอร์ม
mac_permissions.xml- แพลตฟอร์ม Android
mac_permissions.xmlที่ไม่มี การเปลี่ยนแปลงเฉพาะอุปกรณ์ - ต้องอยู่ในพาร์ติชัน
systemที่/system/etc/selinux/.
- แพลตฟอร์ม Android
- นอกแพลตฟอร์ม
mac_permissions.xml- ส่วนขยายเฉพาะอุปกรณ์ไปยังแพลตฟอร์ม
mac_permissions.xmlสร้างจากmac_permissions.xmlพบในไดเรกทอรีที่ระบุโดยBOARD_SEPOLICY_DIRSในBoardconfig.mkของอุปกรณ์ - ต้องอยู่ในพาร์ติชัน
vendorที่/vendor/etc/selinux/.
- ส่วนขยายเฉพาะอุปกรณ์ไปยังแพลตฟอร์ม
การเปลี่ยนแปลงหน่วยความจำที่ใช้ร่วมกันสำหรับ Android 17
ตั้งแต่ Android 17 เป็นต้นไป อุปกรณ์ที่เปิดตัวโดยมีพร็อพเพอร์ตี้ต่อไปนี้ต้องเปิดใช้ความสามารถของนโยบาย memfd_class และอัปเดตนโยบายที่เกี่ยวข้องกับหน่วยความจำที่ใช้ร่วมกันเพื่อรองรับออบเจ็กต์คลาส memfd_file
- ระดับ API ผู้ให้บริการ 202604 ขึ้นไปเพื่อให้ผู้ให้บริการและ OEM มีโอกาสปรับปรุงนโยบายผู้ให้บริการเพื่อรองรับ
memfdนอกจากนี้ยังช่วยให้อุปกรณ์ที่มีอยู่สามารถอัปเกรดเป็น Android เวอร์ชันที่สูงขึ้นได้โดยไม่ต้องอัปเดตพาร์ติชันของผู้ให้บริการ android16-6.12ขึ้นไป เนื่องจากเคอร์เนลเหล่านั้นรองรับฟีเจอร์memfd_classซึ่งจำเป็นสำหรับการใช้นโยบายแบบละเอียดสำหรับmemfd
เปิดใช้ความสามารถของนโยบาย memfd_class
ก่อนหน้านี้ SELinux จะติดป้ายกำกับ memfd เป็นไฟล์ที่มีประเภทเดียวกับระบบไฟล์สำรอง ซึ่งก็คือ tmpfs ซึ่งทำให้ไม่สามารถแยกความแตกต่างระหว่าง memfd กับไฟล์อื่นๆ ในการติดตั้ง tmpfs จากมุมมองด้านนโยบาย ตอนนี้ SELinux จะติดป้ายกำกับ memfd ด้วยบริบทความปลอดภัยของกระบวนการจัดสรร และจะถือว่า memfds เป็นออบเจ็กต์คลาส memfd_file ฟังก์ชันนี้ได้รับการปกป้องโดยความสามารถของนโยบาย memfd_class เพื่อรักษาความเข้ากันได้แบบย้อนหลังกับสภาพแวดล้อมของพื้นที่ผู้ใช้รุ่นเก่า
หากต้องการเปิดใช้ความสามารถด้านนโยบาย memfd_class ให้สร้างไฟล์ policy_capabilities ใน BOARD_VENDOR_SEPOLICY_DIRS ไฟล์ควรมีรายการต่อไปนี้
# $BOARD_VENDOR_SEPOLICY_DIRS/*/policy_capabilities
policycap memfd_class;จากนั้นสร้างอิมเมจใหม่และแฟลชไปยังอุปกรณ์เพื่อยืนยันว่าได้เปิดใช้ความสามารถแล้ว
ตรวจสอบว่าได้เปิดใช้ความสามารถของนโยบาย memfd_class แล้ว
ใช้คำสั่งต่อไปนี้เพื่อตรวจสอบสถานะของความสามารถด้านนโยบาย memfd_class
adb shell 'cat /sys/fs/selinux/policy_capabilities/memfd_class'
หากผลลัพธ์เป็น 1 แสดงว่าเปิดใช้ความสามารถของนโยบาย memfd_class แล้ว ไม่เช่นนั้น ระบบจะไม่เปิดใช้
เปลี่ยนนโยบายที่มีอยู่เป็น memfd
กระบวนการบางอย่างใช้มาโคร tmpfs_domain() ในนโยบายเพื่อเข้าถึงและตั้งชื่อพื้นที่ memfds เช่น
# foo.te
tmpfs_domain(foo)ซึ่งจะช่วยในเรื่องต่างๆ ดังนี้
# foo.te type_transition foo tmpfs:file foo_tmpfs; allow foo foo_tmpfs:file { read write getattr map };
และอนุญาตให้กระบวนการ bar เข้าถึง foo ของกระบวนการ memfds ดังนี้
# bar.te allow bar foo_tmpfs:file { read write getattr map };
เมื่อเปิดใช้ความสามารถของนโยบาย memfd_class แล้ว คุณก็ไม่จำเป็นต้องใช้มาโคร tmpfs_domain() อีกต่อไป เนื่องจากเราได้อัปเดตนโยบายแพลตฟอร์มเพื่อให้กระบวนการใดๆ สามารถสร้างและใช้ memfds ของตัวเองได้ ดังที่เห็นที่นี่
# system/sepolicy/private/domain.te allow domain self:memfd_file { create read write getattr map };
และกระบวนการ bar จะเข้าถึง memfds ที่สร้างโดยกระบวนการ foo ได้ดังนี้
# bar.te allow bar foo:memfd_file { read write getattr map };
เราได้ปรับปรุงนโยบายของแพลตฟอร์มเพื่อรองรับการใช้งาน memfd ที่มีอยู่ อย่างไรก็ตาม คุณต้องอัปเดตนโยบายเฉพาะผู้ให้บริการและอุปกรณ์ที่ใช้ป้ายกำกับ tmpfs ให้ใช้ memfd_file หากมีการแชร์นโยบายระหว่าง SoC หรืออุปกรณ์ที่ไม่มีระดับ API 202604 ขึ้นไปของผู้ให้บริการ เราขอแนะนำให้เก็บรักษานโยบาย tmpfs เดิมไว้ควบคู่กับนโยบาย memfd_file ใหม่เพื่อความเข้ากันได้
ระบุการปฏิเสธ AVC ที่เกี่ยวข้องกับ memfd
คุณเรียกข้อมูลการปฏิเสธที่เกี่ยวข้องกับ Memfd ได้โดยใช้คำสั่งต่อไปนี้
adb shell logcat -d -b events | grep memfd
การปฏิเสธ avc ที่มี tmpfs เป็นเป้าหมาย
ตัวอย่างต่อไปนี้แสดงการปฏิเสธ avc ที่กระบวนการซึ่งพยายามเขียนไปยัง memfd ที่ไม่มีสิทธิ์เขียนพบ
audit(0.0:539): avc: denied { write } for comm="binder:665_1" name="memfd:MessageQueue"
dev="tmpfs" ino=8324 scontext=u:r:mediacodec:s0 tcontext=u:object_r:tmpfs:s0 tclass=file
permissive=0
เมื่อเปิดใช้ความสามารถของนโยบาย memfd_class บริบทเป้าหมายของ memfd คือบริบทความปลอดภัยของกระบวนการจัดสรร ไม่ใช่ tmpfs และคลาสเป้าหมายคือ memfd_file ไม่ใช่ file ดังนั้น หากคุณพบการปฏิเสธ avc ที่เกี่ยวข้องกับ memfd ซึ่ง memfd ที่เป็นปัญหาติดป้ายกำกับเป็นไฟล์ tmpfs แสดงว่าไม่ได้เปิดใช้ความสามารถของนโยบาย memfd_class
การปฏิเสธ AVC ที่มี memfd_file เป็นคลาสเป้าหมาย
ตัวอย่างต่อไปนี้แสดงการปฏิเสธ avc ที่พบโดยกระบวนการที่พยายามเขียนไปยัง memfd ที่ไม่มีสิทธิ์เขียน และเปิดใช้ความสามารถด้านนโยบาย memfd_class รวมถึงบรรทัดเพิ่มเติมที่ logd ส่งออกมาหลังจากการปฏิเสธที่มีการประทับเวลาเดียวกัน
audit(0.0:86): avc: denied { read } for
path=2F6D656D66643A4D6564696142756666657247726F7570202864656C6574656429 ino=512 dev=""
scontext=u:r:mediaserver:s0 tcontext=u:object_r:mediaextractor:s0 tclass=memfd_file
auditd : Decoded path for audit(0.0:86): /memfd:MediaBufferGroup (deleted)
การประทับเวลาที่ตรงกันแสดงว่า Decoded path for … log เกี่ยวข้องกับการปฏิเสธ avc ที่มีการประทับเวลา 0.0.86 บันทึกนี้จะถอดรหัสสตริงเลขฐานสิบหกจากค่าเส้นทางใน avc denial และระบุชื่อmemfdรีเจียนหน่วยความจำ ซึ่งอาจมีประโยชน์ในการทำความเข้าใจว่ามีการแชร์บัฟเฟอร์ใด บริบทต้นทางและบริบทเป้าหมายมีประโยชน์ในการทำความเข้าใจว่ากระบวนการใดบ้างที่ต้องแชร์หน่วยความจำ จากตัวอย่างก่อนหน้า เห็นได้ชัดว่าmediaserverต้องเข้าถึงmediaextractorของmemfdsได้ ดังนั้น นโยบายที่เหมาะสมคือ
# mediaserver.te allow mediaserver mediaextractor:memfd_file { getattr read write map };
การอัปเดตโดเมนความปลอดภัยใน Android 17
ASharedMemory_create() API ใน Android 17 ใช้ตรรกะแบบมีเงื่อนไขเพื่อเลือกระหว่างไดรเวอร์ ashmem เดิมกับเฟรมเวิร์ก memfd สำหรับการจัดสรรหน่วยความจำที่ใช้ร่วมกัน
สำหรับอุปกรณ์ที่ตรงตามmemfdข้อกำหนด (API ระดับ 202604 ขึ้นไปของผู้ให้บริการและเคอร์เนล android16-6.12 ขึ้นไป) API จะประเมิน targetSdkVersion ของแอปที่เรียกใช้ หาก SDK เวอร์ชันเป้าหมายเป็น 37 ขึ้นไป ระบบจะจัดสรร memfd ซึ่งช่วยให้นักพัฒนาแอปแก้ไขปัญหาที่พบขณะอัปเกรดเวอร์ชัน SDK เป้าหมายได้
หากอุปกรณ์ไม่เป็นไปตามข้อกำหนดเบื้องต้นของ memfd's ASharedMemory จะกลับไปใช้ ashmem ซึ่งจะช่วยรักษาความเข้ากันได้สำหรับอุปกรณ์ที่อัปเกรดแล้วซึ่งมีพาร์ติชันหรือเคอร์เนลของผู้ให้บริการรุ่นเก่า
เพื่อบังคับใช้การเปลี่ยนผ่านนี้ นโยบาย SELinux ของแพลตฟอร์มจะบล็อกแอปที่กำหนดเป้าหมายเป็น SDK เวอร์ชัน 37 ขึ้นไปในโดเมนความปลอดภัย platform_app, priv_app และ untrusted_app ไม่ให้เปิด /dev/ashmem และเรียกใช้คำสั่ง ioctl ของ ashmem ใน memfd ซึ่งทำได้โดยการแยกโดเมนแอปเหล่านั้นตามเวอร์ชัน SDK เป้าหมาย ซึ่งจะเปิดตัวโดเมนความปลอดภัย platform_app_36, priv_app_36 และ untrusted_app_34 ซึ่งจะคงสิทธิ์เปิด ashmem และความสามารถในการเรียกใช้คำสั่ง ioctl ของ ashmem ใน memfds พร้อมกับโดเมนแอปอื่นๆ
ใน Android รุ่นต่อๆ ไป ระบบจะลดชุดแอปที่ยังคงมีสิทธิ์เปิดอุปกรณ์ ashmem และเรียกใช้คำสั่ง ioctl ของ ashmem ใน memfds ให้เหลือเพียง platform_app_36, priv_app_36 และ untrusted_app_34 รวมถึงโดเมนแอปที่ไม่น่าเชื่อถือสำหรับ SDK เวอร์ชันเก่า
นโยบาย SELinux ของผู้ให้บริการหรือ OEM ที่กำหนดเองสำหรับแอปที่ตรึง SDK เวอร์ชันเป้าหมายจะต้องได้รับการอัปเดตให้สอดคล้องกับการเปลี่ยนแปลงโดเมนเหล่านี้ตามที่ระบุไว้ในส่วนต่อไปนี้
การอัปเดตโดเมน SELinux ของ platform_app
โดเมน platform_app จะแยกตาม targetSdkVersion ของแอป แอปแพลตฟอร์มที่กำหนดเป้าหมายเป็น SDK เวอร์ชัน 37 ขึ้นไปจะได้รับโดเมน platform_app ส่วนแอปที่กำหนดเป้าหมายเป็น SDK เวอร์ชัน 36 ลงไปจะใช้ platform_app_36 โดเมน platform_app_36 ยังคงเปิด /dev/ashmem ได้เพื่อให้เข้ากันได้แบบย้อนหลัง หากต้องการลดความซับซ้อนของการจัดการนโยบายในทั้ง 2 โดเมน ให้ใช้แอตทริบิวต์ platform_app_all
พิจารณากรณีที่แอปแพลตฟอร์ม sample-plat-app ต้องอ่านและเขียนจากและไปยัง /dev/foo_device นโยบาย SELinux ของผู้ให้บริการที่มีอยู่อาจมีลักษณะดังนี้
# This will only allow sample-plat-app to access the device if it # is placed in the platform_app domain (i.e. target SDK version is 37 or higher). allow platform_app foo_device:chr_file rw_file_perms;
อย่างไรก็ตาม หาก sample-plat-app ปักหมุดที่ SDK เวอร์ชันเป้าหมาย 36 ระบบจะวางไว้ในโดเมน platform_app_36 และนโยบาย SELinux จากก่อนหน้านี้จะไม่มีผล และจะสังเกตเห็นการปฏิเสธ AVC ต่อไปนี้
auditd : type=1400 audit(0.0:11): avc: denied { read write } for comm="sample-plat-app" path="/dev/foo_device" dev="tmpfs" ino=1609 scontext=u:r:platform_app_36:s0:c512,c768 tcontext=u:object_r:foo_device:s0 tclass=chr_file permissive=0
หากต้องการแก้ไขปัญหานี้ คุณสามารถอัปเดตนโยบายได้ดังนี้ เนื่องจากแอปควรมีสิทธิ์เข้าถึงโหนดอุปกรณ์เสมอ
# This allows sample-plat-app to access the device independent of # target SDK version. allow platform_app_all foo_device:chr_file rw_file_perms;
platform_app_all อาจใช้ไม่ได้ในบางสถานการณ์ เช่น หากใช้มาโคร hal_client_domain() กับ platform_app_all นโยบายจะคอมไพล์ไม่สำเร็จ เนื่องจาก platform_app_all เป็นแอตทริบิวต์ และ hal_client_domain() จะพยายามแนบแอตทริบิวต์อื่นกับแอตทริบิวต์นี้ ซึ่งทำไม่ได้
# platform_app.te
hal_client_domain(platform_app, hal_foo)
ในสถานการณ์ดังกล่าว คุณต้องใช้ประเภท platform_app_36 โดยตรง เพื่อให้นโยบายมีเนื้อหาต่อไปนี้
# platform_app.te hal_client_domain(platform_app, hal_foo) # platform_app_36.te hal_client_domain(platform_app_36, hal_foo)
การอัปเดตโดเมน SELinux ของแอปที่มีสิทธิ์
โดเมน priv_app จะแยกตาม targetSdkVersion ของแอป ระบบจะกำหนดโดเมน priv_app ให้กับแอปที่มีสิทธิ์ที่กำหนดเป้าหมายเป็น SDK เวอร์ชัน 37 ขึ้นไป ส่วนแอปที่กำหนดเป้าหมายเป็น SDK เวอร์ชัน 36 ลงมาจะใช้ priv_app_36 โดเมน priv_app_36 ยังคงเปิด /dev/ashmem ได้เพื่อให้เข้ากันได้แบบย้อนหลัง หากต้องการลดความซับซ้อนของการจัดการนโยบายในทั้ง 2 โดเมน ให้ใช้แอตทริบิวต์ priv_app_all
พิจารณากรณีที่แอปแพลตฟอร์ม sample-priv-app ต้องอ่านและเขียนจากและไปยัง /dev/foo_device นโยบาย SELinux ของผู้ให้บริการที่มีอยู่อาจมีลักษณะดังนี้
# This will only allow sample-priv-app to access the device if it # is placed in the priv_app domain (i.e. target SDK version is 37 or higher). allow priv_app foo_device:chr_file rw_file_perms;
อย่างไรก็ตาม หาก sample-priv-app ปักหมุดที่ SDK เวอร์ชันเป้าหมาย 36 ระบบจะวางไว้ในโดเมน priv_app_36 และนโยบาย SELinux จากก่อนหน้านี้จะไม่มีผล และจะสังเกตเห็นการปฏิเสธ AVC ต่อไปนี้
auditd : type=1400 audit(0.0:11): avc: denied { read write } for comm="sample-priv-app" path="/dev/foo_device" dev="tmpfs" ino=1609 scontext=u:r:priv_app_36:s0:c512,c768 tcontext=u:object_r:foo_device:s0 tclass=chr_file permissive=0
หากต้องการแก้ไขปัญหานี้ คุณสามารถอัปเดตนโยบายได้ดังนี้ เนื่องจากแอปควรมีสิทธิ์เข้าถึงโหนดอุปกรณ์เสมอ
# This allows sample-priv-app to access the device independent of # target SDK version. allow priv_app_all foo_device:chr_file rw_file_perms;
priv_app_all อาจใช้ไม่ได้ในบางสถานการณ์ เช่น หากใช้มาโคร hal_client_domain() กับ priv_app_all นโยบายจะคอมไพล์ไม่สำเร็จ เนื่องจาก priv_app_all เป็นแอตทริบิวต์ และ hal_client_domain() จะพยายามแนบแอตทริบิวต์อื่นกับแอตทริบิวต์นี้ ซึ่งทำไม่ได้
# priv_app.te
hal_client_domain(priv_app, hal_foo)
ในกรณีดังกล่าว คุณจะต้องใช้ประเภท priv_app_36 โดยตรง ไฟล์นโยบายจึงจะมีลักษณะดังนี้
# priv_app.te hal_client_domain(priv_app, hal_foo) # priv_app_36.te hal_client_domain(priv_app_36, hal_foo)
การอัปเดตโดเมน SELinux ของ untrusted_app
โดเมน untrusted_app จะแยกตาม targetSdkVersion ของแอป แอปที่ไม่น่าเชื่อถือซึ่งกำหนดเป้าหมายเป็น SDK เวอร์ชัน 37 ขึ้นไปจะได้รับโดเมน untrusted_app ส่วนแอปที่กำหนดเป้าหมายเป็น SDK เวอร์ชัน 34-36 จะได้รับโดเมน untrusted_app_34 ใหม่ โดเมน untrusted_app_34 รวมถึงโดเมน untrusted_app_X ซึ่ง `X` เป็น SDK เวอร์ชันเป้าหมายที่เก่ากว่า จะยังคงเปิด `/dev/ashmem` ได้เพื่อความเข้ากันได้แบบย้อนหลัง