یکپارچگی جریان را کنترل کنید

از سال 2016 ، حدود 86٪ از تمام آسیب پذیری های Android مربوط به ایمنی حافظه است. بیشتر آسیب پذیری ها توسط مهاجمین مورد استفاده قرار می گیرند که جریان کنترل طبیعی برنامه را تغییر می دهند تا فعالیت های مخرب خودسرانه را با تمام امتیازات برنامه بهره برداری انجام دهند. یکپارچگی جریان کنترل (CFI) یک مکانیسم امنیتی است که تغییرات در نمودار جریان کنترل اصلی یک باینری کامپایل شده را مجاز نمی داند ، و انجام چنین حملاتی را دشوارتر می کند.

در Android 8.1 ، ما می توانیم LLVM را از CFI در پشته رسانه فعال کنیم. در اندروید 9 ، ما CFI را در اجزای بیشتر و همچنین هسته فعال می کنیم. CFI سیستم به طور پیش فرض روشن است اما شما باید هسته CFI را فعال کنید.

CFI LLVM نیاز به کامپایل با بهینه سازی لینک زمان دارد (LTO) . LTO نمایش بیت کد LLVM از پرونده های شی را تا زمان اتصال حفظ می کند ، که به کامپایلر اجازه می دهد دلیل بهتری در مورد انجام بهینه سازی ها داشته باشد. فعال کردن LTO اندازه باینری نهایی را کاهش می دهد و عملکرد را بهبود می بخشد ، اما زمان کامپایل را افزایش می دهد. در آزمایش بر روی Android ، ترکیبی از LTO و CFI منجر به سربار ناچیز به اندازه کد و عملکرد می شود. در چند مورد هر دو بهبود یافته است.

برای جزئیات بیشتر فنی در مورد CFI و نحوه انجام سایر بررسی های کنترل جلو ، به اسناد طراحی LLVM مراجعه کنید.

مثالها و منبع

CFI توسط کامپایلر ارائه می شود و ابزار را در زمان کامپایل به باینری اضافه می کند. ما از CFI در ابزار ابزار Clang و سیستم ساخت Android در AOSP پشتیبانی می کنیم.

CFI به طور پیش فرض برای دستگاه های Arm64 برای مجموعه ای از م componentsلفه ها در /platform/build/target/product/cfi-common.mk . همچنین به طور مستقیم در مجموعه ای از پرونده های تشکیل دهنده / نقشه اولیه اجزای رسانه مانند /platform/frameworks/av/media/libmedia/Android.bp و /platform/frameworks/av/cmds/stagefright/Android.mk .

سیستم پیاده سازی CFI

اگر از Clang و سیستم ساخت Android استفاده می کنید ، CFI به طور پیش فرض فعال می شود. از آنجا که CFI به امنیت کاربران Android کمک می کند ، بنابراین نباید آن را غیرفعال کنید.

در حقیقت ، ما به شدت شما را تشویق می کنیم تا CFI را برای اجزای اضافی فعال کنید. نامزدهای ایده آل کد محلی ممتاز یا کد محلی هستند که ورودی کاربر نامعتبر را پردازش می کنند. اگر از کلنگ و سیستم ساخت آندروید استفاده می کنید ، می توانید با افزودن چند خط به فایل های makefiles یا برنامه های اصلی خود ، CFI را در اجزای جدید فعال کنید.

پشتیبانی از CFI در پرونده ها

برای فعال کردن CFI در یک پرونده ساخت ، مانند /platform/frameworks/av/cmds/stagefright/Android.mk ، اضافه کنید:

LOCAL_SANITIZE := cfi
# Optional features
LOCAL_SANITIZE_DIAG := cfi
LOCAL_SANITIZE_BLACKLIST := cfi_blacklist.txt
  • LOCAL_SANITIZE CFI را به عنوان ضدعفونی کننده هنگام ساخت تعیین می کند.
  • LOCAL_SANITIZE_DIAG حالت تشخیصی را برای CFI روشن می کند. حالت تشخیصی اطلاعات اشکال زدایی اضافی را در logcat در هنگام خرابی چاپ می کند ، که برای توسعه و آزمایش ساختهای شما مفید است. اگرچه مطمئن شوید که حالت تشخیصی را در ساخت و سازها حذف کنید.
  • LOCAL_SANITIZE_BLACKLIST به م components LOCAL_SANITIZE_BLACKLIST امکان را می دهد تا ابزار CFI را برای عملکردهای جداگانه یا پرونده های منبع به طور انتخابی غیرفعال کنند. برای رفع هرگونه مشکل در مواجهه با کاربر که ممکن است در غیر این صورت وجود داشته باشد ، می توانید از لیست سیاه به عنوان آخرین چاره استفاده کنید. برای جزئیات بیشتر ، به غیرفعال کردن CFI مراجعه کنید.

پشتیبانی از CFI در پرونده های طرح

برای فعال کردن CFI در یک فایل نقشه ، مانند /platform/frameworks/av/media/libmedia/Android.bp ، اضافه کنید:

   sanitize: {
        cfi: true,
        diag: {
            cfi: true,
        },
        blacklist: "cfi_blacklist.txt",
    },

عیب یابی

اگر CFI را در م componentsلفه های جدید فعال می کنید ، ممکن است با چند مورد از خطاهای عدم تطبیق نوع عملکرد و خطاهای عدم تطبیق نوع مونتاژ مواجه شوید .

خطاهای عدم تطبیق نوع عملکرد به این دلیل رخ می دهد که CFI تماس های غیرمستقیم را محدود می کند و فقط به توابع پرش می شوند که از نوع پویای مشابه نوع استاتیک استفاده شده در تماس برخوردار هستند. CFI تماسهای عضو مجازی و غیرمجازی را محدود می کند تا فقط به اشیا پرش شود که یک کلاس مشتق شده از نوع ساکن شی object مورد استفاده برای ایجاد تماس هستند. این بدان معناست که وقتی کدی دارید که هر یک از این فرضیات را نقض می کند ، ابزاری که CFI اضافه می کند سقط می شود. به عنوان مثال ، ردیابی پشته SIGABRT را نشان می دهد و logcat حاوی یک خط در مورد یکپارچگی جریان کنترل است که یک عدم تطابق را پیدا می کند.

برای رفع این مشکل ، اطمینان حاصل کنید که عملکرد فراخوانی شده از همان نوعی که به صورت استاتیک اعلام شده است ، برخوردار باشد. در اینجا دو نمونه CL وجود دارد:

مسئله احتمالی دیگر تلاش برای فعال کردن CFI در کدی است که شامل تماسهای غیرمستقیم برای اجتماع است. از آنجا که کد اسمبلی تایپ نشده است ، این امر منجر به عدم تطابق نوع می شود.

برای رفع این مشکل ، برای هر فراخوانی اسمبلی ، بسته بندی کد بومی ایجاد کنید و عملکرد بسته بندی کننده همان علامت تنظیم کننده تماس را بدهید. سپس بسته بندی می تواند مستقیماً با کد مونتاژ تماس بگیرد. از آنجا که شعب مستقیم توسط CFI مورد استفاده قرار نمی گیرند (نمی توان آنها را در زمان اجرا مجدداً تغییر داد و بنابراین خطری برای امنیت ایجاد نمی کنند) ، این مسئله مشکل را برطرف می کند.

اگر توابع مونتاژ بیش از حد زیاد باشد و همه آنها قابل رفع نباشند ، می توانید تمام توابع حاوی تماس غیرمستقیم به مونتاژ را در لیست سیاه قرار دهید. این امر توصیه نمی شود زیرا بررسی CFI در این توابع را غیرفعال می کند ، در نتیجه سطح حمله را باز می کند.

غیرفعال کردن CFI

ما هیچ سربار عملکردی را مشاهده نکردیم ، بنابراین شما نیازی به غیرفعال کردن CFI ندارید. با این وجود ، در صورت وجود تأثیرات در کاربر ، می توانید با تهیه یک فایل لیست سیاه ضدعفونی کننده در زمان کامپایل ، CFI را برای عملکردهای جداگانه یا پرونده های منبع غیرفعال کنید. لیست سیاه به کامپایلر دستور می دهد تا ابزار دقیق CFI را در مکانهای مشخص غیرفعال کند.

سیستم ساخت Android پشتیبانی از لیست های سیاه برای هر جز per را فراهم می کند (به شما امکان می دهد فایل های منبع یا توابع جداگانه ای را که ابزار CFI دریافت نخواهند کرد انتخاب کنید) برای Make و Soong. برای جزئیات بیشتر در مورد قالب یک فایل لیست سیاه ، به اسناد بالادستی Clang مراجعه کنید .

اعتبار سنجی

در حال حاضر ، هیچ تست CTS مخصوص CFI وجود ندارد. درعوض ، مطمئن شوید که آزمایش های CTS با یا بدون CFI فعال شده اند تا تأیید کنید که CFI روی دستگاه تأثیر نمی گذارد.