Android ขอแนะนำให้ OEM ทดสอบการใช้งาน SELinux อย่างละเอียด เมื่อผู้ผลิตใช้ SELinux แล้ว ผู้ผลิตควรใช้นโยบายใหม่กับกลุ่มอุปกรณ์ทดสอบก่อน
หลังจากใช้นโยบายใหม่แล้ว ให้ตรวจสอบว่า SELinux ทำงานในโหมดที่ถูกต้องในอุปกรณ์โดยใช้คำสั่ง getenforce
ซึ่งจะพิมพ์โหมด SELinux ทั่วโลก ไม่ว่าจะเป็น Enforcing หรือ Permissive หากต้องการ
กำหนดโหมด SELinux สำหรับแต่ละโดเมน คุณต้องตรวจสอบไฟล์ที่เกี่ยวข้อง
หรือเรียกใช้ sepolicy-analyze
เวอร์ชันล่าสุดด้วยแฟล็กที่เหมาะสม (-p
) ซึ่งอยู่ใน
/platform/system/sepolicy/tools/
การปฏิเสธการอ่าน
ตรวจสอบข้อผิดพลาดซึ่งจะกำหนดเส้นทางเป็นบันทึกเหตุการณ์ไปยัง dmesg
และ logcat
และดูได้ในอุปกรณ์ ผู้ผลิต
ควรตรวจสอบเอาต์พุต SELinux เพื่อdmesg
ในอุปกรณ์เหล่านี้ และ
ปรับแต่งการตั้งค่าก่อนที่จะเผยแพร่ต่อสาธารณะในโหมดที่อนุญาต และเปลี่ยนไปใช้
โหมดบังคับใช้ในที่สุด ข้อความบันทึกของ SELinux มี avc:
และอาจ
ค้นหาได้ง่ายด้วย grep
คุณสามารถบันทึกบันทึกการปฏิเสธที่กำลังดำเนินการได้โดยเรียกใช้ cat /proc/kmsg
หรือบันทึกบันทึกการปฏิเสธจากการบูตครั้งก่อนได้โดยเรียกใช้ cat /sys/fs/pstore/console-ramoops
ข้อความแสดงข้อผิดพลาดของ SELinux จะถูกจำกัดอัตราหลังจากบูตเสร็จสมบูรณ์เพื่อหลีกเลี่ยงการท่วมท้น
ในบันทึก หากต้องการให้แน่ใจว่าคุณเห็นข้อความที่เกี่ยวข้องทั้งหมด คุณสามารถปิดใช้ฟีเจอร์นี้ได้
โดยเรียกใช้ adb shell auditctl -r 0
เอาต์พุตนี้ช่วยให้ผู้ผลิตระบุได้ทันทีเมื่อผู้ใช้ระบบหรือ คอมโพเนนต์ละเมิดนโยบาย SELinux จากนั้นผู้ผลิตจะซ่อมแซม ลักษณะการทำงานที่ไม่ดีนี้ได้ ไม่ว่าจะด้วยการเปลี่ยนแปลงซอฟต์แวร์ นโยบาย SELinux หรือทั้ง 2 อย่าง
โดยเฉพาะอย่างยิ่ง ข้อความบันทึกเหล่านี้จะระบุว่ากระบวนการใดจะล้มเหลวใน โหมดบังคับใช้และเหตุใด มีตัวอย่างดังต่อไปนี้
avc: denied { connectto } for pid=2671 comm="ping" path="/dev/socket/dnsproxyd" scontext=u:r:shell:s0 tcontext=u:r:netd:s0 tclass=unix_stream_socket
ตีความเอาต์พุตนี้ดังนี้
-
{ connectto }
ด้านบนแสดงถึงการดำเนินการที่กำลังดำเนินการ เมื่อรวมกับtclass
ที่ท้าย (unix_stream_socket
) จะบอกให้คุณทราบโดยประมาณว่ามีการดำเนินการใด กับสิ่งใด ในกรณีนี้ มีบางอย่างพยายามเชื่อมต่อกับซ็อกเก็ตสตรีม Unix -
scontext (u:r:shell:s0)
จะบอกให้คุณทราบว่าบริบทใดที่เริ่มการดำเนินการ ใน กรณีนี้ นี่คือสิ่งที่ทำงานเป็นเชลล์ -
tcontext (u:r:netd:s0)
จะบอกบริบทของเป้าหมายการดำเนินการ ในกรณีนี้คือ unix_stream_socket ที่เป็นของnetd
-
comm="ping"
ที่ด้านบนจะให้คำใบ้เพิ่มเติมเกี่ยวกับสิ่งที่กำลัง ทำงานอยู่ ณ เวลาที่ระบบปฏิเสธ ในกรณีนี้ นี่เป็นคำใบ้ที่ดี
อีกตัวอย่างหนึ่ง
adb shell su root dmesg | grep 'avc: '
เอาต์พุต:
<5> type=1400 audit: avc: denied { read write } for pid=177 comm="rmt_storage" name="mem" dev="tmpfs" ino=6004 scontext=u:r:rmt:s0 tcontext=u:object_r:kmem_device:s0 tclass=chr_file
องค์ประกอบสำคัญจากการปฏิเสธนี้มีดังนี้
- การดำเนินการ - ระบบจะไฮไลต์การดำเนินการที่พยายามในวงเล็บ
read write
หรือsetenforce
- ผู้ดำเนินการ - รายการ
scontext
(บริบทของแหล่งที่มา) แสดง ผู้ดำเนินการ ซึ่งในกรณีนี้คือ Daemonrmt_storage
- ออบเจ็กต์ - รายการ
tcontext
(บริบทเป้าหมาย) แสดง ออบเจ็กต์ที่ดำเนินการ ในกรณีนี้คือ kmem - ผลลัพธ์ - รายการ
tclass
(คลาสเป้าหมาย) ระบุประเภท ของออบเจ็กต์ที่ดำเนินการ ในกรณีนี้คือchr_file
(อุปกรณ์อักขระ)
ทิ้งสแต็กผู้ใช้และเคอร์เนล
ในบางกรณี ข้อมูลที่อยู่ในบันทึกเหตุการณ์ไม่เพียงพอที่จะระบุ แหล่งที่มาของการปฏิเสธ การรวบรวมห่วงโซ่การเรียก รวมถึงเคอร์เนลและ พื้นที่ผู้ใช้ มักมีประโยชน์ในการทำความเข้าใจสาเหตุที่เกิดการปฏิเสธได้ดียิ่งขึ้น
เคอร์เนลล่าสุดกำหนด Tracepoint ที่ชื่อ avc:selinux_audited
ใช้ Android
simpleperf
เพื่อเปิดใช้ Tracepoint นี้และบันทึก Callchain
การกำหนดค่าที่รองรับ
- รองรับเคอร์เนล Linux >= 5.10 โดยเฉพาะสาขา Android Common Kernel
mainline
และ
android12-5.10
นอกจากนี้ ยังรองรับกิ่ง android12-5.4
ด้วย คุณสามารถใช้
simpleperf
เพื่อตรวจสอบว่ามีการกำหนดจุดติดตามในอุปกรณ์หรือไม่adb root && adb shell simpleperf list | grep avc:selinux_audited
สำหรับเคอร์เนลเวอร์ชันอื่นๆ คุณอาจเลือกคอมมิต dd81662 และ 30969bc - คุณควรทำซ้ำเหตุการณ์ที่คุณกำลังแก้ไขข้อบกพร่องได้ เหตุการณ์เวลาบูตไม่รองรับการใช้ simpleperf แต่คุณอาจยังคงรีสตาร์ทบริการเพื่อทริกเกอร์เหตุการณ์ได้
บันทึกลำดับการเรียกใช้
ขั้นตอนแรกคือการบันทึกเหตุการณ์โดยใช้ simpleperf record
adb shell -t "cd /data/local/tmp && su root simpleperf record -a -g -e avc:selinux_audited"
จากนั้นควรทริกเกอร์เหตุการณ์ที่ทำให้เกิดการปฏิเสธ หลังจากนั้น ให้หยุดการบันทึก ในตัวอย่างนี้ การใช้ Ctrl-c
ควรจะบันทึกตัวอย่างได้
^Csimpleperf I cmd_record.cpp:751] Samples recorded: 1. Samples lost: 0.
สุดท้ายนี้ คุณสามารถใช้ simpleperf report
เพื่อตรวจสอบ Stacktrace ที่บันทึกไว้ได้
ตัวอย่างเช่น
adb shell -t "cd /data/local/tmp && su root simpleperf report -g --full-callgraph" [...] Children Self Command Pid Tid Shared Object Symbol 100.00% 0.00% dmesg 3318 3318 /apex/com.android.runtime/lib64/bionic/libc.so __libc_init | -- __libc_init | -- main toybox_main toy_exec_which dmesg_main klogctl entry_SYSCALL_64_after_hwframe do_syscall_64 __x64_sys_syslog do_syslog selinux_syslog slow_avc_audit common_lsm_audit avc_audit_post_callback avc_audit_post_callback
ห่วงโซ่การเรียกข้างต้นคือห่วงโซ่การเรียกเคอร์เนลและพื้นที่ผู้ใช้แบบรวม ซึ่งช่วยให้คุณเห็นโฟลว์ของโค้ดได้ดีขึ้น
โดยเริ่มการติดตามจากพื้นที่ผู้ใช้ไปจนถึงเคอร์เนลที่
เกิดการปฏิเสธ ดูข้อมูลเพิ่มเติมเกี่ยวกับ simpleperf
ได้ที่
ข้อมูลอ้างอิงคำสั่งที่เรียกใช้งานได้ของ Simpleperf
เปลี่ยนเป็นแบบไม่จำกัด
คุณปิดใช้การบังคับใช้ SELinux ได้ด้วย adb ในการสร้าง userdebug หรือ eng โดยให้
เปลี่ยน ADB เป็นรูทก่อนโดยเรียกใช้ adb root
จากนั้นหากต้องการปิดใช้การบังคับใช้ SELinux
ให้เรียกใช้คำสั่งต่อไปนี้
adb shell setenforce 0
หรือที่บรรทัดคำสั่งเคอร์เนล (ระหว่างการเริ่มต้นอุปกรณ์ในช่วงแรก)
androidboot.selinux=permissive
androidboot.selinux=enforcing
หรือผ่าน bootconfig ใน Android 12
androidboot.selinux=permissive
androidboot.selinux=enforcing
ใช้ audit2allow
audit2allow
เครื่องมือจะใช้dmesg
การปฏิเสธและ
แปลงเป็นการประกาศนโยบาย SELinux ที่เกี่ยวข้อง ดังนั้น จึงช่วยเร่งการพัฒนา SELinux ได้เป็นอย่างมาก
หากต้องการใช้ ให้เรียกใช้คำสั่งต่อไปนี้
adb pull /sys/fs/selinux/policy
adb logcat -b events -d | audit2allow -p policy
อย่างไรก็ตาม คุณต้องพิจารณาอย่างรอบคอบถึงการเพิ่มฟีเจอร์แต่ละอย่างที่อาจเกิดขึ้นเพื่อดูว่ามีการขอสิทธิ์มากเกินไปหรือไม่ ตัวอย่างเช่น การป้อนaudit2allow
การปฏิเสธ
rmt_storage
ที่แสดงก่อนหน้านี้จะส่งผลให้มีคำสั่งนโยบาย SELinux ที่แนะนำดังนี้
#============= shell ============== allow shell kernel:security setenforce; #============= rmt ============== allow rmt kmem_device:chr_file { read write };
ซึ่งจะทำให้ rmt
มีสิทธิ์เขียนหน่วยความจำเคอร์เนล ซึ่งเป็นช่องโหว่ด้านความปลอดภัยที่ร้ายแรง โดยส่วนใหญ่แล้วaudit2allow
คำสั่งต่างๆ เป็นเพียง
จุดเริ่มต้นเท่านั้น หลังจากใช้ข้อความเหล่านี้แล้ว คุณอาจต้องเปลี่ยน
โดเมนแหล่งที่มาและป้ายกำกับของเป้าหมาย รวมถึงรวม
มาโครที่เหมาะสมเพื่อให้เป็นนโยบายที่ดี บางครั้งการปฏิเสธที่กำลังตรวจสอบไม่ควรส่งผลให้มีการเปลี่ยนแปลงนโยบายใดๆ แต่ควรเปลี่ยนแอปที่ละเมิดแทน