اسکودو

Scudo یک تخصیص دهنده حافظه پویا در حالت کاربر یا تخصیص دهنده هیپ است که به گونه ای طراحی شده است که در برابر آسیب پذیری های مرتبط با هیپ (مانند سرریز بافر مبتنی بر هیپ ، استفاده پس از آزاد شدن و دو برابر رایگان ) مقاوم باشد و در عین حال عملکرد را حفظ کند. این استانداردهای اولیه تخصیص و توزیع C (مانند malloc و رایگان)، و همچنین C++ اولیه (مانند جدید و حذف) را ارائه می دهد.

Scudo بیشتر یک کاهش دهنده است تا یک آشکارساز خطای حافظه کامل مانند AddressSanitizer (ASan) .

با شروع نسخه اندروید 11، scudo برای همه کدهای بومی استفاده می شود (به جز در دستگاه های با حافظه کم، جایی که هنوز از jemalloc استفاده می شود). در زمان اجرا، تمام تخصیص‌ها و تخصیص‌های محلی Heap توسط Scudo برای همه فایل‌های اجرایی و وابستگی‌های کتابخانه آن‌ها سرویس‌دهی می‌شود، و در صورت شناسایی خرابی یا رفتار مشکوک در پشته، این فرآیند متوقف می‌شود.

در اندروید 10، scudo باید به صورت پر باینری با تنظیم گزینه LOCAL_SANITIZE := scudo scudo در فایل mk. یا sanitize: { scudo: true, } در فایل .bp فعال می شد.

Scudo منبع باز و بخشی از پروژه compiler-rt LLVM است. اسناد در https://llvm.org/docs/ScudoHardenedAllocator.html موجود است. زمان اجرا Scudo به عنوان بخشی از زنجیره ابزار اندروید و پشتیبانی به Soong و Make اضافه شد تا امکان فعال کردن آسان تخصیص دهنده را در یک باینری فراهم کند.

می توانید با استفاده از گزینه های توضیح داده شده در زیر، کاهش اضافی را در تخصیص دهنده فعال یا غیرفعال کنید.

سفارشی سازی

برخی از پارامترهای تخصیص دهنده را می توان بر اساس هر فرآیند از چند راه تعریف کرد:

  • Statically: یک تابع __scudo_default_options را در برنامه تعریف کنید که رشته گزینه ها را برای تجزیه برمی گرداند. این تابع باید نمونه اولیه زیر را داشته باشد: extern "C" const char *__scudo_default_options() .
  • به صورت پویا: از متغیر محیطی SCUDO_OPTIONS که شامل رشته گزینه هایی است که باید تجزیه شود استفاده کنید. گزینه‌هایی که به این روش تعریف می‌شوند، هر تعریفی را که از طریق __scudo_default_options ایجاد شده است، لغو می‌کنند.

گزینه های زیر در دسترس هستند.

گزینه 64 بیت پیش فرض 32 بیت پیش فرض شرح
QuarantineSizeKb 256 64 اندازه (به کیلوبایت) قرنطینه مورد استفاده برای به تاخیر انداختن تخصیص واقعی تکه ها. مقدار کمتر ممکن است استفاده از حافظه را کاهش دهد اما اثربخشی کاهش را کاهش دهد. یک مقدار منفی به حالت پیش فرض برمی گردد. صفر کردن این و ThreadLocalQuarantineSizeKb قرنطینه را به طور کامل غیرفعال می کند.
QuarantineChunksUpToSize 2048 512 اندازه (بر حسب بایت) که تکه ها را تا آن حد می توان قرنطینه کرد.
ThreadLocalQuarantineSizeKb 64 16 اندازه (به کیلوبایت) حافظه نهان در هر رشته برای تخلیه قرنطینه جهانی استفاده می شود. مقدار کمتر ممکن است استفاده از حافظه را کاهش دهد اما ممکن است مشاجره در قرنطینه جهانی را افزایش دهد. صفر کردن این و QuarantineSizeKb را به طور کامل غیرفعال می کند.
DeallocationTypeMismatch false false گزارش خطا در malloc/delete، new/free، new/delete[]
DeleteSizeMismatch true true گزارش خطا در مورد عدم تطابق بین اندازه های جدید و حذف را فعال می کند.
ZeroContents false false محتویات قطعه صفر را در تخصیص و تخصیص فعال می کند.
allocator_may_return_null false false مشخص می کند که تخصیص دهنده می تواند در صورت بروز خطای قابل بازیابی، به جای خاتمه دادن به فرآیند، null را برگرداند.
hard_rss_limit_mb 0 0 هنگامی که RSS فرآیند به این حد می رسد، فرآیند خاتمه می یابد.
soft_rss_limit_mb 0 0 هنگامی که RSS فرآیند به این حد می رسد، تخصیص های بیشتر با شکست مواجه می شوند یا null برمی گردند (بسته به مقدار allocator_may_return_null )، تا زمانی که RSS به پایین برود تا امکان تخصیص های جدید فراهم شود.
allocator_release_to_os_interval_ms N/A 5000 فقط بر یک تخصیص دهنده 64 بیتی تأثیر می گذارد. اگر تنظیم شود، سعی می کند حافظه استفاده نشده را در سیستم عامل آزاد کند، اما نه بیشتر از این فاصله زمانی (بر حسب میلی ثانیه). اگر مقدار منفی باشد، حافظه در سیستم عامل آزاد نمی شود.
abort_on_error true true در صورت تنظیم، ابزار پس از چاپ پیام خطا به جای _exit() abort() را فراخوانی می کند.

اعتبار سنجی

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

عیب یابی

اگر مشکلی غیر قابل بازیابی تشخیص داده شود، تخصیص دهنده پیام خطا را به توصیفگر خطای استاندارد نمایش می دهد و سپس فرآیند را خاتمه می دهد. ردپای پشته ای که منجر به خاتمه می شود در گزارش سیستم اضافه می شود. خروجی معمولاً با Scudo ERROR: پس از آن یک خلاصه کوتاه از مشکل به همراه هر نشانگر ارائه می شود.

در اینجا لیستی از پیام های خطای فعلی و دلایل احتمالی آنها آمده است:

  • corrupted chunk header : تأیید جمع‌بندی بررسی سرصفحه قطعه ناموفق بود. این احتمالاً به دلیل یکی از دو چیز است: سرصفحه بازنویسی شده است (جزئی یا کامل)، یا نشانگر ارسال شده به تابع یک تکه نیست.
  • race on chunk header : دو رشته مختلف در حال تلاش برای دستکاری یک هدر در یک زمان هستند. این معمولاً نشانه وضعیت مسابقه یا عدم قفل کلی هنگام انجام عملیات روی آن قطعه است.
  • invalid chunk state : قطعه در حالت مورد انتظار برای یک عملیات مشخص نیست، به عنوان مثال، هنگام تلاش برای آزاد کردن آن تخصیص داده نمی شود، یا هنگام تلاش برای بازیافت آن قرنطینه نمی شود. دو برابر رایگان دلیل معمولی برای این خطا است.
  • misaligned pointer : الزامات تراز اساسی به شدت اعمال می شود: 8 بایت در سیستم عامل های 32 بیتی و 16 بایت در سیستم عامل های 64 بیتی. اگر اشاره گر ارسال شده به توابع ما با آن ها مطابقت نداشته باشد، نشانگر ارسال شده به یکی از توابع از تراز خارج می شود.
  • allocation type mismatch : هنگامی که این گزینه فعال است، یک تابع توزیع فراخوانی شده روی یک قطعه باید با نوع تابعی که برای تخصیص فراخوانی شده است مطابقت داشته باشد. این نوع عدم تطابق می تواند مسائل امنیتی را ایجاد کند.
  • invalid sized delete : هنگامی که از اپراتور حذف با اندازه C++14 استفاده می‌شود، و بررسی اختیاری فعال است، بین اندازه‌ای که هنگام انتقال یک تکه ارسال شده و اندازه درخواست شده هنگام تخصیص آن ناسازگاری وجود دارد. این معمولاً یک مشکل کامپایلر یا یک سردرگمی نوع در شیء در حال واگذاری است.
  • RSS limit exhausted تمام شده است: از حداکثر RSS تعیین شده به صورت اختیاری فراتر رفته است.

اگر در حال رفع اشکال در خود سیستم عامل هستید، می توانید از ساخت سیستم عامل HWASan استفاده کنید. اگر در حال رفع اشکال یک خرابی در یک برنامه هستید، می‌توانید از ساخت برنامه HWASan نیز استفاده کنید.