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

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

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

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

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

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

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

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

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

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

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

MediaServer تغییر می کند

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

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

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

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

MediaCodecService تغییر می کند

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

  • رمزگشاها و رمزگذارهای نرم افزاری غیر ایمن در فرآیند کدک زندگی می کنند.
  • رمزگشاهای ایمن و رمزگذارهای سخت افزاری در 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_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 اطلاع می دهد که باید از دسته های بومی استفاده کند.