Ради безопасности

9 май, 2006 - 23:00Андрей Зубинский

Как-то незаметно в мире операционных систем наступило почти полное затишье. Как будто пять-шесть лет назад ничего вообще и не было – ни экспрессивных и, на первый взгляд, грамотных предреканий неудачи Windows XP, ни не менее громких обещаний скорой, полной и окончательной победы Linux в мире настольных компьютеров.

Время все расставляет по своим местам и без сожаления отправляет фактически в забвение довольно красивые и небездарные разработки, такие как Atheos (некогда мы говорили об этом Open Source клоне BeOS) и Bluebottle. Забвение некоторых систем становится отправной точкой для появления их клонов (так случилось с Atheos – от нее «отпочковалась» ОС Syllable, но их судьба во многом предрешена: в маленьких замкнутых сообществах разработчиков-энтузиастов со временем и под давлением обстоятельств иссякают запасы самого главного ресурса – интереса. Сделанное для себя своими руками, без сомнения, радует глаз создателя и становится предметом его гордости, но при всем этом оно перестает быть интересным.

...N упало, что осталось на трубе?

Как это ни странно, но в среде новоявленных приверженцев UNIX-подобных операционных систем и идеологии Open Source (эти слова умышленно оставляются без перевода) ОС GNU Hurd почти неизвестна. А ведь в свое время именно это «вечнонедоделанное» ядро операционной системы фактически отвечало за отрицание в рекурсивной аббревиатуре GNU (GNU – GNU is Not UNIX). Именно Hurd и было, но так и не стало, основой той самой по сей день не рожденной «не UNIX». И именно на Hurd небезосновательно возлагались надежды сторонников сильнозащищенных систем. Но время шло, Hurd так и пребывала в непригодном к повседневному применению состоянии, ее место заняло практически каноническое UNIX-подобное ядро Linux. То, что получилось, можно смело называть не GNU, а GU (GU is UNIX) – традиционное для мира UNIX ядро в обрамлении (де-факто и, что важнее, де-юре) стандартных утилит.

Что же случилось с Hurd? Ответ на этот вопрос на самом деле весьма важен – он позволяет понять и в какой-то мере даже достаточно обоснованно прогнозировать развитие операционных систем, и не только UNIX-подобных.

Итак, Hurd. Это объектно-ориентированное ядро современной операционной системы, использующее микроядро Mach и надстройки над ним. Так было, по крайней мере, до недавних времен. Теперь в судьбе проекта Hurd наступил серьезный переломный момент. Все ресурсы архитектурных идей, лежащих в основе проекта и во многом определенных свойствами микроядра Mach, сегодня фактически выработаны. В связи с этим ведущие архитекторы проекта Нил Уолфилд и Маркус Бринкман приняли решение... отказаться от использования Mach, несмотря даже на то, что ОС Mac OS X с ядром аналогичной архитектуры успешно реализована, развивается, портирована на новую платформу и эксплуатируется сотнями тысяч пользователей. Не следует поспешно обвинять Уолфилда и Бринкмана в волюнтаризме – принятию ими решения предшествовали серьезные дебаты и обсуждения, в которых участвовали такие гранды системного проектирования, как, например, Джонатан Шапиро (идеолог и разработчик ОС EROS). Но прежде чем мы ознакомимся с главной причиной, вызвавшей отказ разработчиков GNU Hurd от микроядра Mach, сделаем небольшое отступление – часто применяемые понятия надо часто повторять, иначе они утрачивают смысл.

Процесс – самый крупный объект, использование которого планирует (scheduling) ядро операционной системы. Фактически это набор различных ресурсов и как минимум одного потока исполнения (thread). Ресурсы здесь и в дальнейшем понимаются в терминах операционной системы и, естественно, являются памятью, идентификаторами файлов, сокетов, окон и пр. Ресурсы процесса обычно уникальны, и это не прихоть, а дань требованиям надежности и безопасности – процессы должны быть максимально изолированы друг от друга так, чтобы «выход из строя» одного из них минимально сказался на прочих его собратьях. В развитых операционных системах предусмотрены компромиссные механизмы, в какой-то мере обходящие требование уникальности ресурсов процесса, например механизм разделяемой памяти (shared memory). Это уже дань требованиям к производительности системы. Из сказанного выше очевидно, что поток исполнения (thread), в отличие от процесса, не включает в себя (иными словами – не владеет) высокоуровневые ресурсы ОС. Его собственность весьма невелика – стек, счетчик команд и копия регистров процессора. Потоков исполнения внутри процесса может быть множество – именно это позволяет «раздать» одно «тяжелое» приложение нескольким процессорам многопроцессорных машин (здесь надо бы сделать одно уточнение – симметричных многопроцессорных, но в контексте статьи оно не важно). Классификация потоков исполнения более чем скромна и основывается на принадлежности механизмов управления и планирования. Если они принадлежат ядру операционной системы – речь идет о так называемых kernel threads, если же механизмы управления потоками исполнения реализованы на пользовательском, непривилегированном уровне – о «волокнах» (fiber, в отличие от «нити» thread).

Теперь мы можем вернуться к обсуждению проблем, вынудивших архитекторов Hurd отказаться от ранее принятых решений. Все дело в том, что им пришлось согласиться со следующим весьма обоснованным утверждением: потоки, управляемые механизмами ядра ОС (kernel threads), – недешевое удовольствие. Серьезное обоснование этого положения в свое время привел ведущий разработчик и идеолог микроядра «второго поколения» Йохан Лидке (Jochen Liedtke) в своей статье «Модернизация механизмов межпроцессного взаимодействия на уровне архитектурных решений ядра ОС» (Improving IPC by Kernel Design, эта заслуженно считающаяся уже неоклассикой статья доступна в формате pdf, например, здесь. Несмотря на то что работа Лидке датируется 1993 г. и в качестве оценочного примера в ней рассматривается совершенно допотопный и неповоротливый по сегодняшним меркам процессор с тактовой частотой 50 MHz, основные положения статьи актуальности не утратили. Более того, можно говорить о том, что в некотором смысле архитектурные предложения Лидке обогнали свое время и их важность только-только начинает оцениваться по достоинству. Логика, обусловливающая это утверждение, на самом деле проста – только с массовой доступностью многопроцессорных (или многоядерных, что не существенно) компьютеров эффективность реализации механизмов межпроцессного взаимодействия (IPC, InterProcess Communications) становится ключевым фактором, определяющим производительность всей вычислительной системы в целом. Ведь в таких системах потоковое программирование массово применяется и для полноценного использования вычислительных ресурсов, и для достижения лучших характеристик надежности и безопасности ПО. Куда серьезнее влияние эффективности механизмов IPC сказывается на работе ОС, основанных на микроядре, – ведь в них фактически все многочисленные компоненты системного уровня «общаются» исключительно посредством этих механизмов, пусть низкоуровневых, но практически аналогичных «классическим». А жесткие требования реальности к безопасности и надежности вычислений постепенно вынуждают всех разработчиков операционных систем внимательно присматриваться к идеям «микроядерной» ОС.

Еще в 1993 г. микроядро, созданное Лидке, демонстрировало впечатляющее превосходство в быстродействии механизмов IPC по сравнению с Mach – от трехкратного до более чем двадцатикратного! К слову, оставленный творческим наследством Лидке опыт этой впечатляющей победы представляет вполне самостоятельную ценность, ведь Mach – проект, и далеко не «игрушечный», и вовсе не однодневка, и превзойти достигнутые в нем результаты – более чем достойно. Принципы проектирования, обеспечившие Лидке победу (а сейчас, уже после ухода из жизни этого талантливого архитектора и системного программиста, можно уверенно говорить, что он победил), таковы:

  • явная формулировка главной задачи проектного процесса (конкретно – производительности реализации механизмов IPC);
  • анализ соотношения всех рассматриваемых проектных решений с главной задачей;
  • отказ от попыток оптимизации известных проектных решений в пользу поиска новых;
  • строгий учет синергетических эффектов, проявляющихся при одновременном использовании разных проектных решений;
  • признанные пригодными проектные решения реализуются на всех уровнях – от высокоуровневой архитектуры до кода реализации.

Иными словами, принципы Лидке вполне соответствуют классическим «недемократическим» и «не хайтек» процессам проектирования и конструирования. В детали работы механизмов IPC микроядра L3, описанного в статье Лидке, мы вдаваться не будем – нам важнее сам факт того, что еще в 1993 г. существовало настоящее микроядро (размер реализации около 128 KB), существенно превосходящее по ключевому параметру не только конкурирующую Mach, но и такой признанный шедевр «операционного системостроения», как ОС QNX. Понадобилось всего каких-то 12 с лишним лет, чтобы разработкам ныне покойного Лидке нашлось применение в проекте, потенциально ориентированном на куда большую, чем профильно-факультетсткую, аудиторию пользователей. Новое ядро Hurd, по сей день остающееся старой надеждой GNU на создание полноценной «не UNIX» операционной системы, будет реализовано на основе микроядра L4 – продолжателя идей и архитектур, чьим автором является Йохан Лидке.

TUD:OS

Ради безопасности
Минимализм реализации, виртуализация с одновременным отказом от потенциально опасного исполнения в привилегированном режиме – главные особенности графической оболочки ОС TUD:OS Nitpicker. Правда, при реальном использовании (насколько можно о нем говорить, когда мы имеем дело все-таки с демонстрационной системой) ощущается главный недостаток любой новой графической оболочки – отсутствие драйверов, позволяющих полностью реализовать потенциал аппаратной акселерации видеоадаптера

С одной стороны, по-настоящему нового в новой ОС TUD:OS не так уж и много (TUD:OS – исследовательская ОС технического университета Дрездена, TU Dresden Research Operating System, demo.tudos.org). Эта система фактически является овеществлением ряда идей Лидке и во многом основывается на разработанном им коде микроядра L4/Fiasco (в этом имени L4 означает спецификации, созданные Лидке, а Fiasco – имя конкретной реализации микроядра для платформ семейства x86). Ключевое проектное решение на уровне микроядра – механизмы межпроцессного взаимодействия, исключающие как блокировки (событий, когда запросивший «общения» поток исполнения приостанавливается до разрешения «общения» с ядром, в подобной системе быть не может), так и ожидания. Именно благодаря ему будем говорить о пригодности основанных на таком микроядре систем к применению как в универсальных ОС, так и в ОС РВ (реального времени), и справедливость этого утверждения убедительно доказывается практикой. Например, задержка вызова обработчика периодически вызываемого прерывания для основанной на Fiasco Linux-совместимой ОС всего на 12% выше аналогичного показателя для системы реального времени RTLinux – и это при учете того, что в «микроядерной» системе обработчик прерывания – обычная пользовательская непривилегированная программа, а в RTLinux – фактически модуль ядра ОС. Как эта особенность Fiasco связана с безопасностью и надежностью всей системы в целом, достаточно очевидно – высокое быстродействие позволяет «лишить привилегий» огромные объемы кода, что, в свою очередь, резко снижает вероятность появления ошибок с фатальными последствиями: выход из строя обычного, непривилегированного приложения – это проблема совершенно иного уровня по сравнению с ошибкой драйвера защищенного режима.

Что касается модного общеполезного лишения лишних повышенных прав, то с этим как раз в TUD:OS все в полном порядке. В этой ОС не только канонические для микроядерных систем драйверы, серверы и «надстраивающие» над микроядром необходимые сервисы прослойки имитации других ОС работают в пользовательском режиме. Здесь и у святой святых «настольной» ОС – подсистемы пользовательского графического интерфейса – полностью отобраны привилегии. Даже у такой большой и требовательной, как X Window с соответствующими надстройками.

Welcome to the real world

Все, рассказанное выше, можно считать полезным разве что для ознакомления с одним из вероятных путей развития операционных систем в будущем, а если учесть их темп, характерный для проекта Hurd, то в весьма отдаленном будущем. Совершенно непонятна и трудно прогнозируема судьба самой TUD:OS – сложно сказать, вырастет ли эта несомненно красивая разработка из «академических штанишек» или продолжит судьбу своих «микроядерных» предшественниц. А между тем жизнь течет, и ожидать милостей безопасных и надежных вычислений в светлом будущем подавляющее большинство пользователей уже не согласно. Тем более что существующие массовые операционные системы далеко не так плохи, как об этом любят кричать истеричные пропагандисты – в той же Windows XP автор статьи специально держит хранитель экрана «blue screen of death». Чтобы не забывать, как оно когда-то давно было. И все-таки это не повод расслабляться – пусть сочетание нормального персонального брандмауэра и хорошего браузера вполне надежно защищают от всякой (знать бы, какой именно) сетевой нечисти, всегда остается ощущение потенциальной опасности. Особенно учитывая то, что в Windows XP и по сей день удобнее всего работать фактически в режиме суперпользователя, дающем без лишних усилий доступ к разнообразным периферийным устройствам. Речь идет именно об удобстве – всякой ПК-центричной «мелочи» становится все больше и больше, а из-за проблем унаследованного дизайна в Windows все-таки лучше работать именно так (и не следует забывать, что прикладные программы пишут тоже люди, и, вероятно, поэтому многим программам удобнее работать именно с правами администратора).

Было бы заманчиво многозначительно оборвать на предыдущем предложении статью. Но... как бы в качестве компенсации за ознакомление с непонятно когда обещающей дойти (и обещающей ли вообще) до пригодного к повседневному использованию уровня ОС маленький полезный совет из «реального мира».

Ради безопасности
«Поражение» в правах штатного Internet Explorer внешне никак не проявляется. Здесь показаны две копии программы, одна из которых, – левая, запущена в обычном режиме, вторая – в режиме с ограничением прав. С помощью утилиты ProcessExplorer (автор – Марк Руссинович), можно убедиться в том, что мы добились поставленной цели: и сокращения списка привилегий, и запрета администраторских прав

Windows XP позволяет запускать приложения с «поражением в правах». Что дает такая возможность? По минимуму она обеспечивает существенное усложнение жизни разработчиками всякого вредоносного кода, пытающимися распространять его посредством использования различных высокоуровневых и мощных (и потому непременно потенциально опасных) механизмов, таких как Active X. По крайней мере, «пораженный в правах» браузер не даст чему-то нехорошему, запущенному из него, ни модифицировать системные файлы, ни затронуть системно-значимые ветви реестра, ни выполнить привилегированные команды (например, остановить или запустить процессы).

Итак, давайте добавим к брандмауэру и браузеру еще один прием, повышающий безопасность. Общесистемными средствами, к сожалению, реализовать запуск приложения с «поражением в правах» в Windows не удастся. Но это не беда – знаменитый Марк Руссинович разработал крохотную утилитку PsExec (ее дистрибутив размером всего 50 KB, безусловно, заслуживает загрузки отсюда. Эта программа не требует инсталляции – просто распакуйте ее куда-нибудь и добавьте для удобства путь к ней к системной переменной Path. Из небольшого набора флагов PsExec безопасности ради вам понадобится всего два (к слову, системным администраторам, желающим принудительно обезопасить пользователей, PsExec дает возможность запускать задачи удаленно): -l и –d. Первый, собственно, и информирует утилиту о том, что указанное далее в командной строке приложение надо запускать с «поражением в правах». Таким образом, если вы хотите локально «поразить в правах» свой браузер, используйте для его запуска следующий шаблон командной строки:

psexec –l –d полный_путь_исполняемого_файла_браузера

Аналогично целесообразно поступать и с почтовым клиентом, сколь бы вы ни доверяли ему, и сколь бы «супербезопасным» он не считался.

Утилита PsExec основана на механизмах безопасности ОС Windows, в частности на механизме заимствования прав (impersonation), благодаря чему можно назначить определенные маркеры доступа (access token) не только процессу, но и отдельным потокам исполнения процесса. Интересующиеся подробностями могут обратиться к справочным материалам MSDN по ключевому слову CreateRestrictedToken – именно так называется функция, с помощью которой утилита PsExec осуществляет «поражение в правах» запускаемого приложения.