| RSS



Меню

Bookmark and Share


Статистика
Ваш IP: 54.92.190.11
Вы используете: v





Сейчас на сайте:

Тех поддержка ->

Облако тэгов
ОС видио Tor Обратная сторона антенна 4.6 PHP Эксплоит Windows Server 2008 qip Virtual chroot kernel proc sysctl tune FreeBSD bridge Boot Disk Bluetooth GEO game directx Emulator Python Shell DDoS червь Conficker вирус троян Лаборатория Касперского пиратство apple iPhone ИТ-отрасль Щеголев Microsoft экономический кризис Twitter социальная сеть анонимность Лицензия Open Source ASP.NET MVC уязвимость MySQL база данных файлообмен закон франция пират Skype мобильный Deutsche Telekom Хакер киберпреступник Trend Micro кибератака Германия робот утечка данных персональные данные ноутбук интернет Китай цензура ядро Linux Торвальдс Windows Vista Acer Linux патент браузер Firefox Internet Explorer Opera Net Applications Safari Intel Linux Foundation Moblin Oracle патч банкомат кардер HSM IBM X-Force Cofee сша кибервойна Эстония Dell ИТ-специалист хакерские атаки Pirate Bay контроль кибербезопасность язык программирования The Pirate Bay Пиратская партия утечка информации приговор Mozilla Chrome безопасность Госдума СМИ Windows 8 Баллмер взлом Пентагон ботнет Украина Facebook Cisco cloud Windows XP нетбук торрент музыка биометрический nokia ФБР IP-адрес CIPAV Comcast sms RSA java Google CAPTCHA Symantec спам конфиденциальная информация инсайдер Perimetrix антивирус тест Anti-Malware Windows 7 операционная система Windows провайдер авторское право RapidShare UNIX свиной грипп шантаж дети EFF BluWiki копирайт экстремизм Panda Security cloud computing McAfee Cybercrime Response Unit Bottle Domains HTTPS ICANN студент шпионское ПО Норвегия школьник New York Times XSS YouTube Warner Music кибершпионаж КНДР Ubuntu свободное ПО AMD ATI касперский Россия РФ сервер хостинг фальшивый антивирус Comodo CA Wi-Fi D-Link суд пароль блог фишинг Одноклассники медведев контрафакт мошенник штраф Sony GPS по Gumblar JAVASCRIPT хакеры вредоносное ПО Yahoo ФАС компьютер Софт MPAA кибероружие PandaLabs Red Hat Минкомсвязи сбой ASUSTeK Computer мошенничество Доктор Веб ВКонтакте Cyber-Arc исходный код PCI DSS МВД фильтр порнография BREIN свобода слова Казахстан GEMA Autodesk сисадмин Gmail кредитная карта кибермошенник LiveJournal шифрование криптография Deep Purple банк нанотехнологии Wikipedia zero-day ColdFusion выборы кража данных DNS BIND Android BASIC атака Black Hat Mac OS X Click Forensics Clampi домен фсб Прокуратура Уголовное дело icq Barrelfish киберпреступность Sophos AT&T ошибка Electa Gamma Knife OpenBSD DARPA военные Сайт Visual Studio 2010 .NET Framework 4 Chrome OS электронная почта турция конференция спамер FTC полиция российская ОС Koobface Великобритания БЕЛОРУССИЯ грузия BSA Bittorrent облачные вычисления Azure Европа Dr.Web Билл Гейтс спецслужбы Cryzip Живой Журнал Royal Bank of Scotland смартфон Canonical Pwn2Own F-Secure Symbian Hotmail фильм

Главная » Статьи » Общие Статьи

Аппаратная виртуализация на практике: переход к практике
В прошлой статье я кратко познакомил тебя с архитектурой AMD-V. В этой мы продолжим разбираться с нелегкой темой. Я намерено упустил множество важных деталей относительно механизма работы гипервизора, дабы с первого раза не перегружать твой мозг большими объемами информации. Будем заполнять этот пробел.

Я буду приводить примеры и форматы регистров в Long Mode по ходу, поэтому сразу следует сказать (или напомнить), что Long Mode — это режим работы процессора, в котором работают все 64-битные ОС-и.
Инструкция VMRUN

Как ты помнишь из предыдущей статьи (ведь еще помнишь? :)) — инструкция VMRUN запускает виртуальную машину. Состояние хоста сохраняется в специальной области памяти, указатель на которую хранится в регистре VM_HSAVE_PA. А состояние запускаемого гостя — загружается из VMCB (на которую указывает регистр rax). Сегодня мы будем разбираться с этой чрезвычайно важной инструкцией, чтобы успешно заполнить управляющий блок виртуальной машины и запустить гостевую систему...
А верна ли VMCB?

VMRUN производит кучу проверок правильности контрольного блока виртуальной машины (а то мало ли что мы ей подсунуть хотим). Если обнаруживается что-то подозрительное и недопустимое, то нас посылают с кодом VMEXIT_INVALID (кстати, некоторые коды VMEXIT я уже упоминал в предыдущей статье).

Итак, в каких же случаях VMRUN откажется запускать гостя? Буду перечислять эти ситуации по пунктам, а тебе при прочтении рекомендую иметь перед глазами структуру VMCB.

Заголовочный файл, содержащий VMCB:

http://cvs.opensolaris.org/source/xref/xen-gate/xvm-3.4+xen.hg/xen/include/asm-x86/hvm/svm/vmcb.h

1. Флаг в SVME в регистре EFER равен 0. Аппаратная виртуализация в госте должна быть включена.

2. Сброшен бит CR0.CD и одновременно установлен CR0.NW. Первый бит расшифровывается как Cache Disable — когда он установлен, инструкции и данные не помещаются во внутренние кэши. А вот второй бит (по крайней мере, так написано в мануале AMD) — вообще игнорируется. Странно, что VMRUN его проверяет при сброшенном бите CD.

3. Старшие 32 бита CR0 не равны 0. Если ты посмотришь на формат регистра CR0 (в long mode), то увидишь, что эти биты должны быть равны 0.

4. В регистрах CR3, CR4, DR6, DR7, EFER не равны нулю биты, отмеченные как MBZ (Must Be Zero).

5. ASID равен 0. ASID — это идентификатор адресного пространства, позволяющий отличать элементы хоста от гостевых в ассоциативном буфере трансляции (TLB). То есть поле ASID должно быть обязательно проинициализировано. На всякий случай напомню, что TLB используется для ускорения преобразования виртуальных адресов в физические. Наличие ASID-идентификатора позволяет избежать сброса TLB при каждом входе и выходе из гостя. Что, конечно, положительно сказывается на производительности.

6. Ошибочная инъекция события. Инжектированное событие — это прерывание или исключение, выполняемое перед первой инструкцией гостя.

// Структура eventinj_t в VMCB описывает параметры инжектированного
события

typedef union

{

u64 bytes;

struct

{

u64 vector: 8; // номер прерывания или исключения

u64 type: 3; // тип события

u64 ev: 1; // бит, указывающий на правильность кода ошибки (поле errorcode).

u64 resvd1: 19; // зарезервированные биты

u64 v: 1; // Valid. Если этот бит установлен, событие инжектировано, если
сброшен — не инжектировано

u64 errorcode:32; // код ошибки

} fields;

} __attribute__ ((packed))

eventinj_t;

Вообще, возможных типов инжектированных событий (поле type) всего 4:
0 — INTR (внешнее прерывание);
2 — NMI (немаскируемое прерывание). Если мы укажем тип NMI, то поле номера прерывания (vector) будет игнорироваться;
3 — исключение;
4 — программное прерывание.

Если бит ev (Error code valid) установлен, то код ошибки errorcode будет "затолкнут" в стек. В каких случаях инъекция события неверна? Например, если гость в 64-битном режиме, а мы пытаемся инжектировать исключение #BR (вызывается командой bound), невозможное в этом режиме. Мы также получим VMEXIT_INVALID, если будем использовать зарезервированные значения поля type (1,5,6 или 7). Или если мы укажем тип исключения, а номер вектора — 2, что соответствует NMI (это немаскируемое прерывание, а не исключение!).

7. Биты EFER.LMA (Long Mode Active) или LME (Long Mode Enable), отвечающие за активацию Long Mode, установлены, а процессор не поддерживает Long Mode. Вполне логично, что такое сочетание будет признано невалидным.

8. Одновременная установка битов EFER. LME и CR0.PG (флаг включения страничного преобразования адресов) при сброшенном бите CR4.PAE (или CR0.PE) — недопустимая комбинация.

9. Флаги EFER.LME, CR0.PG, CR4.PAE (бит расширения физического адреса), CS.L и CS.D одновременно установлены. CS — сегмент кода. Биты L и D содержатся в дескрипторе сегмента. В 32-битном защищенном режиме бит D использовался для указания размера операнда и адреса (32 или 16 бит), а бит L — это бит, указывающий, что размер адреса и операнда у нас 64 бита. Теперь, я думаю, тебе понятно, почему одновременная установка этих двух битов является ошибкой (то есть мы указываем, что у нас одновременно по умолчанию установлен размер операнда 64 и 32 бита).

10. Бит перехвата инструкции VMRUN (в области управления VMCB) сброшен — эта инструкция должна перехватываться в обязательном порядке. Да, ты все верно подумал. Действительно, можно вызывать VMRUN, уже находясь в режиме гостя. Вот пример, связанный с Голубой пилюлей. Некоторым людям удавалось запускать более 20 (!) вложенных пилюль. Главное — правильно сделать перехват этой инструкции.

В VMCB бит перехвата VMRUN располагается в двойном слове по смещению 10h от начала управляющего блока виртуальной машины и перехватить VMRUN можно так:

...

// Бит VMRUN_INTERCEPT имеет номер 0

pVmcb->general2_intercepts|=1;

...

Вообще, поле general2_intercepts помимо бита перехвата VMRUN содержит флаги перехвата других инструкций из svm-расширения: VMMCALL, VMLOAD, VMSAVE, STGI, CLGI и SKINIT, но перехватывать эти инструкции уже необязательно.

11. Физические адреса карты разрешения MSR (MSRPM) или ввода-вывода (IOPM) равны или больше максимального поддерживаемого физического адреса. А иначе им (картам) просто не хватит места! Карта разрешения MSR (как и ввода-вывода) должна быть выровнена по границе 4 килобайта. И VMRUN игнорируются младшие 12 бит адреса MSRPM и IOPM. О картах, кстати, я упоминал в предыдущей статье.

Если VMCB верная, то можно продолжать. Теперь ты знаешь, чего делать нельзя. Дальше поговорим о том, что можно и нужно :).

VMRUN после проверок и сохранения состояния хоста загружает следующую информацию из контрольного блока виртуальной машины.

Первое, что обрабатывается VMRUN — это область состояния гостя (она же State Save Area):

1. CS и rip — определяют, откуда начнет выполняться гость. CS — сегмент кода, а rip — указатель инструкции в long mode (когда мы имели дело с 32-битами, у нас был регистр eip).

2. Регистры rflags,rax...

3. SS (сегмент стека) и rsp — стек гостя. В 32-битном режиме был не rsp, a esp :).

4. CR0, CR2 (в этом регистре содержится виртуальный адрес ошибки страницы — page fault), CR3, CR4 и EFER — эти регистры отвечают за страничное преобразование адресов в гостевой системе.

5. IDTR, GDTR(база и размер таблиц дескрипторов GDT и IDT),ES и DS, DR7 и DR6.

6. V_TPR — виртуальный регистр приоритета задачи (TPR). Значение поля v_tpr записывается в регистр CR8 гостя. Регистр приоритета задачи используется в случаях, если, у нас, например, пришло какое-то "не очень важное" прерывание, а выполняется какая-то задача, которую ну никак нельзя прервать. Тогда мы записываем приоритет прерывания (например, 7) в регистр CR8 и все прерывания с приоритетом меньше 7(включительно) будут игнорироваться.

7. V_IRQ. Этот флаг определяет, будет ли виртуальное прерывание отложено.

8. CPL или текущий уровень привилегий. Если гостевая система загружается в реальный режим — CPL = 0, если в режим виртуального 8086, то 3. CPL определяет кольцо защиты: 0 — нулевое, 3, соответственно, третье. После этого VMRUN переходит к обработке области флагов (Control Area).

Здесь можно отметить так называемый TSC_OFFSET. Значение TSC_OFFSET добавляется к счетчику меток реального времени (в мануалах — TSC) в госте, когда тот решит получить его значение. То есть, когда мы выполним в госте команду rdtsc, то к значению счетчика будет автоматически прибавлено значение TSC_OFFSET. С этим полем связан известный баг (Erratum 140), когда при чтении TSC MSR через rdmsr, а не rdtsc значение TSC_OFFSET не прибавлялось к счетчику.

Конечно, в Control Area мы можем указать множество различных событий или инструкций, которые хотим перехватывать. Так же считывается уже упоминавшийся идентификатор ASID и т.д.

В нашей структуре VMCB каждый сегмент описывается структурой segment_register (код взят из Xen), содержащей части дескриптора сегмента и селектор на этот дескриптор:

// структура, описывающая атрибуты сегмента

typedef union segment_attributes

{

uint16_t bytes;

struct

{

uint16_t type:4; /* 0; Bit 40-43 */

uint16_t s: 1; /* 4; Bit 44 */

uint16_t dpl: 2; /* 5; Bit 45-46 */

uint16_t p: 1; /* 7; Bit 47 */

uint16_t avl: 1; /* 8; Bit 52 */

uint16_t l: 1; /* 9; Bit 53 */

uint16_t db: 1; /* 10; Bit 54 */

uint16_t g: 1; /* 11; Bit 55 */

uint16_t pad: 4;

} fields;

}

__attribute__ ((packed)) segment_

attributes_t;

// Структура, описывающая сегмент в VMCB

struct segment_register

{

// селектор на дескриптор сегмента

uint16_t sel;

// атрибуты сегмента

segment_attributes_t attr;

// размер

uint32_t limit;

// адрес начала сегмента

uint64_t base;

} __attribute__ ((packed));

К атрибутам сегментов в VMCB предъявляются определенные требования. Подробнее:

1. Не разрешен нулевой сегмент кода, поэтому воспринимаются аппаратурой только некоторые биты в дескрипторе (D, L, R).

2. Регистр TR может иметь только тип TSS (напоминаю, что тип сегмента определяется в дескрипторе сегмента).

3. У LDTR из атрибутов не игнорируется только бит присутствия сегмента (P). Когда сработает какое-либо перехватываемое событие, управление получит инструкция после VMRUN (впрочем, я об этом уже говорил). После VMRUN необходимо разместить код проверки и обработки различных условий #VMEXIT.

Ядро гипервизора составляет цикл из VMRUN и обработки VMEXIT:

// основной цикл гипервизора (в общем виде)

// paVmcb — physical address vmcb

// vaVmcb — virtual address vmcb

do

{

// после каждого VMEXIT нужно устанавливать все перехваты заново, т.к. они
очищаются

InstallIntercepts(vaVmcb);

// передаем VMRUN физический адрес VMCB

_VMRUN(paVmcb);

// обработка кодов выхода из гостя

switch(vaVmcb->exitcode)

{

case VMEXIT_RDTSC:

...

break;

case VMEXIT_VMRUN:

...

break;

...

// другие обрабатываемые события

}

}while(1);

Для полного понимания сказанного тебе придется подтянуть знания защищенного режима работы процессора (если ты не знаком с этой темой).
Создаем VMCB

Ну что, твоих знаний еще недостаточно для создания полноценного гипервизора? Однако продолжаю потихоньку вводить тебя в курс дела :).

Что касается выделения блока памяти под VMCB и Host Save Area — это можно сделать ядерной функцией MmAllocateContiguousMemorySpecifyCache. Ее прототип:

NTKERNELAPI

PVOID

MmAllocateContiguousMemorySpeci

fyCache(

IN SIZE_T NumberOfBytes, // количество выделяемых байт

IN PHYSICAL_ADDRESS LowestAcceptableAddress, // нижняя граница при выделении
памяти

IN PHYSICAL_ADDRESS HighestAcceptableAddress, // верхняя граница при выделении
памяти

IN PHYSICAL_ADDRESS BoundaryAddressMultiple OPTIONAL, // выравнивание региона

IN MEMORY_CACHING_TYPE

CacheType

);

В прошлой статье я упоминал, что для понимания кода понадобится опыт разработки дров под Винду (ну или хотя бы минимальные знания, чтобы понимать сорс). Примерный код для выделения памяти под VMCB:

..

l1.QuadPart = 0; // минимальный адрес для выделения

l2.QuadPart = -1; // максимальный адрес

l3.QuadPart = 0x10000; // выравнивание

// VMCB занимает 1 страницу, => uNumberOfPages = 1

// CacheType = MmCached

PageVA = MmAllocateContiguousMe

morySpecifyCache (uNumberOfPages *

PAGE_SIZE,l1, l2, l3, CacheType);

if (!PageVA)

return NULL;

// обнуляем выделенный регион

RtlZeroMemory (PageVA,

uNumberOfPages * PAGE_SIZE);

// получаем физический адрес выделенного региона

PagePA = MmGetPhysicalAddress

(PageVA);

...

Аналогичным образом память выделяется и для HSA, и для карт разрешения MSR и IOIO.







Категория: Общие Статьи | Добавил: aka_kludge (16.02.2011) | Автор: R0064
Просмотров: 788 | Рейтинг: 0.0/0
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
    Главная      
...
На службе : дней

01:35
Обновить


Пользователи
aka_kludge
qwerty
LeadyTOR
aka_Atlantis
AdHErENt
mAss
Sissutr
hiss
DrBio
tHick

Поиск


Copyright tHR - TeAM 2018 г. admin: aka_kludge (ICQ:334449009) Moderator's: LeadyTOR, ... Яндекс.Метрика