Издательский дом ООО "Гейм Лэнд"ЖУРНАЛ ХАКЕР 124, АПРЕЛЬ 2009 г.

Обреченные на успех. Обзор самых интересных проектов, представленных на UNIX-конференциях

Евгений «j1m» Зобнин (zobnin@gmail.com)




Ежегодно по всему миру проходит множество конференций, так или иначе связанных с UNIX и FOSS. Участие IT-специалиста в программе одной из них - отличный способ выделиться, продемонстрировать неординарность своего мышления и умение излагать мысли. Мы ознакомимся с пятью наиболее креативными проектами, представленными на конференциях USENIX и Linux Symposium за последние два года.

Korset - HIDS без ложных срабатываний

Феноменальная популярность небезопасных языков программирования C и C++ оказалась фатальной с появлением интернета и сетевых технологий. Проблеме срыва стека уже свыше 25 лет, но эффективного ее решения до сих пор не придумано. Производители железа снабжают процессоры NX-битом, который, как оказалось, способен остановить только учителей информатики. В операционные системы встраивают разнообразные рандомизаторы адресов, – они хоть и усложняют процесс внедрения shell-кода, но также легко обходятся. Создатели компиляторов не отстают и придумывают прополисы и прочие расширения. Идеалисты постоянно кричат о типо-безопасных языках и виртуальных машинах. Каждый год исследователи представляют новые системы защиты, но явного прогресса нет и кажется, что эффективное решение не будет найдено никогда.

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

Существует два типа HIDS: обучаемые и основанные на правилах. Слабость первых в необходимости предварительного «прогона» приложения, – обучаемой HIDS нужно время на анализ того, что обычно делает приложение, чтобы уже потом на основе этих данных ограничить софтину в возможностях. В то же время такая HIDS просто технически не способна узнать обо всем, что может приложение, и довольно часто дает ложные срабатывания.

HIDS, основанные на правилах, действуют по-другому. Они предлагают пользователю самому составить список того, что дозволено приложению (какие системные вызовы разрешены, к каким файлам и устройствам оно может обращаться и т.д.), а все остальные действия будут пресекаться. Недостаток: чтобы точно составить правила, нужно серьезно попотеть (попробуй как-нибудь на досуге написать список правил SELinux для Apache и всех его модулей с нуля).

Разработчики концептуальной HIDS Korset (www.korset.org), анонсированной на Linux Symposium 2008, предложили объединить оба типа систем обнаружения вторжений для создания сверхнадежной HIDS, работающей без вмешательства пользователя и не требующей обучения или написания правил. Korset базируется на идее Control Flow Graph (CFG), который представляет собой граф, отражающий очередность выполнения системных вызовов приложением. Такой граф строится автоматически во время сборки приложения и загружается ядром перед его исполнением. Если во время работы процесс инициирует системные вызовы, не описанные в графе, или даже делает их не в том порядке - процесс завершается.

Чтобы воплотить мысль в реальность, создатели Korset снабдили GNU build tools (gcc, ld, as, ar) специальными обертками, которые строят CFG на основе исходных текстов и объектных файлов приложения. Для реализации сидящего в ядре Monitoring Agent был модифицирован ELF-загрузчик, который во время загрузки исполняемого файла в память находит и загружает закрепленный за ним CFG (файл приложение.korset). Специальная хук-функция security_system_call, прописанная в структуре security_operations, запускается при каждом системном вызове и сверяет его с записью в CFG. Ну, а чтобы связать все это воедино, в структуру task_struct добавили ссылку на CFG и его состояние.

На первый взгляд, Korset прост в реализации и удобен в использовании. Но не все так радужно. Во-первых, CFG убивает возможность генерации кода на лету, без которой в некоторых случаях просто не обойтись. Во-вторых, CFG - не панацея. Если взломщик умудрится оформить системные вызовы shell-кода таким образом, чтобы они соответствовали прописанным в CFG (например, сделает open(), но не конфигурационного файла, а псевдотерминала), то ничто не помешает ему в проникновении. Ну и, в-третьих, в текущем состоянии Korset далек от продакшн: работа только на x86, с программами без динамической линковки, многопоточности, сигналов и инструкций вроде setjmp и longjmp.

Vx32 - песочница в пространстве пользователя

Идея использовать песочницы для запуска небезопасного кода далеко не нова. Близкие примеры: Chroot, FreeBSD Jail, Linux Lguest, Solaris Zones. JavaVM – тоже своего рода песочница, принуждающая использовать типо-безопасный язык для создания приложений и применяющая многочисленные рантайм проверки на безопасность. Даже VMWare и qemu есть не что иное, как песочницы, позволяющие запустить ОС в изолированном виртуальном окружении.

Особого внимания заслуживают песочницы, основанные на прозрачной трансляции опкодов x86. Чтобы понять, что это такое, представь себе Java, которая умеет исполнять обычный x86-код, скомпилированный с помощью gcc. При этом подконтрольная программа не может выйти за границы своей области памяти и навредить работе виртуальной машины. Единственный путь наружу - специальный API. Ничего кроме для нее не существует. Такой вид песочниц наиболее интересен, потому как не требует вмешательств в ядро, не принуждает к использованию типо-безопасных языков, транслируемых в байт-код, не эмулирует целую аппаратную платформу и позволяет как угодно ограничить исполняемую программу с помощью урезания API до минимума. На его основе даже можно построить целую операционную систему, работающую в пространстве пользователя.

К сожалению, популярности такой тип песочниц не получил. Реализация требует софтверной интерпретации инструкций процессора (с целью их модификации), ведь чтобы подконтрольное приложение оставалось в изоляции, нельзя допустить, чтобы оно смогло производить системные вызовы или обращаться к функциям, не оговоренным в API (инструкции int и call). Нельзя передавать управление на код за пределами своего адресного пространства (jmp) или читать данные вне своей зоны видимости (тут уж совсем засада). Поэтому инструкции должны анализироваться и при необходимости исправляться. Как следствие: на порядки отстающая производительность.

Проект Vx32 (pdos.csail.mit.edu/~baford/vm/), представленный на конференции USENIX'08, вдохнул в идею подобных песочниц новую жизнь благодаря одному хитрому приему, который позволил вывести производительность чуть ли не на уровень нэйтивного кода. Все дело в границах области данных. Обычно для ограничения области данных подконтрольной программы интерпретаторы анализируют все куски кода, содержащие хоть какое-то упоминание об адресе, будь то чтение из буфера, работа со стеком или обращение к файлу. Анализируется и, в случае необходимости, исправляется каждая инструкция, несущая в себе адрес. В то же время на долю различных переходов и обращений к подпрограммам остается жалкий процент действий, не несущий особой нагрузки на интерпретатор.

Разработчики Vx32, отлично это понимая, просто ограничили область данных программы сегментными регистрами (ds, es, ss), которые все равно не применяются в современных ОС из-за плоской модели памяти. В результате, интерпретатор Vx32 должен заботиться только об анализе инструкций-переходов (число которых очень мало: jmp и производные, call, int, ret) и пресекать попытки изменения сегментных регистров, а самую трудоемкую работу по соблюдению границ видимости области данных выполнит процессор, который делает это в сотни раз быстрее. Уже сейчасVx32 стабильно работает, а на его основе создано несколько проектов, среди которых ОС Plan9, работающая в режиме хост-системы, и «эмулятор» Linux (Linux API поверх Vx32). Производительность этих систем приближается к нэйтивному коду (оверхед редко превышает 80%). Недостаток же у системы всего один: привязанность к x86.

KvmFS - удаленное управление виртуальными серверами

Технологии виртуализации плотно вошли в нашу жизнь. Разработчики используют виртуальные машины для прогонки и отладки низкоуровнего кода, администраторы - чтобы сэкономить на покупке железных серверов, а хостеры начали применять технологии виртуализации с целью создать иллюзию постоянной доступности сервера. Особенно полюбились виртуальные сервера сервисам по сдаче в аренду компьютерных мощностей (теперь для каждого клиента они могут выделить отдельный виртуальный сервер и при необходимости перенести его на другую машину). Виртуализация применяется в кластерах повышенной производительности (HPC) для эффективного использования всех ядер современных многоядерных процессоров (для каждого ядра - отдельная виртуальная машина).

Бум популярности виртуализации начался сразу после появления ее поддержки в современных x86-процессорах. Теперь виртуальный сервер может работать без явного оверхеда и модификации практически на любой ОС, оснащенной соответствующим драйвером.

В Linux такой драйвер называется kvm, и для его задействования обычно применяется виртуальная машина qemu. Сама по себе qemu представляет множество интересных возможностей для управления серверами, включая функции заморозки/разморозки, простой способ миграции по Сети, поддержку сжатых образов дисков и т.д. Управлять сервером с помощью qemu одно удовольствие, но если таких серверов сотни, а то и тысячи, и все они разбросаны по множеству машин, начинаются серьезные проблемы.

Проект KvmFS, представленный на Linux Symposium 2007, как раз и призван упростить процесс администрирования множества удаленных виртуальных машин. KvmFS использует протокол 9P (тот, что из Plan9) для создания виртуальной файловой системы, которую можно удаленно монтировать, например из Linux, и управлять множеством инстанций qemu на удаленном сервере путем записи специальных команд в файлы. Сервер KvmFS прочитает команды и отправит их нужному процессу qemu. Для наглядности далее приводится пример запуска виртуальной машины на сервере host.org:

# mount -t 9p host.org /mnt/9
# cd /mnt/9
# tail -f clone &
# cd 0
# cp ~/disk.img fs/disk.img
# cp ~/vmstate fs/vmstate
# echo dev hda disk.img > ctl
# echo net 0 00:11:22:33:44:55 > ctl
# echo power on freeze > ctl
# echo loadvm vmstate > ctl
# echo unfreeze > ctl

А вот так производится миграция виртуального сервера на другую машину:

# mount -t 9p host1.org /mnt/9/1
# mount -t 9p host2.org /mnt/9/2
# tail -f /mnt/9/2/clone &
# cd /mnt/9/1/0
# echo freeze > ctl
# echo 'clone 0 host2.org!7777/0' > ctl
# echo power off > ctl

Даже если машин с виртуальными серверами в сети сотни, не составит особого труда написать небольшой скрипт, который проходит по списку адресов и монтирует их все к нужным точкам.

AXFS - запуск приложений без помещения в RAM

Linux стремительно завоевывает рынок мобильной и встраиваемой техники. Все больше производителей смартфонов заявляют об использовании открытой ОС в следующих моделях своих устройств. Множество компаний выдвигают на рынок специальные версии дистрибутивов Linux для мобильных устройств. Линус Торвальдс пропускает в ядро огромное количество патчей с реализацией поддержки того или иного мобильного оборудования и кажется, что хакерский рай уже так близко…
К сожалению, не все так просто.

Изначально ядро Linux разрабатывалось для рабочих станций и серверов, и только совсем недавно тукс потянул крылышки к смартфонам. Поэтому почти все подсистемы ядра рассчитаны (и оптимизированы) на применение в стандартных настольных конфигурациях, которые непременно обладают жесткими дисками, быстрым видеоадаптером, большим объемом оперативной памяти и весьма нескромной производительностью. Некоторые из этих проблем решаются достаточно просто. Например, требуемые объемы памяти можно понизить до приемлемого уровня, собрав ядро с поддержкой только самого необходимого и потюнив систему через /proc. Низкопроизводительная видеоподсистема? Ну, тогда и тяжелый X Server не нужен, хватит framebuffer'а! А вот с остальным сложнее. В частности, в ядре до сих пор нет файловой системы, позволяющей использовать все возможности современных flash-накопителей.

Список фич, которыми должна обладать такая файловая система, следующий:

  1. Переписывание данных только в случае крайней необходимости. Основанные на flash-памяти накопители имеют ограничение по части количества циклов перезаписи.
  2. Прозрачное сжатие данных.
  3. Умение работать без уровня эмуляции блочного устройства, который создает совершенно ненужный оверхед.
  4. Устойчивость к перебоям питания.
  5. Поддержка XIP (eXecute-In-Place), т.е. возможности запустить программу прямо с flash-накопителя, без загрузки в оперативную память.

Давно интегрированная в ядро jffs2 не поддерживает и половины этих возможностей, а вот созданная компанией Nokia ubifs (интегрирована в ядро 2.6.27) очень хороша и умеет почти все, кроме пятого пункта. За счет XIP можно сделать большой шаг вперед. Поясню. На мобильных устройствах операционная система обычно прошивается в память типа NOR, которая, в отличие от используемой во флешках NAND-памяти, поддерживает обращение к произвольным ячейкам. Произвольный доступ делает ее очень похожей на оперативную память и даже позволяет использовать в этом качестве. Надо только научить файловую систему мапить отдельные участки NOR-памяти в память виртуальную – и, о чудо, полноценная операционная система может работать, не потребляя RAM.

Загвоздка с XIP лишь в том, что это технология никак не вписывается в дизайн универсальной операционной системы. По сути это хак, который пытается смешать несовместимые подсистемы ядра. Создатели файловой системы AXFS (Advanced XIP File System), анонсированной на Linux Symposium 2008, попытались исправить этот недочет при помощи официальных механизмов ядра. Еще в ядро 2.6.13, в рамках интеграции dcss-драйвера для архитектуры s390, был добавлен специальный механизм, позволяющий обращаться к памяти flash-диска напрямую (файл /mm/filemap_xip.c). До создателей AXFS этот механизм попытались использовать разработчики xip-патчей для cramfs, но в результате получили грязный хак, который никак нельзя было выдать за оптимальное решение. Разработчики же AXFS проконсультировались с авторами подсистемы виртуальной памяти и создали 64-битную файловую систему, достоинства которой:

  1. XIP для памяти NOR-типа.
  2. Возможность работать с NAND-памятью (XIP автоматически отключается).
  3. Прозрачная компрессия с размером блока от 4 кб до 4 Гб.
  4. Умение работать как с блочными устройствами, так и напрямую.

Записывать она не умеет (образ файловой системы создается специальной утилитой), но это и не требуется для прошивок, выпускаемых производителем аппарата.

Libferris - новый уровень виртуальных ФС

В последнее время виртуальные файловые системы завоевали особую популярность. Пользователей они привлекают своей универсальностью, благодаря которой не нужно тратить время на изучение новых интерфейсов и чтение мануалов. С точки зрения программистов, виртуальная ФС - очень удобный и простой способ связывания компонентов большой системы без выдумывания нового API и использования сложных RPC.

Чтобы не быть голословным, приведу лишь некоторые примеры из громадного списка таких ФС: подсистема Gnome VFS, которая позволяет «ходить» по архивам, ssh-сессиям, ISO-образам; подсистема KDE KIO, разработанная для тех же целей; ядерный модуль fuse, на основе которого создано просто гигантское количество самых разнообразных файловых систем.

А если уж мыслить в более глобальных масштабах, то не обойтись без упоминания об операционных системах Inferno и Plan9, где виртуальные ФС являются центральной частью ОС и связывают все компоненты системы в единый комплекс.

Проект libferris (www.libferris.com), которому была посвящена одна из лекций Linux Symposium, в этом плане идет еще дальше. Кроме возможности монтирования массы разнообразных ресурсов, он предлагает механизм управления приложением (Firefox, X Window) через файловый интерфейс, позволяет легко преобразовать XML-документ в файловую систему и обратно, поддерживает атрибуты, которые на лету извлекаются из внутренних метаданных документа, и обладает еще массой интересных особенностей. Другими словами, проект libferris выводит виртуальные ФС на новый уровень, который раньше был доступен лишь в упомянутом Plan9.

Содержание
загрузка...
Журнал Хакер #151Журнал Хакер #150Журнал Хакер #149Журнал Хакер #148Журнал Хакер #147Журнал Хакер #146Журнал Хакер #145Журнал Хакер #144Журнал Хакер #143Журнал Хакер #142Журнал Хакер #141Журнал Хакер #140Журнал Хакер #139Журнал Хакер #138Журнал Хакер #137Журнал Хакер #136Журнал Хакер #135Журнал Хакер #134Журнал Хакер #133Журнал Хакер #132Журнал Хакер #131Журнал Хакер #130Журнал Хакер #129Журнал Хакер #128Журнал Хакер #127Журнал Хакер #126Журнал Хакер #125Журнал Хакер #124Журнал Хакер #123Журнал Хакер #122Журнал Хакер #121Журнал Хакер #120Журнал Хакер #119Журнал Хакер #118Журнал Хакер #117Журнал Хакер #116Журнал Хакер #115Журнал Хакер #114Журнал Хакер #113Журнал Хакер #112Журнал Хакер #111Журнал Хакер #110Журнал Хакер #109Журнал Хакер #108Журнал Хакер #107Журнал Хакер #106Журнал Хакер #105Журнал Хакер #104Журнал Хакер #103Журнал Хакер #102Журнал Хакер #101Журнал Хакер #100Журнал Хакер #099Журнал Хакер #098Журнал Хакер #097Журнал Хакер #096Журнал Хакер #095Журнал Хакер #094Журнал Хакер #093Журнал Хакер #092Журнал Хакер #091Журнал Хакер #090Журнал Хакер #089Журнал Хакер #088Журнал Хакер #087Журнал Хакер #086Журнал Хакер #085Журнал Хакер #084Журнал Хакер #083Журнал Хакер #082Журнал Хакер #081Журнал Хакер #080Журнал Хакер #079Журнал Хакер #078Журнал Хакер #077Журнал Хакер #076Журнал Хакер #075Журнал Хакер #074Журнал Хакер #073Журнал Хакер #072Журнал Хакер #071Журнал Хакер #070Журнал Хакер #069Журнал Хакер #068Журнал Хакер #067Журнал Хакер #066Журнал Хакер #065Журнал Хакер #064Журнал Хакер #063Журнал Хакер #062Журнал Хакер #061Журнал Хакер #060Журнал Хакер #059Журнал Хакер #058Журнал Хакер #057Журнал Хакер #056Журнал Хакер #055Журнал Хакер #054Журнал Хакер #053Журнал Хакер #052Журнал Хакер #051Журнал Хакер #050Журнал Хакер #049Журнал Хакер #048Журнал Хакер #047Журнал Хакер #046Журнал Хакер #045Журнал Хакер #044Журнал Хакер #043Журнал Хакер #042Журнал Хакер #041Журнал Хакер #040Журнал Хакер #039Журнал Хакер #038Журнал Хакер #037Журнал Хакер #036Журнал Хакер #035Журнал Хакер #034Журнал Хакер #033Журнал Хакер #032Журнал Хакер #031Журнал Хакер #030Журнал Хакер #029Журнал Хакер #028Журнал Хакер #027Журнал Хакер #026Журнал Хакер #025Журнал Хакер #024Журнал Хакер #023Журнал Хакер #022Журнал Хакер #021Журнал Хакер #020Журнал Хакер #019Журнал Хакер #018Журнал Хакер #017Журнал Хакер #016Журнал Хакер #015Журнал Хакер #014Журнал Хакер #013Журнал Хакер #012Журнал Хакер #011Журнал Хакер #010Журнал Хакер #009Журнал Хакер #008Журнал Хакер #007Журнал Хакер #006Журнал Хакер #005Журнал Хакер #004Журнал Хакер #003Журнал Хакер #002Журнал Хакер #001