سخت شدن چارچوب رسانه ای

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

  • تقسیم اجزای خط لوله AV به فرآیندهای جعبه ایمنی مخصوص برنامه.
  • فعال کردن اجزای رسانه ای قابل به روز رسانی (استخراج کننده ها، کدک ها و غیره).

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

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

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

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

سخت شدن مدیا سرور

شکل 1. تغییرات معماری برای سخت شدن مدیا سرور

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

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

MediaServer تغییر می کند

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

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

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

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

MediaCodecService تغییر می کند

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

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

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

MediaDrmServer تغییر می کند

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

AudioServer تغییر می کند

فرآیند AudioServer اجزای مرتبط با صدا مانند ورودی و خروجی صدا، سرویس Policymanager که مسیریابی صدا را تعیین می‌کند و سرویس رادیو FM را میزبانی می‌کند. برای جزئیات در مورد تغییرات صوتی و راهنمای پیاده سازی، به پیاده سازی صدا مراجعه کنید.

CameraServer تغییر می کند

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

ExtractorService تغییراتی دارد

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

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

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

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

پیاده سازی

برای حمایت از انتقال مولفه های MediaDrm و MediaCrypto به فرآیند جدید mediadrmserver ، فروشندگان باید روش تخصیص بافرهای امن را تغییر دهند تا بافرها بتوانند بین فرآیندها به اشتراک گذاشته شوند.

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

شکل 2. اندروید 6.0 و تخصیص بافر پایین تر در مدیا سرور.

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

شکل 3. تخصیص بافر اندروید 7.0 و بالاتر در مدیا سرور.

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

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

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

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

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

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

از آنجایی که allocateBuffer یک عملیات استاندارد OMX است، Android 7.0 شامل یک افزونه OMX جدید ( OMX.google.android.index.allocateNativeHandle ) برای درخواست این پشتیبانی و یک فراخوانی OMX_SetParameter است که به اجرای OMX اطلاع می دهد که باید از دسته های بومی استفاده کند.