Смекни!
smekni.com

Побудова надійних операційних систем, що допускають наявність ненадійних драйверів пристроїв (стр. 5 из 9)

Заборона доступу до портів введення-виведення

Для кожного драйвера в ядрі підтримується список портів введення-виведення, з яких він може читати, а також тих, у які він може писати. Читання і запис захищаються по окремо, так що процес, у якого є право на тільки читання з деякого порту вводу-виводу, не може писати в нього. Будь-яка спроба порушення цих правил призводить до вироблення коду помилки, що повертається закликають учасника. Таким чином, драйвер принтера може бути обмежений доступом тільки до портів введення-виведення принтера, аудіо-драйвер може бути обмежений доступом тільки до портів введення-виведення звукової карти і т.д.

На відміну від цього, в монолітних системах відсутній спосіб обмеження доступу внутрішньоядерної драйвера тільки до невеликого числа портів введення-виведення. Ядерний драйвер може випадково виконати запис в будь-який порт вводу-виводу і завдати істотної шкоди.

У деяких випадках в адресний простір драйвера можуть відображатися реальні регістри пристрої введення-виведення, щоб уникнути якого б то не було взаємодії з ядром при здійсненні введення-виведення. Однак, оскільки не в усіх архітектурах допускається відображення регістрів введення-виведення в призначені для користувача процеси із забезпеченням необхідного рівня захисту, ми вибрали модель, в якій реальні операції введення-виведення виконуються тільки ядром. Це проектне рішення є ще одним прикладом того, що ми віддаємо перевагу надійності на шкоду ефективності.

Хоча в даний час таблиці, що дозволяють доступ до портів введення-виведення, ініціалізувалися з конфігураційного файлу, ми плануємо реалізувати сервер шини PCI, який буде робити це автоматично. Сервер шини PCI може отримати з BIOS порти введення-виведення, необхідні кожному драйверу, і використовувати цю інформацію для ініціалізації таблиць ядра.

Перевірка параметрів

Оскільки всі виклики ядра проводяться шляхом генерації внутрішнього переривання, ядро може виконати обмежену валідацію параметрів до диспетчеризації дзвінка. Ця валідація включає перевірки як справності (sanity), так і прав доступу (permission). Наприклад, якщо драйвер просить ядро записати блок даних з використанням фізичної адресації, то цей виклик може бути відхилений, оскільки не в усіх драйверів є право на такі дії. Використовуючи віртуальну адресацію, ядро, мабуть, не зможе сказати, чи є ця адреса записи правильним, але воно, принаймні, зможе перевірити, що ця адреса дійсно є допустимим адресою в сегменті даних або стека користувацького процесу, а не відноситься до сегменту тексту і не є якимось випадковим недійсним адресою.

Хоча такі перевірки справності є грубими, це краще, ніж нічого. У монолітних системах ніщо не перешкоджає драйверу виконувати запис за адресами, за якими не можна писати не за яких умов, таким як адреси в сегменті тексту ядра.

Відлов поганих покажчиків

У програмах на мовах C і C + + використовується безліч покажчиків, і ці програми весь час схильні помилок, пов'язаних з використанням поганих покажчиків. Разменованіе невірного покажчика часто призводить до виявлення апаратурою помилки сегментації. У нашій розробці сервер або драйвер, що намагаються разименовать поганий покажчик, примусово завершуються, і видається дамп пам'яті для майбутньої налагодження, точно так само, як і для інших користувальницьких процесів. Якщо поганий покажчик виявляється в частині операційної системи, що виконується в режимі користувача, то сервер реінкарнації негайно помічає наявність збійної ситуації і замінює примусово завершений процес його свіжою копією.

Приборкання нескінченних циклів

Коли драйвер впадає в нескінченний цикл, це створює загрозу споживання нескінченного часу ЦП. Планувальник зауважує наявність такої поведінки і поступово знижує пріоритет несправного процесу, поки він не стає непрацюючим процесом. Проте інші процеси можуть продовжувати нормально працювати. Після вичерпання зумовленого інтервалу часу сервер реінкарняціі помітить, що даний драйвер не відповідає на запити, примусово завершить і перезапустить його.

На відміну від цього, коли в нескінченний цикл впадає ядерний драйвер, він споживає весь час ЦП і фактично завішують всю систему.

Перевірка DMA

Однією з речей, яку ми не можемо забезпечити, є запобігання заподіяння шкоди системі через невірного DMA (Direct Memory Access, прямий доступ до пам'яті). Для запобігання перезапису драйвером через DMA довільної частини реальної пам'яті потрібно апаратна захист. Проте ми можемо виявити деякі помилки DMA наступним чином. DMA зазвичай запускається шляхом запису адреси DMA в деякий порт вводу-виводу. Ми можемо надати бібліотечну процедуру, яка викликається для запису в деякий порт вводу-виводу з попередніми декодуванням (способом, що залежить від пристрою) записів у цей порт вводу-виводу з метою знаходження використовуваних адрес DMA і перевірки їх допустимості. У зловмисних драйверах така перевірка може обходитися, але в добропорядних драйверах цей спосіб дозволяє виловити хоча б деякі помилки при помірних накладних витратах.

Залежно від апаратури ми можемо надійти ще краще. Якщо б на периферійної шині малося MMU (Memory Management Unit, пристрій управління пам'яттю) введення-виведення, ми могли б точно обмежити доступ до пам'яті для кожного драйвера [16]. Для систем з шиною PCI-X ми збираємося покласти на свій сервер шини PCI відповідальність за ініціалізацію таблиць MMU введення-виведення. Це частина нашої майбутньої роботи.


6. Аналіз надійності

Для перевірки надійності системи ми вручну внесли деякі ретельно підібрані помилки в деякі з своїх серверів і драйверів, щоб побачити, що в результаті відбудеться. Як описувалося в розд. 3.3, наша система розробляється для виявлення та виправлення багатьох помилок, і саме це ми і спостерігали. Якщо з якої б то не було причини відбувався збій деякого компонента, це розпізнавалася сервером реінкарнації, який застосовував усі необхідні кошти для пожвавлення збійного компонента. Нижче це описується більш детально.

Для розуміння роботи нашої системи потрібно розрізняти два класи помилок. Перший клас складають логічні помилки, що означають, що сервер або драйвер дотримується протоколу межмодульних взаємодій і нормально відповідає на запити, як якщо б він успішно виконав роботу, чого насправді не відбувається. Прикладом є драйвер принтера, який друкує безглузду інформацію, але виробляє нормальні повернення. Для будь-якої системи дуже важко, якщо не неможливо, відловлювати помилки такого роду. Логічні помилки перебувають за межами цього дослідження.

Другий клас складається з протокольних помилок, за наявності яких порушуються правила, що визначають поведінку серверів і драйверів. Наприклад, в нашій системі від серверів і драйверів потрібно відповідати на періодичні запити стану, що надходять від сервера реінкарнації. Якщо вони не підкоряються цьому правилу, робиться коригуючий дію. Наша система розробляється для боротьби з протокольними помилками.

Сервер реінкарнації

Сервер реінкарнації – це центральний сервер, керуючий усіма серверами і драйверами операційної системи. Він дозволяє істотно підвищити надійність, забезпечуючи:

1. Негайне розпізнавання фатальних збоїв.

2. Періодичний моніторинг стану.

Таким чином, він допомагає відловлювати два поширених виду збоїв: померлі або погано себе провідні системні процеси і негайно береться за вирішення найбільш гострої проблеми. Якщо системний процес завершується, то сервер реінкарнації безпосередньо оповіщається про це і перевіряє свої таблиці, щоб зрозуміти, чи слід перезапустити сервіс. Цей механізм, наприклад, забезпечує негайну заміну драйвера, примусово завершеного через використання поганого покажчика. Крім того, періодичний моніторинг стану допомагає дисциплінувати погано себе провідні системні сервіси. Наприклад, драйвер, який впадає в нескінченний цикл і не може відповісти на запит стану від сервера реінкарнації, буде примусово завершений і перезапущений.

Заміна драйвера пристрою складається з суворо контрольованій послідовності дій. По-перше, сервер реінкарнації породжує новий процес, виконання якого затримується, оскільки для нього ще не призначено привілеї. Потім сервер реінкарнації повідомляє про новий драйвері файлової системи і, нарешті, призначає необхідні привілеї. Коли всі ці кроки успішно виконуються, новий процес починає працювати і виконує код драйвера, що береться з файлової системи. В якості додаткової обережності двійковий код деяких драйверів може дублюватися в основній пам'яті, щоб, наприклад, драйвер для диска кореневої файлової системи можна було завантажити без потреби в обміні з диском.

Надійність рівня додатків

Наявність збійного драйвера може приводити до наслідків для файлової системи і додатків, що виробляють введення-виведення. Якщо у файлової системи був невиконаний запит вводу-виводу, їй буде повернуто код помилки, що говорить про збій драйвера. У цей момент можуть бути зроблені різні дії. Необхідно проводити відмінність між блоковими і символьними пристроями, тому що введення-виведення для блокових пристроїв буферізуется в буферному кеші файлової системи. На рис. 3 наводиться огляд різних сценаріїв відновлення на рівні програми.

При фатальному збої блокового драйвера можливо повне відновлення без втрати даних, прозоре для програми. Коли розпізнається збій, сервер реінкарнації запускає нову копію драйвера і скидає кеш файлової системи для синхронізації. Таким чином, буферний кеш не тільки підвищує продуктивність, але також є важливим і для надійності.

Прозоре відновлення іноді є можливим і при збоях драйверів символьних пристроїв. Оскільки запит вводу-виводу не буферізуется в кеші блоків файлової системи, інформація про помилку вводу-виводу повинна бути доведена до програми. Якщо програма не може призвести відновлення, про проблему буде сповіщений користувач. Фактично, збої драйверів проштовхуються нагору, що призводить до різних сценаріїв відновлення. Наприклад, якщо відбувається збій драйвера Ethernet, то мережевий сервер помітить відсутність пакетів і зробить прозоре відновлення, якщо додаток використовує надійний транспортний протокол, такий як TCP. З іншого боку, якщо відбувається збій драйвера принтера, то користувач, звичайно, помітить, що його виведення на друк не вдався і повторить команду друку.