Чем выше ум, тем тень длиннее ляжет,
Отброшенная им на дальний мир.
Р. Браунинг. "Парацельс"
В статьях и обзорах, посвященных скрытым каналам, обычно пишут, что этот термин введен в работе Лэмпсона [1]. Важно отметить, однако, что Батлер Лэмпсон упоминает о скрытых каналах как бы между делом, не они являются предметом исследования. Его трехстраничная заметка называется "О проблеме ограничения" ("A Note on the Confinement Problem") и посвящена она, выражаясь современным языком, контролируемому выполнению (недоверенных) программ с целью помешать им организовать утечку конфиденциальной информации.
Идея дополнительного ограничения действий, которые разрешается выполнять программе, (помимо применения имеющихся в операционной системе механизмов контроля доступа), является исключительно важной и глубокой, опередившей свое время. По сути Лэмпсон пунктиром обозначил будущие модели безопасности для Java-аплетов — от "песочницы" до контроля по стеку вызовов, причем сделал это на 25 лет раньше разработчиков Java (заметка была сдана в редакцию в июле 1972 года, а по ссылкам видно, что он занимался проблемами динамической защиты еще в 1960-е годы).
Лэмпсон рассматривает следующую задачу. Пусть клиент вызывает некоторый сервис, передавая ему в качестве параметров конфиденциальную информацию, утечка которой нежелательна. Спрашивается, как следует ограничить поведение произвольного сервиса? (В 1972 году сервис представлял собой процедуру, вызываемую из клиентской программы; о распределенных архитектурах речь не шла, но многопроцессные конфигурации были обычным явлением.)
Подчеркнем, что речь идет о создании "песочницы" для произвольной программы. Если ограничения окажутся нарушенными, выполнение сервиса должно аварийно завершаться.
Чтобы понять характер налагаемых ограничений, Лэмпсон сначала исследует возможные каналы утечки информации, выделяя следующие:
- Если у сервиса есть память, он может сохранить клиентскую информацию, дождаться, когда его вызовет хозяин, и передать тому сохраненную информацию;
- Сервис может записать информацию в постоянный файл в каталоге хозяина;
Сервис может создать временный файл (что само по себе вполне законно: как же без временных файлов?); хозяин может периодически проверять его (файла) существование и прочитать информацию прежде, чем сервис завершит работу и удалит все временное;
Сервис может послать сообщение процессу, контролируемому хозяином;
- Сервис может закодировать информацию в счете за свои услуги, поскольку хозяин должен получить копию этого счета; ограничения на формат счета способны свести объем утечки к нескольким десяткам бит, но полностью ликвидировать ее нереально;
- Если могут возникать конфликты по ресурсам, сам факт конфликта может быть использован для передачи информации (чуть ниже мы подробнее рассмотрим этот канал утечки);
- Сервис может варьировать отношение вычислительной активности к темпу подкачки страниц или числу операций ввода/вывода, кодируя таким способом информацию; параллельно работающий процесс способен наблюдать поведение системы и получать передаваемую информацию; это зашумленный канал, его пропускная способность невелика, но он есть, и им можно воспользоваться.
Всегда интересно не просто теоретически знать, что каналы утечки существуют, но и понять на практике, как они могут быть устроены. Лэмпсон описывает "эксплойт" для использования конфликтов по ресурсам (мы приведем его в несколько модифицированном виде). Пусть, например, один и тот же файл нельзя параллельно открыть из двух процессов (при попытке сделать это фиксируется ошибка). Данный факт можно использовать для побитной передачи информации. Две следующие процедуры, написанные на АЛГОЛоподобном языке обеспечивают, соответственно, установку нужного бита и его проверку.
Листинг 1
setbit (file, bit);
Boolean bit;
begin
if bit = true then
loop1: open (file, loop1)
else
close (file)
end;
Boolean procedure testbit (file);
begin
testbit : = true;
open (file, loop2);
testbit := false;
close (file)
loop2: end;
|
(К своему стыду, автор не знает, как окружение АЛГОЛ-программ реагирует на попытку закрыть неоткрытый файл).
Сейчас далеко не все помнят тонкости АЛГОЛа-60, поэтому нужно пояснить по крайней мере два момента. Во-первых, метки в АЛГОЛе являются допустимым типом данных, значения которого можно передавать в качестве параметров. Во-вторых, если (занятый) файл открыть не удалось, управление нелокально передается на метку, заданную в качестве второго аргумента процедуры open. Кстати, это более практичный способ обработки исключительных ситуаций, чем проверка кодов возврата, которую зачастую забывают сделать, что является одним из источников уязвимостей программных систем.
Теперь, располагая элементарными операциями, можно организовать передачу бита между процессами. Для этого Лэмпсон использует три файла: data, sendclock и receiveclock.
В программе-сервисе может присутствовать такой фрагмент (написанный нами с некоторыми вольностями):
Листинг 2
:
setbit (data, bitbeingsent);
while testbit (receiveclock) = false do
;
setbit (sendclock, false);
while testbit (receiveclock) = true do
;
|
Процесс-получатель может осуществлять прием бита так:
Листинг 3
:
while testbit (sendclock) = false do
;
receivedbit : = testbit (data);
setbit (receiveclock, true);
while testbit (sendclock) = true do
;
setbit (receiveclock, false);
|
Переходя к правилам ограничения (контролируемого выполнения), Лэмпсон прежде всего указывает, что ограничиваемая программа не должна иметь возможности сохранять информацию между вызовами. Для процедур это условие легко проверяется: оно означает отсутствие обращений к нелокальным переменным.
Если нелокальная память отсутствует, то для успешной реализации ограничения достаточно, чтобы ограничиваемая программа не вызывала других программ. Это правило полной изоляции по сути совпадает с моделью "песочницы" в версии JDK 1.0. Разумеется, Лэмпсон тут же отвергает его как нереалистичное, поскольку, как показывают два последних из перечисленных выше примеров утечек, в числе прочих должны быть запрещены явные и неявные вызовы супервизора (ядра ОС). Попытка применить правило полной изоляции "насквозь" и потребовать, чтобы ограничивались все вызываемые программы, не проходит, поскольку супервизор нельзя ограничивать.
Чтобы исправить ситуацию, предлагается, как и следовало ожидать, поделить всех на чистых и нечистых, то есть на тех, кому доверяют, и тех, кого ограничивают. В результате получается следующее правило: если ограничиваемая программа вызывает недоверенную, то последнюю также необходимо ограничивать.
Дело осталось за малым — написать доверенный супервизор. Как показывают два последних из перечисленных выше примеров утечек, дело это непростое, поскольку используемые для этого каналы могут быть самыми неожиданными. Тем не менее Лэмпсон придерживается оптимистической точки зрения: каналов утечки, конечно, на удивление много, но все-таки конечное число. Необходимо их перенумеровать, а потом и заблокировать. В качестве отправной точки предлагается следующая классификация каналов:
- Разного рода память, управляемая супервизором, в которую может писать ограничиваемая программа (в рассматриваемых примерах — сервис), а читать — неограничиваемая (вскоре после записи или позднее); все приведенные выше примеры, кроме двух, относятся к этому классу;
- Легальные каналы, используемые ограничиваемой программой (например, счет за обслуживания);
- Скрытые каналы, вообще не предназначенные для передачи информации, (например, влияние сервиса на загруженность системы).
Вот в каком контексте вводится понятие скрытого канала (covert channel) и как оно определяется Лэмпсоном. Обратим внимание читателя на то, что все каналы по памяти отнесены к другому классу утечек. Важно и то, что помимо скрытых, Лэмпсон рассматривает и так называемые "подсознательные" или потайные каналы (легальные каналы, по которым передаются данные, допускающие нестандартную интерпретацию и, следовательно, которые могут служить каналом утечки конфиденциальной информации), хотя используемый в настоящее время термин subliminal channel, по-видимому, введен Б. Шнейером [2] примерно двадцать лет спустя.
По мнению Лэмпсона предотвратить утечки через память довольно просто. Например, чтобы избавиться от блокировок при совместном доступе к ресурсам, можно при попытке записи копировать файл и бесконфликтно предоставлять копию для чтения ограничиваемой программой. (Заметим, что идея эта весьма глубока, только лучше при попытке записи открывать новую версию файла и писать в нее, применяя в дальнейшем механизмы конфигурационного управления.)
Для блокирования легальных и скрытых каналов предлагается следующий принцип маскирования: ограничиваемая программа должна позволять вызывающему полностью определять вывод в легальные и скрытые каналы. Таким образом каналы маскируются вызывающим (клиентом).
Это — центральная идея работы Лэмпсона. Программа ограничивается в соответствии с ожидаемой семантикой и специфическими потребностями вызывающего. Например программа для просмотра документов не должна изменять или создавать файлы. Напротив компилятору без создания файлов (временных и постоянных) не обойтись.
Вообще говоря при разных вызовах одного сервиса ограничения могут быть разными. Тем более они могут быть разными для разных сервисов. Если сервис не в состоянии удовлетворить требования клиента, вызов отвергается.
Для скрытых каналов Лэмпсон формулирует еще одно правило — проведения в жизнь: супервизор обязан обеспечить соответствие вывода ограничиваемой программы в скрытые каналы спецификациям вызывающего. Считается, что концептуально это несложно: можно искусственно замедлять выполнение программы, генерировать фиктивные обращения к дискам и т.п., короче говоря, зашумлять скрытые каналы. Цена проведения в жизнь может быть большой. Более практичной альтернативой (если клиент готов допустить некоторую утечку) является ограничение пропускной способности скрытых каналов.
Конечно, можно отметить, что некоторые положения работы Лэмпсона, касающиеся концептуальной простоты или принципиальной реализуемости выявления и блокирования каналов утечки (в частности, скрытых каналов), остались необоснованными. Более того, как показали последующие исследования, они неверны. Тем не менее эта работа продолжает оставаться актуальной и в наше время, а ее идейный потенциал далеко не исчерпан. Тематика ограничения (контролируемого выполнения) программ ждет дальнейшего развития.