امروزه مجازیسازی تودرتو (Nested virtualization) به طور گسترده توسط تأمینکنندگان اصلی خدمات ابری پشتیبانی میشود و به کاربران امکان میدهد از فناوریهای مبتنی بر مجازیسازی در فضای ابری بهرهمند شوند. با این حال، پشتیبانی از مجازیسازی تودرتو به طور قابل توجهی بر پیچیدگی هایپروایزر (hypervisor) میزبان میافزاید و سطح حمله جدیدی را در بسترهای ابری ایجاد میکند. اگرچه پژوهشهای پیشین متعددی فازینگ هایپروایزرها را مورد بررسی قرار دادهاند، اما هیچکدام به طور مشخص به مسئله مجازیسازی تودرتو نپرداختهاند. علت این امر چالش تولید نمونههای مؤثر از ماشینهای مجازی با فضای حالت (state space) گسترده به عنوان ورودیهای فازینگ است.
ما در این مقاله، NecoFuzz را ارائه میدهیم: اولین چارچوب فازینگ که به طور سیستماتیک منطق مختص مجازیسازی تودرتو را در هایپروایزرها هدف قرار میدهد. NecoFuzz با هدایت یک مدل تقریبی از مشخصات مجازیسازی مبتنی بر سختافزار، ماشینهای مجازی مهار فاز (fuzz-harness VM) قابل اجرایی را سنتز میکند که وضعیت داخلی آنها در مرز میان حالت معتبر و نامعتبر قرار دارد. از آنجا که آسیبپذیریها در مجازیسازی تودرتو اغلب ناشی از مدیریت نادرست وضعیتهای غیرمنتظره ماشین مجازی هستند، این رویکرد تولید مرزگرا با هدایت مشخصات، به طور قابل توجهی پوشش کدهای حیاتی امنیتی را در هایپروایزرهای مختلف بهبود میبخشد.
ما NecoFuzz را بر روی Intel VT-x و AMD-V با گسترش ++AFL برای پشتیبانی از ماشینهای مجازی مهار فاز پیادهسازی کردیم. NecoFuzz به ترتیب به ۸۴٫۷٪ و ۷۴٫۲٪ پوشش کد برای کدهای مختص مجازیسازی تودرتو در Intel VT-x و AMD-V دست یافت و شش آسیبپذیری ناشناخته قبلی را در سه هایپروایزر مختلف کشف کرد که دو مورد از آنها دارای شناسه CVE هستند.
1. مقدمه
مجازیسازی تودرتو به یکی از ویژگیهای مهم در رایانش ابری مدرن تبدیل شده است. در حالی که مجازیسازی سنتی ویژگیهای ضروری بسترهای ابری را امکانپذیر میسازد، مجازیسازی تودرتو فناوریهای مبتنی بر مجازیسازی را برای کاربران ابر باز میکند و طیف گستردهای از موارد استفاده مانند امنیت پیشرفته، مهاجرت سامانههای قدیمی و بازیابی رخداد را امکانپذیر میسازد ]۱۶، ۲۲، ۳۱، ۳۲، ۴۸[. از زمان پشتیبانی اولیه آن در سال ۲۰۱۷، مجازیسازی تودرتو توسط چندین تأمینکننده اصلی ابر [۲، ۱۸، ۳۳، ۴۳] به کار گرفته شده است و اکنون به عنوان واحد اصلی سازنده ماشینهای مجازی محرمانه مبتنی بر Intel TDX در مایکروسافت آژور (Microsoft Azure) عمل میکند [۳۰]. در نتیجه، این فناوری به یک ویژگی قابل دسترس تجاری در خدمات ابر عمومی تبدیل شده است.
متأسفانه، مجازیسازی تودرتو سطح حمله جدیدی را در پلتفرمهای ابری ایجاد میکند. برای پشتیبانی از مجازیسازی تودرتو، هایپروایزرهای میزبان باید یک رابط مجازیسازی با کمک سختافزار، مانند Intel VT-x [20] یا AMD-V [1]، را در اختیار هایپروایزرهای مهمان که در داخل ماشینهای مجازی کاربر اجرا میشوند، قرار دهند. از آنجایی که CPU های فعلی به طور طبیعی از مجازیسازی تودرتو پشتیبانی نمیکنند، هایپروایزرهای میزبان باید رابط را در نرمافزار مجدداً مجازیسازی کنند [5].
مجازیسازی مبتنی بر سختافزار پیشتر در محیطهای غیرتودرتو به عنوان فناوری پیچیده و خطاخیز شناخته شده است [4]. مجازیسازی مجدد آن، بار پیادهسازی را بیشتر افزایش میدهد و نیاز به مدیریت دقیق رفتارهای پیچیده و موارد ظریف دارد. حتی با پشتیبانی سختافزاری پیشرفته برای مجازیسازی تودرتو [24، 56]، مدیریت ایمن رابط کاربری در عمل همچنان دشوار است. در واقع، طی چند سال گذشته آسیبپذیریهای متعددی در کد مجازیسازی تودرتو کشف شده است [34-40]. با توجه به استقرار آن در پلتفرمهای ابری عملیاتی، چنین آسیبپذیریهایی خطرات جدی برای زیرساختهای ابری، از جمله به خطر افتادن احتمالی هایپروایزرهای میزبان (host) و مستاجران هممکان (co-located tenants)، ایجاد میکنند. فازینگ یک تکنیک مؤثر برای کشف آسیبپذیریهای امنیتی است و بسیاری از مطالعات، کاربرد آن را در هایپروایزرها بررسی کردهاند.
با این حال، هیچ یک از آنها به صراحت به مجازیسازی تودرتو نمیپردازند و رابط مجازیسازی با کمک سختافزار را کاملاً آزمایش نشده باقی میگذارند. به عنوان مثال، اکثر فازینگ هایپروایزرهای قبلی، رابطهای ورودی/خروجی مانند ورودی/خروجی قابل برنامهریزی PIO، ورودی/خروجی نگاشت شده با حافظه MMIO یا DMA را هدف قرار میدهند [7،8،19، 26، 44، 49، 50]. این رویکردهای مبتنی بر ورودی/خروجی به هیچ وجه به رابط مجازیسازی تودرتو دسترسی ندارند، که از طریق دستورالعملهای اختصاصی CPU قابل دسترسی است. مطالعات دیگر، فازینگ را از طریق جریانهای دستورالعمل بررسی کردهاند و شبیهسازهای CPU و منطق مدیریت دستورالعمل آنها را هدف قرار دادهاند [3، 9، 13، 15، 27-29]. با این حال، این مطالعات نیز دستورالعملهای مجازیسازی با کمک سختافزار را که بر روی حالتهای ساختاریافته ماشین مجازی عمل میکنند و نیاز به هماهنگی در سطح هایپروایزر دارند، پوشش نمیدهند. فازینگ درایور دستگاه [46، 51، 57] ماژولهای هسته سیستم عامل را که در لایه و رابطی متفاوت از هایپروایزر عمل میکنند، تمرین میدهد.
چالش کلیدی در ورودی فازینگ مجازیسازی تودرتو نهفته است. از آنجایی که مجازیسازی تودرتو شامل اجرای یک VMin در داخل یک ماشین مجازی دیگر است، ورودی یک نمونه کامل ماشین مجازی است نه مقادیر ساده. رابطهای مجازیسازی با کمک سختافزار معمولاً هنگام اجرای یک نمونه ماشین مجازی، یک حالت ماشین مجازی را به عنوان آرگومان برای دستورالعملهای ویژه CPU میگیرند. یک حالت ماشین مجازی شامل چندین کیلوبایت داده است که نشاندهنده حالت داخلی CPU مجازی vCPU است و یک فضای حالت وسیع را تشکیل میدهد که به حالتهای معتبر و نامعتبر تقسیم میشود، جایی که مرز آن توسط محدودیتهای پیچیده در بسیاری از فیلدهای وابسته به هم تعیین میشود.
این فضای حالت عظیم، همراه با این محدودیتها، تولید حالت مؤثر ماشین مجازی از طریق مقادیر تصادفی را بسیار غیرعملی میکند. حتی هنگام شروع از یک بذر طلایی معتبر [51]، مکانها و جهتهای متعددی در حالت ماشین مجازی برای جهش وجود دارد و تعیین استراتژیهای جهش مؤثر، امری بدیهی نیست. آزمایش نمادین و کانکولیک نیز با این فضای حالت وسیع با مشکلاتی روبرو هستند، حتی اگر برای پایگاههای کد مجازیسازی تودرتو کوچک مؤثر به نظر برسند.
در این مقاله، ما NecoFuzz را معرفی میکنیم؛ نخستین فریمورک فازینگ برای مجازیسازی تودرتو. NecoFuzz نمونههای کامل ماشین مجازی (VM) را تولید میکند که «ماشینهای مجازی فاز هارنس یا fuzz-harness VMs » نامیده میشوند. وضعیتهای داخلی این ماشینها متنوع بوده، اما عمداً نزدیک به مرز میان پیکربندیهای معتبر و نامعتبر قرار دارند تا بتوانند بهطور مؤثر رفتارهای مستعد خطای هایپروایزر را فعال کنند.
این سامانه از اعتبارسنجهای وضعیت ماشین مجازی (VM state validators) استفاده میکند که مشخصات مجازیسازیِ مبتنی بر سختافزار را مدلسازی میکنند تا این مرز را بهصورت کارآمد کاوش کند. برای مقابله با پیچیدگیها و بخشهای مستندسازینشدهٔ این مشخصات، NecoFuzz وضعیتهای تولیدشده را روی CPUهای واقعی بررسی میکند و از رفتار سختافزار بهعنوان مرجع صحیح بهره میگیرد تا نادرستیهای مدلسازی را در زمان اجرا شناسایی و اصلاح کند.
NecoFuzz به منظور افزایش پوشش، پیکربندیهای vCPU را که از طریق رابطهای کاربری کنترل میشوند، دستخوش جهش (mutation) میکند. برای پر کردن این شکاف، از یک پیکربندیکنندهٔ vCPU در سمت میزبان (host) استفاده میشود. NecoFuzz ناهنجاریها را از طریق ابزارهای سنتی تایزر (sanitizer) و پایش لاگها شناسایی میکند و بخشهایی از کد مجازیسازی تودرتو را هدف قرار میدهد که در پژوهشهای پیشین بهخوبی آزمایش نشدهاند. با ترکیب این قابلیتها، این فریمورک امکان فازینگ عملیِ این سطح حملهٔ پیشتر کاوش نشده را فراهم میکند.
ما NecoFuzz را بر روی Intel VT-x و AMD-V پیادهسازی کردیم. ماشین مجازی مهار فاز به صورت یک باینری UEFI منفرد ساختار یافته است که بر روی هایپروایزر میزبان بوت (Boot) میشود، مجازیسازی مبتنی بر سختافزار را به عنوان یک هایپروایزر مهمان مقداردهی اولیه میکند و یک ماشین مجازی مهمان تودرتو را راهاندازی میکند. اعتبارسنج با استفاده از کد شبیهساز پردازنده استخراج شده از Bochs [۵۳] ساخته شده است، و پیکربندیکننده vCPU به صورت یک اسکریپت (script) پیادهسازی شده است که گزینههای vCPU را از طریق پارامترهای خط فرمان تنظیم میکند. از آنجا که فازرهای هایپروایزر موجود نمیتوانند نمونههای کامل ماشین مجازی را در خود جای دهند، ما AFL++ [12] را گسترش دادیم تا با ماشین مجازی فاز هارنس (fuzz-harness) تعامل کرده و مسیرهای کد مجازیسازی تودرتو را در هایپروایزر میزبان کاوش کند.
ما NecoFuzz را روی KVM (نسخهٔ Linux 6.5) ارزیابی کردیم تا میزان پوشش کدِ (code coverage) بخشهای ویژهٔ مجازیسازی تودرتو اندازهگیری شود. بهعنوان مبنا، از Syzkaller [17] (commit 96a211b)، که تنها فازرِ موجود با پشتیبانی از مجازیسازی تودرتو است، و همچنین IRIS [9]، یک فازر پیشرفته برای هایپروایزر Xen که بهطور صریح از مجازیسازی تودرتو پشتیبانی نمیکند و به پردازندههای Intel محدود است، استفاده کردیم.
NecoFuzz توانست به پوشش 84.7٪ در Intel VT-x و 74.2٪ در AMD-V دست یابد که بهترتیب نشاندهندهٔ بهبود 1.4 برابری و 11.0 برابری نسبت به Syzkaller در Intel VT-x و AMD-V، و همچنین بهبود 1.6 برابری نسبت به IRIS در Intel VT-x است. این بهبود از طریق دسترسی خودکار به وضعیتهای مرزیِ مشخصات (specification-boundary states) حاصل شد.
همچنین NecoFuzz را روی Xen و VirtualBox ارزیابی کردیم تا کارایی آن در کشف آسیبپذیریها بررسی شود. این ابزار موفق شد شش آسیبپذیری ناشناختهٔ پیشین را در میان سه هایپروایزر شناسایی کند که همگی توسط توسعهدهندگان تأیید شدند. چهار مورد از آنها اصلاح شدهاند و برای دو مورد شناسهٔ CVE اختصاص داده شده است [41، 42]. علاوه بر این، در طی توسعهٔ اعتبارسنجها، دو باگ نیز در Bochs [21] شناسایی و اصلاح شد.
دستاوردهای این مقاله به شرح زیر است:
- ما NecoFuzz را معرفی میکنیم؛ نخستین فریمورک فازینگ که بهصورت نظاممند منطق مجازیسازی تودرتو در هایپروایزرها را هدف قرار میدهد. این کار از طریق تولید نمونههای کامل ماشین مجازی به عنوان ورودی برای رابط مجازیسازی مبتنی بر سختافزار انجام میشود؛ سطح حملهای که در فازرهای پیشین مورد توجه قرار نگرفته بود.
- ما یک مولد ماشین مجازی مستقل از هایپروایزر طراحی میکنیم که متناسب با پیچیدگی ساختاری مجازیسازی تودرتو است. این سامانه با هدایت مشخصات فنی، ماشینهای فاز هارنس (fuzz-harness) را در نزدیکی مرز میان حالتهای معتبر و نامعتبر تولید کرده و پیکربندیهای متنوع vCPU را کاوش میکند.
- ما NecoFuzz را برای Intel VT-x و AMD-V پیادهسازی کرده و چارچوب ++AFL را گسترش میدهیم تا فازینگ کارآمد از طریق ماشینهای مجازی قابل بوت (bootable VMs) بدون نیاز به کد منبع هایپروایزر یا رابطهای syscall امکانپذیر شود.
- ما NecoFuzz را روی KVM، Xen و VirtualBox ارزیابی میکنیم و نشان میدهیم که در مقایسه با ابزارهای موجود (مانند Syzkaller و IRIS) بهبود چشمگیری در پوشش کدِ منطق مجازیسازی تودرتو حاصل میشود. همچنین این ابزار موفق به کشف شش آسیبپذیری ناشناختهٔ پیشین، از جمله دو مورد دارای شناسهٔ CVE، شده است.
2. پیشزمینه
این بخش دانش زمینهای مربوط به مجازیسازی مبتنی بر سختافزار و مجازیسازی تودرتو (nested virtualization) را بهصورت خلاصه مرور میکند.
2.1 مجازیسازی مبتنی بر سختافزار
در مجازیسازی یک CPU برای ایجاد یک ماشین مجازی (VM)، بخش غالب از نظر آماریِ دستورالعملهای پردازنده باید مستقیماً روی سختافزار فیزیکی اجرا شود [45]. برای امکانپذیر شدن این موضوع، دستورالعملهای حساس باید قابلیت به دامافتادن (trap) توسط هایپروایزر را داشته باشند. با این حال، مجموعهدستورالعمل کلاسیک x86 بهطور کامل قابل مجازیسازی نیست، چرا که برخی دستورالعملهای حساس، دارای سطح دسترسی ارتقاء یافته (privileged) نبودند [47].
برای رفع این مشکل، شرکتهای Intel و AMD فناوری مجازیسازی مبتنی بر سختافزار را معرفی کردند که بهترتیب با نامهای Intel VT-x و AMD-V شناخته میشوند. از آنجا که طراحی این دو از نظر مفهومی مشابه است (مگر در مواردی که خلاف آن ذکر شود)، در ادامه از اصطلاحات مربوط به Intel استفاده میکنیم.
در Intel VT-x دو حالت پردازنده معرفی میشود که مستقل از حالتهای موجود هستند: حالت non-root و حالت root. هنگام جابهجایی بین این حالتها،CPU وضعیت داخلی خود را در یک ساختار دادهٔ مقیم حافظه به نام ساختار کنترل ماشین مجازی (VMCS) ذخیره میکند. هایپروایزر با اجرای دستور vmlaunch و استفاده از VMCS متناظر به عنوان ورودی، یک ماشین مجازی را راهاندازی میکند.
توالی دستورالعملهای لازم برای مقداردهی اولیهٔ مجازیسازی مبتنی بر سختافزار تا حد زیادی ثابت است: ابتدا هایپروایزر با استفاده از دستور vmclear یک VMCS را مقداردهی اولیه میکند، سپس با vmptrld پوینتر VMCS را تنظیم مینماید، و مقادیر VMCS را از طریق مجموعهای از دستورهای vmwrite مینویسد. پس از آن، ماشین مجازی با اجرای vmlaunch آغاز میشود که به آن ورود به VM (VM entry) گفته میشود.
زمانی که کنترل از ماشین مجازی به هایپروایزر بازمیگردد، رویدادی که خروج از VM (VM exit) نام دارد، هایپروایزر با استفاده از vmread دلیل خروج را مشخص میکند، وضعیت VM را از طریق vmwrite بهروزرسانی میکند و اجرای ماشین مجازی را با دستور vmresume از سر میگیرد. عدم رعایت این توالی باعث میشود ماشین مجازی هرگز به وضعیت مقداردهیشده و آمادهٔ اجرا نرسد.
شرایط لازم برای وضعیت معتبر یک ماشین مجازی بسیار پیچیده است. برای مثال، VMCS شامل فیلدهای کنترلی با بیتهای رزرو شده است که باید به مقادیر ثابتی تنظیم شوند؛ هر تنظیم نادرست باعث شکست ورود به VM میشود. علاوه بر این، VMCS مقادیر ثباتهای ذخیره شده (register values)، از جمله مقادیر داخلی، را نگهداری میکند که هر کدام تحت محدودیتهای دقیق هستند، هم بهصورت فردی و هم در ترکیب با یکدیگر، تا صحت و امنیت ماشین مجازی تضمین شود. این محدودیتها توسط CPU فیزیکی اعمال میشوند و اگر حتی یکی از آنها نقض شود، ورود به VM ناموفق خواهد بود.
هر نسل جدید از CPU با خود بهبودهایی برای مجازیسازی مبتنی بر سختافزار به همراه دارد. برای مثال، پردازندههای اولیه Intel از nested paging پشتیبانی نمیکردند، که بعدها بهصورت extended page tables (EPT) معرفی شد. اجرای حالت واقعی (real-mode execution) در ابتدا پشتیبانی نمیشد، اما با ویژگی unrestricted guest در دسترس قرار گرفت. در دسترس بودن چنین قابلیتهایی توسط رجیسترهای خاص مدل (MSRs) تعیین میشود.
2.2 مجازیسازی تودرتو
مجازیسازی تودرتو (Nested Virtualization) به یک هایپروایزر مهمان اجازه میدهد تا روی یک هایپروایزر میزبان دیگر اجرا شود. هایپروایزر سطح پایینتر L0 نامیده میشود و هایپروایزر بالاتر L1 است (به شکل ۱ مراجعه شود). سیستمعامل یا ماشین مجازی تحت کنترل هایپروایزر L1 به عنوان L2 شناخته میشود.
هایپروایزر L0 مستقیماً از مجازیسازی مبتنی بر سختافزار ارائهشده توسط CPU فیزیکی استفاده میکند و آن را برای هایپروایزر L1 شبیهسازی میکند. برای این کار، L0 هایپروایزر L1 را در حالت non-root اجرا میکند و رفتار سختافزار را در نرمافزار شبیهسازی مینماید.
شبیهسازی VMCSها بهویژه پیچیده است. هایپروایزر L1 فرض میکند که مستقیماً با سختافزار در تعامل است و برای هر مهمان L2 خود یک VMCS نگهداری میکند که VMCS12 نامیده میشود. با این حال، VMCS12 توسط سختافزار شناسایی نمیشود و باید توسط L0 شبیهسازی گردد.
برای اجرای L1، L0 از VMCS01 استفاده میکند، جایی که L0 میزبان و L1 مهمان است. بهطور مشابه، برای اجرای L2، از VMCS02 استفاده میشود، که در آن L0 میزبان و L2 مهمان است. L0 بین VMCS01 و VMCS02 جابهجا میشود تا جابهجایی حالت بین L1 و L2 را شبیهسازی کند.
برای شبیهسازی صحیح VMCSها، L0 باید محتوای آنها را همگامسازی کند و این کار را با تفسیر فیلدهای VMCS و ترجمهٔ آنها میان VMCS12، VMCS01 و VMCS02 انجام دهد. علاوه بر این، باید بررسیهای امنیتی و اطمینان از سازگاری که توسط CPU انجام میشود را نیز شبیهسازی کند.
برای مثال، L0 باید از این که L1 بتواند VMCS12 را طوری پیکربندی کند که به ناحیه حافظهٔ L0 دسترسی پیدا کند، جلوگیری نماید. همچنین، وضعیت داخلی شبیهسازیشده توسط L0 باید با وضعیت واقعی VMCS در سختافزار همخوانی داشته باشد. برای نمونه، CPU ممکن است مقادیر نادرست فیلدها را بهطور غیرمستقیم اصلاح کند، و L0 باید این رفتار را دقیقاً شبیهسازی نماید.
علاوه بر این، قابلیتهای مجازیسازی مبتنی بر سختافزار که در اختیار ماشین مجازی L1 قرار دارد، به پیکربندی vCPU بستگی دارد. در حالی که L0 برخی قابلیتها را در نرمافزار شبیهسازی میکند، وضعیت نرمافزار و سختافزار به هم وابسته هستند. بنابراین، زمانی که یک قابلیت در پیکربندی vCPU غیرفعال باشد، L0 باید اطمینان حاصل کند که رفتار ماشین مجازی با سختافزار زیرین سازگار و همخوان باشد.
3. طراحی
این بخش طراحی NecoFuzz را توضیح میدهد. ابتدا مدل تهدید ارائه میشود، سپس نمای کلی NecoFuzz بیان شده و در ادامه سه مؤلفهٔ اصلی آن تشریح میگردد.
۳.۱ مدل تهدید
ما یک محیط ابری را فرض میکنیم که در آن ارائهدهنده، هایپروایزر L0 را مدیریت میکند و مهاجم به یک نمونهٔ ماشین مجازی دسترسی پیدا میکند. مهاجم کنترل کامل محیط نرمافزاری داخل VM را دارد و قادر است کد دلخواه را اجرا کند.
در این VM، مجازیسازی تودرتو فعال است و مهاجم میتواند دستورالعملهای مجازیسازی مبتنی بر سختافزار را از داخل ماشین اجرا کند. آنها میتوانند برنامههای سفارشی را بهعنوان هایپروایزر L1 و سیستمعامل مهمان L2 اجرا کنند، بدون محدودیت توسط پیادهسازیهای موجود هایپروایزر یا سیستمعامل. مهاجم میتواند دنبالههای دستورالعمل و وضعیتهای VM را ایجاد کند که سیستمهای استاندارد تولید نمیکنند.
تمرکز ما روی هایپروایزر L0 است، زیرا این لایه زیرساخت ابری را پشتیبانی میکند و در محیطهای تولیدی بهکار گرفته میشود. ما به آسیبپذیریهای نرمافزاری که در داخل ماشینهای مجازی اجرا میشوند، صرفنظر از استفاده از مجازیسازی تودرتو، توجه نمیکنیم، زیرا این ماشینها کاملاً تحت کنترل مهاجم هستند.
ما بهطور خاص حملاتی را هدف قرار میدهیم که از رابطهای مجازیسازی مبتنی بر سختافزار در دسترس ماشینهای مهمان سوءاستفاده میکنند. رابطهایی که ارتباط مستقیمی با مجازیسازی تودرتو ندارند، مانند رابطهای دستگاه مجازی (PIO، MMIO، DMA) و hypercalls، از دامنهٔ بررسی خارج هستند.
همچنین رابطهایی که تنها از سمت میزبان قابل فراخوانی هستند، مانند ()ioctl برای مهاجرت زنده (live migration)، شامل بررسی ما نمیشوند، زیرا فرض میکنیم هایپروایزر L0 و سیستمعامل میزبان کاملاً مورد اعتماد ارائهدهندهٔ ابری هستند. کانالهای جانبی، کانالهای مخفی و سایر مسیرهای حملهٔ غیرمستقیم نیز خارج از حوزهٔ این مطالعه قرار دارند.
۳.۲ نمای کلی
NecoFuzz یک مولد ماشین مجازی (VM generator) معرفی میکند که ماشینهای فاز هارنس (fuzz-harness) را بهطور کارآمد تولید میکند و توسط مشخصات مجازیسازی مبتنی بر سختافزار هدایت میشود. این سیستم شامل سه مؤلفه است:
- هارنس اجرای ماشین مجازی (VM execution harness)
- اعتبارسنج وضعیت ماشین مجازی (VM state validator)
- پیکربندی کننده پردازنده مجازی (vCPU configurator)
(نمای کلی آن در شکل ۲ نشان داده شده است). NecoFuzz از یک فازر موجود به عنوان پایه استفاده میکند و آن را برای تولید ورودی دودویی به منظور فازینگ تطبیق میدهد. این ورودی تقسیمبندی شده و به هر مؤلفهٔ مولد VM ارسال میشود تا بخشهای مشخصی از VM فاز هارنس دستخوش جهش (mutation) شوند. برای مثال:
- هارنس اجرای VM، ترتیب اجرای دستورالعملها و پارامترهای داخل VM را تغییر میدهد.
- اعتبارسنج وضعیت VM، مقادیر VMCS را تغییر میدهد تا وضعیتهای متنوع VM تولید شود.
- پیکربندی کننده vCPU، ترکیبهای مختلف ویژگیهای vCPU را دستخوش تغییر میکند.
هایپروایزر L0 روی سختافزار واقعی (bare metal) اجرا میشود، زیرا اجرای آن در محیط مجازی نیازمند مجازیسازی تودرتو دوگانه (یعنی «مجازیسازی سهگانه») است که در عمل بسیار کُند و ناپایدار خواهد بود.
هنگامی که یک باگ یا آسیب پذیری در هایپروایزر L0 در حین فازینگ فعال شود، ممکن است سیستم کرش کند یا پیام خطا تولید شود. برای مدیریت این شرایط و حفظ فازینگ مداوم، NecoFuzz یک مکانیزم watchdog شامل یک ویژگی سختافزاری و یک عامل (agent) داخل L0 را فراهم میکند تا خطاها را شناسایی کرده و هایپروایزر را بهطور خودکار راهاندازی مجدد کند. از آنجا که کرشها نادر هستند، بار اضافه ناشی از راهاندازی مجدد تأثیر چندانی بر کارایی فازینگ ندارد.
۳.۳ هارنس اجرای ماشین مجازی (VM execution harness)
هارنس اجرای ماشین مجازی، اساس و پایه VM فاز هارنس را تشکیل میدهد که نقش هر دو، هایپروایزر L1 و سیستمعامل مهمان L2 را ایفا میکند. این مؤلفه امکان مقداردهی اولیه و اجرای VM روی هایپروایزر L0 را فراهم میکند و بهطور کارآمد رابط مجازیسازی مبتنی بر سختافزار را تمرین میدهد. عملکرد آن در دو فاز انجام میشود: فاز مقداردهی اولیه (initialization) و فاز زمان اجرا (runtime).
در فاز مقداردهی اولیه، هارنس یک دنبالهٔ دستورالعملهای مجازیسازی مبتنی بر سختافزار را به عنوان هایپروایزر L1 اجرا میکند تا ماشین مجازی L2 را مقداردهی کند. همانطور که در بخش ۲.۱ توضیح داده شد، این دنبالهٔ مقداردهی اولیه تا حد زیادی ثابت است و هر انحراف قابل توجهی توسط منطق بررسی خطای هایپروایزر L0 رد میشود، که کمکی به بهبود پوشش کد نمیکند. با این حال، پایبندی صرف به این دنبالهٔ ثابت ممکن است باعث شود آسیب پذیریهای موجود در منطق شبیهسازی مجازیسازی تودرتو نادیده گرفته شوند.
برای رفع این مشکل، یک الگوی دست نویس از دنبالهٔ دستورالعملها آماده شده و با استفاده از ورودی فازینگ تغییر داده میشود. این الگو تنها شامل چند صد خط کد است و نیاز به تلاش زیادی ندارد. با تغییر آرگومانها و ترتیب دستورالعملها، کد شبیهسازی دنبالهٔ مقداردهی اولیه در هایپروایزر L0 بهطور مؤثر فاز میشود. پس از دستیابی به پوشش کافی از این کد، هارنس به فاز زمان اجرا میرود.
در فاز زمان اجرا، هارنس دستورالعملهای CPU را اجرا میکند که باعث VM exit یا خروج از ماشین مجازی به هایپروایزر L0 میشوند. خروج از VM معمولاً توسط یک دستورالعمل منفرد ایجاد میشود که ممکن است چند دستورالعمل آمادهسازی نیاز داشته باشد و با سطح دسترسی L1 یا L2 اجرا شود. برای پشتیبانی از این حالت، الگوهایی برای تمام این دستورالعملها آماده شده است. هارنس با استفاده از ورودی فازینگ، انتخاب و آرگومانهای این الگوها را تغییر داده و آنها را بارها اجرا میکند. این روش بهطور کارآمد باعث ایجاد وضعیت VM exit یا خروج از ماشین مجازی میشود و کد مربوط به مجازیسازی تودرتو در هایپروایزر L0 را تمرین میدهد.
۳.۴ اعتبارسنج وضعیت ماشین مجازی (VM state validator)
اعتبارسنج وضعیت ماشین مجازی، صحت وضعیتهای ماشین مجازی (VM states) را در VM فاز هارنس (fuzz-harness) بررسی میکند، به ویژه زمانی که ماشین وارد VM میشود (VM entry). همانطور که در بخش ۲.۱ توضیح داده شد، VMCS تحت شرایط پیچیدهای برای اعتبارسنجی قرار دارد.
در مجازیسازی تودرتو، هایپروایزر L0 باید این منطق اعتبارسنجی را بازتولید کند تا تعیین نماید که آیا VMCS ارائه شده توسط هایپروایزر L1 معتبر است یا خیر. اگر اعتبارسنجی ناقص یا نادرست باشد، VMCS12 نامعتبر ممکن است به VMCS01 یا VMCS02 منتقل شود و امنیت هایپروایزر L0 را به خطر بیندازد. بنابراین، آزمایش دقیق کد اعتبارسنجی وضعیت VM در محیط مجازیسازی تودرتو اهمیت حیاتی دارد.
با این حال، یک VMCS تولید شده بهصورت تصادفی احتمالاً شامل خطاهای آشکار خواهد بود. چنین فیلدهای نامعتبری بهسرعت توسط هایپروایزر L0 شناسایی شده و با بازگرداندن خطا، پوشش کد را بهبود نمیبخشند. علاوه بر این، از آنجا که VMCS چندین کیلوبایت فضا را اشغال میکند، بررسی همهٔ مقادیر ممکن بهصورت جامع بسیار ناکارآمد است.
برای حل این مشکل، اعتبارسنج وضعیت ماشین مجازی ابتدا یک VMCS را بر اساس ورودی فازینگ تولید میکند، آن را به وضعیت معتبر (valid state) سوق میدهد و سپس به صورت انتخابی بخشهایی از آن را دستخوش تغییر میکند تا مقادیر نامعتبر وارد شوند. این روش به طور مؤثر VMCSهایی تولید میکند که متنوع هستند اما نه کاملاً معتبر و نه بهطور ساده نامعتبر، و امکان آزمایش هدفمند نزدیک به مرز میان وضعیتهای معتبر و نامعتبر را فراهم میکند. در مقایسه با تغییر تدریجی یک بذر طلایی (golden seed)، این روش دامنهٔ وسیعتری از مقادیر را کاوش میکند و در عین حال همواره نزدیک به ناحیهٔ مرزی باقی میماند.
یکی از چالشها، پیادهسازی صحیح اعتبارسنج وضعیت ماشین مجازی است. همانطور که پیشتر ذکر شد، شرایطی که VMCS را معتبر میسازند بسیار پیچیده هستند؛ راهنمای Intel آنها را در صفحات متعدد با توضیحات متنی ارائه میکند. علاوه بر این، پردازندههای Intel مشخص نمیکنند کدام فیلد خاص در VMCS باعث شکست ورود به VM شده است، که تأیید صحت را دشوار میکند. برخی محدودیتها نیز مستندسازی نشدهاند و در مواردی CPU مقادیر VMCS را بهصورت غیرمستقیم گرد میکند تا ناسازگاریها اصلاح شوند. بنابراین، پیادهسازی یک اعتبارسنج کاملاً دقیق تنها بر اساس مستندات عملی نیست.
برای رفع این مشکل، اعتبارسنج VMCS تولیدشده را روی CPU واقعی تنظیم میکند، تلاش برای ورود به VM انجام میدهد و وضعیت VMCS حاصل را با وضعیت مورد انتظار مقایسه میکند. با استفاده از CPU فیزیکی بهعنوان oracle، این روش نهتنها صحت VMCS را بررسی میکند، بلکه پیادهسازی خود VM state validator را نیز اعتبارسنجی میکند. این ایده مشابه روشهای فازینگ شبیهساز CPU موجود [27، 29] است، اما به صورت معکوس: به جای بررسی شبیهساز تحت فازینگ، ما یک مؤلفه از خود فازر را بررسی میکنیم. این روش امکان آزمایش دقیقتر بررسیهای مرزی در کد مجازیسازی تودرتو را فراهم میکند و خطاهای پیادهسازی اعتبارسنج را شناسایی و اصلاح میکند.
لازم است تنها یک VM state validator برای هر معماری CPU آماده شود، زیرا شرایط اعتبارسنجی VMCS توسط معماری CPU تعیین میشوند. بنابراین، اعتبارسنج وضعیت ماشین مجازی عملاً مستقل از هایپروایزر است و میتواند روی هر هایپروایزر L0 اعمال شود.
۳.۵ پیکربندی کننده vCPU
پیکربندی کننده vCPU، مانند فعال یا غیرفعال کردن ویژگیهای خاص CPU، معمولاً هنگام راهاندازی VM از طریق پارامترهایی که به هایپروایزر ارسال میشوند تعیین میشود. گزینههای قابل پیکربندی مرتبط با مجازیسازی مبتنی بر سختافزار شامل پشتیبانی از EPT، مهمان نامحدود (unrestricted guest)، شناسهٔ پردازندهٔ مجازی (virtual processor ID) و موارد دیگر است.
با افزایش تعداد ویژگیها، فضای ترکیبهای ممکن فعال/غیرفعال بهصورت نمایی افزایش مییابد. علاوه بر این، این ویژگیها با یکدیگر و با وضعیت VM تعامل دارند که پیچیدگی را بیشتر میکند. از آنجا که پیکربندی VM تأثیر قابل توجهی بر رفتار هایپروایزر دارد، ترکیبهای غیرمنتظره میتوانند آسیبپذیریها را آشکار کنند. با این حال، فازینگ سنتی هایپروایزر معمولاً از پیکربندیهای vCPU ثابت استفاده میکند و ممکن است آسیبپذیریهای مرتبط با تنظیمات خاص را از دست بدهد.
برای حل این مشکل، NecoFuzz از یک پیکربندی کننده vCPU استفاده میکند تا دامنهٔ گستردهای از پیکربندیها را کاوش کند. این ابزار بر اساس ورودیهای فازینگ، پارامترهای راهاندازی ارسالی به هایپروایزر L0 را تغییر میدهد تا پیکربندیهای متنوع VM تولید شود. ترکیب این روش با اعتبارسنج وضعیت ماشین مجازی، امکان پوشش دامنهٔ وسیعتری از سناریوها، بررسی تعامل بین اجزای مختلف هایپروایزر و افزایش احتمال کشف آسیبپذیریها را فراهم میکند.
در حالی که خود پیکربندی vCPU مستقل از CPU است، باید توسط هایپروایزر میزبان L0 از طریق رابط مخصوص هایپروایزر اعمال شود. برای پر کردن این شکاف، پیکربندی کننده vCPU شامل یک هستهٔ مستقل از هایپروایزر است که پیکربندیها را از ورودیهای فازینگ تولید میکند و یک مبدل کوچک که اتصال به هر هایپروایزر L0 را فراهم میکند. این طراحی امکان سازگاری آسان بین هایپروایزرها را با کمترین تلاش فراهم میآورد.
۴. پیادهسازی
این بخش پیادهسازی NecoFuzz را شرح میدهد. ابتدا نمای کلی فریمورک فازینگ ارائه شده و سپس جزئیات پیادهسازی VM execution harness، VM state validator و vCPU configurator توضیح داده میشود. در ادامه، برنامهٔ agent و نحوهٔ ادغام آن با هایپروایزر شرح داده میشود.
۴.۱ فریمورک فازینگ (Fuzzing Framework)
ما از AFL++ [12] به عنوان چارچوب پایه فازینگ استفاده میکنیم. از آنجایی که ++AFL برای فازینگ برنامههای کاربر-فضا (user-space) طراحی شده است، یک برنامهٔ agent روی سیستمعامل میزبان پیادهسازی کردهایم که فازر، VM فاز هارنس (fuzz-harness) و هایپروایزر هدف L0 را به هم متصل میکند.
این agent ورودیهای فازینگ را از ++AFL دریافت میکند (۲ کیلوبایت دادهٔ باینری) و آنها را به VM فاز هارنس ارسال میکند، در حالی که دادههای پوشش کد (coverage data) را از هایپروایزر L0 جمعآوری کرده و به ++AFL بازمیگرداند. برای جمعآوری اطلاعات پوشش، از مکانیزمهای خاص هایپروایزر استفاده میکنیم، اما آنها را در یک رابط یکپارچه برای ++AFL انتزاعی کردهایم.
- روی KVM، از رابط kcov [54] برای دریافت ردیابی سطح دستورالعمل استفاده میشود.
- روی Xen، از gcov [14] با یک wrapper سفارشی استفاده میکنیم که خروجی آن را به فرمتی سازگار تبدیل میکند.
agent این ردیابیها را به bitmap حافظهٔ مشترک (shared memory bitmap) نگاشت میکند که توسط ++AFL نظارت میشود و برای هدایت جهشها (mutations) استفاده میشود. این طراحی منطق فازینگ را از جزئیات داخلی هایپروایزر جدا میکند و به NecoFuzz امکان میدهد تا بهطور عمده بهصورت مستقل از هایپروایزر (hypervisor-agnostic) عمل کند.
منطق اصلی فازینگ درون VM فاز هارنس (fuzz-harness) توسط یک اجرا کننده (executor) هماهنگ میشود، که بهصورت یک برنامهٔ مستقل UEFI پیادهسازی شده و هارنس اجرای VM (بخش ۴.۲) و اعتبارسنج وضعیت VM (بخش ۴.۳) را یکپارچه میکند. این اجرا کننده با سطح دسترسی مورد نیاز برای اجرای دستورالعملها در هر دو زمینه L1 (هایپروایزر) و L2 (مهمان) اجرا میشود.
اجرا کننده برای Intel VT-x، شامل تقریباً ۳,۵۰۰ خط کد C میباشد که به شرح زیر سازماندهی شده است:
- هماهنگی فازینگ ( حدود 600 خط کد): کل فرآیند فازینگ را هماهنگ میکند، شامل مقداردهی اولیه، مدیریت VMEXIT و خاتمهٔ فرآیند.
- هارنس اجرای VM (حدود 900 خط کد): دستورالعملهای CPU را اجرا میکند (مانند عملیات VMX، دسترسی به رجیسترها، I/O، خواندن/نوشتن MSR) که در L1 یا L2 قابل اجرا هستند.
- اعتبارسنج وضعیت VM (حدود 2000 خط کد): اعتبار VMCS را تضمین میکند. این بخش منطق مشتق شده از Bochs را با تصحیح فیلدها، گرد کردن مقادیر و مکانیزمهای یکپارچهسازی توسعه میدهد.
۴.۲ هارنس اجرای VM (VM Execution Harness)
هارنس اجرای VM به دو فاز تقسیم میشود: فاز مقداردهی اولیه (initialization) و فاز اجرا (execution). هر دو فاز دستورالعملهای CPU مربوط به مجازیسازی مبتنی بر سختافزار را بر اساس ورودیهای فازینگ اجرا میکنند، که از طرفagent به صورت دادهٔ باینری دریافت میشوند.
فاز مقداردهی اولیه VM. دنبالهٔ مقداردهی اولیه حیاتی اما شکننده است: هر انحراف از آن باعث شکست فوری ورود به VM میشود. برای مدیریت این مسئله، ما یک الگوی خاص دامنهای (domain-specific template) از دستورالعملهای مقداردهی اولیه طراحی کردهایم که دنبالهٔ استاندارد VMX setup را بازتاب میدهد (مانند vmxon, vmclear, vmptrld, vmwrite, vmlaunch). این الگو توسط یک موتور سبک و سفارشی تفسیر میشود و ورودی فازینگ ترتیب دستورالعملها، مقادیر آرگومانها و تعداد تکرار آنها را دستخوش تغییر میکند. این طراحی امکان کاوش تغییرات ظریف جریان کنترل را فراهم میکند در حالی که صحت ساختاری حفظ میشود و از ایجاد وضعیتهای نامعتبر که باعث خاتمهٔ زودهنگام فازینگ میشوند، جلوگیری میکند.
فاز اجرای VM. در این فاز، VMها بهصورت مکرر اجرا میشوند و فشار را بر هایپروایزر L0 اعمال میکنند. هارنس یک حلقهٔ فشرده اجرا میکند که مراحل زیر را شامل میشود:
- انتخاب و اجرای یک دنبالهٔ دستورالعمل در زمینهٔ مهمان L2 بر اساس ورودی فازینگ، که ممکن است خروج از VM (VM exit) به L1 ایجاد کند.
- اگر خروج ماشین مجازی به L1 رخ دهد، دنباله دستورالعمل دیگری را در زمینه هایپروایزر L1 انتخاب و اجرا میکند، که توسط هایپروایزر L0، بر اساس ورودی فازینگ، شبیهسازی میشود.
- بازگشت به مهمان L2 با استفاده از vmresume.
هارنس اجرا به جای اجرای جریانهای دستورالعمل بدون ساختار (unstructured instruction streams)، از کتابخانه الگوها (library of templates) استفاده میکند که نمایندهٔ دستورالعملهایی با قابلیت خروج از VM شناخته شده میباشند (مانند mov cr*، rdmsr، in/out) و با منطق آمادهسازی حداقلی بستهبندی شدهاند.
این استراتژی مبتنی بر الگو، نسبت سیگنال به نویز را بهبود میبخشد، زیرا احتمال اینکه دستورالعملهای اجرا شده مسیرهای معنادار خروج ازVM را تمرین کنند، افزایش مییابد. پارامترهای هر دستورالعمل (مانند رجیستر هدف، مقادیر عملوند) از ورودی فازینگ استخراج میشوند و امکان فازینگ سطح دستورالعمل با مقیاسپذیری بالا و محدودیتهای معنایی را در هر دو زمینه L1 و L2 فراهم میکنند.
اگرچه جزئیات دستورالعملها درAMD-V متفاوت است، رویکرد کلی یکسان باقی میماند. این چرخه ادامه مییابد تا زمانی که شرط خاتمه یا به دلیل یک خطای بحرانی و یا رسیدن به حداکثر تعداد تکرارها برقرار شود.
4.3 اعتبارسنج وضعیت VM
VMCS یک ساختار تعریف شده توسط سختافزار است که بیش از ۱۵۰ فیلد دارد و این فیلدها در بخشهایی مانند فیلدهای کنترلی، وضعیت مهمان و میزبان، و کنترلهای ورود و خروج گروهبندی شدهاند. هر فیلد تحت محدودیتها و وابستگیهای سختگیرانه است؛ برای مثال، برخی فیلدهای کنترلی باید با قابلیتهای MSR همخوانی داشته باشند و مقادیر CR0/CR4 مهمان باید قوانین معماری را رعایت کنند. این ساختار چند کیلوبایت فضا را اشغال میکند و چالش قابل توجهی برای جهش مؤثر (efficient mutation) ایجاد میکند.
به جای پیادهسازی مجدد این بررسیها از ابتدا، ما منطق اعتبارسنجی VMCS با دقت بالا موجود در Bochs را استخراج و توسعه دادیم و آن را طوری تطبیق دادیم که بهصورت دینامیک درون VM فاز هارنس (fuzz-harness) عمل کند.
این رویکرد نه تنها وابستگی به وضعیت طلایی (golden states) ثابت را حذف میکند، بلکه امکان فازینگ آگاه از مرز (boundary-aware fuzzing) را نیز فراهم میکند: وضعیتهای تولیدشده به اندازهٔ کافی معتبر هستند تا چکهای L0 را پاس کنند اما به حد رد شدن نزدیکاند، که پوشش منطق اعتبارسنجی را به حداکثر میرسانند.
منطق اعتبارسنجی که ما تطبیق دادیم حدود ۲,۵۰۰ خط کد C دارد. این منطق را از ساختارهای داخلی Bochs جدا کرده و در VM فاز هارنس یکپارچه کردیم. به طور خاص، روالهای زیر را وارد کردیم، که هر کدام مسئول اعتبارسنجی یک گروه فیلد VMCS در حین ورود شبیهسازیشده به VM در Bochs هستند:
- () VMenterLoadCheckVmControls: فیلدهای کنترلی اجرای VM (Pin-Based، Processor-Based Primary و Secondary)، bitmap اجرا، ماسکها (mask) و read shadowهای CR0/CR4 مهمان و میزبان، و آدرسهای مرتبط (مانند آدرسهای I/O bitmap و MSR bitmap).
- () VMenterLoadCheckHostState: فیلدهای منطقه وضعیت میزبان، شامل رجیسترهای کنترلی (CR0, CR3, CR4)، انتخابگرها و مبناهای Segment، مبناهای GDT/IDT و MSRهایی مانند IA32_SYSENTER_CS, ESP, EIP.
- () VMenterLoadCheckGuestState: فیلدهای منطقه وضعیت مهمان، شامل RFLAGS، رجیسترهای کنترلی (CR0, CR3, CR4)، رجیسترهای Segment، GDT/IDT/LDT/TR، MSRها، وضعیت فعالیت (activity state) و وضعیت قابلیت دریافت وقفه (interruptibility state).
برای تولید دادههای VMCS، ابتدا چند کیلوبایت دادهٔ باینری از ورودی فازینگ که توسط agent ارائه شده استخراج میکنیم و آن را به عنوان محتوای خام VMCS در نظر میگیریم. سپس منطق اعتبارسنجی فوق را اعمال میکنیم تا فیلدهای نامعتبر با گرد کردن به نزدیکترین مقادیر معتبر اصلاح شوند. پس از آن، فیلدهای اصلاح شده VMCS با استفاده از بایتهای اضافی ورودی فازینگ دستخوش جهش میشوند. در نهایت، VMCS حاصل با دستور vmwrite نوشته میشود.
منطق جهش به صورت زیر عمل میکند:
- انتخاب فیلد (Field Selection): یک فیلد VMCS برای جهش انتخاب میشود و با فازینگ ورودی، نواحی مختلف فضای حالت VMCS بررسی میشوند.
- انتخاب بیت (Bit Selection): درون فیلد انتخاب شده، یک یا چند موقعیت بیت بر اساس ورودی فازینگ انتخاب میشوند. انتخاب محدود به عرض بیت معتبر فیلد است.
- جهش (Mutation): بیتهای انتخاب شده معکوس (flip) میشوند.
- تکرار (Iteration): مراحل ۲ و ۳ معمولاً برای یک تا سه فیلد VMCS در هر تکرار فازینگ انجام میشود و یک تا هشت بیت در هر فیلد دستخوش تغییر میشوند. تعداد فیلدها و بیتها توسط ورودی فازینگ تعیین میگردد.
این استراتژی جهش عمداً فیلدهای VMCS را پس از اینکه عمدتاً اعتبارسنجی شدهاند، دستکاری میکند. با تمرکز روی بیتهای حیاتی امنیتی مانند فیلدهای کنترلی و رجیسترهای حقوق دسترسی، فازر وضعیتهای VM نزدیک به مرز میان پیکربندیهای معتبر و نامعتبر تولید میکند. چنین وضعیتهایی احتمال بیشتری دارند تا نقایص ظریف در مدیریت خطا یا تعاملات غیرمنتظره در منطق مدیریت VMX هایپروایزر را آشکار سازند.
برای رسیدگی به محدودیتهای میان فیلدها (cross-field constraints)، ما رویهٔ گرد کردن (rounding procedure) اعتبارسنج را طوری طراحی کردیم که بهصورت متوالی روی سه گروه فیلد VMCS اجرا شود: ابتدا فیلدهای کنترلی، سپس فیلدهای وضعیت میزبان، و در نهایت فیلدهای وضعیت مهمان. در هر گروه، ابتدا فیلدها با استفاده از منطق اعتبارسنجی Bochs به مقادیر مطابق با مشخصات گرد میشوند و سپس محدودیتهای درون گروهی بررسی و در صورت نیاز اصلاح میشوند.
به عنوان مثال، اگر IA32_EFER.LME (فعالسازی حالت طولانی) برای اجرای x86-64 mode تنظیم شده باشد اما CR4.PAE (افزونه آدرس فیزیکی) در فیلدهای وضعیت مهمان یا میزبان تنظیم نشده باشد، اعتبارسنج این بیت را به ۱ تغییر میدهد تا محدودیتهای معماری رعایت شود.
محدودیتهای بین گروهی نیز بررسی و بر اساس گروههای قبلی اصلاح میشوند. فیلدهای مستقل میتوانند بهصورت جداگانه طبق مشخصات تغییر کنند و حتی فیلدهای وابسته یک گراف یکطرفه تشکیل میدهند که امکان اصلاح قطعی و مرحلهای را فراهم میکند. با استفاده از این اعتبارسنجیهای متوالی، رویهٔ گرد کردن در تعداد محدودی از مراحل کامل میشود و سازگاری میان فیلدهای VMCS با وابستگیهای پیچیده را تضمین میکند.
4.4 پیکربندی کنندهvCPU
پیکربندی کننده vCPU معمولاً بهصورت یک آرایهٔ بیت نمایش داده میشود، که هر بیت نشان میدهد یک ویژگی خاص CPU فعال یا غیرفعال است. این پیکربندی بر اساس ورودی فازینگ دستخوش تغییر (mutation) میشود.
برای اعمال پیکربندی تولید شده روی هایپروایزر L0، یک مبدل کوچک (adapter) برای هر هایپروایزر پیادهسازی کردهایم. برای KVM، این مبدل پیکربندیهای vCPU را از طریق دو رابط اعمال میکند:
پارامترهای ماژول کرنل (Kernel Module Parameters): بخشهای خاص فروشنده در KVM (Intel VT-x و AMD-V) بهصورت ماژولهای کرنل جداگانه پیادهسازی شدهاند (kvm-intel.ko, kvm-amd.ko). این ماژولها پارامترهایی را میپذیرند که ویژگیهای مجازیسازی مبتنی بر سختافزار را پیکربندی میکنند، مانند فعال یا غیرفعال کردن EPT.
گزینههای خط فرمان هایپروایزر (Hypervisor Command-line Options): پیکربندیهای عمومیتر vCPU به صورت گزینههای خط فرمان برای هایپروایزر، در اینجا QEMU، مشخص میشوند. این پیکربندیها شامل ویژگیهای مدل CPU (مانند فعال/غیرفعال کردن VMX/SVM extensions یا فلگهای خاص CPUID مانند hv-passthrough)، توپولوژی CPU مجازی و پارامترهای تخصیص حافظه هستند.
ما مبدل KVM را بهصورت یک اسکریپت شل پیادهسازی کردهایم که ماژول کرنل را با رشته پارامتر مورد نظر دوباره بارگذاری میکند و QEMU را با گزینههای خط فرمان مناسب اجرا میکند. این گزینهها از لیست از پیش تعیینشدهای از ویژگیهای CPU بر اساس معماری میزبان (Intel یا AMD) انتخاب میشوند.
۴.۵ برنامهٔ Agent
برنامهٔ agent به عنوان هماهنگ کنندهٔ مرکزی کل فرآیند فازینگ عمل میکند. علاوه بر مدیریت ارتباط بین AFL++، VM فاز هارنس و هایپروایزر هدف L0، نقشهای زیر را نیز ایفا میکند:
- هماهنگی فازینگ (Fuzzing Orchestration): agent کل حلقهٔ فازینگ را برای هر مورد آزمایشی مدیریت میکند. ابتدا UEFI اجرا کننده (executor UEFI) را در VM فاز هارنس راهاندازی میکند (برای KVM با استفاده از دستور qemu-kvm) و سپس پس از اتمام تکرار فازینگ یا شناسایی یک آسیبپذیری بالقوه، آن را متوقف میکند.
- در طول اجرای VM، agent دادههای پوشش کد (coverage data) را از هایپروایزر L0 جمعآوری کرده و پس از خاتمه VM، از طریق حافظهٔ مشترک (shared memory) به ++AFL منتقل میکند.
برای جدا کردن VM فاز هارنس از هایپروایزر L0، UEFI اجرا کننده بهصورت خودکفا طراحی شده است. agent در هر اجرا، ورودی فازینگ را بهصورت دادهٔ باینری درون فایل باینری UEFI جاسازی میکند، که امکان اجرای اجرا کننده را بهصورت مستقل و بدون نیاز به تعامل با فازر در طول اجرا فراهم میکند. این طراحی قابلیت انتقال پذیری (portability) را بهبود میبخشد و وابستگی به محیطهای اجرای خاص را کاهش میدهد.
- شناسایی آسیبپذیری (Vulnerability Detection): برنامهٔ agent همچنین آسیبپذیریهای بالقوه را شناسایی کرده و گزارشهای مرتبط را برای بازتولید ذخیره میکند. برای شناسایی ناهنجاریها (anomalies) که ممکن است نشاندهنده آسیبپذیری باشند، agent از مکانیزمهای شناسایی خطای خاص هایپروایزر استفاده میکند:
- در KVM، agent از سنی تایزر آدرس کرنل (KASAN یا Kernel Address Sanitizer) و (UBSAN یا Undefined Behavior Sanitizer) بهره میگیرد و پیامهای لاگ کرنل را برای ناهنجاریهای مرتبط نظارت میکند.
- agent در Xen نیز لاگهای تشخیصی مختص هایپروایزر را برای خطاهای ادعایی، هشدارهای بحرانی یا سایر نشانههای رفتار غیرمنتظره هایپروایزر بررسی میکند.
هنگامی که ناهنجاری شناسایی شود یا پوشش کد جدید مشاهده شود (با یک فلگ داخلی مشخص میشود)، agent ورودی فازینگ فعلی را در فایلی با برچسب زمان در یک دایرکتوری مشخصشده در پیکربندی ذخیره میکند. این کار تضمین میکند که هر کرش یا رفتار منحصربهفرد بهطور قابل اعتماد برای تحلیل و اشکالزدایی دستی بعدی بازتولید شود.
۵. ارزیابی
در این بخش، NecoFuzz از طریق مجموعهای از آزمایشها ارزیابی میشود. هدف اصلی، پاسخ به سؤالات پژوهشی زیر است:
- سوال ۱: NecoFuzz نسبت به تکنیکهای موجود، تا چه حد پوشش کد (code coverage) را بهبود میبخشد؟
- سوال ۲: هر یک از اجزای NecoFuzz تا چه حد در بهبود پوشش کد مؤثر هستند؟
- سوال ۳: آیا NecoFuzz در هایپروایزرهای مختلف مؤثر است؟
- سوال ۴: آیا NecoFuzz در کشف آسیبپذیریها مؤثر است؟
۵.۱ تنظیمات تجربی
برای KVM، آزمایشهای فازینگ با کرنل لینوکس نسخه ۶.۵ روی پردازندههای Intel Core i9-12900K و AMD Ryzen Threadripper PRO 5995WX انجام شد. پوشش کد با استفاده از KCOV [54] اندازهگیری شد، که اشارهگرهای دستورالعمل (instruction pointers) مربوط به بلوکهای پایه اجراشده را از طریق instrumentation زمان کامپایل جمعآوری میکند. سپس این اشارهگرها با استفاده از addr2line به خطوط منبع نگاشت شدند.
برای تمرکز بر کد مخصوص مجازیسازی تودرتو (nested virtualization) که سایر تکنیکها نمیتوانند به آن دسترسی پیدا کنند، اندازهگیری پوشش محدود به مسیرهای linux/arch/x86/kvm/{vmx,svm}/nested.c شد. این فایلها شامل منطق اصلی مجازیسازی تودرتو هستند، از جمله شبیه سازی VMCS/VMCB، بررسیهای سازگاری، و مدیریت خروجی VMهای تودرتو. سایر فایلها نیز کدی برای پشتیبانی از مجازیسازی تودرتو دارند، مانند:
- vmx.c / svm.c برای مدیریت عمومی vCPU
- mmu.c برای صفحهبندی سایهای
- tdp_mmu.c برای صفحهبندی دوبعدی (nested paging)
- posted_intr.c و lapic.c برای پردازش وقفهها
با این حال، این کدها با عملکردهای غیرتودرتو مخلوط شدهاند و پوشش آنها کمتر مشخص و بیشتر مستعد نویز است.
ما تأیید کردیم که تمام VM exitهای L2-to-L0 و L1-to-L0 تودرتو در نهایت به handlerهای nested.c ارسال میشوند، که نشان میدهد این فایلها مسیرهای کدی را پوشش میدهند که منحصراً توسط مجازیسازی تودرتو تحریک میشوند. گسترش اندازهگیری پوشش به مسیرهای کد مرتبط اما غیرمستقیم، یک جهت جالب برای کارهای آینده باقی میماند.
برای مقایسه، دو فازر ارزیابی شدند:
- IRIS [9]: یک فازر پیشرفته برای Xen hypervisor است که دادههای VMCS را در داخل Xen دستخوش تغییر میکند. اگرچه مستقیماً هدفش مجازیسازی تودرتو نیست، ما IRIS را در یک VM L1 روی L0 KVM اجرا کردیم تا بهطور غیرمستقیم کد مجازیسازی تودرتو تحت فشار قرار گیرد.
- Syzkaller [17]: تنها ابزار فازینگ موجود که به طور صریح مجازیسازی تودرتو را هدف قرار میدهد و از harnessهای دستی نوشتهشده استفاده میکند. آن را برای تمرکز کامل بر رابط ioctl KVM پیکربندی کردیم تا پوشش کد سریعتر افزایش یابد.
ما همچنین سایر چارچوبهای فازینگ را بررسی کردیم. با این حال:
- HyperPill [8] هنگام اجرا در VM کرش میکرد.
- ViDeZZo [26] از مجازیسازی مبتنی بر سختافزار استفاده نمیکند.
- Hyper-Fuzzer [15] دارای کد منبع بسته (closed-source) است.
حتی زمانی که این ابزارها اجرا میشوند، آنها رابطهای مجازیسازی تودرتو را هدف نمیگیرند و بنابراین پوشش کد را بهبود نمیبخشند؛ همانطور که آزمایشهای ما با IRIS نیز نشان داد. علاوه بر این، از دو ابزار تست استفاده کردیم:
- Selftests [55]: شامل برنامههای تست مختلف KVM در درخت منبع لینوکس است. تمام این تستها را اجرا کرده و پوشش آنها را جمعآوری کردیم، با حذف بخشهای تکراری.
- KVM-unit-tests [25]: یک سیستمعامل مهمان حداقلی است که تستهای واحد برای KVM را پیادهسازی میکند. این ابزارها بهطور مستقیم کد مجازیسازی مبتنی بر سختافزار را تمرین میدهند.
برای Xen، از نسخه ۴.۱۸ Xen روی Intel Core i9-12900K و AMD Ryzen 9 5950X استفاده شد. پوشش کد با استفاده از gcov [14] اندازهگیری شد. برای تمرکز بر مجازیسازی تودرتو، اندازهگیری محدود به فایلهای منبع xen/arch/x86/hvm/{vmx/vmx, svm/nestedsvm}.c شد.
برای مقایسه، از Xen Test Framework (XTF) [58] به عنوان مجموعهٔ تست مرجع استفاده کردیم. در اندازهگیری پوشش، راهنماییهای Klees و همکاران [23] را دنبال کردیم. در اندازهگیری پوشش، ما از دستورالعملهای کلیس و همکاران [23] پیروی میکنیم و میانههای پنج اجرا در طول زمان را به همراه فواصل اطمینان 95٪ (CI) آنها، مقادیر 𝑝 از آزمونهای U دوطرفه من ویتنی و اندازههای اثر 𝑑 کوهن گزارش میدهیم.
۵.۲ RQ1: بهبود پوشش کد (Coverage Improvement)
برای پاسخ به RQ1، پیشرفت پوشش کد در KVM با استفاده از NecoFuzz اندازهگیری شد و با IRIS، Syzkaller، Selftests و KVM-unit-tests مقایسه گردید. این ابزارها برای ۴۸ ساعت اجرا شدند. IRIS در محیط مجازیسازی تودرتو ناپایدار بود و پس از چند دقیقه کرش کرد؛ ما پوشش کد را در نقطه توقف آن گزارش میکنیم. جدول ۲ نتایج اندازهگیری را نشان میدهد.
NecoFuzz در پردازندههای Intel، پوشش میانهای برابر ۸۴.۷٪ (فاصله اطمینان ۹۵٪: ۸۴.۲–۸۵.۲) به دست آورد که بهبود ۱.۴× نسبت به Syzkaller است، که پوشش آن ۶۱.۴٪ (CI: ۵۶.۰–۶۳.۳) بود، با 𝑝 = 0.012 و اندازه اثر بزرگ (Cohen’s 𝑑 = 12.17).
NecoFuzz در پردازندههای AMD، پوشش ۷۴.۲٪ (CI: ۷۳.۶–۷۴.۷) داشت که بهبود ×11 نسبت به Syzkaller با پوشش ۷.۰٪ (CI: ۷.۰–۷.۰) نشان میدهد، با 𝑝 = 0.014 و Cohen’s 𝑑 = 171.97. کدهایی که بهطور منحصربهفرد توسط Syzkaller پوشش داده شدند (Syzkaller–NecoFuzz) تنها ۷.۳٪ روی Intel و ۱.۳٪ روی AMD را تشکیل میدهند، در حالی که کدهایی که منحصراً توسط NecoFuzz پوشش داده شدند (NecoFuzz–Syzkaller) به ترتیب ۳۰.۵٪ روی Intel و ۶۸.۵٪ روی AMD بودند.
توجه داشته باشید که هارنس Syzkaller مخصوص AMD ندارد و بنابراین پوشش کد مجازیسازی تودرتو محدود است. این نتایج نشان میدهد که NecoFuzz پوشش کد را بهطور قابل توجهی افزایش میدهد و تقریباً تمام خطوطی که Syzkaller پوشش میدهد را نیز شامل میشود.
کدهایی که در آزمایشهای ما پوشش داده نشدهاند شامل توابعی هستند که تنها توسط عملیات سمت میزبان قابل فراخوانی هستند، مانند live migration، راهاندازی و پاکسازی وضعیتهای تودرتو، و رویههای مقداردهی یا پاکسازی سختافزار که هنگام بارگذاری یا خارج کردن ماژول KVM اجرا میشوند. همانطور که در بخش ۳.۱ گفته شد، توابعی که نمیتوانند مستقیماً از طریق اجرای دستورالعملها در مهمان (Guest)های L1 یا L2 فعال شوند، خارج از محدوده مدل تهدید ما هستند. این توابع معمولاً از طریق ()ioctl فراخوانی میشوند و تقریباً ۴.۸٪ در Intel و ۹.۸٪ در AMD را تشکیل میدهند، اگرچه شناسایی دقیق اینکه کدام ioctlها از داخل مهمان قابل دسترسی نیستند، دشوار است.
دسته دوم شامل کدی است که تنها در شرایط نادر اجرا میشود، از جمله بررسیهای تشخیص باگ مانند ()BUG، مدیران شکست تخصیص حافظه، پشتیبانی از ویژگیهای جزئی سختافزاری مانند Intel PT، Intel SGX و پردازش وقفههای ارسالشده (posted-interrupt)، و پشتیبانی خاص هایپروایزر مانند enlightened VMCS برای Hyper-V، که مجموعاً تا ۲.۰٪ را تشکیل میدهند.
این دسته همچنین شامل بخش کوچکی از کد است که با دانههای تصادفی قابل تمرین نیستند، مانند دستوراتی که نیاز به مقادیر عملوند یا پیکربندیهای خاص VMCS دارند. پوشش این کد باقیمانده (در مجموع کمتر از ۱۰٪) نیازمند هارنسهای فازینگ پیشرفته در سطح سیستمعامل مهمان است تا محیطهای اجرای مربوطه را مقداردهی اولیه کرده و رویدادهای مناسب را تحریک کنند.
IRIS تقریباً بلافاصله به پوشش ۵۲.۳٪ رسید، که NecoFuzz هنوز آن را ×۱.۶ پشت سر گذاشت، و پوشش آن در عرض چند دقیقه به سرعت اشباع شد. اگرچه نتوانستیم IRIS را برای مدت طولانی اجرا کنیم، احتمال بهبود قابل توجه بیشتر کم است، زیرا پوشش آن از حالتهای معتبر VMCS محدود است. در مقایسه با Selftests، که بهطور مستقیم کد مجازیسازی تودرتو را از طریق ioctl فراخوانی میکند، NecoFuzz پوشش ۲.۱× بالاتر روی Intel و ۱.۱× روی AMD بهدست آورد. پوشش منحصر به Selftests (“Selftests–NecoFuzz”) برابر ۲.۴٪ روی Intel و ۸.۰٪ روی AMD بود، در حالی که پوشش منحصراً NecoFuzz (“NecoFuzz–Selftests”) به ترتیب ۲۹.۳٪ روی Intel و ۸.۸٪ روی AMD بود.
در مقایسه با KVM-unit-tests، که شامل تستهای واحد دستی نوشتهشده است، NecoFuzz خطوط بیشتری را پوشش داد: ×۱.۱۸ بیشتر روی Intel و ×۱.۰۶ بیشتر روی AMD. توجه داشته باشید که افزایش پوشش در تستهای واحد میتواند به راحتی با نوشتن دستی کد تست که کد هدف را تمرین میکند، حاصل شود، اما چنین تستهایی لزوماً آرگومانهای پیچیده را بررسی نمیکنند و بنابراین ممکن است به افزایش نرخ کشف آسیبپذیری منجر نشوند. در واقع، Selftests تنها ۶۰ مورد تست را در حدود ۸۰ ثانیه اجرا میکند و KVM-unit-tests تنها ۸۴ مورد تست را در حدود ۲۰ دقیقه اجرا میکند، هر دو با مجموعهای ثابت از تستهای قطعی، در حالی که چارچوب فازینگ ما کد هدف را برای ۴۸ ساعت یا بیشتر تحت فشار قرار میدهد.
شکل 3a و شکل 3b روند پیشرفت پوشش کد را طی ۴۸ ساعت برای NecoFuzz و Syzkaller نشان میدهند (IRIS به صورت یک خط نقطهچین افقی برای مرجع نمایش داده شده است؛ این ابزار پس از چند دقیقه کرش کرد). هر دو ابزار در ابتدا پوشش متوسطی دارند که ناشی از harness مربوط به خودشان است. NecoFuzz پوشش کد را بهسرعت افزایش میدهد (از تقریباً ۷۰٪ به ۸۴.۷٪ روی Intel و از ۶۵٪ به ۷۴.۲٪ روی AMD). در مقابل، Syzkaller همگرایی بسیار کُندتری دارد؛ روی Intel، پس از ۴۸ ساعت تنها به ۶۱.۴٪ رسید. این نتایج نشان میدهد کهNecoFuzz با تغییر مؤثرتر ورودیهای VM، پوشش کد مربوط به منطق مجازیسازی تودرتو را بهطور کارآمدی گسترش میدهد.
۵.۳ RQ2: اثربخشی مولفه
برای پاسخ به RQ2، سهم هر مؤلفه را با غیرفعالسازی انتخابی آن و اندازهگیری پوشش حاصل بررسی کردیم. همچنین توزیع وضعیتهای تولید شده VM را تحلیل کردیم تا اثربخشی آنها را ارزیابی کنیم.
۵.۳.۱ سهم مولفه در پوشش کد
پوشش کد NecoFuzz را با غیرفعال کردن انتخابی هر مؤلفه از مولد VM (یا VM generator) اندازهگیری کردیم. جدول ۳ پوشش در علامت ۲۴ ساعت را نشان میدهد و شکل 4a و 4b روند پیشرفت پوشش را در طول زمان نمایش میدهند. غیرفعال کردن هر مؤلفه بهتنهایی باعث کاهش قابل توجه پوشش نسبت به پیکربندی کامل (“with ALL”) شد.
حذف هارنس اجرای VM روی Intel، پوشش را ۶.۱ درصد کاهش داد، اعتبارسنج وضعیت ماشین مجازی و پیکربندی کننده vCPU نیز به ترتیب باعث کاهش ۱۶.۹ و ۱۱.۰ درصد شدند. کاهشهای متناظر بر روی AMD نیز ۲۰.۲، ۱۵.۸ و ۶.۰ درصد بودند.
اعتبارسنج وضعیت ماشین مجازی در بین مؤلفهها، بیشترین تأثیر را روی Intel داشت (۱۶.۹ درصد)، در حالی که هارنس اجرای VM بیشترین اهمیت را روی AMD داشت (۲۰.۲ درصد). وقتی همه مؤلفهها غیرفعال شدند (“w/o ALL”)، تنها از یک قالب پیشفرض و پیکربندی vCPU پیشفرض استفاده شد که منجر به کاهش پوشش ۲۸.۲ درصد روی Intel و ۲۲.۵ درصد روی AMD گردید. این نتایج نشان میدهند که هر سه مؤلفه سهم معناداری در افزایش پوشش کد مجازیسازی تودرتو دارند.
۵.۳.۲ توزیع وضعیتهای VM
برای ارزیابی اثربخشی اعتبارسنج وضعیت ماشین مجازی، فاصله همینگ (Hamming distance) بین وضعیتهای VM تولید شده به صورت تصادفی و نسخههای اعتبارسنجی شده آنها توسط اعتبارسنج وضعیت ماشین مجازی اندازهگیری شد. از چیدمان VMCS استفاده کردیم که یک وضعیت VM شامل ۸,۰۰۰ بیت در ۱۶۵ فیلد با عرضهای از پیش تعیین شده را تعریف میکند. این آزمایش ۱۰,۰۰۰ بار تکرار گردید. نتایج در سمت چپ شکل ۵ نمایش داده شده است. میانگین فاصله همینگ ۴۹۲.۶ بیت با انحراف معیار ۵۳.۹ بود، که نشان میدهد وضعیتهای VM تولید شده بهصورت تصادفی احتمال بسیار کمی دارند که با وضعیتهای معتبر مطابقت داشته باشند، تقریباً یک در 2492.6.
برای ارزیابی تنوع وضعیتها (state diversity)، وضعیتهای VM تولید شده را با آنهایی که از مقادیر پیشفرض ساده مقداردهی اولیه شده بودند، مقایسه کردیم. همانطور که در مرکز شکل ۵ نشان داده شده است، میانگین فاصله همینگ ۲۸۴.۷ بیت با انحراف معیار ۳۶.۴ بود. این موضوع نشان میدهد که اعتبارسنج، وضعیتهای متنوعتری نسبت به آنچه میتوان با تغییرات ساده پیشفرض به دست آورد، تولید میکند.
در نهایت، برای ارزیابی متغیرپذیری درونمجموعهای (intra-set variability)، فاصله همینگ بین جفتهای وضعیتهای VM تولید شده محاسبه شد. سمت راست شکل ۵ میانگین فاصله ۳۵۳ بیت با انحراف معیار ۶۳.۹ را نشان میدهد. این نتایج تأیید میکنند که اعتبارسنج تعداد زیادی وضعیت VM تولید میکند که هم نزدیک به وضعیتهای معتبر هستند و هم از نظر داخلی متنوع میباشند.
۵.۴ RQ3: مستقل از هایپروایزر (Hypervisor Independence)
برای نشان دادن انعطافپذیری NecoFuzz، ارزیابی خود را به هایپروایزر Xen گسترش دادیم. جدول ۴ پوشش کدی را که NecoFuzz و XTF پس از ۲۴ ساعت فازینگ بهدست آوردند، مقایسه میکند. نتایج با روند مشاهده شده در جدول ۲ برای KVM همخوانی دارند. NecoFuzz پوشش ۸۳.۴٪ روی Intel ( ۹۵٪ CI: ۸۱.۸–۸۳.۹) و ۷۹.۰٪ روی AMD (۹۵٪ CI: ۷۷.۷–۸۰.۵) را به دست آورد و به ترتیب ۶۳.۰ و ۶۸.۲ واحد درصد از XTF پیشی گرفت. این نتایج تأیید میکنند که NecoFuzz پوشش بسیار بالاتری نسبت به روشهای موجود در هایپروایزرهای مختلف ارائه میدهد.
سپس، برای ارزیابی قابلیت اعمال NecoFuzz بر هایپروایزرهای کد بسته (closed-source)، تأثیر راهنمایی پوشش (coverage guidance) در KVM بررسی شد. جدول ۵ نتایج را پس از ۴۸ ساعت فازینگ نشان میدهد. جالب این است که فعال یا غیرفعال کردن راهنمایی پوشش تنها تأثیر جزئی بر پوشش نهایی داشت. این ممکن است به این دلیل باشد که، بهویژه هنگام کاوش فضای وضعیت VMCS، آزمایش گسترده مناطق مرزی ظریف با استفاده از اعتبارسنج وضعیت VM مؤثرتر از دنبال کردن مسیرهای اجرای عمیق برای بهبود پوشش است. این نتایج نشان میدهند که NecoFuzz میتواند بهعنوان یک فازر جعبهسیاه مؤثر برای هایپروایزرهای کد بسته که اطلاعات پوشش ارائه نمیدهند، عمل کند.
۵.۵ RQ4: قابلیتهای کشف آسیبپذیری
برای ارزیابی قابلیتهای کشف آسیبپذیری NecoFuzz، بررسی کردیم که آیا این ابزار میتواند باگهای واقعی در هایپروایزرهای موجود را شناسایی کند یا خیر. NecoFuzz روی KVM، Xen و VirtualBox اعمال شد و خروجیهای فازر و ردپاهای اجرایی تحلیل گردید تا مشکلات تأیید شوند.
نتیجه این بود که NecoFuzz شش آسیبپذیری ناشناخته قبلی را شناسایی کرد: دو مورد در KVM، سه مورد در Xen و یک مورد در VirtualBox. تمام موارد به توسعهدهندگان مربوطه گزارش شد و چهار مورد از آنها تأیید و اصلاح شدند. دو مورد از آسیبپذیریهای تأیید شده دارای CVE اختصاصی هستند. یکی در KVM و دیگری در VirtualBox. جدول ۶ خلاصهای از آسیبپذیریهای کشف شده ارائه میدهد. در ادامه، برخی مثالها بهطور مفصلتر توضیح داده شدهاند.
۵.۵.۱ آسیبپذیریهای جدید در KVM
ابتدا توضیح میدهیم که NecoFuzz چگونهCVE-2023-30456 [41]، یک باگ در پیادهسازی مجازیسازی تودرتو KVM روی Intel را کشف کرد. این مشکل ناشی از عدم وجود بررسی سازگاری در VMCS12 است که منجر به خطای نوشتن خارج از محدوده آرایه در حین page walkهای مهمان L2 توسط هایپروایزر L1 میشود.
برای فعال کردن این باگ، ماژول KVM باید با مجازیسازی تودرتو فعال ولی EPT غیرفعال بارگذاری شود. سپس هایپروایزر L1 بیت “IA-32e mode guest” در فیلد کنترل VM-entry را روی ۱ قرار میدهد، در حالی که بیت GUEST CR4.PAE صفر باقی میماند. اگرچه Intel Software Developer Manuals [20] مشخص میکند که CR4.PAE باید هنگام فعال شدن IA-32e mode تنظیم شود، CPU به صورت پنهان آن را فرض میکند و اجازه ادامه ورود VM را میدهد. KVM اما CR4.PAE را بهصورت حرف به حرف تفسیر کرده و جدولهای صفحه را بهدرستی مدیریت نمیکند که منجر به فساد دادهها میشود. با کمک VM state validator و vCPU configurator، NecoFuzz توانست این حالت مرزی را بهصورت خودکار تولید کند.
همچنین، NecoFuzz باگ دومی را در مدیریت shadow roots در عملیات EPT KVM تودرتو کشف کرد. در این حالت، هایپروایزر L1 یک pointer نامعتبر EPT (EPTP) را در VMCS12 قرار میدهد و L2 guest را اجرا میکند. KVM تلاش میکند روت EPT را از طریق ()mmu_check_root اعتبارسنجی و در صورت شکست، بهطور نادرست یک خروج از VM ایجاد کند، حتی اگر VM L2 هرگز شروع نشده باشد. این رفتار نادرست توسط وضعیتهای VM تولید شده با اعتبارسنج (validator) آشکار شد.
برای رفع این مشکل، توسعهدهندگان KVM یک پچ [10] اعمال کردند که یک root جعلی از zero page بارگذاری میکند. این کار تضمین میکند که هر دسترسی به حافظه مهمان پس از ورود L2 باعث تولید خطای صحیح و خروج از VM درست شود و از انتقال نادرست از L2 به L1 جلوگیری گردد.
۵.۵.۲ آسیبپذیریهای جدید در Xen
NecoFuzz سه باگ جدید در پیادهسازی مجازیسازی تودرتو Xen کشف کرد. باگ اول زمانی رخ میدهد که nested virtualization در یک HVM guest فعال است و هایپروایزر L1 فیلد وضعیت فعالیت (activity state) در VMCS12 را روی ۳ (“wait-for-SIPI”) تنظیم میکند قبل از اجرای vmlaunch برای ورود به L2. این وضعیت باعث فریز شدن VM مهمان و همچنین از کار افتادن کل سیستم میزبان میشود. مشکل از اینجا ناشی میشود که Xen بهطور کورکورانه وضعیت فعالیت را از VMCS12 به VMCS02 کپی میکند.
برخی وضعیتهای فعالیت مانند SHUTDOWN یا WAIT-FOR-SIPI برای مدیریت پردازندههای جانبی در Intel TXT طراحی شدهاند و رویدادها را متفاوت از حالت فعال عادی مسدود یا فیلتر میکنند. برای مثال، تنظیم وضعیت فعالیت روی SHUTDOWN باعث ریست شدن پلتفرم میشود و WAIT-FOR-SIPI تمام وقفهها به جز SIPIها را بلاک میکند. این وضعیتها در پیکربندیهای عادی VM تودرتو نباید استفاده شوند. عدم بررسی و تصحیح وضعیت فعالیت توسط Xen هنگام ورود به L2 باعث رفتار غیرقابل پیشبینی [11] میشود.
باگ دوم و سوم روی پلتفرمهای AMD رخ میدهند که به جای Intel VMCS از VMCB (Virtual Machine Control Block) استفاده میکنند.
باگ دوم زمانی رخ میدهد که هایپروایزر L1 پس از اجرای مهمان L2 با حالت ۶۴ بیتی، CR0.PG = 0 را در VMCB12 تنظیم میکند. این باعث ایجاد وضعیت ناسازگار میشود: بیت Long Mode Enable (LME) در EFER برابر ۱ است، اما CR0.PG (صفحهبندی) پاک شده است. در حالت عادی، برای عملکرد long mode، صفحه بندی باید فعال باشد، بنابراین این ترکیب نامعتبر است. این ناسازگاری باعث خرابی حافظه و فعال شدن نادرست AVIC در VMCB02 میشود. در نتیجه، Xen یک VM exit با دلیل AVIC_NOACCEL ایجاد میکند، حتی اگر AVIC پشتیبانی نشده باشد. این مشکل نشان دهنده ابهام معماری در مشخصات AMD [1] است که چنین وضعیت VMCB را ممکن میکند اما رفتار vmrun را روشن نمیسازد و این باعث دشواری در پشتیبانی صحیح از مجازی سازی تودرتو میشود.
باگ سوم در Xen نیز ناشی از مقدار نامعتبر در CR4 در VMCB12 است که توسط هایپروایزر L1 تنظیم شده است. در این حالت، Xen به درستی vmrun را شکست میدهد و یک VM exit به L1 انجام میشود.
با این حال، در طول شبیهسازی خروج از VM، تابع ()nsvm_vcpu_vmexit_inject وضعیت Virtual GIF Enable (VGIF) را بررسی میکند. اگر VGIF فعال باشد، فرض میشود که Virtual GIF (Global Interrupt Flag) نیز فعال است. در این مورد مشاهده شده، VGIF به طور غیرمنتظره صفر بود که باعث خطای assert شد. اگرچه این خطا سیستم را کرش نمیکند، اما نقصی در فرض Xen درباره رفتار پیشفرض mask کردن وقفهها هنگام فعال بودن VGIF را نشان میدهد.
هر سه باگ با استفاده از VM stateهای تولید شده توسط اعتبارسنج وضعیت VM در NecoFuzz کشف شدند که نشان میدهد این ابزار توانایی تمرین edge caseها در معماریهای مختلف را دارد.
۵.۵.۳ آسیبپذیریهای جدید در VirtualBox
در نهایت، NecoFuzz موفق شد CVE-2024-21106 [42] را در نسخه ۷.۰.۱۲ VirtualBox کشف کند. این آسیبپذیری مربوط به اعتبارسنجی نامناسب مقادیر MSR هنگام ورود به VM تودرتو است. مشکل اینگونه است که آدرسهای غیر canonical میتوانند در MSR نوشته شوند، که باعث ایجاد خطای حفاظت عمومی (general protection fault) در میزبان میشود.
برای بازتولید این باگ، VirtualBox باید با مجازی سازی تودرتو فعال اجرا شود. هایپروایزر L1 یک آدرس غیر متعارف (مانند 0x8000000000000000) را در vmentry_msr_load برای MSR KernelGSBase (0xC0000102) در VMCS12 تنظیم کرده و سپس vmlaunch را اجرا میکند. طبق مشخصات Intel [20]، آدرسهای بارگذاری شده در MSRهایی مانند KernelGSBase باید متعارف باشند، اما VirtualBox این شرط را هنگام ورود به VM تودرتو بررسی نمیکند.
این آسیب پذیری دو نوع رفتار ایجاد میکند:
- VM به طور غیرمنتظره خاتمه مییابد
- VM نمیتواند به درستی خاموش شود و سیستم فریز میشود.
گزارشهای سیستم خطای زیر را نشان میدهند:
“general protection fault, probably for non-canonical address 0x8000000000000000”
ترجمه گزارش خطا: یک خطای حفاظت عمومی رخ داده است، که به احتمال زیاد ناشی از استفاده از آدرس نامتعارف 0x8000000000000000 است.
این رفتار با KVM متفاوت است که مقادیر MSR را هنگام ورود تودرتو به درستی اعتبارسنجی میکند و اگر مقدار غی متعارف باشد، ورود را متوقف میکند. بنابراین، شکست VirtualBox نشان دهنده کمبود در منطق اعتبارسنجی آن است.
NecoFuzz این باگ را با تولید یک VMCS در حالت مرزی (boundary state) و مقدار غیر متعارف برای MSR از طریق اعتبارسنج وضعیت VM (یا VM state validator) خود فعال کرد که اثربخشی رویکرد guided-by-specification ما را نشان میدهد.
۵.۶ درسهای آموختهشده دربارهٔ تولید ورودی
ما دریافتیم که ترکیبِ گرد کردن (rounding) به یک VMCS معتبر و سپس تزریق انتخابی مقادیر نامعتبر، روشی بسیار مؤثر برای تولید ورودیهای مفید فازینگ است. عمل گرد کردن، جهشهای خام (raw mutations) را به نزدیکی حالتهای معتبر منتقل میکند؛ این کار از رد شدن زودهنگام جلوگیری کرده و به فازر اجازه میدهد منطقهای اعتبارسنجی را اجرا کند. سپس، تزریق انتخابی بیتهای نامعتبر پس از مرحلهٔ گرد کردن، VMCS را از مرزهای ظریف اعتبار عبور میدهد و احتمال آشکار شدن کدهای مستعد خطا را افزایش میدهد.
همچنین مشاهده کردیم که راهنمایی مبتنی بر پوشش (coverage guidance) سنتی در این محیط کمتر از حد انتظار مؤثر است. از آنجا که فرآیند گرد کردن بسیاری از جهشهای کوچک را نرمالسازی میکند، ورودیهایی که توسط بازخورد پوشش پیشنهاد میشوند اغلب پس از گرد کردن به حالتهای معادل فرو میریزند و بنابراین سیگنال اضافی محدودی فراهم میکنند. در نتیجه، یک راهبرد breadth-first (سطح-اول) که طیف گستردهای از حالتهای نزدیک به معتبر را کاوش میکند، نسبت به راهبرد depth-first (عمق-اول) که تغییرات ریز هدایت شده توسط پوشش را دنبال میکند، پوشش بهتری تولید کرد.
بر اساس این مشاهدات، پیشنهاد میکنیم در فازینگ مجازیسازی تودرتو، تنوع فضای حالت در اطراف مرزهای مشخصات (specification boundaries) در اولویت قرار گیرد و تبدیلهای سبکِ آگاه از اعتبارسنجی همراه با نامعتبرسازی هدفمند، بهعنوان یک دستورکار عملی برای تولید ورودیها مورد استفاده قرار گیرد.
6. بحث
در این بخش، محدودیتهای بالقوه در کشف باگها و همچنین دامنهٔ محدود کدهای هدف مورد بحث قرار میگیرد.
6.1 کشف باگ
ما در NecoFuzz، از sanitizerهای موجود مانند UBSAN و KASAN که در KVM تعبیه شدهاند استفاده کردیم. با این حال، با وجود تلاش برای بازتولید و شناسایی برخی آسیبپذیریهای شناختهشده (CVEها) [37–39]، موفق به کشف آنها نشدیم.
هرچند کشف باگ یکی از جنبههای حیاتی fuzzing محسوب میشود، آسیبپذیریها در مجازیسازی تودرتو (nested virtualization) اغلب به سازوکارهای تشخیص تخصصیتری نیاز دارند؛ برای مثال، تشخیص سوءاستفاده از سطح دسترسی هایپروایزر L0 از داخل یک ماشین مجازی L1، نه صرفاً شناسایی کرش در هایپروایزر L0.
این موضوع نشان میدهد که اتکا صرف به سنی تایزرها (sanitizer) برای کشف جامع آسیب پذیریها دارای محدودیت است و نیاز به روشهای پیشرفتهتر تشخیص باگ که متناسب با معناشناسی (semantics) مجازیسازی تودرتو طراحی شده باشند را برجسته میکند.
6.2 پوشش کد (Code Coverage)
NecoFuzz بهطور انحصاری بر اندازهگیری پوشش کدِ مرتبط با مجازیسازی تودرتو تمرکز دارد. این تمرکز به این دلیل انتخاب شد که اغلب فازرهای موجود برای هایپروایزرها هیچ پوششی برای این بخشهای کد فراهم نمیکنند؛ بنابراین، برای انجام fuzzing مؤثر در مجازیسازی تودرتو، ابتدا لازم بود قابلیت دسترسی (reachability) این ناحیه ارزیابی شود. با این حال، زیرسیستمهای دیگر هایپروایزر، مانند مدیریت حافظه و مدیریت وقفهها، ممکن است بهطور غیرمستقیم با مجازیسازی تودرتو مرتبط باشند و احتمال وجود آسیبپذیریهای مرتبط در آنها نیز وجود دارد. شناسایی چنین کدی دشوار است، زیرا در فایلهای منبع متعددی پراکنده شده و بهطور صریح بهعنوان منطق مجازیسازی تودرتو برچسبگذاری نشده است. در حالی که بهبود بیشتر پوشش کدهای اختصاصی مجازیسازی تودرتو همچنان اهمیت دارد، کارهای آینده باید طراحی harnessهای تخصصی را بررسی کنند که بتوانند مسیرهای اجراییِ بهطور غیرمستقیم مرتبط با مجازیسازی تودرتو را نیز هدف قرار دهند.
6.3 رویدادهای ناهمگام (Asynchronous Events)
NecoFuzz بر خروج از VMهایی تمرکز دارد که به طور صریح توسط دستورالعملهای مهمان (guest) ایجاد میشوند. این خروج از VMها قطعی (deterministic) هستند و از طریق ورودیهای فازینگ کنترل آنها آسانتر است. در حال حاضر، ما رویدادهای خارجی ناهمگام (مانند وقفهها، NMIها و VM exitهای مبتنی بر تایمر) را مدلسازی نمیکنیم، زیرا این موارد نیازمند تزریق دقیق رویداد و کنترل زمانی هستند که تکرارپذیری و قطعیت اجرا را پیچیده میکند. با وجود اهمیت این رویدادها برای آزمون کامل سیستم، مطالعات پیشین [13، 15] نشان دادهاند که خروج از VMهای ناشی از دستورالعملها بخش عمدهای از منطق امنیتمحور هایپروایزر را پوشش میدهند. مدلسازی و تزریق رویدادهای ناهمگام را به کارهای آینده واگذار میکنیم.
6.4 محدودیتها
در حال حاضر، NecoFuzz تنها یک هارنس مهمان تک vCPU را پیادهسازی میکند، که توانایی آن را در کشف باگهایی که از تعامل میان چند CPU به وجود میآیند محدود میسازد. علاوه بر این، NecoFuzz فقط از یک ماشین مجازی تودرتو پشتیبانی میکند و باگهایی را که ناشی از ارتباط بین چند VM هستند پوشش نمیدهد. تودرتوسازی عمیقتر، مانند پشتیبانی از یک سیستمعامل مهمان L3، نیز پشتیبانی نمیشود. برای بررسی این نوع تعاملات میان دامنهها (برای مثال تعامل بین vCPUها، بین VMها، و بین لایههای مختلف)، لازم است VMهای فاز هارنس (fuzz-harness) سازوکارهای ارتباطی متناظر را پیادهسازی کرده و با فازر هماهنگ شوند تا این تعاملات مورد آزمایش قرار گیرند. هرچند این مسیرهای ارتباطی لزوماً بهطور مستقیم به منطق مجازیسازی تودرتو در هایپروایزر میزبان مرتبط نیستند، اما ممکن است همچنان شامل بخشهایی از کد باشند که فقط در محیطهای تودرتو اجرا میشوند؛ مشابه مواردی که در بخش 5.1 بحث شد. گسترش NecoFuzz برای پشتیبانی از چنین ارتباطاتی را بهعنوان یکی از مسیرهای جالب برای کارهای آینده در نظر میگیریم.
7. کارهای مرتبط
NecoFuzz نخستین فریمورک فازینگ است که بهطور مؤثر کدهای اختصاصی مجازیسازی تودرتو را هدف قرار میدهد. تا جایی که میدانیم، NestFuzz [52] تنها کار پیشین است که بهطور صریح تلاش کرده مجازیسازی تودرتو را fuzz کند. با این حال، این کار در مرحلهای ابتدایی قرار دارد و صرفاً دستورالعملهای تصادفی VMX را بدون پرداختن به چالشهای کلیدی مانند اعتبار وضعیت VM، توالیهای مقداردهی اولیه، یا هارنس اجرایی صادر میکند، و همچنین فاقد ارزیابی پوشش کد یا قابلیت کشف آسیبپذیری است. پژوهشهای پیشین در زمینه فازینگ هایپروایزر را میتوان بهطور کلی بر اساس هدف اصلی آنها به دو دسته تقسیم کرد: فازینگ پردازندهٔ مجازی (virtual CPU) و فازینگ دستگاههای مجازی (virtual device).
7.1 فازینگ پردازندهٔ مجازی (Virtual CPU Fuzzing)
کارهای پیشین در زمینه فازینگ پردازندهٔ مجازی، شبیهسازی مجازیسازی مبتنی بر سختافزار را مورد توجه قرار ندادهاند. اگرچه برخی مطالعات تلاش کردهاند با استفاده از قالبها (templates) پردازندههای هدف را به حالتهای مقداردهی اولیهشده برسانند، اما چالشهای ناشی از فضای بسیار بزرگ وضعیت VM و وابستگیهای پیچیده موجود در پیکربندی vCPU هنگام راهاندازی VM را نادیده گرفتهاند.
ما این تلاشها را به دو نوع تقسیم میکنیم: فازینگ جعبهسیاه (black-box fuzzing)، که هدف را بهصورت یک سامانهٔ غیرشفاف در نظر میگیرد و به دانش داخلی نیاز ندارد، و فازینگ غیر جعبه سیاه (non-blackbox fuzzing)، که از ابزارگذاری داخلی یا استدلال نمادین بهره میبرد.
فازینگ جعبهسیاه بدون دسترسی به کد منبع یا دانش داخلی از هایپروایزر هدف عمل میکند. این رویکرد امکان استقرار سریع را فراهم میکند، اما معمولاً به دلیل نبود بینش معنایی کافی، پوشش کد پایینتری به دست میدهد. EmuFuzzer [29] فازینگ را برای شبیهسازهای CPU بهکار میگیرد تا انحرافهای رفتاری نسبت به CPUهای واقعی را شناسایی کند. این ابزار قالب دستورالعملها را بهصورت تجربی روی سختافزار واقعی استنتاج میکند و بدین ترتیب بدون نیاز به دیاسمبلرها، پوشش گستردهای از مجموعه دستورالعملها فراهم میسازد. با این حال، تنها از دستورالعملهای حالت کاربر (user-mode) پشتیبانی میکند و قادر به آزمون رفتارهای سطح دسترسی بالا که برای هایپروایزرها اهمیت دارند نیست. KEmuFuzzer [28] نسخهای توسعهیافته از EmuFuzzer است که از دستورالعملهای حالت کرنل نیز پشتیبانی میکند. این ابزار از قالبهایی با فیلدهای نمادین استفاده میکند تا یک سیستمعامل مهمان حداقلی برای اجرای موارد آزمون تولید کند. اگرچه این روش برخی حالتهای معتبر ایجاد میکند، تنوع آنها محدود است. همچنین از مقداردهی اولیه مجازیسازی مبتنی بر سختافزار پشتیبانی نمیکند و نمیتواند ساختارهایی مشابه VMCS را بهطور مستقیم جهش دهد. Amit و همکاران [3] ابزارهای اعتبارسنجی CPU اینتل را برای آزمون هایپروایزرها تطبیق دادهاند و نتایج را با شبیهساز اینتل مقایسه میکنند. موارد آزمون آنها ترکیبی از قالبهای دستی و توالیهای تصادفی دستورالعملها است و تنظیمات CPU از طریق یک فایل پیکربندی مشخص میشود. با وجود اشارهٔ مقاله به مجازیسازی تودرتو، به دلیل محدودیتهای KVM ارزیابی عملی انجام نشده و چالشهای خاص آن نیز بررسی نشدهاند.
فازینگ غیرجعبهسیاه، شامل رویکردهای خاکستری (graybox)، سفید (whitebox) و ترکیبی (hybrid)، از دانش داخلی هایپروایزر هدف برای هدایت تولید ورودیهای آزمون از طریق بازخورد پوشش یا اجرای نمادین استفاده میکند. این تکنیکها معمولاً به دسترسی به کد منبع نیاز دارند و اعمال آنها روی هایپروایزرهای متنبسته دشوار است. PokeEMU [27] از شبیهسازهای با دقت بالا مانند Bochs استفاده میکند تا بهصورت نمادین موارد آزمون را برای اهداف کمدقتتر مانند QEMU تولید کند. این روش نیازمند نشانهگذاری دستی ثباتها و حافظهٔ نمادین است، که اعمال آن را روی ساختارهای پیچیدهای مانند VMCS دشوار میسازد.
MultiNyx [13] هایپروایزر را بر روی یک مشخصهٔ اجرایی (executable specification) اجرا میکند تا رفتار آن را بهصورت نمادین کاوش کند. دستورالعملهای ساده بهطور مستقیم اجرا میشوند، در حالی که دستورالعملهای پیچیدهتر، مانند عملیات مجازیسازی، توسط مشخصه مدیریت میشوند. با این حال، این روش درستی وضعیت VM را اعتبارسنجی نمیکند و برای نشانهگذاری ورودیها نیازمند تغییر در کد منبع است. HyperFuzzer [15] راهنمایی مبتنی بر پوشش را با اجرای نمادین ترکیب میکند و با استفاده از رهگیری Intel PT تحلیل سبکوزنی را روی سختافزار واقعی انجام میدهد. این ابزار تنها بر جریان کنترل تمرکز دارد، فاقد اعتبارسنجی وضعیت VM است و به سیستمهای سازگار با Intel PT محدود میشود.
IRIS [9] از روش ثبت و بازپخش (record-and-replay) استفاده میکند؛ بدین صورت که ردپاهای اجرایی سیستمعامل مهمان را جمعآوری کرده و آنها را بهعنوان بذرهای فازینگ دوباره استفاده میکند. از آنجا که این ردپاها از سیستمعاملهای پایدار و رفتارمند بهدست میآیند، تنوع وضعیتهای VM محدود باقی میماند و در نتیجه کارایی آن در آشکارسازی آسیبپذیریها کاهش مییابد.
Syzkaller [17]، که یک فازر کرنل است، از مجازیسازی تودرتوی KVM با فراخوانی system callها و تخصیص مقادیر تصادفی به وضعیتهای VM پشتیبانی میکند. این رویکرد تنوع توالیهای دستورالعمل معتبر را محدود کرده و پوشش کد را کاهش میدهد. آزمون نمادین و متعارف در نگاه نخست ممکن است برای پایگاههای کدی مجازیسازی تودرتو (که شامل شبیهسازی پیچیدهٔ دستورالعملها هستند اما اندازهٔ نسبتاً کوچکی دارند) مؤثر به نظر برسند.
با این حال، چالش اصلی در سناریوی ما از فضای وضعیت بسیار بزرگ VMCS ناشی میشود که شامل بیش از ۱۵۰ فیلد وابسته به یکدیگر است؛ در نظر گرفتن کل این ساختار بهصورت نمادین، حلکنندههای SMT را با بار بیشازحد مواجه میکند. آزمون متعارف همچنین نیازمند یکپارچهسازی عمیق با هدف است که برای هایپروایزرهای متن بسته عملی نیست، در حالی که فازینگ جعبه سفید (whitebox) مستلزم مدلهای دقیق سختافزاری است؛ مدلهایی که ساخت آنها به دلیل رفتار پیچیده و تا حدی مستندسازی نشدهٔ CPU دشوار است. با این وجود، رویکردهای نمادین سبکوزن یا ترکیبی میتوانند مکمل چارچوب فازینگ ما باشند و همچنان به عنوان مسیری جالب برای پژوهشهای آینده مطرح هستند.
7.2 فازینگ دستگاههای مجازی (Virtual Device Fuzzing)
فازینگ دستگاههای مجازی رابطهای ورودی/خروجی (I/O) را هدف قرار میدهد و توانسته است آسیبپذیریهایی را در هایپروایزرهایی مانند QEMU/KVM، VirtualBox و VMware Fusion کشف کند.
VDF [19] آغازگر این مسیر بود و با ثبت فعالیتهای MMIO و استفاده از آنها بهعنوان بذر برای فازینگ مبتنی بر AFL عمل کرد. HYPER-CUBE [50] فازینگ جعبهسیاه را روی PIO/MMIO با استفاده از یک سیستمعامل سفارشی و مفسر بایتکد انجام میدهد و بدون بهرهگیری از راهنمایی پوشش (coverage guidance) به توان عملیاتی بالایی دست مییابد. NYX [49] فازینگ ساختیافته را بر اساس مشخصات پروتکل تعریف شده توسط کاربر پیادهسازی میکند، هرچند به تلاش دستی قابلتوجهی نیاز دارد. V-Shuttle [44] دسترسیهای DMA را رهگیری کرده و دادههای فازینگ را در ساختارهای DMA تودرتو تزریق میکند.
Morphuzz [7] با استنتاج بازههای I/O از نقشههای آدرس مهمان، کارایی فازینگ را بهبود میدهد.ViDeZZo [26] بر وابستگیهای درونپیامی و بینپیامی دستگاههای مجازی تمرکز دارد. HyperPill [8] از مجازیسازی سختافزاری برای فازینگ مبتنی بر snapshot در دستگاههای QEMU استفاده میکند.
با این حال، این رویکردها برای مجازیسازی تودرتو قابل اعمال نیستند، زیرا مجازیسازی تودرتو بر دستورالعملهای مجازیسازیِ مبتنی بر پشتیبانی سختافزاری تکیه دارد، نه رابطهای I/O. در نتیجه، فازینگ دستگاههای مجازی قادر به دسترسی به کدهای اختصاصی مجازیسازی تودرتو نیست.
8. نتیجهگیری
ما در این مقاله NecoFuzz را معرفی کردیم؛ نخستین فریمورک فازینگی که بهطور ویژه برای مجازیسازی تودرتو در هایپروایزرها طراحی شده است. NecoFuzz یک مولد ماشین مجازی (VM generator) ارائه میدهد که نمونههای کامل ماشین مجازی، موسوم به VM فاز هارنس (fuzz-harness)، را بهصورت کارآمد تولید میکند تا منطق امنیتحساس واقع در مرز میان حالتهای معتبر و نامعتبر VM را مورد کاوش قرار دهد. این مولد از سه مؤلفه تشکیل شده است: (۱) یک هارنس اجرای VM (VM execution harness) که مسیرهای کد مربوط به مجازیسازی تودرتو را فعال میکند، (۲) یک اعتبارسنج وضعیت VM (VM state validator) که با استفاده از مدلهای مبتنی بر مشخصات سختافزار، تولید ورودیها را هدایت میکند، و (۳) یک پیکربندی کننده vCPU (vCPU configurator) که ترکیبهای مختلف ویژگیهای مجازیسازیِ مبتنی بر پشتیبانی سختافزاری را بهصورت نظاممند بررسی میکند. ما NecoFuzz را برای هر دو معماری Intel VT-x و AMD-V پیادهسازی کرده و آن را برای فازینگ KVM، Xen و VirtualBox بهکار گرفتیم.
ارزیابی ما نشان داد که NecoFuzz در مقایسه با فازرهای موجود از جمله Syzkaller که تنها ابزار پیشین با پشتیبانی صریح از مجازیسازی تودرتو است، پوشش کد مربوط به مجازیسازی تودرتو را بهطور چشمگیری افزایش میدهد.
علاوه بر این، NecoFuzz موفق به کشف شش آسیبپذیری ناشناخته پیشین در میان این سه هایپروایزر شد که دو مورد از آنها شناسه CVE دریافت کردهاند. این نتایج نشان میدهد که NecoFuzz یک پایه عملی و مؤثر برای فازینگ سطح حملهای فراهم میکند که پیشتر در حوزه مجازیسازی تودرتو تقریباً بررسینشده باقی مانده بود.
منابع
[1] Advanced Micro Devices, Inc. 2024. AMD64 Architecture Programmer’s Manual, Volumes 1–5, Publication 40332, Revision 4.08. https://docs.amd.com/v/u/en-US/40332-PUB_4.08
[2] Alibaba Cloud. 2025. Compute Nest — Cloud Engine for Enterprise Applications. https://www.alibabacloud.com/product/compute-nest
[3] Nadav Amit, Dan Tsafrir, Assaf Schuster, Ahmad Ayoub, and Eran Shlomo. 2015. Virtual CPU validation. In Proceedings of the 25th Symposium on Operating Systems Principles (Monterey, California) (SOSP ’15). Association for Computing Machinery, New York, NY, USA, 311–327. doi:10.1145/2815400.2815420
[4] B. Asvija, R. Eswari, and M.B. Bijoy. 2019. Security in hardware assisted virtualization for cloud computing—State of the art issues and challenges. Computer Networks 151 (2019), 68–92. doi:10.1016/j. comnet.2019.01.013
[5] Muli Ben-Yehuda, Michael D. Day, Zvi Dubitzky, Michael Factor, Nadav Har’El, Abel Gordon, Anthony Liguori, Orit Wasserman, and Ben-Ami Yassour. 2010. The Turtles Project: Design and Implementation of Nested Virtualization. In Proceedings of the 9th USENIX Symposium on Operating Systems Design and Implementation (OSDI 10) (Vancouver, BC, Canada). USENIX Association, 423–436. https://www.usenix.org/conference/osdi10/turtles-project-design-and-implementation-nested-virtualization
[6] Paolo Bonzini. 2023. KVM: nVMX: add missing consistency checks for CR0 and CR4 (Linux kernel commit 112e660). https://github.com/torvalds/linux/commit/112e66017bff7f2837030f34c2bc19501e9212d5
[7] Alexander Bulekov, Bandan Das, Stefan Hajnoczi, and Manuel Egele. 2022. Morphuzz: Bending (Input) Space to Fuzz Virtual Devices. In Proceedings of the 31st USENIX Security Symposium (USENIX Security 22) (Boston, MA). USENIX Association, 1221–1238. https://www. usenix.org/conference/usenixsecurity22/presentation/bulekov
[8] Alexander Bulekov, Qiang Liu, Manuel Egele, and Mathias Payer. 2024. HYPERPILL: Fuzzing for Hypervisor-bugs by Leveraging the Hardware Virtualization Interface. In Proceedings of the 33rd USENIX Security Symposium (USENIX Security 24) (Philadelphia, PA). USENIX Association, 919–935. https://www.usenix.org/conference/usenixsecurity24/presentation/bulekov
[9] Carmine Cesarano, Marcello Cinque, Domenico Cotroneo, Luigi De Simone, and Giorgio Farina. 2023. IRIS: a Record and Replay Framework to Enable Hardware-assisted Virtualization Fuzzing. In Proceedings of the 53rd Annual IEEE/IFIP International Conference on Dependable Systems and Networks (DSN 2023). 389–401. doi:10.1109/DSN58367.2023.00045
[10] Sean Christopherson and Paolo Bonzini. 2023. KVM: x86/mmu:Use dummy root, backed by zero page, for !visible guest roots (Linux kernel commit 0e3223d8d). https://github.com/torvalds/linux/commit/0e3223d8d00ac05849661f1b8b476d3caca251cf
[11] Andrew Cooper. 2023. [PATCH 0/2] x86/vmx: Multiple fixes (xen-devel mailing list). https://lists.xen.org/archives/html/xen-devel/2023-11/msg00089.html
[12] Andrea Fioraldi, Dominik Maier, Heiko Eißfeldt, and Marc Heuse. 2020. AFL++ : Combining Incremental Steps of Fuzzing Research. In Proceedings of the 14th USENIX Workshop on Offensive Technologies (WOOT 20). USENIX Association, 12 pages. https://www.usenix.org/conference/woot20/presentation/fioraldi
[13] Pedro Fonseca, Xi Wang, and Arvind Krishnamurthy. 2018. MultiNyx: a multi-level abstraction framework for systematic analysis of hypervisors. In Proceedings of the Thirteenth EuroSys Conference (Porto,Portugal) (EuroSys ’18). Association for Computing Machinery, NewYork, NY, USA, Article 23, 12 pages. doi:10.1145/3190508.3190529
[14] Free Software Foundation. 2025. gcov—a Test Coverage Program. https://gcc.gnu.org/onlinedocs/gcc/Gcov.html
[15] Xinyang Ge, Ben Niu, Robert Brotzman, Yaohui Chen, HyungSeok Han, Patrice Godefroid, and Weidong Cui. 2021. HyperFuzzer: An Efficient Hybrid Fuzzer for Virtual CPUs. In Proceedings of the 2021 ACM SIGSAC Conference on Computer and Communications Security (Virtual Event, Republic of Korea) (CCS ’21). Association for Computing Machinery,New York, NY, USA, 366–378. doi:10.1145/3460120.3484748
[16] Google. 2025. crosvm - The ChromeOS Virtual Machine Monitor. https://chromium.googlesource.com/chromiumos/platform/crosvm/
[17] Google. 2025. syzkaller - kernel fuzzer. https://github.com/google/syzkaller
[18] Google Cloud. 2025. About nested virtualization. https://cloud.google.com/compute/docs/instances/nested-virtualization/overview
[19] Andrew Henderson, Heng Yin, Guang Jin, Hao Han, and Hongmei Deng. 2017. VDF: Targeted Evolutionary Fuzz Testing of Virtual Devices, In Proceedings of the 20th International Symposium on Research in Attacks, Intrusions, and Defenses (RAID 2017) (Atlanta, Georgia). Lecture Notes in Computer Science 10453, 3–25. doi:10.1007/978-3-319-66332-6_1
[20] Intel Corporation. 2025. Intel® 64 and IA-32 Architectures Software Developer’s Manual. https://www.intel.com/content/www/us/en/developer/articles/technical/intel-sdm.html
[21] Reima Ishii. 2023. Fixes in VM Entry Checks for Guest Segment Registers (Bochs PR #51). https://github.com/bochs-emu/Bochs/pull/51
[22] Kata Containers Community. 2025. Kata Containers. https://katacontainers.io/
[23] George Klees, Andrew Ruef, Benji Cooper, Shiyi Wei, and Michael Hicks. 2018. Evaluating Fuzz Testing. In Proceedings of the 2018 ACM SIGSAC Conference on Computer and Communications Security (Toronto, Canada) (CCS ’18). Association for Computing Machinery, New York, NY, USA, 2123–2138. doi:10.1145/3243734.3243804
[24] Jin Tack Lim and Jason Nieh. 2020. Optimizing Nested Virtualization Performance Using Direct Virtual Hardware. In Proceedings of the Twenty-Fifth International Conference on Architectural Support for Programming Languages and Operating Systems (Lausanne, Switzerland) (ASPLOS ’20). Association for Computing Machinery, New York, NY, USA, 557–574. doi:10.1145/3373376.3378467
[25] Linux KVM Project. 2025. KVM Unit Tests. https://www.linux-kvm.org/page/KVM-unit-tests
[26] Qiang Liu, Flavio Toffalini, Yajin Zhou, and Mathias Payer. 2023. ViDeZZo: Dependency-aware Virtual Device Fuzzing. In 2023 IEEE Symposium on Security and Privacy (SP). 3228–3245. doi:10.1109/SP46215.2023.10179354
[27] Lorenzo Martignoni, Stephen McCamant, Pongsin Poosankam, Dawn Song, and Petros Maniatis. 2012. Path-exploration lifting: hi-fi tests for lo-fi emulators. In Proceedings of the Seventeenth International Conference on Architectural Support for Programming Languages and Operating Systems (London, England, UK) (ASPLOS XVII). Association for Computing Machinery, New York, NY, USA, 337–348. doi:10.1145/2150976.2151012
[28] Lorenzo Martignoni, Roberto Paleari, Giampaolo Fresi Roglia, and Danilo Bruschi. 2010. Testing system virtual machines. In Proceedings of the 19th International Symposium on Software Testing and Analysis (Trento, Italy) (ISSTA ’10). Association for Computing Machinery, New York, NY, USA, 171–182. doi:10.1145/1831708.1831730
[29] Lorenzo Martignoni, Roberto Paleari, Giampaolo Fresi Roglia, and Danilo Bruschi. 2009. Testing CPU emulators. In Proceedings of the Eighteenth International Symposium on Software Testing and Analysis (Chicago, IL, USA) (ISSTA ’09). Association for Computing Machinery, New York, NY, USA, 261–272. doi:10.1145/1572272.1572303
[30] Microsoft. 2024. OpenHCL: The New Open-Source Paravisor. https://techcommunity.microsoft.com/blog/windowsosplatform/openhcl-the-new-open-source-paravisor/4273172
[31] Microsoft. 2025. Virtualization-based Security (VBS). https://learn.microsoft.com/windows-hardware/design/device experiences/oem-vbs
[32] Microsoft. 2025. Windows Sandbox. https://learn.microsoft.com/windows/security/application-security/application isolation/windows-sandbox/
[33] Microsoft Azure. 2017. Nested Virtualization in Azure. https://azure.microsoft.com/ja-jp/blog/nested-virtualization-in-azure/
[34] National Vulnerability Database. 2017. CVE-2017-12188. https://nvd.nist.gov/vuln/detail/CVE-2017-12188
[35] National Vulnerability Database. 2017. CVE-2017-2596. https://nvd.nist.gov/vuln/detail/CVE-2017-2596
[36] National Vulnerability Database. 2018. CVE-2018-16882. https://nvd.nist.gov/vuln/detail/CVE-2018-16882
[37] National Vulnerability Database. 2019. CVE-2019-3887. https://nvd.nist.gov/vuln/detail/CVE-2019-3887
[38] National Vulnerability Database. 2021. CVE-2021-29657. https://nvd.nist.gov/vuln/detail/CVE-2021-29657
[39] National Vulnerability Database. 2021. CVE-2021-3656. https://nvd.nist.gov/vuln/detail/CVE-2021-3656
[40] National Vulnerability Database. 2022. CVE-2022-45869. https://nvd.nist.gov/vuln/detail/CVE-2022-45869
[41] National Vulnerability Database. 2023. CVE-2023-30456. https://nvd.nist.gov/vuln/detail/CVE-2023-30456
[42] National Vulnerability Database. 2024. CVE-2024-21106. https://nvd.nist.gov/vuln/detail/CVE-2024-21106
[43] Oracle. 2017. You Can Now Run VMware VMs on Oracle Cloud Infrastructure with Ravello. https://blogs.oracle.com/cloud-infrastructure/post/you-can-now-run-vmware-vms-on-oracle-cloud-infrastructure-with-ravello
[44] Gaoning Pan, Xingwei Lin, Xuhong Zhang, Yongkang Jia, Shouling Ji, Chunming Wu, Xinlei Ying, Jiashui Wang, and Yanjun Wu. 2021. V-Shuttle: Scalable and Semantics-Aware Hypervisor Virtual Device Fuzzing. In Proceedings of the 2021 ACM SIGSAC Conference on Computer and Communications Security (Virtual Event, Republic of Korea) (CCS ’21). Association for Computing Machinery, New York, NY, USA, 2197–2213. doi:10.1145/3460120.3484811
[45] Gerald J. Popek and Robert P. Goldberg. 1974. Formal requirements for virtualizable third generation architectures. Commun. ACM 17, 7 (July 1974), 412–421. doi:10.1145/361011.361073
[46] Matthew J. Renzelmann, Asim Kadav, and Michael M. Swift. 2012.SymDrive: Testing Drivers without Devices. In 10th USENIX Symposium on Operating Systems Design and Implementation (OSDI 12)(Hollywood, CA). USENIX Association, 279–292. https://www.usenix. org/conference/osdi12/technical-sessions/presentation/renzelmann.
[47] John Scott Robin and Cynthia E. Irvine. 2000. Analysis of the Intel Pentium’s Ability to Support a Secure Virtual Machine Monitor. In 9th USENIX Security Symposium (USENIX Security 00) (Denver, CO). USENIX Association. https://www.usenix.org/conference/9th-usenix-security-symposium/analysis-intel-pentiums-ability-support-secure-virtual
[48] Scale Computing. 2025. Disaster Recovery Solutions. https://www.scalecomputing.com/disaster-recovery
[49] Sergej Schumilo, Cornelius Aschermann, Ali Abbasi, Simon Wör-ner, and Thorsten Holz. 2021. Nyx: Greybox Hypervisor Fuzzing using Fast Snapshots and Affine Types. In 30th USENIX Security Symposium (USENIX Security 21). USENIX Association, 2597–2614. https://www.usenix.org/conference/usenixsecurity21/presentation/schumilo
[50] Sergej Schumilo, Cornelius Aschermann, Ali Abbasi, Simon Wörner, and Thorsten Holz. 2020. HYPER-CUBE: High-Dimensional Hypervisor Fuzzing. In Proceedings of the Network and Dis-tributed System Security (NDSS) Symposium 2020 (San Diego, CA, USA). https://www.ndss-symposium.org/ndss-paper/hyper-cube-high-dimensional-hypervisor-fuzzing/
[51] Zekun Shen, Ritik Roongta, and Brendan Dolan-Gavitt. 2022. Drifuzz: Harvesting Bugs in Device Drivers from Golden Seeds. In 31st USENIX Security Symposium (USENIX Security 22) (Boston, MA). USENIX Association, 1275–1290. https://www.usenix.org/conference/usenixsecurity22/presentation/shen-zekun
[52] Changmin Teng. 2020. NestFuzz: A Framework for Fuzzing Nested Virtualization Environments. Master’s thesis. Brown University.
[53] The Bochs Project. 2025. Bochs: The Open Source IA-32 Emulation Project. https://bochs.sourceforge.io
[54] The Linux Kernel Project. 2025. KCOV: code coverage for fuzzing. https://docs.kernel.org/dev-tools/kcov.html
[55] The Linux Kernel Project. 2025. Linux Kernel Selftests. https://docs. kernel.org/dev-tools/kselftest.html
[56] Lluís Vilanova, Nadav Amit, and Yoav Etsion. 2019. Using SMT to accelerate nested virtualization. In Proceedings of the 46th International Symposium on Computer Architecture (Phoenix, Arizona) (ISCA ’19). Association for Computing Machinery, New York, NY, USA, 750–761. doi:10.1145/3307650.3322261
[57] Yilun Wu, Tong Zhang, Changhee Jung, and Dongyoon Lee. 2023. DevFuzz: Automatic Device Model-Guided Device Driver Fuzzing. In 2023 IEEE Symposium on Security and Privacy (SP). 3246–3261. doi:10.1109/SP46215.2023.10179293
[58] Xen Project. 2024. Xen Test Framework. https://xenbits.xenproject. org/docs/xtf/
[59] Xen Project. 2025. [BUG] Assertion failure with vmcb _vintr.fields.vgif in nested SVM. https://gitlab.com/xen-project/xen/-/issues/215
[60] Xen Project. 2025. [BUG] Nested SVM BUG() (LMA && !PG). https://gitlab.com/xen-project/xen/-/issues/216