অ্যান্ড্রয়েড OEM-দেরকে তাদের SELinux বাস্তবায়ন পুঙ্খানুপুঙ্খভাবে পরীক্ষা করতে জোরালোভাবে উৎসাহিত করে। নির্মাতারা যখন SELinux বাস্তবায়ন করবে, তখন তাদের প্রথমে পরীক্ষামূলকভাবে কিছু ডিভাইসে এই নতুন নীতিটি প্রয়োগ করা উচিত।
নতুন পলিসি প্রয়োগ করার পর, getenforce কমান্ডটি দিয়ে নিশ্চিত করুন যে ডিভাইসে SELinux সঠিক মোডে চলছে।
এটি গ্লোবাল SELinux মোড প্রিন্ট করে: হয় Enforcing অথবা Permissive। প্রতিটি ডোমেইনের জন্য SELinux মোড নির্ধারণ করতে, আপনাকে অবশ্যই সংশ্লিষ্ট ফাইলগুলো পরীক্ষা করতে হবে অথবা /platform/system/sepolicy/tools/ -এ থাকা উপযুক্ত ( -p ) ফ্ল্যাগ সহ sepolicy-analyze এর সর্বশেষ সংস্করণটি চালাতে হবে।
অস্বীকৃতিগুলো পড়ুন
ত্রুটিগুলি পরীক্ষা করুন, যেগুলি ইভেন্ট লগ হিসাবে dmesg এবং logcat এ পাঠানো হয় এবং ডিভাইসে স্থানীয়ভাবে দেখা যায়। নির্মাতাদের উচিত এই ডিভাইসগুলিতে dmesg এ SELinux-এর আউটপুট পরীক্ষা করা এবং পারমিসিভ মোডে সর্বসাধারণের জন্য প্রকাশের আগে ও পরবর্তীতে এনফোর্সিং মোডে পরিবর্তনের আগে সেটিংস পরিমার্জন করা। SELinux লগ মেসেজগুলিতে avc: থাকে, তাই grep ব্যবহার করে এগুলি সহজেই খুঁজে পাওয়া যায়। cat /proc/kmsg কমান্ডটি চালিয়ে চলমান ডিনায়াল লগগুলি ক্যাপচার করা সম্ভব, অথবা cat /sys/fs/pstore/console-ramoops চালিয়ে পূর্ববর্তী বুটের ডিনায়াল লগগুলি ক্যাপচার করা যায়।
বুট সম্পন্ন হওয়ার পর লগ ফাইল যাতে ভরে না যায়, সেজন্য SELinux-এর ত্রুটির বার্তাগুলোর প্রদর্শন সীমিত করা হয়। সমস্ত প্রাসঙ্গিক বার্তা যাতে আপনি দেখতে পান, তা নিশ্চিত করতে adb shell auditctl -r 0 কমান্ডটি চালিয়ে আপনি এটি নিষ্ক্রিয় করতে পারেন।
এই আউটপুটের মাধ্যমে নির্মাতারা সহজেই শনাক্ত করতে পারেন কখন সিস্টেম ব্যবহারকারী বা কম্পোনেন্টগুলো SELinux পলিসি লঙ্ঘন করছে। এরপর নির্মাতারা সফটওয়্যার, SELinux পলিসি বা উভয়টিতে পরিবর্তন এনে এই ত্রুটিপূর্ণ আচরণটি সংশোধন করতে পারেন।
বিশেষভাবে, এই লগ বার্তাগুলো নির্দেশ করে যে এনফোর্সিং মোডে কোন প্রসেসগুলো ব্যর্থ হবে এবং কেন। এখানে একটি উদাহরণ দেওয়া হলো:
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)-এর সাথে মিলে এটি মোটামুটিভাবে বলে দেয় যে কার সাথে কী করা হচ্ছিল। এই ক্ষেত্রে, কোনো কিছু একটি ইউনিক্স স্ট্রিম সকেটের সাথে সংযোগ করার চেষ্টা করছিল। -
scontext (u:r:shell:s0)আপনাকে বলে দেয় কোন কনটেক্সট থেকে অ্যাকশনটি শুরু করা হয়েছে। এই ক্ষেত্রে, এটি হলো শেল হিসেবে চলমান কোনো কিছু। -
tcontext (u:r:netd:s0)আপনাকে অ্যাকশনটির টার্গেটের কনটেক্সট সম্পর্কে জানায়। এই ক্ষেত্রে, সেটি হলোnetdএর মালিকানাধীন একটি unix_stream_socket। - শীর্ষে থাকা
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(সোর্স কনটেক্সট) এন্ট্রিটি অ্যাক্টরকে প্রতিনিধিত্ব করে, এক্ষেত্রে যা হলোrmt_storageডেমন। - অবজেক্ট -
tcontext(টার্গেট কনটেক্সট) এন্ট্রিটি সেই অবজেক্টকে প্রতিনিধিত্ব করে যার উপর কাজ করা হচ্ছে, এই ক্ষেত্রে kmem। - ফলাফল -
tclass(টার্গেট ক্লাস) এন্ট্রিটি নির্দেশ করে কোন ধরনের অবজেক্টের উপর কাজ করা হচ্ছে, এক্ষেত্রে এটি একটিchr_file(ক্যারেক্টার ডিভাইস)।
ব্যবহারকারী এবং কার্নেল স্ট্যাক ডাম্প করুন
কিছু ক্ষেত্রে, প্রত্যাখ্যানের উৎস সঠিকভাবে চিহ্নিত করার জন্য ইভেন্ট লগে থাকা তথ্য যথেষ্ট হয় না। প্রত্যাখ্যানটি কেন ঘটল তা আরও ভালোভাবে বোঝার জন্য, কার্নেল এবং ইউজারস্পেস সহ কল চেইন সংগ্রহ করা প্রায়শই সহায়ক হয়।
সাম্প্রতিক কার্নেলগুলিতে avc:selinux_audited নামের একটি ট্রেসপয়েন্ট সংজ্ঞায়িত করা আছে। এই ট্রেসপয়েন্টটি সক্রিয় করতে এবং কলচেইন ক্যাপচার করতে অ্যান্ড্রয়েড simpleperf ব্যবহার করুন।
সমর্থিত কনফিগারেশন
- লিনাক্স কার্নেল >= 5.10, বিশেষ করে অ্যান্ড্রয়েড কমন কার্নেলের মেইনলাইন এবং অ্যান্ড্রয়েড১২-৫.১০ শাখাগুলো সমর্থিত। অ্যান্ড্রয়েড১২-৫.৪ শাখাও সমর্থিত। আপনার ডিভাইসে ট্রেসপয়েন্টটি সংজ্ঞায়িত আছে কিনা তা জানতে আপনি
simpleperfব্যবহার করতে পারেন:adb root && adb shell simpleperf list | grep avc:selinux_audited। অন্যান্য কার্নেল সংস্করণের জন্য, আপনি dd81662 এবং 30969bc কমিটগুলো চেরি পিক (cherry pick) করতে পারেন। - আপনি যে ইভেন্টটি ডিবাগ করছেন, সেটি পুনরায় ঘটানো সম্ভব হওয়া উচিত। 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 ব্যবহার করা যেতে পারে। উদাহরণস্বরূপ:
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 Executable commands reference) দেখুন।
অনুমতিমূলক মোডে পরিবর্তন করুন
userdebug বা eng বিল্ডে adb ব্যবহার করে SELinux এনফোর্সমেন্ট নিষ্ক্রিয় করা যায়। এটি করার জন্য, প্রথমে adb root চালিয়ে ADB-কে রুটে সুইচ করুন। তারপর, SELinux এনফোর্সমেন্ট নিষ্ক্রিয় করতে, নিম্নলিখিত কমান্ডটি চালান:
adb shell setenforce 0
অথবা কার্নেল কমান্ড লাইনে (ডিভাইস চালু হওয়ার প্রাথমিক পর্যায়ে):
androidboot.selinux=permissiveandroidboot.selinux=enforcing
অথবা অ্যান্ড্রয়েড ১২-এর bootconfig-এর মাধ্যমে:
androidboot.selinux=permissiveandroidboot.selinux=enforcing
audit2allow ব্যবহার করুন
audit2allow টুলটি dmesg ডিনায়ালগুলো গ্রহণ করে এবং সেগুলোকে সংশ্লিষ্ট SELinux পলিসি স্টেটমেন্টে রূপান্তরিত করে। এর ফলে, এটি SELinux ডেভেলপমেন্টের গতি ব্যাপকভাবে বাড়িয়ে তুলতে পারে।
এটি ব্যবহার করতে, চালান:
adb pull /sys/fs/selinux/policyadb logcat -b events -d | audit2allow -p policy
তথাপি, ক্ষমতার অপব্যবহার হচ্ছে কিনা তা খতিয়ে দেখতে প্রতিটি সম্ভাব্য সংযোজন অবশ্যই সতর্কভাবে পরীক্ষা করতে হবে। উদাহরণস্বরূপ, পূর্বে দেখানো rmt_storage ডিনায়ালটি audit2allow জানালে নিম্নলিখিত প্রস্তাবিত SELinux পলিসি স্টেটমেন্টটি তৈরি হয়:
#============= shell ==============
allow shell kernel:security setenforce;
#============= rmt ==============
allow rmt kmem_device:chr_file { read write };
এর ফলে rmt কার্নেল মেমরিতে লেখার ক্ষমতা পাবে, যা একটি মারাত্মক নিরাপত্তা ত্রুটি। প্রায়শই audit2allow স্টেটমেন্টগুলো কেবল একটি সূচনা বিন্দু। এই স্টেটমেন্টগুলো প্রয়োগ করার পর, একটি ভালো পলিসিতে পৌঁছানোর জন্য আপনাকে সোর্স ডোমেইন এবং টার্গেটের লেবেল পরিবর্তন করার পাশাপাশি যথাযথ ম্যাক্রো অন্তর্ভুক্ত করতে হতে পারে। কখনও কখনও যে ডিনায়ালটি পরীক্ষা করা হচ্ছে, তার ফলে কোনো পলিসি পরিবর্তন করা উচিত নয়; বরং সমস্যা সৃষ্টিকারী অ্যাপটিই পরিবর্তন করা উচিত।