مقاوم‌سازی چارچوب رسانه

برای بهبود امنیت دستگاه، Android 7.0 فرایند یکپارچه mediaserver را به چند فرایند با اجازه‌ها و قابلیت‌هایی که فقط به موارد موردنیاز هر فرایند محدود شده‌اند تقسیم می‌کند. این تغییرات آسیب‌پذیری‌های امنیتی چارچوب رسانه را ازطریق موارد زیر کاهش می‌دهد:

  • تقسیم مؤلفه‌های خط لوله صوتی-تصویری به فرایندهای محدودشده ویژه برنامه.
  • فعال کردن مؤلفه‌های رسانه‌ای قابل‌به‌روزرسانی (استخراج‌کننده‌ها، کدک‌ها، و غیره).

این تغییرات همچنین با کاهش قابل‌توجه شدت اکثر آسیب‌پذیری‌های امنیتی مربوط به رسانه، امنیت کاربران نهایی را بهبود می‌بخشد و دستگاه‌ها و داده‌های کاربران نهایی را ایمن نگه می‌دارد.

تولیدکنندگان تجهیزات اصلی و فروشندگان SoC باید HAL و تغییرات چارچوب خود را به‌روز کنند تا آن‌ها را با معماری جدید سازگار کنند. به‌طور دقیق‌تر، ازآنجایی‌که کد Android ارائه‌شده توسط فروشنده اغلب فرض می‌کند همه چیز در یک فرایند اجرا می‌شود، فروشندگان باید کد خود را به‌روز کنند تا دسته‌های بومی (native_handle) را که در فرایندهای مختلف معنا دارند منتقل کنند. برای پیاده‌سازی مرجع تغییرات مربوط به ایمن‌سازی رسانه، به frameworks/av و frameworks/native مراجعه کنید.

تغییرات معماری

نسخه‌های قبلی Android از یک فرایند واحد و یکپارچه mediaserver با اجازه‌های بسیار زیاد (دسترسی به دوربین، دسترسی به صدا، دسترسی به درایور ویدیو، دسترسی به فایل، دسترسی به شبکه، و غیره) استفاده می‌کردند. ‫Android نسخه ۷.0 فرایند mediaserver را به چند فرایند جدید تقسیم می‌کند که هرکدام به مجموعه اجازه‌های بسیار کوچک‌تری نیاز دارند:

مقاوم‌سازی mediaserver

شکل ۱. تغییرات معماری برای مستحکم‌سازی سرور رسانه

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

توجه: به‌دلیل وابستگی‌های فروشنده، برخی‌از کدک‌ها همچنان در mediaserver اجرا می‌شوند و درنتیجه اجازه‌های بیشتری از حد لازم به mediaserver اعطا می‌کنند. به‌طور خاص، Widevine Classic در mediaserver برای Android 7.0 همچنان اجرا می‌شود.

تغییرات MediaServer

در Android 7.0، فرایند mediaserver برای هدایت بازپخش و ضبط وجود دارد، مثلاً ارسال و همگام‌سازی میان‌گیرها بین مؤلفه‌ها و فرایندها. فرایندها ازطریق سازوکار استاندارد Binder با یکدیگر ارتباط برقرار می‌کنند.

در جلسه بازپخش فایل محلی استاندارد، برنامه توصیف‌گر فایل (FD) را به mediaserver (معمولاً ازطریق MediaPlayer Java API) ارسال می‌کند و mediaserver:

  1. ‫FD را در شیء Binder DataSource می‌پیچد که به استخراج‌کننده پردازش ارسال می‌شود و از آن برای خواندن فایل بااستفاده از Binder IPC استفاده می‌کند. (mediaextractor‏ FD را دریافت نمی‌کند، بلکه برای دریافت داده‌ها با mediaserver تماس‌های Binder برقرار می‌کند.)
  2. فایل را بررسی می‌کند، استخراج‌کننده مناسب را برای نوع فایل ایجاد می‌کند (مثلاً MP3Extractor یا MPEG4Extractor)، و میانای Binder را برای استخراج‌کننده به فرایند mediaserver برمی‌گرداند.
  3. برای تعیین نوع داده‌های موجود در فایل (برای نمونه، داده‌های MP3 یا H.264)، تماس‌های Binder IPC با استخراج‌کننده برقرار می‌کند.
  4. برای ایجاد کدک‌های نوع موردنیاز، فرایند mediacodec را فرا می‌خواند؛ واسط‌های Binder را برای این کدک‌ها دریافت می‌کند.
  5. برای خواندن نمونه‌های کدبندی‌شده، تماس‌های مکرر Binder IPC با استخراج‌کننده برقرار می‌کند، از Binder IPC برای ارسال داده‌های کدبندی‌شده به فرایند mediacodec برای رمزگشایی استفاده می‌کند، و داده‌های رمزگشایی‌شده را دریافت می‌کند.

در برخی‌از موارد استفاده، هیچ کدکی دخیل نیست (مانند بازپخش بارگذاری‌نشده که در آن داده‌های کدبندی‌شده مستقیماً به دستگاه خروجی ارسال می‌شود)، یا کدک ممکن است داده‌های کدگشایی‌شده را مستقیماً به‌جای برگرداندن میان‌گیر داده‌های کدگشایی‌شده (بازپخش ویدیو) ارائه دهد.

تغییرات MediaCodecService

سرویس کدک جایی است که کدبندها و کدگشاها در آن قرار دارند. به‌دلیل وابستگی‌های فروشنده، هنوز همه کدک‌ها در فرایند کدک وجود ندارند. در Android 7.0:

  • رمزگشاهای غیرایمن و کدبندهای نرم‌افزاری در فرایند کدک قرار دارند.
  • رمزگشاهای امن و کدبندهای سخت‌افزاری در mediaserver (بدون تغییر) قرار دارند.

برنامه‌ای (یا mediaserver) فرایند کدک را برای ایجاد کدک از نوع موردنیاز فرا می‌خواند، سپس آن کدک را برای انتقال داده‌های کدبندی‌شده و بازیابی داده‌های کدگشایی‌شده (برای کدگشایی) یا برای انتقال داده‌های کدگشایی‌شده و بازیابی داده‌های کدبندی‌شده (برای کدبندی) فرا می‌خواند. انتقال داده به و از کدک‌ها ازقبل از حافظه مشترک استفاده می‌کند، بنابراین این فرایند تغییری نکرده است.

تغییرات MediaDrmServer

از سرور DRM هنگام پخش محتوای محافظت‌شده با DRM، مانند فیلم‌ها در «فیلم‌های Google Play»، استفاده می‌شود. این سرویس رمزگشایی داده‌های رمزگذاری‌شده را به‌روش ایمن انجام می‌دهد، و به همین دلیل به فضای ذخیره‌سازی گواهینامه و کلید و دیگر عناصر حساس دسترسی دارد. به‌دلیل وابستگی به فروشنده، فرایند DRM هنوز در همه موارد استفاده نمی‌شود.

تغییرات AudioServer

فرایند AudioServer میزبان مؤلفه‌های مرتبط با صدا مثل ورودی و خروجی صدا، سرویس policymanager که مسیریابی صدا را تعیین می‌کند، و سرویس رادیو FM است. برای جزئیات مربوط به تغییرات «صوتی» و راهنمایی‌های پیاده‌سازی، به پیاده‌سازی صوتی مراجعه کنید.

تغییرات CameraServer

CameraServer دوربین را کنترل می‌کند و هنگام ضبط ویدیو برای دریافت فریم‌های ویدیو از دوربین و سپس ارسال آن‌ها به mediaserver برای پردازش بیشتر استفاده می‌شود. برای جزئیات تغییرات و راهنمایی‌های پیاده‌سازی تغییرات CameraServer، به مستحکم‌سازی چارچوب دوربین مراجعه کنید.

تغییرات ExtractorService

سرویس استخراج‌کننده میزبان استخراج‌کننده‌ها است، مؤلفه‌هایی که قالب‌های فایل مختلف پشتیبانی‌شده توسط چارچوب رسانه را تجزیه می‌کنند. سرویس استخراج‌کننده کمترین امتیاز را در میان همه سرویس‌ها دارد—نمی‌تواند FD را بخواند، بنابراین به‌جای آن، برای دسترسی به فایل‌ها، با میانای Binder (که توسط mediaserver for در هر جلسه بازپخش ارائه می‌شود) تماس می‌گیرد.

برنامه‌ای (یا mediaserver) برای دریافت IMediaExtractor با فرایند استخراج‌کننده تماس می‌گیرد، با IMediaExtractor تماس می‌گیرد تا IMediaSources را برای قطعه موجود در فایل دریافت کند، و سپس با IMediaSources تماس می‌گیرد تا داده‌ها را از آن بخواند.

برای انتقال داده‌ها بین فرایندها، برنامه (یا mediaserver) داده‌ها را در «بسته» پاسخ به‌عنوان بخشی از تراکنش Binder قرار می‌دهد یا از حافظه مشترک استفاده می‌کند:

  • استفاده از حافظه مشترک به فراخوانی Binder اضافی برای آزاد کردن حافظه مشترک نیاز دارد اما برای بافرهای بزرگ سریع‌تر است و از توان کمتری استفاده می‌کند.
  • استفاده از in-Parcel به کپی کردن اضافی نیاز دارد اما سریع‌تر است و برای میان‌گیرهای کوچک‌تر از ۶۴ کیلوبایت از انرژی کمتری استفاده می‌کند.

پیاده‌سازی

برای پشتیبانی از انتقال مؤلفه‌های MediaDrm و MediaCrypto به فرایند جدید mediadrmserver، فروشندگان باید روش تخصیص میان‌گیرهای امن را تغییر دهند تا میان‌گیرها بتوانند بین فرایندها هم‌رسانی شوند.

در نسخه‌های پخش قبلی Android، بافرهای امن در mediaserver توسط OMX::allocateBuffer تخصیص داده می‌شوند و درطول رمزگشایی در همان فرایند استفاده می‌شوند، همان‌طور که در زیر نشان داده شده است:

شکل ۲. اختصاص میان‌گیر Android 6.0 و پایین‌تر در mediaserver.

در Android 7.0، فرایند تخصیص بافر به سازوکار جدیدی تغییر کرده است که ضمن ارائه انعطاف‌پذیری، تأثیر آن بر پیاده‌سازی‌های موجود را به حداقل می‌رساند. با MediaDrm و MediaCrypto پشته در فرایند جدید mediadrmserver، بافرها به‌صورت متفاوت تخصیص داده می‌شوند و فروشندگان باید دسته‌های بافر امن را به‌روز کنند تا بتوانند وقتی MediaCodec عملیات رمزگشایی را روی MediaCrypto فرا می‌خواند، در سراسر پیونددهنده منتقل شوند.

شکل ۳. اختصاص میان‌گیر Android نسخه ۷.۰ و بالاتر در mediaserver.

استفاده از نام‌های کاربری بومی

‫OMX::allocateBuffer باید اشاره‌گری به ساختار native_handle برگرداند که حاوی توصیف‌گرهای فایل (FDs) و داده‌های عدد صحیح اضافی است. ‫native_handle همه مزایای استفاده از FDs را دارد، ازجمله پشتیبانی از پوشه موجود برای سریال‌سازی/واسریال‌سازی، و درعین‌حال انعطاف‌پذیری بیشتری برای فروشندگانی که درحال‌حاضر از FDs استفاده نمی‌کنند فراهم می‌کند.

از native_handle_create() برای تخصیص نام کاربری بومی استفاده کنید. کد چارچوب مالکیت native_handle ساختار تخصیص‌یافته را می‌پذیرد و مسئولیت انتشار منابع را هم در فرایندی که native_handle در آن ابتدا تخصیص داده شده است و هم در فرایندی که در آن واسرشته شده است برعهده می‌گیرد. چارچوب، دسته‌های بومی را با native_handle_close() و سپس native_handle_delete() منتشر می‌کند و native_handle را بااستفاده از Parcel::writeNativeHandle()/readNativeHandle() سریالی/غیرسریالی می‌کند.

فروشندگان SoC که از FD برای نمایش میانگیرهای امن استفاده می‌کنند می‌توانند FD را در native_handle با FD خودشان پر کنند. فروشندگانی که از «فایل‌های داده» استفاده نمی‌کنند می‌توانند بااستفاده از فیلدهای اضافی در native_buffer، بافرهای امن را نشان دهند.

تنظیم مکان رمزگشایی

فروشندگان باید روش رمزگشایی OEMCrypto را که روی native_handle کار می‌کند به‌روز کنند تا هرگونه عملیات خاص فروشنده لازم برای قابل‌استفاده کردن native_handle در فضای فرایند جدید را انجام دهند (تغییرات معمولاً شامل به‌روزرسانی کتابخانه‌های OEMCrypto می‌شود).

As allocateBuffer is a standard OMX operation, Android 7.0 includes a new OMX extension (OMX.google.android.index.allocateNativeHandle) to query for this support and an OMX_SetParameter call that notifies the OMX implementation it should use native handles.