ตรวจสอบ SELinux

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 (บริบทของแหล่งที่มา) แสดง ผู้ดำเนินการ ซึ่งในกรณีนี้คือ Daemon rmt_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คำสั่งต่างๆ เป็นเพียง จุดเริ่มต้นเท่านั้น หลังจากใช้ข้อความเหล่านี้แล้ว คุณอาจต้องเปลี่ยน โดเมนแหล่งที่มาและป้ายกำกับของเป้าหมาย รวมถึงรวม มาโครที่เหมาะสมเพื่อให้เป็นนโยบายที่ดี บางครั้งการปฏิเสธที่กำลังตรวจสอบไม่ควรส่งผลให้มีการเปลี่ยนแปลงนโยบายใดๆ แต่ควรเปลี่ยนแอปที่ละเมิดแทน