В песочнице
С момента релиза, прошедшего несколько недель назад, любопытные разработчики изучали исходный код нового браузера от Google. Исходники Хрома интересны по многим причинам: тут и новая JavaScript-машина V8 с хорошим приростом производительности в некоторых задачах, движок WebKit, обрабатывающий и показывающий web-страницы, и наконец «песочница», изолирующая компоненты в Chrome друг от друга. Именно эта система привлекла внимание многих программистов, по простой причине. При чтении исходников создается впечатление что Google декомпилировали (reverse-engineered) компоненты Windows — а это запрещено лицензионным соглашением.
Но перед тем как мы рассмотрим вопрос реверс-инжиниринга, стоит взглянуть на сам браузер.
Архитектура безопасности Chrome
ИЗ всех нововведений браузера его архитектура безопасности — самое интересное и значительное. Традиционные браузеры (Firefox, Internet Explorer 7 и ниже, Opera, Safari) создают один процесс для всего — отображения интерфейса, соединения с Интернет, парсинга HTML, запуска плагинов. Все вкладки браузера используют этот процесс.
Эта модель «одного процесса» имеет много недостатков, самый очевидный из которых — стоит чему то пойти не так (баг движка отрисовки или одного из плагинов), и браузер отправляется в цифровую Валгаллу целиком. Такая архитектура также имеет и менее заметные особенности. Например, в идеале код выполняющийся в плагинах или движке JavaScript не должен иметь доступа к некоторым ресурсам — например, писать файлы на диск. Но так как все компоненты выполняются в рамках одного процесса, обеспечить такое поведение непросто.
Redmond снова впереди
Windows Vista и IE7 на самом деле опередили Google в отходе от такой модели. В Internet Explorer уже давно применяется концепция "зон безопасности", позволяющая разграничить привилегии для интранета и глобальной сети. Одним из постоянных источников багов в IE было то что специально сформированная страница может «обмануть» браузер и выполняться так будто находится в доверенной зоне. Чтобы избавиться от этой проблемы, в Vista запрещено смешивать источники из разных зон в рамках одного процесса. Если после просмотра сайтов из зоны Internet вы открываете внутренний корпоративный сайт, создается новый экземпляр процесса iexplore.exe, и они действуют отдельно.
Internet Explorer 8, выпущенный в виде бета-релиза в этом году, продвинулся ещё дальше в этом направлении. Вместо одного процесса на зону IE8 использует один процесс на каждую вкладку, плюс один родительский процесс, отвечающий за интерфейс. Это обеспечивает еще лучшую изоляцию. В IE8 даже вкладки в пределах одной зоны безопасности независимы и изолированы друг от друга. Эта архитектура решила еще одну давнюю проблему — теперь скоропостижная смерть одной вкладки не влияет на остальные.
IE8 и предотвращение выполнения данных (DEP)
Другая фича IE8 — поддержка DEP — предотвращение выполнения данных, разработанная чтобы раз и навсегда разделаться с выполнением кода при buffer overflow. Традиционно в архитектуре x86 память может помечаться как чтение-и-выполнение и/или запись. Если было разрешено только чтение, выполнение разрешено. Это привело к возможности сделать buffer overflow — запросить память под временное хранилище (ей выставляются чтение и запись), и поместить туда маленький кусочек исполняемого кода.
С DEP, чтение и запись больше никак не связаны; область памяти может быть помечена как «чтение+запись», без флага выполнения. К сожалению, иногда необходимо создавать области где разрешено «чтение+запись+исполнение». Частый случай — JIT (just-in-time) компиляторы, вроде Java и .NET. Эти программы могут создавать исполняемый код в процессе выполнения, поэтому им надо выделить память, записать туда информацию и потом пометить область для исполнения.
Хотя в x86 нормальная поддержка DEP появилась сравнительно недавно, в Win32 API давно поддерживаются соответствующие функции. Сознательные разработчики корректно обрабатывали DEP даже если это строго не требовалось, чтобы обеспечить совместимость не только со старыми процессорами, но и с будущими (на которых мы сейчас работаем). Однако, ленивые разработчики просто забивали на такую «необязательную» вещь. Поэтому некоторые старые Windows-программы не могут выполняться с DEP — в том числе, некоторые плагины ActiveX.
Чтобы обеспечить совместимость с этими плагинами, разработчики IE7 выключили поддержку DEP по умолчанию. С момента выхода этого браузера многие плагины уже обновились (разработчики поняли, что совсем скоро это станет обязательным требованием), и IE8 уже включает DEP по умолчанию.
Что и приводит нас к Chrome. Как и IE8, Хром создает один процесс на каждую вкладку. На самом деле он идет ещё дальше, создавая дополнительный процесс для каждого плагина. И, как и IE8, Хром включает DEP для всех своих процессов.
Где же здесь reverse-engineering, спросите вы? Если покопаться в исходниках Хрома, можно увидеть интересную вещь.
Сначала Chrome пытается использовать стандартный API для управления DEP. Однако, если это не получается, он пробует второй способ:
// Completely undocumented from Microsoft. You can find this information by
// disassembling Vista's SP1 kernel32.dll with your favorite disassembler.
(цитата из кода браузера).
Большинство используемых функций полностью официально задокументированы — например CreateProcess описана очень хорошо. NtQueryFullAttributesFile — уже недокументированная функция. Для создания процессов в Chrome используются и те, и другие.