یکپارچگی جریان کنترل (CFI) یک مکانیزم امنیتی است که اجازه تغییرات در نمودار جریان کنترل اصلی یک فایل باینری کامپایل شده را نمیدهد و انجام چنین حملاتی را به طور قابل توجهی دشوارتر میکند.
با شروع از اندروید ۹، میتوانید CFI را در هسته فعال کنید.
هسته لینوکس دو پیادهسازی مختلف از CFI داشته است:
- برای لینوکس ۶.۰ و پایینتر، Clang CFI که به Clang LTO متکی است.
- برای لینوکس ۶.۱ و بالاتر، Clang KCFI
Clang CFI نیاز به کامپایل با بهینهسازی زمان پیوند (LTO) دارد. LTO نمایش بیتکد LLVM از فایلهای شیء را تا زمان پیوند حفظ میکند، که به کامپایلر اجازه میدهد تا در مورد اینکه چه بهینهسازیهایی میتواند انجام شود، بهتر استدلال کند. در آزمایش روی اندروید، ترکیب LTO و CFI منجر به سربار ناچیزی در اندازه کد و عملکرد شد. با این حال، فعال کردن LTO زمان ساخت هسته را به میزان قابل توجهی افزایش میدهد.
Clang KCFI به LTO نیاز ندارد، بنابراین هستههای جدیدتر اندروید از CFI بدون سربار زمان ساخت LTO بهرهمند میشوند.
پیادهسازی
CFI توسط گزینه CONFIG_CFI_CLANG کنترل میشود که Clang CFI یا Clang KCFI را فعال میکند.
برای جزئیات فنی بیشتر در مورد CFI و نحوهی مدیریت سایر بررسیهای کنترل رو به جلو، به مستندات طراحی LLVM مراجعه کنید. در آنجا به KCFI به صورت -fsanitize=kcfi اشاره شده است.
عیبیابی
پس از فعالسازی، هرگونه خطای عدم تطابق نوع که ممکن است با درایورهای آنها وجود داشته باشد را بررسی کنید. فراخوانی غیرمستقیم تابع از طریق یک اشارهگر تابع ناسازگار، CFI را از کار میاندازد. هنگامی که یک خرابی CFI شناسایی میشود، هسته هشداری را چاپ میکند که شامل تابعی که فراخوانی شده و stacktrace که منجر به خرابی شده است، میشود. این مشکل را با اطمینان از اینکه اشارهگرهای تابع همیشه از نوع یکسانی با تابعی که فراخوانی میشود، برخوردارند، برطرف کنید.
برای کمک به اشکالزدایی خطاهای CFI، CONFIG_CFI_PERMISSIVE را فعال کنید، که به جای ایجاد اختلال در هسته، یک هشدار چاپ میکند. حالت Permissive نباید در محیط عملیاتی استفاده شود.
اعتبارسنجی
در حال حاضر، هیچ آزمایش CTS مخصوص CFI وجود ندارد. در عوض، مطمئن شوید که آزمایشهای CTS با و بدون فعال بودن CFI با موفقیت انجام میشوند تا تأیید شود که CFI بر دستگاه تأثیر نمیگذارد.