UndefinedBehaviorSanitizer

UndefinedBehaviorSanitizer (UBSan) ابزار دقیق زمان کامپایل را برای بررسی انواع رفتارهای تعریف نشده انجام می دهد. در حالی که UBSan قادر است بسیاری از باگ های رفتاری تعریف نشده را شناسایی کند، اندروید از موارد زیر پشتیبانی می کند:

  • هم ترازی
  • بوول
  • محدوده
  • enum
  • float-cast-overflow
  • شناور تقسیم بر صفر
  • عدد صحیح تقسیم بر صفر
  • ویژگی غیر تهی
  • خالی
  • برگشت
  • بازده-nonnull-ویژگی
  • شیفت پایه
  • شیفت نما
  • signed-integer-overflow
  • غیر قابل دسترسی
  • unsigned-integer-overflow
  • vla-bound

سرریز عدد صحیح بدون علامت، اگرچه از نظر فنی رفتار تعریف نشده ای ندارد، اما در ضدعفونی کننده گنجانده شده است و در بسیاری از ماژول های اندروید، از جمله اجزای مدیاسرور، برای از بین بردن هر گونه آسیب پذیری سرریز اعداد صحیح پنهان استفاده می شود.

پیاده سازی

در سیستم ساخت اندروید، می توانید UBSan را به صورت جهانی یا محلی فعال کنید. برای فعال کردن UBSan به صورت جهانی، SANITIZE_TARGET را در Android.mk تنظیم کنید. برای فعال کردن UBSan در سطح هر ماژول، LOCAL_SANITIZE را تنظیم کنید و رفتارهای تعریف نشده‌ای را که می‌خواهید در Android.mk جستجو کنید، مشخص کنید. مثلا:

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_CFLAGS := -std=c11 -Wall -Werror -O0

LOCAL_SRC_FILES:= sanitizer-status.c

LOCAL_MODULE:= sanitizer-status

LOCAL_SANITIZE := alignment bounds null unreachable integer
LOCAL_SANITIZE_DIAG := alignment bounds null unreachable integer

include $(BUILD_EXECUTABLE)

و پیکربندی طرح اولیه (Android.bp):

cc_binary {

    cflags: [
        "-std=c11",
        "-Wall",
        "-Werror",
        "-O0",
    ],

    srcs: ["sanitizer-status.c"],

    name: "sanitizer-status",

    sanitize: {
        misc_undefined: [
            "alignment",
            "bounds",
            "null",
            "unreachable",
            "integer",
        ],
        diag: {
            misc_undefined: [
                "alignment",
                "bounds",
                "null",
                "unreachable",
                "integer",
            ],
        },
    },

}

میانبرهای UBSan

اندروید همچنین دارای دو میانبر integer و default-ub است تا مجموعه ای از ضدعفونی کننده ها را همزمان فعال کند. عدد صحیح integer-divide-by-zero ، signed-integer-overflow و unsigned-integer-overflow . default-ub چک هایی را فعال می کند که حداقل مشکلات مربوط به عملکرد کامپایلر را دارند: bool, integer-divide-by-zero, return, returns-nonnull-attribute, shift-exponent, unreachable and vla-bound . کلاس ضدعفونی کننده عدد صحیح را می توان با SANITIZE_TARGET و LOCAL_SANITIZE استفاده کرد، در حالی که پیش فرض ub فقط با SANITIZE_TARGET قابل استفاده است.

گزارش بهتر خطا

پیاده‌سازی پیش‌فرض UBSan اندروید، زمانی که رفتار نامشخصی مواجه می‌شود، یک تابع مشخص را فراخوانی می‌کند. به طور پیش فرض، این تابع متوقف شده است. با این حال، از اکتبر 2016، UBSan در اندروید دارای یک کتابخانه زمان اجرا اختیاری است که گزارش خطای دقیق تری را ارائه می دهد، از جمله نوع رفتار نامشخص مواجه شده، فایل و اطلاعات خط کد منبع. برای فعال کردن این گزارش خطا با بررسی اعداد صحیح موارد زیر را به یک فایل Android.mk اضافه کنید:

LOCAL_SANITIZE:=integer
LOCAL_SANITIZE_DIAG:=integer

مقدار LOCAL_SANITIZE ضدعفونی کننده را در طول ساخت فعال می کند. LOCAL_SANITIZE_DIAG حالت تشخیصی را برای ضدعفونی‌کننده مشخص شده روشن می‌کند. می‌توان LOCAL_SANITIZE و LOCAL_SANITIZE_DIAG را روی مقادیر مختلف تنظیم کرد، اما فقط آن بررسی‌ها در LOCAL_SANITIZE فعال هستند. اگر چک در LOCAL_SANITIZE مشخص نشده باشد، اما در LOCAL_SANITIZE_DIAG مشخص شده باشد، چک فعال نمی شود و پیام های تشخیصی داده نمی شود.

در اینجا نمونه ای از اطلاعات ارائه شده توسط کتابخانه زمان اجرا UBSan آمده است:

pixel-xl:/ # sanitizer-status ubsan
sanitizer-status/sanitizer-status.c:53:6: runtime error: unsigned integer overflow: 18446744073709551615 + 1 cannot be represented in type 'size_t' (aka 'unsigned long')

پاکسازی سرریز عدد صحیح

سرریزهای اعداد صحیح ناخواسته می تواند باعث تخریب حافظه یا آسیب پذیری های افشای اطلاعات در متغیرهای مرتبط با دسترسی های حافظه یا تخصیص حافظه شود. برای مبارزه با این موضوع، ضدعفونی‌کننده‌های سرریز اعداد صحیح علامت‌دار و بدون علامت Clang's UndefinedBehaviorSanitizer (UBSan) را اضافه کردیم تا چارچوب رسانه‌ای را در اندروید 7.0 سخت‌تر کنیم . در اندروید 9، UBSan را گسترش دادیم تا اجزای بیشتری را پوشش دهد و پشتیبانی از سیستم ساخت را برای آن بهبود بخشید.

این برای اضافه کردن بررسی‌ها در مورد عملیات / دستورالعمل‌های حسابی - که ممکن است سرریز شوند - طراحی شده است تا در صورت وقوع سرریز، به طور ایمن یک فرآیند را متوقف کند. این ضدعفونی‌کننده‌ها می‌توانند یک کلاس کامل از آسیب‌پذیری‌های حافظه و افشای اطلاعات را که علت اصلی آن سرریز اعداد صحیح است، مانند آسیب‌پذیری اصلی Stagefright، کاهش دهند.

مثال ها و منبع

پاکسازی سرریز عدد صحیح (IntSan) توسط کامپایلر ارائه می شود و ابزار دقیق را در طول زمان کامپایل به باینری اضافه می کند تا سرریزهای حسابی را تشخیص دهد. این به طور پیش فرض در اجزای مختلف در سراسر پلتفرم فعال است، به عنوان مثال /platform/external/libnl/Android.bp .

پیاده سازی

IntSan از ضدعفونی کننده های سرریز اعداد صحیح امضا شده و بدون علامت UBSan استفاده می کند. این کاهش در سطح هر ماژول فعال است. این کمک می کند تا اجزای مهم اندروید را ایمن نگه دارد و نباید غیرفعال شود.

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

پشتیبانی از IntSan در فایل های makefiles

برای فعال کردن IntSan در یک makefile، اضافه کنید:

LOCAL_SANITIZE := integer_overflow
    # Optional features
    LOCAL_SANITIZE_DIAG := integer_overflow
    LOCAL_SANITIZE_BLOCKLIST := modulename_BLOCKLIST.txt
  • LOCAL_SANITIZE فهرستی از ضدعفونی‌کننده‌ها را می‌گیرد که با کاما از هم جدا شده‌اند، با integer_overflow مجموعه‌ای از پیش‌بسته‌بندی‌شده از گزینه‌ها برای پاک‌کننده‌های سرریز اعداد صحیح امضاشده و بدون علامت با یک BLOCKLIST پیش‌فرض است.
  • LOCAL_SANITIZE_DIAG حالت تشخیصی را برای ضدعفونی‌کننده‌ها روشن می‌کند. از حالت عیب‌یابی فقط در حین آزمایش استفاده کنید زیرا این حالت در سرریزها متوقف نمی‌شود و مزیت امنیتی کاهش را کاملاً نفی می‌کند. برای جزئیات بیشتر به عیب یابی مراجعه کنید.
  • LOCAL_SANITIZE_BLOCKLIST به شما امکان می دهد یک فایل BLOCKLIST را مشخص کنید تا از پاکسازی توابع و فایل های منبع جلوگیری کنید. برای جزئیات بیشتر به عیب یابی مراجعه کنید.

اگر می خواهید کنترل دانه ای بیشتری داشته باشید، ضدعفونی کننده ها را به صورت جداگانه با استفاده از یک یا هر دو پرچم فعال کنید:

LOCAL_SANITIZE := signed-integer-overflow, unsigned-integer-overflow
    LOCAL_SANITIZE_DIAG := signed-integer-overflow, unsigned-integer-overflow

پشتیبانی از IntSan در فایل های طرح اولیه

برای فعال کردن پاکسازی سرریز اعداد صحیح در یک فایل طرح اولیه، مانند /platform/external/libnl/Android.bp ، اضافه کنید:

   sanitize: {
          integer_overflow: true,
          diag: {
              integer_overflow: true,
          },
          BLOCKLIST: "modulename_BLOCKLIST.txt",
       },

مانند فایل‌های make، ویژگی integer_overflow مجموعه‌ای از گزینه‌های از پیش بسته‌بندی شده برای پاک‌کننده‌های سرریز اعداد صحیح امضاشده و بدون علامت با یک BLOCKLIST پیش‌فرض است.

مجموعه ویژگی های diag حالت تشخیص را برای ضدعفونی کننده ها فعال می کند. از حالت عیب یاب فقط در طول آزمایش استفاده کنید. حالت عیب‌یابی در سرریزها متوقف نمی‌شود، که به طور کامل مزیت امنیتی کاهش در ساخت‌های کاربر را نفی می‌کند. برای جزئیات بیشتر به عیب یابی مراجعه کنید.

ویژگی BLOCKLIST اجازه می دهد تا یک فایل BLOCKLIST را مشخص کنید که به توسعه دهندگان اجازه می دهد از پاکسازی توابع و فایل های منبع جلوگیری کنند. برای جزئیات بیشتر به عیب یابی مراجعه کنید.

برای فعال کردن ضدعفونی‌کننده‌ها به صورت جداگانه، از موارد زیر استفاده کنید:

   sanitize: {
          misc_undefined: ["signed-integer-overflow", "unsigned-integer-overflow"],
          diag: {
              misc_undefined: ["signed-integer-overflow",
                               "unsigned-integer-overflow",],
          },
          BLOCKLIST: "modulename_BLOCKLIST.txt",
       },

عیب یابی

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

برای یافتن سقط‌های ناشی از پاک‌سازی در ساخت‌های کاربر، خرابی‌های SIGABRT را با پیام‌های Abort جستجو کنید که نشان‌دهنده سرریز شدن توسط UBSan است، مانند:

pid: ###, tid: ###, name: Binder:###  >>> /system/bin/surfaceflinger <<<
    signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------
    Abort message: 'ubsan: sub-overflow'

ردیابی پشته باید شامل تابعی باشد که باعث سقط می شود، با این حال، سرریزهایی که در توابع درون خطی رخ می دهند ممکن است در ردیابی پشته مشهود نباشند.

برای تعیین آسان‌تر علت اصلی، تشخیص را در کتابخانه فعال کنید که باعث سقط می‌شود و سعی کنید خطا را تکرار کنید. با فعال بودن عیب‌یابی، فرآیند متوقف نمی‌شود و در عوض به کار خود ادامه می‌دهد. عدم قطع به حداکثر رساندن تعداد سرریزهای خوش خیم در یک مسیر اجرای خاص بدون نیاز به کامپایل مجدد پس از رفع هر اشکال کمک می کند. Diagnostics یک پیام خطایی ایجاد می کند که شامل شماره خط و فایل منبع است که باعث سقط می شود:

frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp:2188:32: runtime error: unsigned integer overflow: 0 - 1 cannot be represented in type 'size_t' (aka 'unsigned long')

هنگامی که عملیات محاسباتی مشکل ساز مشخص شد، اطمینان حاصل کنید که سرریز خوش خیم و مورد نظر است (مثلاً هیچ پیامد امنیتی ندارد). می‌توانید با موارد زیر به سقط ضدعفونی‌کننده رسیدگی کنید:

  • اصلاح مجدد کد برای جلوگیری از سرریز شدن ( مثال )
  • سرریز به صراحت از طریق توابع __builtin_*_سرریز Clang's ( مثال )
  • غیرفعال کردن sanitization در تابع با مشخص کردن ویژگی no_sanitize ( مثال )
  • غیرفعال کردن پاکسازی یک تابع یا فایل منبع از طریق یک فایل BLOCKLIST ( مثال )

باید از گرانول ترین محلول ممکن استفاده کنید. به عنوان مثال، یک تابع بزرگ با تعداد زیادی عملیات حسابی و یک عملیات سرریز منفرد، به جای اینکه کل تابع BLOCKLIST شود، باید عملیات واحد را بازسازی کند.

الگوهای رایجی که ممکن است منجر به سرریزهای خوش خیم شود عبارتند از:

  • پخش‌های ضمنی که در آن یک سرریز بدون علامت قبل از ریخته شدن به یک نوع علامت‌دار رخ می‌دهد ( مثال )
  • حذف لیست پیوندی که شاخص حلقه در حذف را کاهش می دهد ( مثال )
  • اختصاص یک نوع بدون علامت به -1 به جای تعیین حداکثر مقدار واقعی ( مثال )
  • حلقه هایی که یک عدد صحیح بدون علامت را در شرایط کاهش می دهند ( مثال ، مثال )

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

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

می‌توانید IntSan را با BLOCKLIST یا ویژگی‌های تابع غیرفعال کنید. غیرفعال کردن به مقدار کم و فقط در زمانی که تغییر مجدد کد غیرمنطقی است یا اگر سربار عملکرد مشکلی وجود داشته باشد.

برای اطلاعات بیشتر در مورد غیرفعال کردن IntSan با ویژگی‌های عملکرد و قالب‌بندی فایل BLOCKLIST، به اسناد بالادستی Clang مراجعه کنید. BLOCKLIST باید با استفاده از نام بخش‌هایی که ضدعفونی‌کننده مورد نظر را مشخص می‌کنند، برای ضدعفونی‌کننده‌های دیگر محدود شود.

اعتبار سنجی

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

پاکسازی مرزها

BoundsSanitizer (BoundSan) ابزار دقیق را به باینری‌ها اضافه می‌کند تا بررسی‌های مرزی را در اطراف دسترسی‌های آرایه وارد کند. اگر کامپایلر نتواند در زمان کامپایل ثابت کند که دسترسی امن است و اندازه آرایه در زمان اجرا مشخص است، این بررسی ها اضافه می شوند تا بتوان آن را بررسی کرد. اندروید 10 از BoundSan در بلوتوث و کدک ها استفاده می کند. BoundSan توسط کامپایلر ارائه می شود و به طور پیش فرض در اجزای مختلف در سراسر پلتفرم فعال می شود.

پیاده سازی

BoundSan از ضدعفونی کننده محدوده UBSan استفاده می کند. این کاهش در سطح هر ماژول فعال است. این کمک می کند تا اجزای حیاتی اندروید را ایمن نگه دارد و نباید غیرفعال شود.

ما قویاً شما را تشویق می کنیم که BoundSan را برای اجزای اضافی فعال کنید. نامزدهای ایده آل کد بومی ممتاز یا کد بومی پیچیده هستند که ورودی نامعتبر کاربر را تجزیه می کند. سربار عملکرد مرتبط با فعال کردن BoundSan به تعداد دسترسی‌های آرایه‌ای بستگی دارد که ایمن بودن آن‌ها ثابت نمی‌شود. به طور متوسط ​​انتظار یک درصد سربار کوچک را داشته باشید و بررسی کنید که آیا عملکرد نگران کننده است یا خیر.

فعال کردن BoundSan در فایل های طرح اولیه

BoundSan را می توان با افزودن "bounds" به ویژگی misc_undefined sanitize برای ماژول های باینری و کتابخانه در فایل های طرح اولیه فعال کرد:

    sanitize: {
       misc_undefined: ["bounds"],
       diag: {
          misc_undefined: ["bounds"],
       },
       BLOCKLIST: "modulename_BLOCKLIST.txt",
دیگ

ویژگی diag حالت تشخیص را برای ضدعفونی‌کننده‌ها فعال می‌کند. از حالت عیب یاب فقط در طول آزمایش استفاده کنید. حالت عیب‌یابی در سرریزها متوقف نمی‌شود، که مزیت امنیتی کاهش را نفی می‌کند و سربار عملکرد بالاتری دارد، بنابراین برای ساخت‌های تولیدی توصیه نمی‌شود.

BLOCKLIST

ویژگی BLOCKLIST اجازه می دهد تا یک فایل BLOCKLIST را مشخص کنید که توسعه دهندگان می توانند از آن برای جلوگیری از پاکسازی توابع و فایل های منبع استفاده کنند. فقط در صورتی از این ویژگی استفاده کنید که عملکرد یک نگرانی باشد و فایل‌ها/توابع مورد نظر سهم قابل توجهی داشته باشند. برای اطمینان از ایمن بودن دسترسی‌های آرایه، این فایل‌ها/توابع را به صورت دستی بررسی کنید. برای جزئیات بیشتر به عیب یابی مراجعه کنید.

فعال کردن BoundSan در makefiles

BoundSan را می توان با افزودن "bounds" به متغیر LOCAL_SANITIZE برای ماژول های باینری و کتابخانه ای در فایل های ساخت فعال کرد:

    LOCAL_SANITIZE := bounds
    # Optional features
    LOCAL_SANITIZE_DIAG := bounds
    LOCAL_SANITIZE_BLOCKLIST := modulename_BLOCKLIST.txt

LOCAL_SANITIZE فهرستی از ضدعفونی‌کننده‌ها را می‌پذیرد که با کاما از هم جدا شده‌اند.

LOCAL_SANITIZE_DIAG حالت عیب‌یابی را روشن می‌کند. از حالت عیب یاب فقط در طول آزمایش استفاده کنید. حالت عیب‌یابی در سرریزها متوقف نمی‌شود، که مزیت امنیتی کاهش را نفی می‌کند و سربار عملکرد بالاتری دارد، بنابراین برای ساخت‌های تولیدی توصیه نمی‌شود.

LOCAL_SANITIZE_BLOCKLIST اجازه می دهد تا مشخصات یک فایل BLOCKLIST را مشخص کند که به توسعه دهندگان اجازه می دهد از پاکسازی توابع و فایل های منبع جلوگیری کنند. فقط در صورتی از این ویژگی استفاده کنید که عملکرد یک نگرانی باشد و فایل‌ها/توابع مورد نظر سهم قابل توجهی داشته باشند. برای اطمینان از ایمن بودن دسترسی‌های آرایه، این فایل‌ها/توابع را به صورت دستی بررسی کنید. برای جزئیات بیشتر به عیب یابی مراجعه کنید.

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

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

برای اطلاعات بیشتر در مورد غیرفعال کردن BoundSan با ویژگی های تابع و قالب بندی فایل BLOCKLIST ، به مستندات Clang LLVM مراجعه کنید. با استفاده از نام بخش‌هایی که ضدعفونی‌کننده هدف را مشخص می‌کنند، فهرست BLOCKLIST را به یک ضدعفونی‌کننده خاص محدود کنید تا از تأثیرگذاری دیگر ضدعفونی‌کننده‌ها جلوگیری کنید.

اعتبار سنجی

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

عیب یابی

پس از فعال کردن BoundSan، مؤلفه‌ها را کاملاً آزمایش کنید تا اطمینان حاصل شود که دسترسی‌های خارج از مرزی که قبلاً شناسایی نشده بودند، آدرس‌دهی می‌شوند.

خطاهای BoundSan را می توان به راحتی شناسایی کرد زیرا شامل پیام ابطال سنگ قبر زیر است:

    pid: ###, tid: ###, name: Binder:###  >>> /system/bin/foobar <<<
    signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------
    Abort message: 'ubsan: out-of-bounds'

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

    external/foo/bar.c:293:13: runtime error: index -1 out of bounds for type 'int [24]'