Содержание
- Часть 3. Политика безопасности решения
- Общие сведения об описании политики безопасности решения
- Синтаксис языка PSL
- Описание глобальных параметров политики безопасности решения
- Включение PSL-файлов
- Включение EDL-файлов
- Создание объектов моделей безопасности
- Привязка методов моделей безопасности к событиям безопасности
- Описание профилей аудита безопасности
- Типы данных в языке PSL
- Пример простейшей политики безопасности решения
- Модели безопасности
- Модель безопасности Pred
- Модель безопасности Bool
- Модель безопасности Math
- Модель безопасности Struct
- Модель безопасности Base
- Модель безопасности Regex
- Модель безопасности HashSet
- Модель безопасности StaticMap
- Объект модели безопасности StaticMap
- Правило init модели безопасности StaticMap
- Правило fini модели безопасности StaticMap
- Правило set модели безопасности StaticMap
- Правило commit модели безопасности StaticMap
- Правило rollback модели безопасности StaticMap
- Выражение get модели безопасности StaticMap
- Выражение get_uncommited модели безопасности StaticMap
- Модель безопасности Flow
- Пример ping
- Тестирование политики безопасности решения на языке Policy Assertion Language (PAL)
Часть 3. Политика безопасности решения
В предыдущих частях руководства показано, как реализовать взаимодействие между сущностями. При этом для простоты все решения собирались без модуля безопасности (ksm.module
), которым представлена подсистема Kaspersky Security System.
Между тем, именно подсистема Kaspersky Security System контролирует обращения сущностей друг к другу и другие события. Это значит, что решение можно разделить на сущности, управлять их взаимодействиями и, как следствие, повысить безопасность решения.
В этой части руководства рассматриваются:;
- синтаксис языка PSL;
- модели безопасности, поддерживаемые в Kaspersky Security System;
- пример политики безопасности решения.
Общие сведения об описании политики безопасности решения
В упрощенном представлении описание политики безопасности решения состоит из привязок, которые ассоциируют описания событий безопасности с вызовами методов, предоставляемых объектами моделей безопасности. Объект модели безопасности – это экземпляр класса, определение которого является формальным представлением модели безопасности (в PSL-файле). Формальные представления моделей безопасности содержат сигнатуры методов моделей безопасности, которые определяют допустимость взаимодействий сущностей между собой и с ядром KasperskyOS. Эти методы делятся на два вида:
- Правила моделей безопасности – это методы моделей безопасности, возвращающие результат "разрешено" или "запрещено". Правила моделей безопасности могут изменять контексты безопасности (о контексте безопасности см. "Управление доступом к ресурсам").
- Выражения моделей безопасности – это методы моделей безопасности, возвращающие значения, которые могут использоваться как входные данные для других методов моделей безопасности.
Объект модели безопасности предоставляет методы, специфичные для одной модели безопасности, и хранит параметры, используемые этими методами (например, начальное состояние конечного автомата или размер контейнера для каких-либо данных). Один объект может применяться для множества ресурсов. При этом этот объект будет независимо использовать контексты безопасности этих ресурсов. Также несколько объектов одной или разных моделей безопасности может применяться для одного и того же ресурса. В этом случае разные объекты будут использовать контекст безопасности одного ресурса без взаимного влияния.
События безопасности – это сигналы об инициации взаимодействий сущностей между собой и с ядром KasperskyOS. К событиям безопасности относятся следующие события:
- отправка IPC-запросов клиентами;
- отправка IPC-ответов серверами или ядром;
- инициация запусков сущностей ядром или сущностями;
- запуск ядра;
- обращения сущностей к модулю безопасности Kaspersky Security Module через интерфейс безопасности.
События безопасности обрабатываются модулем безопасности.
Модели безопасности
В составе KasperskyOS SDK поставляются PSL-файлы, которые описывают следующие модели безопасности:
- Base – методы, реализующие простейшую логику;
- Pred – методы, реализующие операции сравнения;
- Bool – методы, реализующие логические операции;
- Math – методы, реализующие операции целочисленной арифметики;
- Struct – методы, обеспечивающие доступ к структурным элементам данных (например, доступ к параметрам интерфейсных методов, передаваемых в IPC-сообщениях);
- Regex – методы для валидации текстовых данных по регулярным выражениям;
- HashSet – методы для работы с одномерными таблицами, ассоциированными с ресурсами;
- StaticMap – методы для работы с двумерными таблицами типа "ключ–значение", ассоциированными с ресурсами;
- Flow – методы для работы с конечными автоматами, ассоциированными с ресурсами.
Обработка событий безопасности модулем безопасности Kaspersky Security Module
Модуль безопасности Kaspersky Security Module вызывает все методы (правила и выражения) моделей безопасности, связанные с произошедшим событием безопасности. Если все правила вернули результат "разрешено", модуль безопасности возвращает решение "разрешено". Если хотя бы одно правило вернуло результат "запрещено", модуль безопасности возвращает решение "запрещено".
Если хотя бы один метод, связанный с произошедшим событием безопасности, не может быть корректно выполнен, модуль безопасности возвращает решение "запрещено".
Если с произошедшим событием безопасности не связано ни одно правило, модуль безопасности возвращает решение "запрещено". То есть все взаимодействия компонентов решения между собой и с ядром KasperskyOS, которые явно не разрешены политикой безопасности решения, запрещены (принцип Default Deny).
Аудит безопасности
Аудит безопасности (далее также аудит) представляет собой следующую последовательность действий. Модуль безопасности Kaspersky Security Module сообщает ядру KasperskyOS сведения о решениях, принятых этим модулем. Затем ядро передает эти данные системной программе Klog
, которая декодирует их и передает системной программе KlogStorage
(передача данных осуществляется через IPC). Последняя выводит полученные данные через стандартный вывод или сохраняет в файл.
Данные аудита безопасности (далее данные аудита) – это сведения о решениях модуля безопасности Kaspersky Security Module, которые включают сами решения ("разрешено" или "запрещено"), описания событий безопасности, результаты вызовов методов моделей безопасности, а также данные о некорректности IPC-сообщений.
В началоСинтаксис языка PSL
Базовые правила
- Декларации могут располагаться в файле в любом порядке.
- Одна декларация может быть записана в одну или несколько строк. Вторая и последующие строки декларации должны быть записаны с отступами относительно первой строки. Закрывающая фигурная скобка, которая завершает декларацию, может быть записана на уровне первой строки.
- В многострочной декларации используются отступы разных размеров, чтобы отразить вложенность конструкций, составляющих эту декларацию. Строки многострочной конструкции, заключенные в фигурные скобки, и открывающая фигурная скобка должны быть записаны с отступом относительно первой строки этой конструкции. Закрывающая фигурная скобка многострочной конструкции может быть записана с отступом или на уровне первой строки конструкции.
- Поддерживаются однострочные и многострочные комментарии:
/* Это комментарий
И это тоже */
// Ещё один комментарий
Типы деклараций
В языке PSL есть следующие типы деклараций:
- описание глобальных параметров политики безопасности решения;
- включение PSL-файлов;
- включение EDL-файлов;
- создание объектов моделей безопасности;
- привязка методов моделей безопасности к событиям безопасности;
- описание профилей аудита безопасности.
Описание глобальных параметров политики безопасности решения
Глобальными являются следующие параметры политики безопасности решения:
- Execute-интерфейс, через который ядро KasperskyOS обращается к модулю безопасности Kaspersky Security Module, чтобы сообщить о запуске ядра или об инициации запуска сущностей ядром или другими сущностями. Чтобы задать этот интерфейс, нужно использовать декларацию:
execute: kl.core.Execute
В настоящее время в KasperskyOS поддерживается только один execute-интерфейс
Execute
, определенный в файлеkl/core/Execute.idl
. (Этот интерфейс состоит из одного методаmain
, который не имеет параметров и не выполняет никаких действий. Методmain
зарезервирован для возможного использования в будущем.) - [Опционально] Глобальный профиль аудита безопасности и начальный уровень аудита безопасности. Чтобы задать эти параметры, нужно использовать декларацию:
audit default = <имя профиля аудита безопасности> <уровень аудита безопасности>
Пример:
audit default = global 0
По умолчанию в качестве глобального используется пустой профиль аудита безопасности
empty
, описанный в файлеtoolchain/include/nk/base.psl
из состава KasperskyOS SDK, и уровень аудита безопасности 0.
Включение PSL-файлов
Для включения PSL-файла нужно использовать декларацию:
use <ссылка на PSL-файл._>
Ссылка на PSL-файл представляет собой путь к PSL-файлу (без расширения и точки перед ним) относительно директории, которая включена в набор директорий, где компилятор nk-psl-gen-c
ищет PSL-, IDL-, CDL-, EDL-файлы. (Этот набор директорий задается параметрами скрипта makekss
вида "-I <путь к файлам>"
.) В качестве разделителя в описании пути используется точка. Декларация завершается последовательностью символов ._
.
Пример:
use policy_parts.flow_part._
Эта декларация включает файл flow_part.psl
, который находится в директории policy_parts
. Директория policy_parts
должна находиться в одной из директорий, где компилятор nk-psl-gen-c
выполняет поиск PSL-, IDL-, CDL-, EDL-файлов. Например, директория policy_parts
может располагаться в одной директории с PSL-файлом, содержащим эту декларацию.
Включение PSL-файла с формальным представлением модели безопасности
Чтобы использовать методы требуемой модели безопасности, нужно включить PSL-файл с формальным представлением этой модели. PSL-файлы с формальными представлениями моделей безопасности находятся в <KOS_KASPERSKY> SDK по пути:
toolchain/include/nk
Пример:
/* Включение файла base.psl с формальным представлением модели
* безопасности Base */
use nk.base._
/* Включение файла flow.psl с формальным представлением модели
* безопасности Flow */
use nk.flow._
/* Компилятор nk-psl-gen-c должен быть настроен на поиск
* PSL-, IDL-, CDL-, EDL-файлов в директории toolchain/include. */
Включение EDL-файлов
Чтобы включить EDL-файл для ядра KasperskyOS, нужно использовать декларацию:
use EDL kl.core.Core
Чтобы включить EDL-файл для прикладной или системной программы (или для драйвера), нужно использовать декларацию:
use EDL <ссылка на EDL-файл>
Ссылка на EDL-файл представляет собой путь к EDL-файлу (без расширения и точки перед ним) относительно директории, которая включена в набор директорий, где компилятор nk-psl-gen-c
ищет PSL-, IDL-, CDL-, EDL-файлы. (Этот набор директорий задается параметрами скрипта makekss
вида "-I <путь к файлам>"
.) В качестве разделителя в описании пути используется точка.
Пример:
/* Включение файла UART.edl
, который находится
* в KasperskyOS SDK по пути sysroot-*-kos/include/kl/drivers. */
use EDL kl.drivers.UART
/* Компилятор nk-psl-gen-c должен быть настроен на поиск
* PSL-, IDL-, CDL-, EDL-файлов в директории sysroot-*-kos/include. */
Компилятор nk-psl-gen-c
находит IDL-, CDL-файлы через EDL-файлы, так как EDL-файлы содержат ссылки на соответствующие CDL-файлы, а CDL-файлы содержат ссылки на соответствующие CDL-, IDL-файлы.
Создание объектов моделей безопасности
Для вызова методов требуемой модели безопасности, нужно создать объект этой модели безопасности.
Чтобы создать объект модели безопасности, нужно использовать декларацию:
policy object <имя объекта модели безопасности : название модели безопасности> {
[параметры объекта модели безопасности]
}
Параметры объекта модели безопасности специфичны для модели безопасности. Описание параметров и примеры создания объектов разных моделей безопасности приведены в разделе "Модели безопасности".
В началоПривязка методов моделей безопасности к событиям безопасности
Чтобы выполнить привязку методов моделей безопасности к событию безопасности, нужно использовать декларацию:
<вид события безопасности> [селекторы события безопасности] {
[профиль аудита безопасности]
<вызываемые правила моделей безопасности>
}
Вид события безопасности
Чтобы задать вид события безопасности, используются следующие спецификаторы:
request
– отправка IPC-запросов;response
– отправка IPC-ответов;error
– отправка IPC-ответов, содержащих сведения об ошибках;security
– попытки обращений сущностей к модулю безопасности Kaspersky Security Module через интерфейс безопасности;execute
– инициация запусков сущностей или запуск ядра KasperskyOS.
При взаимодействии сущностей с модулем безопасности применяется механизм, отличный от IPC. Но при разработке политики безопасности решения на обращения сущностей к модулю безопасности можно смотреть как на передачу IPC-сообщений, так как сущности действительно передают модулю безопасности сообщения (в этих сообщениях не указывается приемник).
Для запуска сущностей не используется механизм IPC. Но когда инициируется запуск сущности, ядро обращается к модулю безопасности, сообщая сведения об инициаторе запуска и запускаемой сущности. Поэтому с точки зрения автора политики безопасности решения можно считать, что запуск сущности – это передача IPC-сообщения от инициатора запуска к запускаемой сущности. Также при запуске ядра можно считать, что ядро отправляет IPC-сообщение самому себе.
Селекторы события безопасности
Селекторы события безопасности позволяют уточнить описание события безопасности заданного вида. Используются следующие селекторы:
src=
<имя класса сущностей/ядро
> – сущности заданного класса или ядро KasperskyOS являются источниками IPC-сообщений;dst=
<имя класса сущностей/ядро
> – сущности заданного класса или ядро являются приемниками IPC-сообщений;interface=
<имя интерфейса
>- клиенты пытаются обратиться к серверам или ядру через интерфейс с заданным именем;
- сущности обращаются к модулю безопасности Kaspersky Security Module через интерфейс безопасности с заданным именем;
- серверы или ядро отправляют клиентам результаты обработки обращений через интерфейс с заданным именем;
endpoint=
<квалифицированное имя службы
> – описывает следующие события безопасности:- клиенты пытаются использовать службу серверов или ядра с заданным именем;
- серверы или ядро отправляют клиентам результаты использования службы с заданным именем;
method=
<имя метода
> – описывает следующие события безопасности:- клиенты пытаются обратиться к серверам или ядру, вызывая метод службы с заданным именем;
- сущности обращаются к модулю безопасности, вызывая метод интерфейса безопасности с заданным именем;
- серверы или ядро отправляют клиентам результаты вызова метода службы с заданным именем;
- ядро сообщает о своем запуске модулю безопасности, вызывая метод execute-интерфейса с заданным именем;
- ядро инициирует запуски сущностей, вызывая метод execute-интерфейса с заданным именем;
- сущности инициируют запуски других сущностей, в результате чего ядро вызывает метод execute-интерфейса с заданным именем.
Квалифицированное имя службы является конструкцией вида <путь к службе.имя службы
>. Путь к службе представляет собой последовательность разделенных точкой имен экземпляров компонентов (из формальной спецификации компонента решения), среди которых каждый последующий экземпляр компонента вложен в предыдущий, а последний предоставляет службу с заданным именем.
Классы сущностей, интерфейсы, службы, методы должны называться так, как они называются в IDL-, CDL-, EDL-описаниях. Ядро должно называться kl.core.Core
.
Если селекторы не указаны, участниками события безопасности считаются все сущности и ядро (кроме событий вида security
, где ядро не участвует).
Можно использовать комбинации селекторов. При этом селекторы можно разделять запятыми.
На использование селекторов есть ограничения. Для событий безопасности вида execute
нельзя использовать селекторы interface
и endpoint
. Для событий безопасности вида security
нельзя использовать селекторы dst
и endpoint
.
Также есть ограничения на комбинации селекторов. Для событий безопасности видов request
, response
и error
селектор method
можно использовать только совместно с одним или обоими селекторами endpoint
и interface
. (Селекторы method
, endpoint
и interface
должны быть согласованы, то есть метод должен соответствовать службе или интерфейсу, служба должна соответствовать интерфейсу.) Для событий безопасности вида request
селектор endpoint
можно использовать только совместно с селектором dst
. Для событий безопасности видов response
и error
селектор endpoint
можно использовать только совместно с селектором src
.
Профиль аудита безопасности
Профиль аудита безопасности задается конструкцией audit
<имя профиля аудита безопасности
>. Если профиль аудита безопасности не задан, используется глобальный профиль аудита безопасности.
Вызываемые правила моделей безопасности
Вызываемые правила моделей безопасности задаются списком из конструкций следующего вида:
[имя объекта модели безопасности.]<имя правила модели безопасности> <параметр>
Входными данными для правил моделей безопасности могут быть значения, возвращаемые выражениями моделей безопасности. Для вызова выражения модели безопасности используется конструкция:
[имя объекта модели безопасности.]<имя выражения модели безопасности> <параметр>
Также в качестве входных данных для методов моделей безопасности (правил и выражений) могут использоваться параметры интерфейсных методов. (О получении доступа к параметрам интерфейсных методов см. "Модель безопасности Struct"). Кроме этого, входными данными для методов моделей безопасности могут быть значения SID сущностей и ядра KasperskyOS, которые задаются ключевыми словами src_sid
и dst_sid
. Первое означает SID сущности (или ядра), которая является источником IPC-сообщения. Второе означает SID сущности (или ядра), которая является приемником IPC-сообщения (при обращениях к модулю безопасности Kaspersky Security Module dst_sid
использовать нельзя).
Для вызовов некоторых правил и выражений моделей безопасности можно не указывать имя объекта модели безопасности или использовать операторы. Подробнее о методах моделей безопасности см. "Модели безопасности".
Вложенные конструкции для привязки методов моделей безопасности к событиям безопасности
В одной декларации можно выполнить привязку методов моделей безопасности к разным события безопасности одного вида. Для этого нужно использовать match-секции, которые представляют собой конструкции вида:
match <селекторы события безопасности> {
[профиль аудита безопасности]
<вызываемые правила моделей безопасности>
}
Match-секции могут быть вложены в другую match-секцию. Match-секция использует одновременно свои селекторы события безопасности и селекторы события безопасности уровня декларации и всех match-секций, которые "оборачивают" эту match-секцию. Также match-секция применяет по умолчанию профиль аудита безопасности своего контейнера (match-секции предыдущего уровня или уровня декларации), но можно задать отдельный профиль аудита безопасности для match-секции.
Также в одной декларации можно задать различные варианты обработки события безопасности в зависимости от условий, при которых это событие наступило (например, от состояния конечно автомата, ассоциированного с ресурсом). Для этого нужно использовать условные секции, которые являются элементами конструкции:
choice <вызов выражения модели безопасности, проверяющего выполнение условий> {
"<условие 1>" : [{] // Условная секция 1
[профиль аудита безопасности]
<вызываемые правила моделей безопасности>
[}]
"<условие 2>" : ... // Условная секция 2
...
_ : ... // Условная секция, если ни одно условие не выполняется.
}
Конструкцию choice
можно использовать внутри match-секции. Условная секция использует селекторы события безопасности и профиль аудита безопасности своего контейнера, но можно задать отдельный профиль аудита безопасности для условной секции.
Если при обработке события безопасности выполняется сразу несколько условий, описанных в конструкции choice
, то срабатывает только одна условная секция, соответствующая первому в списке подходящему условию.
В качестве выражения, проверяющего выполнение условий в конструкции choice
, можно использовать только те выражения, которые предназначены специально для этого. Некоторые модели безопасности содержат такие выражения (подробнее см. "Модели безопасности").
Описание профилей аудита безопасности
Для выполнения аудита безопасности нужно ассоциировать объекты моделей безопасности с профилем (профилями) аудита безопасности. Профиль аудита безопасности (далее также профиль аудита) объединяет в себе конфигурации аудита безопасности (далее также конфигурации аудита), каждая из которых задает объекты моделей безопасности, покрываемые аудитом, а также условия выполнения аудита. Можно задать глобальный профиль аудита (подробнее см. "Описание глобальных параметров политики безопасности решения") и/или назначить профиль (профили) аудита на уровне деклараций привязки методов моделей безопасности к событиям безопасности, и/или назначить профиль (профили) аудита на уровне match-секций или choice-секций (подробнее см. "Привязка методов моделей безопасности к событиям безопасности").
Независимо от того, используются профили аудита или нет, данные аудита содержат сведения о решениях "запрещено", которые приняты модулем безопасности Kaspersky Security Module при некорректности IPC-сообщений и обработке событий безопасности, не связанных ни с одним правилом моделей безопасности.
Чтобы описать профиль аудита безопасности, нужно использовать декларацию:
audit profile <имя профиля аудита безопасности> =
{ <уровень аудита безопасности>:
// Описание конфигурации аудита безопасности
{ <имя объекта модели безопасности>:
{ kss : <условия выполнения аудита безопасности, связанные с результатами
вызовов правил модели безопасности>
[, условия выполнения аудита безопасности, специфичные для модели безопасности]
}
[,]...
...
}
[,]...
...
}
Уровень аудита безопасности
Уровень аудита безопасности (далее уровень аудита) является глобальным параметром политики безопасности решения и представляет собой беззнаковое целое число, которое задает активную конфигурацию аудита безопасности. (Слово "уровень" здесь означает вариант конфигурации и не предполагает обязательной иерархии.) Уровень аудита можно изменять в процессе работы модуля безопасности Kaspersky Security Module. Для этого используется специальный метод модели безопасности Base
, вызываемый при обращении сущностей к модулю безопасности через интерфейс безопасности (подробнее см. "Модель безопасности Base"). Начальный уровень аудита задается совместно с назначением глобального профиля аудита (подробнее см. "Описание глобальных параметров политики безопасности решения"). В качестве глобального можно явно назначить пустой профиль аудита empty
.
В профиле аудита можно задать несколько конфигураций аудита. В разных конфигурациях можно покрыть аудитом разные объекты моделей безопасности и применить разные условия выполнения аудита. Конфигурации аудита в профиле соответствуют разным уровням аудита. Если в профиле нет конфигурации аудита, соответствующей текущему уровню аудита, модуль безопасности задействует конфигурацию, которая соответствует ближайшему меньшему уровню аудита. Если в профиле нет конфигурации аудита для уровня аудита, равного или ниже текущего, модуль безопасности не будет использовать этот профиль (то есть аудит по этому профилю не будет выполняться).
Уровни аудита можно использовать, например, чтобы регулировать детализацию аудита. Чем выше уровень аудита, тем выше детализация. Чем выше детализация, тем больше объектов моделей безопасности покрывается аудитом и/или меньше ограничений применяется в условиях выполнения аудита.
Другим примером применения уровней аудита является возможность переключать аудит с одной подсистемы на другую (например, переключить аудит, связанный с драйверами, на аудит, связанный с прикладными программами, или аудит, связанный с сетевой подсистемой, на аудит, связанный с графической подсистемой).
Имя объекта модели безопасности
Имя объекта модели безопасности указывается, чтобы методы, которые предоставляются этим объектом, могли быть покрыты аудитом. Эти методы будут покрыты аудитом при их вызовах, если условия выполнения аудита будут соблюдены.
Сведения о решениях модуля безопасности Kaspersky Security Module, содержащиеся в данных аудита, включают как общее решение модуля безопасности, так и результаты вызовов отдельных методов моделей безопасности, покрытых аудитом. Чтобы сведения о решении модуля безопасности попали в данные аудита, нужно, чтобы по крайней мере один метод, вызванный при обработке события безопасности, был покрыт аудитом.
Имена объектов моделей безопасности, как и имена методов, предоставляемых этими объектами, попадают в данные аудита.
Условия выполнения аудита безопасности
Условия выполнения аудита безопасности задаются отдельно для каждого объекта модели безопасности.
Чтобы задать условия выполнения аудита, связанные с результатами вызовов правил моделей безопасности, нужно использовать следующие конструкции:
["granted"]
– аудит выполняется, если вызванное правило вернуло результат "разрешено";["denied"]
– аудит выполняется, если вызванное правило вернуло результат "запрещено";["granted", "denied"]
– аудит выполняется, если вызванное правило вернуло результат "разрешено" или "запрещено";[]
– аудит не выполняется независимо от того, какой результат вернуло вызванное правило.
Условия выполнения аудита, связанные с результатами вызовов правил, не применяются к выражениям. Эти условия должны быть заданы (любой возможной конструкцией), даже если модель безопасности содержит только выражения, поскольку этого требует синтаксис языка PSL.
Условия выполнения аудита, специфичные для моделей безопасности, задаются конструкциями, специфичными для этих моделей. Эти условия применяются как к правилам, так и к выражениям. Например, таким условием может быть состояние конечного автомата.
Профиль аудита безопасности для тракта аудита безопасности
Тракт аудита безопасности включает ядро, а также сущности Klog
и KlogStorage
, которые соединены IPC-каналами по схеме "ядро – Klog
– KlogStorage
". Методы моделей безопасности, которые связаны с передачей данных аудита через этот тракт, не должны покрываться аудитом. В противном случае это приведет к лавинообразному росту данных аудита, так как передача данных будет порождать новые данные.
Чтобы "подавить" аудит, заданный профилем более широкой области действия (например, глобальным или профилем на уровне декларации привязки методов моделей безопасности к события безопасности), нужно назначить пустой профиль аудита empty
на уровне декларации привязки методов моделей безопасности к событиям безопасности или на уровне match-секции либо choice-секции.
Типы данных в языке PSL
Типы данных, поддерживаемые в языке PSL, приведены в таблице ниже.
Типы данных в языке PSL
Обозначения типов |
Описание типов |
---|---|
|
Беззнаковое целое число |
|
Знаковое целое число |
|
Логический тип Логический тип включает два значения: |
|
Текстовый тип |
|
Тип Тип |
|
Текстовый литерал Текстовый литерал включает одно неизменяемое текстовое значение. Примеры определений текстовых литералов:
|
|
Целочисленный литерал Целочисленный литерал включает одно неизменяемое целочисленное значение. Примеры определений числовых литералов:
|
< |
Вариантный тип Вариантный тип объединяет два и более типов и может выступать в роли любого из них. Примеры определений вариантных типов:
|
|
Словарь Словарь состоит из полей одного или нескольких типов. Словарь может быть пустым. Примеры определений словарей:
|
|
Кортеж Кортеж состоит из полей одного или нескольких типов, расположенных в порядке перечисления типов. Кортеж может быть пустым. Примеры определений кортежей:
|
|
Множество Множество включает ноль и более уникальных элементов одного типа. Примеры определений множеств:
|
|
Список Список включает ноль и более элементов одного типа. Примеры определений списков:
|
|
Ассоциативный массив Ассоциативный массив включает ноль и более записей типа "ключ-значение" с уникальными ключами. Пример определения ассоциативного массива:
|
|
Массив Массив включает заданное число элементов одного типа. Пример определения массива:
|
|
Последовательность Последовательность включает от ноля до заданного числа элементов одного типа. Пример определения последовательности:
|
Псевдонимы некоторых типов PSL
В файле nk/base.psl
из состава KasperskyOS SDK определены типы данных, которые используются как типы параметров (или структурных элементов параметров) и возвращаемых значений для методов разных моделей безопасности. Псевдонимы и определения этих типов приведены в таблице ниже.
Псевдонимы и определения некоторых типов данных в языке PSL
Псевдоним типа |
Определение типа |
---|---|
|
Беззнаковое целое число
|
|
Знаковое целое число
|
|
Целое число
|
|
Скалярный литерал
|
|
Литерал
|
|
Тип идентификатора безопасности SID
|
|
Тип идентификатора безопасности SID
|
|
Словарь, содержащий поля для SID и маски прав дескриптора
|
|
Тип данных, принимаемых выражениями моделей безопасности, вызываемыми в конструкции
|
|
Тип данных, задающих условия выполнения аудита безопасности
|
Отображение типов IDL на типы PSL
Для описания параметров интерфейсных методов используются типы данных языка IDL. Входные данные для методов моделей безопасности имеют типы из языка PSL. Набор типов данных в языке IDL отличается от набора типов данных в языке PSL. Поскольку параметры интерфейсных методов, передаваемые в IPC-сообщениях, могут использоваться как входные данные для методов моделей безопасности, автору политики безопасности решения нужно понимать, как типы IDL отображаются на типы PSL.
Целочисленные типы IDL отображаются на целочисленные типы PSL, а также на вариантные типы PSL, объединяющие эти целочисленные типы (в том числе с другими типами). Например, знаковые целочисленные типы IDL отображаются на тип Signed
в PSL, целочисленные типы IDL отображаются на тип ScalarLiteral
в PSL.
Тип Handle
в IDL отображается на тип HandleDesc
в PSL.
Объединения и структуры IDL отображаются на словари PSL.
Массивы и последовательности IDL отображаются на массивы и последовательности PSL соответственно.
Строковые буферы в IDL отображаются на текстовый тип PSL.
В настоящее время байтовые буферы в IDL не отображаются на типы PSL. Соответственно, данные, содержащиеся в байтовых буферах, не могут использоваться как входы для методов моделей безопасности.
В началоПример простейшей политики безопасности решения
Ниже приведена простейшая политика безопасности решения вида "все разрешено" для решения, состоящего из пользовательских сущностей Client
и Server
, а также сущности Einit
и ядра KasperskyOS, представленного сущностью kl.core.Core
.
Эта политика разрешает:
- все взаимодействия сущностей (отправку любых запросов и ответов);
- запуск всех сущностей;
Использование такой политики безопасности недопустимо в реальных решениях. Более сложная политика безопасности решения показана в примере ping.
security.psl
execute: kl.core.Execute
use nk.base._
use EDL Einit
use EDL kl.core.Core
use EDL Client
use EDL Server
/* Запуск сущностей разрешен */
execute {
grant ()
}
/* Отправка и получение запросов, ответов и ошибок разрешены.
Это означает, что любая сущность может вызывать методы других сущностей и ядра. */
request {
grant ()
}
response {
grant ()
}
error {
grant ()
}
/* При обращения к модулю безопасности Kaspersky Security Module всегда
* будет получено решение "разрешено". */
security {
grant ()
}
Модель безопасности Pred
Модель безопасности Pred позволяет выполнять операции сравнения.
PSL-файл с описанием модели безопасности Pred находится в KasperskyOS SDK по пути:
toolchain/include/nk/basic.psl
Объект модели безопасности Pred
В файле basic.psl
содержится декларация, которая создает объект модели безопасности Pred с именем pred
. Соответственно, включение файла basic.psl
в описание политики безопасности решения обеспечивает создание объекта модели безопасности Pred по умолчанию.
Объект модели безопасности Pred не имеет параметров и не может быть покрыт аудитом безопасности.
Создавать дополнительные объекты модели безопасности Pred не требуется.
Методы модели безопасности Pred
Модель безопасности Pred содержит выражения, которые выполняют операции сравнения и возвращают значения типа Boolean
. Для вызова этих выражений нужно использовать операторы сравнения:
- <
ScalarLiteral
>==
<ScalarLiteral
> – "равно"; - <
ScalarLiteral
>!=
<ScalarLiteral
> – "не равно"; - <
Number
><
<Number
> – "меньше"; - <
Number
><=
<Number
> – "меньше или равно"; - <
Number
>>
<Number
> – "больше"; - <
Number
>>=
<Number
> – "больше или равно".
Также модель безопасности Pred содержит выражение empty
, которое позволяет определить, содержат ли данные свои структурные элементы. Выражение возвращает значения типа Boolean
. Если данные не содержат своих структурных элементов (например, множество является пустым), выражение возвращает true
, иначе возвращает false
. Чтобы вызвать выражение, нужно использовать конструкцию:
pred.empty <Text | Set | List | Map | ()>
Модель безопасности Bool
Модель безопасности Bool позволяет выполнять логические операции.
PSL-файл с описанием модели безопасности Bool находится в KasperskyOS SDK по пути:
toolchain/include/nk/basic.psl
Объект модели безопасности Bool
В файле basic.psl
содержится декларация, которая создает объект модели безопасности Bool с именем bool
. Соответственно, включение файла basic.psl
в описание политики безопасности решения обеспечивает создание объекта модели безопасности Bool по умолчанию.
Объект модели безопасности Bool не имеет параметров и не может быть покрыт аудитом безопасности.
Создавать дополнительные объекты модели безопасности Bool не требуется.
Методы модели безопасности Bool
Модель безопасности Bool содержит выражения, которые выполняют логические операции и возвращают значения типа Boolean
. Для вызова этих выражений нужно использовать логические операторы:
!
<Boolean
> – "логическое НЕ";- <
Boolean
>&&
<Boolean
> – "логическое И"; - <
Boolean
>||
<Boolean
> – "логическое ИЛИ"; - <
Boolean
>==>
<Boolean
> – "импликация" (!
<Boolean
>||
<Boolean
>).
Также модель безопасности Bool содержит выражения all
, any
и cond
.
Выражение all
выполняет "логическое И" для произвольного числа значений типа Boolean
. Возвращает значения типа Boolean
. Если передать через параметр пустой список значений ([]
), возвращает true
. Чтобы вызвать выражение, нужно использовать конструкцию:
bool.all <List<Boolean>>
Выражение any
выполняет "логическое ИЛИ" для произвольного числа значений типа Boolean
. Возвращает значения типа Boolean
. Если передать через параметр пустой список значений ([]
), возвращает false
. Чтобы вызвать выражение, нужно использовать конструкцию:
bool.any <List<Boolean>>
Выражение cond
выполняет тернарную условную операцию. Возвращает значения типа ScalarLiteral
. Чтобы вызвать выражение, нужно использовать конструкцию:
bool.cond
{ if : <Boolean> // Условие
, then : <ScalarLiteral> // Значение, возвращаемое при истинности условия
, else : <ScalarLiteral> // Значение, возвращаемое при ложности условия
}
Помимо выражений модель безопасности Bool включает правило assert
, которое работает так же, как одноименное правило модели безопасности Base.
Модель безопасности Math
Модель безопасности Math позволяет выполнять операции целочисленной арифметики.
PSL-файл с описанием модели безопасности Math находится в KasperskyOS SDK по пути:
toolchain/include/nk/basic.psl
Объект модели безопасности Math
В файле basic.psl
содержится декларация, которая создает объект модели безопасности Math с именем math
. Соответственно, включение файла basic.psl
в описание политики безопасности решения обеспечивает создание объекта модели безопасности Math по умолчанию.
Объект модели безопасности Math не имеет параметров и не может быть покрыт аудитом безопасности.
Создавать дополнительные объекты модели безопасности Math не требуется.
Методы модели безопасности Math
Модель безопасности Math содержит выражения, которые выполняют операции целочисленной арифметики. Для вызова части этих выражений нужно использовать арифметические операторы:
- <
Number
>+
<Number
> – "сложение". Возвращает значения типаNumber
. - <
Number
>-
<Number
> – "вычитание". Возвращает значения типаNumber
. - <
Number
>*
<Number
> – "умножение". Возвращает значения типаNumber
.
Другая часть включает следующие выражения:
neg
<Signed
> – "изменение знака числа". Возвращает значения типаSinged
.abs
<Singed
> – "получение модуля числа". Возвращает значения типаSinged
.sum
<List<Number>
> – "сложение чисел из списка". Возвращает значения типаNumber
. Если передать через параметр пустой список значений ([]
), возвращает0
.product
<List<Number>
> – "перемножение чисел из списка". Возвращает значения типаNumber
. Если передать через параметр пустой список значений ([]
), возвращает1
.
Для вызова этих выражений нужно использовать конструкцию:
math.<имя выражения> <параметр>
Модель безопасности Struct
Модель безопасности Struct позволяет получать доступ к структурным элементам данных.
PSL-файл с описанием модели безопасности Struct находится в KasperskyOS SDK по пути:
toolchain/include/nk/basic.psl
Объект модели безопасности Struct
В файле basic.psl
содержится декларация, которая создает объект модели безопасности Struct с именем struct
. Соответственно, включение файла basic.psl
в описание политики безопасности решения обеспечивает создание объекта модели безопасности Struct по умолчанию.
Объект модели безопасности Struct не имеет параметров и не может быть покрыт аудитом безопасности.
Создавать дополнительные объекты модели безопасности Struct не требуется.
Методы модели безопасности Struct
Модель безопасности Struct содержит выражения, которые обеспечивают доступ к структурным элементам данных. Для вызова этих выражений нужно использовать следующие конструкции:
- <
{...}
>.
<имя поля
> – "получение доступа к полю словаря". Тип возвращаемых данных соответствует типу поля словаря. - <
List | Set | Sequence | Array
>.[
<номер элемента
>]
– "получение доступа к элементу данных". Тип возвращаемых данных соответствует типу элементов. Нумерация элементов начинается с нуля. При выходе за границы набора данных выражение завершается некорректно, и модуль безопасности Kaspersky Security Module возвращает решение "запрещено". - <
HandleDesc
>.handle
– "получение SID". Возвращает значения типаHandle
. (О взаимосвязи между дескрипторами и значениями SID см. "Управление доступом к ресурсам"). - <
HandleDesc
>.rights
– "получение маски прав дескриптора". Возвращает значения типаUInt32
.
Параметры интерфейсных методов сохраняются в специальном словаре message
. Чтобы получить доступ к параметру интерфейсного метода, нужно использовать конструкцию:
message.<имя параметра интерфейсного метода>
Имя параметра нужно указать в соответствии с IDL-описанием.
Чтобы получить доступ к структурным элементам параметров, нужно использовать конструкции, соответствующие выражениям модели безопасности Struct.
В началоМодель безопасности Base
Модель безопасности Base позволяет реализовать простейшую логику.
PSL-файл с описанием модели безопасности Base находится в KasperskyOS SDK по пути:
toolchain/include/nk/base.psl
Объект модели безопасности Base
В файле base.psl
содержится декларация, которая создает объект модели безопасности Base с именем base
. Соответственно, включение файла base.psl
в описание политики безопасности решения обеспечивает создание объекта модели безопасности Base по умолчанию. Методы этого объекта можно вызывать без указания имени объекта.
Объект модели безопасности Base не имеет параметров.
Объект модели безопасности Base может быть покрыт аудитом безопасности. Условия выполнения аудита, специфичные для модели безопасности Base, отсутствуют.
Необходимость создавать дополнительные объекты модели безопасности Base возникает в следующих случаях:
- Если нужно по-разному настроить аудит безопасности для разных объектов модели безопасности Base (например, для разных объектов можно применять разные профили аудита или разные конфигурации аудита одного профиля).
- Если нужно различать вызовы методов, предоставляемых разными объектами модели безопасности Base (поскольку в данные аудита включается как имя метода модели безопасности, так и имя объекта, предоставляющего этот метод, можно понять, что был вызван метод конкретного объекта).
Методы модели безопасности Base
Модель безопасности Base содержит следующие правила:
grant ()
Имеет параметр типа
()
. Возвращает результат "разрешено".Пример:
/* Клиенту класса foo разрешено обращаться
* серверу класса bar. */
request src=foo dst=bar { grant () }
assert
<Boolean
>Возвращает результат "разрешено", если через параметр передать значение
true
. Иначе возвращает результат "запрещено".Пример:
/* Любому клиенту в решении будет разрешено обращаться к серверу класса foo,
* вызывая метод Send службы net.Net, если через параметр port метода Send
* будет передаваться значение больше 80. Иначе любому клиенту в решении
* будет запрещено обращаться к серверу класса foo, вызывая метод Send
* службы net.Net. */
request dst=foo endpoint=net.Net method=Send { assert (message.port > 80) }
deny
<Boolean | ()
>Возвращает результат "запрещено", если через параметр передать значение
true
или()
. Иначе возвращает результат "разрешено".Пример:
/* Серверу класса foo запрещено отвечать
* клиенту класса bar. */
response src=foo dst=bar { deny () }
set_level
<UInt8
>Устанавливает уровень аудита безопасности равным значению, переданному через параметр. Возвращает результат "разрешено". (Подробнее об уровне аудита безопасности см. "Описание профилей аудита безопасности".)
Пример:
/* Сущность класса foo получит решение "разрешено" от модуля безопасности
* Kaspersky Security Module, если вызовет метод интерфейса безопасности SetAuditLevel,
* чтобы изменить уровень аудита безопасности. */
security src=foo method=SetAuditLevel { set_level (message.audit_level) }
Модель безопасности Regex
Модель безопасности Regex позволяет реализовать валидацию текстовых данных по статически заданным регулярным выражениям.
PSL-файл с описанием модели безопасности Regex находится в KasperskyOS SDK по пути:
toolchain/include/nk/regex.psl
Объект модели безопасности Regex
В файле regex.psl
содержится декларация, которая создает объект модели безопасности Regex с именем re
. Соответственно, включение файла regex.psl
в описание политики безопасности решения обеспечивает создание объекта модели безопасности Regex по умолчанию.
Объект модели безопасности Regex не имеет параметров.
Объект модели безопасности Regex может быть покрыт аудитом безопасности. При этом можно задавать условия выполнения аудита, специфичные для модели безопасности Regex. Для этого в описании конфигурации аудита нужно использовать следующие конструкции:
emit : ["match"]
– аудит выполняется, если вызван методmatch
;emit : ["select"]
– аудит выполняется, если вызван методselect
;emit : ["match", "select"]
– аудит выполняется, если вызван методmatch
илиselect
;emit : []
– аудит не выполняется.
Необходимость создавать дополнительные объекты модели безопасности Regex возникает в следующих случаях:
- Если нужно по-разному настроить аудит безопасности для разных объектов модели безопасности Regex (например, для разных объектов можно применять разные профили аудита или разные конфигурации аудита одного профиля).
- Если нужно различать вызовы методов, предоставляемых разными объектами модели безопасности Regex (поскольку в данные аудита включается как имя метода модели безопасности, так и имя объекта, предоставляющего этот метод, можно понять, что был вызван метод конкретного объекта).
Методы модели безопасности Regex
Модель безопасности Regex
содержит следующие выражения:
match {text :
<Text
>, pattern :
<Text
>}
Возвращает значение типа
Boolen
. Если текстtext
соответствует регулярному выражениюpattern
, возвращаетtrue
. Иначе возвращаетfalse
.Пример:
assert (re.match {text : message.text, pattern : "^[0-9]*$"})
select {text :
<Text
>}
Предназначено для использования в качестве выражения, проверяющего выполнение условий в конструкции
choice
(о конструкцииchoice
см. "Привязка методов моделей безопасности к событиям безопасности"). Проверяет соответствие текстаtext
регулярным выражениям. В зависимости от результатов этой проверки выполняются различные варианты обработки события безопасности.Пример:
choice (re.select {text : "hello world"}) {
"^hello .*": grant ()
".*world$" : grant ()
_ : deny ()
}
Модель безопасности HashSet
Модель безопасности HashSet позволяет ассоциировать с ресурсами одномерные таблицы уникальных значений одного типа, добавлять и удалять эти значения, а также проверять, входит ли заданное значение в таблицу. Например, можно ассоциировать сущность, в контексте которой выполняется сетевой сервер, с набором портов, который разрешено открывать этому серверу. Эту ассоциацию можно использовать, чтобы проверить, допустимо ли открытие порта, инициированное сервером.
PSL-файл с описанием модели безопасности HashSet находится в KasperskyOS SDK по пути:
toolchain/include/nk/hashmap.psl
Объект модели безопасности HashSet
Чтобы использовать модель безопасности HashSet, нужно создать объект (объекты) этой модели.
Объект модели безопасности HashSet содержит пул одномерных таблиц одинакового размера, предназначенных для хранения значений одного типа. Ресурс может быть ассоциирован только с одной таблицей из пула таблиц каждого объекта модели безопасности HashSet.
Объект модели безопасности HashSet имеет следующие параметры:
type Entry
– тип значений в таблицах (поддерживаются целочисленные типы, типBoolean
, а также словари и кортежи на базе целочисленных типов и типаBoolean
);config
– конфигурация пула таблиц:set_size
– размер таблицы;pool_size
– число таблиц в пуле.
Все параметры объекта модели безопасности HashSet являются обязательными.
Пример:
policy object S : HashSet {
type Entry = UInt32
config =
{ set_size : 5
, pool_size : 2
}
}
Объект модели безопасности HashSet может быть покрыт аудитом безопасности. Условия выполнения аудита, специфичные для модели безопасности HashSet, отсутствуют.
Необходимость создавать несколько объектов модели безопасности HashSet возникает в следующих случаях:
- Если нужно по-разному настроить аудит безопасности для разных объектов модели безопасности HashSet (например, для разных объектов можно применять разные профили аудита или разные конфигурации аудита одного профиля).
- Если нужно различать вызовы методов, предоставляемых разными объектами модели безопасности HashSet (поскольку в данные аудита включается как имя метода модели безопасности, так и имя объекта, предоставляющего этот метод, можно понять, что был вызван метод конкретного объекта).
- Если нужно использовать таблицы разных размеров и/или с разными типами значений.
Правило init модели безопасности HashSet
init {sid : <Sid>}
Ассоциирует свободную таблицу из пула таблиц с ресурсом, который имеет идентификатор безопасности sid
. Если свободная таблица содержит значения после предыдущего использования, то эти значения удаляются.
Возвращает результат "разрешено", если создало ассоциацию таблицы с ресурсом.
Возвращает результат "запрещено" в следующих случаях:
- В пуле нет свободных таблиц.
- Ресурс с идентификатором безопасности
sid
уже ассоциирован с таблицей из пула таблиц используемого объекта модели безопасности HashSet. - Идентификатор безопасности
sid
вне допустимого диапазона.
Пример:
/* Запуск сущности класса Server будет разрешен, если
* при инициации запуска будет создана ассоциация этой
* сущности с таблицей. Иначе запуск сущности класса
* Server будет запрещен. */
execute dst=Server {
S.init {sid : dst_sid}
}
Правило fini модели безопасности HashSet
fini {sid : <Sid>}
Удаляет ассоциацию таблицы с ресурсом, который имеет идентификатор безопасности sid
(таблица становится свободной).
Возвращает результат "разрешено", если удалило ассоциацию таблицы с ресурсом.
Возвращает результат "запрещено" в следующих случаях:
- Ресурс с идентификатором безопасности
sid
не ассоциирован с таблицей из пула таблиц используемого объекта модели безопасности HashSet. - Идентификатор безопасности
sid
вне допустимого диапазона.
Правило add модели безопасности HashSet
add {sid : <Sid>, entry : <Entry>}
Добавляет значение entry
в таблицу, ассоциированную с ресурсом, который имеет идентификатор безопасности sid
.
Возвращает результат "разрешено" в следующих случаях:
- Правило добавило значение
entry
в таблицу. - В таблице уже содержится значение
entry
.
Возвращает результат "запрещено" в следующих случаях:
- Таблица полностью заполнена.
- Ресурс с идентификатором безопасности
sid
не ассоциирован с таблицей из пула таблиц используемого объекта модели безопасности HashSet. - Идентификатор безопасности
sid
вне допустимого диапазона.
Пример:
/* Сущность класса Server получит решение "разрешено"
* от модуля безопасности Kaspersky Security Module, вызывая метод
* интерфейса безопасности Add, если при вызове этого
* метода значение 5 будет добавлено в таблицу,
* ассоциированную с этой сущностью, или уже содержится
* в этой таблице. Иначе сущность класса Server получит
* решение "запрещено" от модуля безопасности, вызывая
* метод интерфейса безопасности Add. */
security src=Server, method=Add {
S.add {sid : src_sid, entry : 5}
}
Правило remove модели безопасности HashSet
remove {sid : <Sid>, entry : <Entry>}
Удаляет значение entry
из таблицы, ассоциированной с ресурсом, который имеет идентификатор безопасности sid
.
Возвращает результат "разрешено" в следующих случаях:
- Правило удалило значение
entry
из таблицы. - В таблице нет значения
entry
.
Возвращает результат "запрещено" в следующих случаях:
- Ресурс с идентификатором безопасности
sid
не ассоциирован с таблицей из пула таблиц используемого объекта модели безопасности HashSet. - Идентификатор безопасности
sid
вне допустимого диапазона.
Выражение contains модели безопасности HashSet
contains {sid : <Sid>, entry : <Entry>}
Проверяет, содержится ли значение entry
в таблице, ассоциированной с ресурсом, который имеет идентификатор безопасности sid
.
Возвращает значение типа Boolean
. Если значение entry
содержится в таблице, возвращает true
. Иначе возвращает false
.
Выполняется некорректно в следующих случаях:
- Ресурс с идентификатором безопасности
sid
не ассоциирован с таблицей из пула таблиц используемого объекта модели безопасности HashSet. - Идентификатор безопасности
sid
вне допустимого диапазона.
Если выражение выполнено некорректно, модуль безопасности Kaspersky Security Module возвращает решение "запрещено".
Пример:
/* Сущность класса Server получит решение "разрешено"
* от модуля безопасности Kaspersky Security Module, вызывая метод
* интерфейса безопасности Check, если значение 42
* содержится в таблице, ассоциированной с этой сущностью.
* Иначе сущность класса Server получит решение "запрещено"
* от модуля безопасности, вызывая метод интерфейса
* безопасности Check. */
security src=Server, method=Check {
assert(S.contains {sid : src_sid, entry : 42})
}
Модель безопасности StaticMap
Модель безопасности StaticMap позволяет ассоциировать с ресурсами двумерные таблицы типа "ключ–значение", читать и изменять значения ключей. Например, можно ассоциировать сущность, в контексте которой выполняется драйвер, с регионом памяти MMIO, который разрешено использовать этому драйверу. Для этого потребуется два ключа, значения которых задают начальный адрес и размер региона памяти MMIO. Эту ассоциацию можно использовать, чтобы проверить, может ли драйвер обращаться к региону памяти MMIO, к которому он пытается получить доступ.
Ключи в таблице имеют одинаковый тип и является уникальными и неизменяемыми. Значения ключей в таблице имеют одинаковый тип.
Одновременно существует два экземпляра таблицы: базовый и рабочий. Оба экземпляра инициализируются одинаковыми данными. Изменения заносятся сначала в рабочий экземпляр, а затем могут быть добавлены в базовый экземпляр или, наоборот, заменены прежними значениями из базового экземпляра. Значения ключей могут быть прочитаны как из базового, так и из рабочего экземпляра таблицы.
PSL-файл с описанием модели безопасности StaticMap находится в KasperskyOS SDK по пути:
toolchain/include/nk/staticmap.psl
Объект модели безопасности StaticMap
Чтобы использовать модель безопасности StaticMap, нужно создать объект (объекты) этой модели.
Объект модели безопасности StaticMap содержит пул двумерных таблиц типа "ключ–значение", которые имеют одинаковый размер. Ресурс может быть ассоциирован только с одной таблицей из пула таблиц каждого объекта модели безопасности StaticMap.
Объект модели безопасности StaticMap имеет следующие параметры:
type Value
– тип значений ключей в таблицах (поддерживаются целочисленные типы);config
– конфигурация пула таблиц:keys
– таблица, содержащая ключи и их значения по умолчанию (ключи имеют типKey = Text | List<UInt8>
);pool_size
– число таблиц в пуле.
Все параметры объекта модели безопасности StaticMap являются обязательными.
Пример:
policy object M : StaticMap {
type Value = UInt16
config =
{ keys:
{ "k1" : 0
, "k2" : 1
}
, pool_size : 2
}
}
Объект модели безопасности StaticMap может быть покрыт аудитом безопасности. Условия выполнения аудита, специфичные для модели безопасности StaticMap, отсутствуют.
Необходимость создавать несколько объектов модели безопасности StaticMap возникает в следующих случаях:
- Если нужно по-разному настроить аудит безопасности для разных объектов модели безопасности StaticMap (например, для разных объектов можно применять разные профили аудита или разные конфигурации аудита одного профиля).
- Если нужно различать вызовы методов, предоставляемых разными объектами модели безопасности StaticMap (поскольку в данные аудита включается как имя метода модели безопасности, так и имя объекта, предоставляющего этот метод, можно понять, что был вызван метод конкретного объекта).
- Если нужно использовать таблицы с разными наборами ключей и/или разными типами значений ключей.
Правило init модели безопасности StaticMap
init {sid : <Sid>}
Ассоциирует свободную таблицу из пула таблиц с ресурсом, который имеет идентификатор безопасности sid
. Ключи инициализируются значениями по умолчанию.
Возвращает результат "разрешено", если создало ассоциацию таблицы с ресурсом.
Возвращает результат "запрещено" в следующих случаях:
- В пуле нет свободных таблиц.
- Ресурс с идентификатором безопасности
sid
уже ассоциирован с таблицей из пула таблиц используемого объекта модели безопасности StaticMap. - Идентификатор безопасности
sid
вне допустимого диапазона.
Пример:
/* Запуск сущности класса Server будет разрешен, если
* при инициации запуска будет создана ассоциация этой
* сущности с таблицей. Иначе запуск сущности класса
* Server будет запрещен. */
execute dst=Server {
M.init {sid : dst_sid}
}
Правило fini модели безопасности StaticMap
fini {sid : <Sid>}
Удаляет ассоциацию таблицы с ресурсом, который имеет идентификатор безопасности sid
(таблица становится свободной).
Возвращает результат "разрешено", если удалило ассоциацию таблицы с ресурсом.
Возвращает результат "запрещено" в следующих случаях:
- Ресурс с идентификатором безопасности
sid
не ассоциирован с таблицей из пула таблиц используемого объекта модели безопасности StaticMap. - Идентификатор безопасности
sid
вне допустимого диапазона.
Правило set модели безопасности StaticMap
set {sid : <Sid>, key : <Key>, value : <Value>}
Задает значение value
ключу key
в рабочем экземпляре таблицы, ассоциированной с ресурсом, который имеет идентификатор безопасности sid
.
Возвращает результат "разрешено", если задало значение value
ключу key
. (Текущее значение ключа будет перезаписано, даже если оно равно новому.)
Возвращает результат "запрещено" в следующих случаях:
- Ключ
key
не содержится в таблице. - Ресурс с идентификатором безопасности
sid
не ассоциирован с таблицей из пула таблиц используемого объекта модели безопасности StaticMap. - Идентификатор безопасности
sid
вне допустимого диапазона.
Пример:
/* Сущность класса Server получит решение "разрешено"
* от модуля безопасности Kaspersky Security Module, вызывая метод
* интерфейса безопасности Set, если при вызове этого
* метода значение 2 будет задано ключу k1 в рабочем
* экземпляре таблицы, ассоциированной с этой сущностью.
* Иначе сущность класса Server получит решение "запрещено"
* от модуля безопасности, вызывая метод интерфейса
* безопасности Set. */
security src=Server, method=Set {
M.set {sid : src_sid, key : "k1", value : 2}
}
Правило commit модели безопасности StaticMap
commit {sid : <Sid>}
Копирует значения ключей из рабочего в базовый экземпляр таблицы, ассоциированной с ресурсом, который имеет идентификатор безопасности sid
.
Возвращает результат "разрешено", если скопировало значения ключей из рабочего в базовый экземпляр таблицы.
Возвращает результат "запрещено" в следующих случаях:
- Ресурс с идентификатором безопасности
sid
не ассоциирован с таблицей из пула таблиц используемого объекта модели безопасности StaticMap. - Идентификатор безопасности
sid
вне допустимого диапазона.
Правило rollback модели безопасности StaticMap
rollback {sid : <Sid>}
Копирует значения ключей из базового в рабочий экземпляр таблицы, ассоциированной с ресурсом, который имеет идентификатор безопасности sid
.
Возвращает результат "разрешено", если скопировало значения ключей из базового в рабочий экземпляр таблицы.
Возвращает результат "запрещено" в следующих случаях:
- Ресурс с идентификатором безопасности
sid
не ассоциирован с таблицей из пула таблиц используемого объекта модели безопасности StaticMap. - Идентификатор безопасности
sid
вне допустимого диапазона.
Выражение get модели безопасности StaticMap
get {sid : <Sid>, key : <Key>}
Возвращает значение ключа key
из базового экземпляра таблицы, ассоциированной с ресурсом, который имеет идентификатор безопасности sid
.
Возвращает значение типа Value
.
Выполняется некорректно в следующих случаях:
- Ключ
key
не содержится в таблице. - Ресурс с идентификатором безопасности
sid
не ассоциирован с таблицей из пула таблиц используемого объекта модели безопасности StaticMap. - Идентификатор безопасности
sid
вне допустимого диапазона.
Если выражение выполнено некорректно, модуль безопасности Kaspersky Security Module возвращает решение "запрещено".
Пример:
/* Сущность класса Server получит решение "разрешено"
* от модуля безопасности Kaspersky Security Module, вызывая метод
* интерфейса безопасности Get, если значение ключа k1
* в базовом экземпляре таблицы, ассоциированной с этой
* сущностью, отлично от нуля. Иначе сущность класса
* Server получит решение "запрещено" от модуля
* безопасности, вызывая метод интерфейса
* безопасности Get. */
security src=Server, method=Get {
assert(M.get {sid : src_sid, key : "k1"} != 0)
}
Выражение get_uncommited модели безопасности StaticMap
get_uncommited {sid: <Sid>, key: <Key>}
Возвращает значение ключа key
из рабочего экземпляра таблицы, ассоциированной с ресурсом, который имеет идентификатор безопасности sid
.
Возвращает значение типа Value
.
Выполняется некорректно в следующих случаях:
- Ключ
key
не содержится в таблице. - Ресурс с идентификатором безопасности
sid
не ассоциирован с таблицей из пула таблиц используемого объекта модели безопасности StaticMap. - Идентификатор безопасности
sid
вне допустимого диапазона.
Если выражение выполнено некорректно, модуль безопасности Kaspersky Security Module возвращает решение "запрещено".
В началоМодель безопасности Flow
Модель безопасности Flow позволяет ассоциировать с ресурсами конечные автоматы, получать и изменять состояния конечных автоматов, а также проверять, что состояние конечного автомата входит в заданный набор состояний. Например, можно ассоциировать сущность с конечным автоматом, чтобы разрешать и запрещать этой сущности использовать накопители и/или сеть в зависимости от состояния конечного автомата.
PSL-файл с описанием модели безопасности Flow находится в KasperskyOS SDK по пути:
toolchain/include/nk/flow.psl
Объект модели безопасности Flow
Чтобы использовать модель безопасности Flow, нужно создать объект (объекты) этой модели.
Один объект модели безопасности Flow позволяет ассоциировать множество ресурсов со множеством конечных автоматов, которые имеют одинаковую конфигурацию. Ресурс может быть ассоциирован только с одним конечным автоматом каждого объекта модели безопасности Flow.
Объект модели безопасности Flow имеет следующие параметры:
type State
– тип, определяющий множество состояний конечного автомата (вариантный тип, объединяющий текстовые литералы);config
– конфигурация конечного автомата:states
– множество состояний конечного автомата (должно совпадать со множеством состояний, заданных типомState
);initial
– начальное состояние конечного автомата;transitions
– описание допустимых переходов между состояниями конечного автомата.
Все параметры объекта модели безопасности Flow являются обязательными.
Пример:
policy object service_flow : Flow {
type State = "sleep" | "started" | "stopped" | "finished"
config = { states : ["sleep", "started", "stopped", "finished"]
, initial : "sleep"
, transitions : { "sleep" : ["started"]
, "started" : ["stopped", "finished"]
, "stopped" : ["started", "finished"]
}
}
}
Диаграмма состояний конечного автомата в примере
Объект модели безопасности Flow может быть покрыт аудитом безопасности. При этом можно задавать условия выполнения аудита, специфичные для модели безопасности Flow. Для этого в описании конфигурации аудита нужно использовать следующую конструкцию:
omit : [
<"состояние 1"
>[,
] ...]
– аудит не выполняется, если конечный автомат находится в одном из перечисленных состояний.
Необходимость создавать несколько объектов модели безопасности Flow возникает в следующих случаях:
- Если нужно по-разному настроить аудит безопасности для разных объектов модели безопасности Flow (например, для разных объектов можно применять разные профили аудита или разные конфигурации аудита одного профиля).
- Если нужно различать вызовы методов, предоставляемых разными объектами модели безопасности Flow (поскольку в данные аудита включается как имя метода модели безопасности, так и имя объекта, предоставляющего этот метод, можно понять, что был вызван метод конкретного объекта).
- Если нужно использовать конечные автоматы с разными конфигурациями.
Правило init модели безопасности Flow
init {sid : <Sid>}
Создает конечный автомат и ассоциирует его с ресурсом, который имеет идентификатор безопасности sid
. Созданный конечный автомат имеет конфигурацию, заданную в параметрах используемого объекта модели безопасности Flow.
Возвращает результат "разрешено", если создало ассоциацию конечного автомата с ресурсом.
Возвращает результат "запрещено" в следующих случаях:
- Ресурс с идентификатором безопасности
sid
уже ассоциирован с конечным автоматом используемого объекта модели безопасности Flow. - Идентификатор безопасности
sid
вне допустимого диапазона.
Пример:
/* Запуск сущности класса Server будет разрешен, если
* при инициации запуска будет создана ассоциация этой
* сущности с конечным автоматом. Иначе запуск сущности
* класса Server будет запрещен. */
execute dst=Server {
service_flow.init {sid : dst_sid}
}
Правило fini модели безопасности Flow
fini {sid : <Sid>}
Удаляет ассоциацию конечного автомата ресурсом, который имеет идентификатор безопасности sid
. Конечный автомат, который более не ассоциирован с ресурсом, уничтожается.
Возвращает результат "разрешено", если удалило ассоциацию конечного автомата с ресурсом.
Возвращает результат "запрещено" в следующих случаях:
- Ресурс с идентификатором безопасности
sid
не ассоциирован с конечным автоматом используемого объекта модели безопасности Flow. - Идентификатор безопасности
sid
вне допустимого диапазона.
Правило enter модели безопасности Flow
enter {sid : <Sid>, state : <State>}
Переводит конечный автомат, ассоциированный с ресурсом, который имеет идентификатор безопасности sid
, в состояние state
.
Возвращает результат "разрешено", если перевело конечный автомат в состояние state
.
Возвращает результат "запрещено" в следующих случаях:
- Переход в состояние
state
из текущего состояния не допускается конфигурацией конечного автомата. - Ресурс с идентификатором безопасности
sid
не ассоциирован с конечным автоматом используемого объекта модели безопасности Flow. - Идентификатор безопасности
sid
вне допустимого диапазона.
Пример:
/* Любому клиенту в решении будет разрешено обращаться
* к серверу класса Server, если конечный автомат,
* ассоциированный с этим сервером, будет переведен
* в состояние started при инициации обращения. Иначе
* любому клиенту в решении будет запрещено обращаться
* к серверу класса Server. */
request dst=Server {
service_flow.enter {sid : dst_sid, state : "started"}
}
Правило allow модели безопасности Flow
allow {sid : <Sid>, states : <Set<State>>}
Проверяет, что состояние конечного автомата, ассоциированного с ресурсом, который имеет идентификатор безопасности sid
, входит в набор состояний states
.
Возвращает результат "разрешено", если состояние конечного автомата входит в набор состояний states
.
Возвращает результат "запрещено" в следующих случаях:
- Состояние конечного автомата не входит в набор состояний
states
. - Ресурс с идентификатором безопасности
sid
не ассоциирован с конечным автоматом используемого объекта модели безопасности Flow. - Идентификатор безопасности
sid
вне допустимого диапазона.
Пример:
/* Любому клиенту в решении разрешено обращаться к серверу класса
* Server, если конечный автомат, ассоциированный с этим сервером,
* находится в состоянии started или stopped. Иначе любому клиенту
* в решении запрещено обращаться к серверу класса Server. */
request dst=Server {
service_flow.allow {sid : dst_sid, states : ["started", "stopped"]}
}
Выражение query модели безопасности Flow
query {sid : <Sid>}
Предназначено для использования в качестве выражения, проверяющего выполнение условий в конструкции choice
(о конструкции choice
см. "Привязка методов моделей безопасности к событиям безопасности"). Проверяет состояние конечного автомата, ассоциированного с ресурсом, который имеет идентификатор безопасности sid
. В зависимости от результатов этой проверки выполняются различные варианты обработки события безопасности.
Выполняется некорректно в следующих случаях:
- Ресурс с идентификатором безопасности
sid
не ассоциирован с конечным автоматом используемого объекта модели безопасности Flow. - Идентификатор безопасности
sid
вне допустимого диапазона.
Если выражение выполнено некорректно, модуль безопасности Kaspersky Security Module возвращает решение "запрещено".
Пример:
/* Любому клиенту в решении разрешено
* обращаться к серверу класса ResourceDriver,
* если конечный автомат, ассоциированный с этим
* сервером, находится в состоянии started или
* stopped. Иначе любому клиенту в решении
* запрещено обращаться к серверу класса
*ResourceDriver. */
request dst=ResourceDriver {
choice (service_flow.query {sid : dst_sid}) {
"started" : grant ()
"stopped" : grant ()
_ : deny ()
}
}
Пример ping
Пример ping демонстрирует использование политики безопасности решения для управления взаимодействиями между сущностями.
О примере ping
Пример ping включает в себя две сущности: Client
и Server
.
Сущность Server
предоставляет два идентичных метода Ping
и Pong
, которые получают число и возвращают измененное число:
Ping(in UInt32 value, out UInt32 result);
Pong(in UInt32 value, out UInt32 result);
Сущность Client
вызывает оба этих метода в различной последовательности. Если вызов метода запрещен политикой безопасности решения, выводится сообщение Failed to call...
Транспортная часть примера ping практически аналогична таковой для примера echo. Единственное отличие состоит в том, что в примере ping используется два метода (Ping
и Pong
), а не один.
Поскольку использование IPC-транспорта подробно рассмотрено в комментариях к примеру echo, в примере ping оно рассматривается кратко.
В примере ping реализуется политика безопасности решения (security.psl
) на базе модели безопасности модели безопасности Flow.
Состав примера ping
Пример ping состоит из следующих файлов:
client/src/client.c
resources/edl/Client.edl
server/src/server.c
resources/edl/Server.edl
,resources/cdl/Control.cdl
,resources/idl/Connection.idl
init.yaml
security.psl
Реализация сущности Client в примере ping
Сущность Client
для вызывает методы Ping
и Pong
в различной последовательности.
Инициализация транспорта до сервера, использование прокси-объекта и интерфейсных методов, а также назначение файла Connection.idl.h
рассматриваются более подробно в комментариях к файлу client.c в примере echo.
client.c
/* Файлы, необходимые для инициализации транспорта. */
/* Описание интерфейса сервера, по которому обращается клиентская сущность. */
static const char *Tag = "[Client]";
static struct Connection_proxy proxy;
static uint32_t ping(uint32_t value)
{
/* Структуры запроса и ответа */
struct Connection_Ping_req req;
struct Connection_Ping_res res;
req.value = value;
/**
* Вызываем интерфейсный метод Connection_Ping.
* Серверу будет отправлен запрос для вызова метода Ping интерфейса
* control.connectionimpl с аргументом value. Вызывающий поток блокируется
* до момента получения ответа от сервера.
*/
if (Connection_Ping(&proxy.base, &req, NULL, &res, NULL) == rcOk)
{
fprintf(stderr, "%s Ping(%d), result = %d\n", Tag, value, res.result);
value = res.result;
}
else
{
fprintf(stderr, "%s Ping(%d), failed\n", Tag, value);
}
return value;
}
static uint32_t pong(uint32_t value)
{
/* Структуры запроса и ответа */
struct Connection_Pong_req req;
struct Connection_Pong_res res;
req.value = value;
/**
* Вызываем интерфейсный метод Connection_Pong.
* Серверу будет отправлен запрос для вызова метода Pong интерфейса
* controlimpl.connectionimpl с аргументом value. Вызывающий поток блокируется
* до момента получения ответа от сервера.
*/
if (Connection_Pong(&proxy.base, &req, NULL, &res, NULL) == rcOk)
{
fprintf(stderr, "%s Pong(%d), result = %d\n", Tag, value, res.result);
value = res.result;
}
else
{
fprintf(stderr, "%s Pong(%d), failed\n", Tag, value);
}
return value;
}
/* Точка входа в клиентскую сущность. */
int main(int argc, const char *argv[])
{
NkKosTransport transport;
uint32_t value;
int i;
fprintf(stderr, "%s Entity started\n", Tag);
/**
* Получаем клиентский IPC-дескриптор соединения с именем
* "server_connection".
*/
Handle handle = ServiceLocatorConnect("server_connection");
if (INVALID_HANDLE == handle)
{
fprintf(stderr, "%s ServiceLocatorConnect failed\n", Tag);
return EXIT_FAILURE;
}
/* Инициализируем IPC-транспорт для взаимодействия с серверной сущностью. */
NkKosTransport_Init(&transport, handle, NK_NULL, 0);
/* Получаем Runtime Interface ID (RIID) для интерфейса ping.Control.connectionimpl. */
nk_iid_t riid = ServiceLocatorGetRiid(handle, "ping.Control.connectionimpl");
if (INVALID_RIID == riid)
{
fprintf(stderr, "%s ServiceLocatorGetRiid failed\n", Tag);
return EXIT_FAILURE;
}
/**
* Инициализируем прокси-объект, указав транспорт (&transport)
* и идентификатор интерфейса сервера (riid). Каждый метод
* прокси-объекта будет реализован как отправка запроса серверу.
*/
Connection_proxy_init(&proxy, &transport.base, riid);
/* Тестовый цикл. */
value = EXAMPLE_VALUE_TO_SEND;
for (i = 0; i < 5; ++i)
{
value = ping(value);
value = pong(value);
}
value = ping(value);
value = ping(value);
value = pong(value);
value = pong(value);
return EXIT_SUCCESS;
}
Реализация сущности Server в примере ping
Инициализация транспорта до клиента, подготовка структур запроса и ответа, а также назначение файла Server.edl.h
рассматриваются более подробно в комментариях к файлу server.c в примере echo.
server.c
/* Файлы, необходимые для инициализации транспорта. */
/* Описания сущности-сервера на языках EDL, CDL, IDL. */
static const char *Tag = "[Server]";
/* Тип объекта реализующего интерфейс. */
typedef struct ObjectImpl
{
struct Connection base; /* базовый интерфейс объекта */
int step; /* дополнительные параметры */
} ObjectImpl;
/* Реализация метода Ping. */
static nk_err_t Ping_impl(
struct Connection *self,
const struct Connection_Ping_req *req,
const struct nk_arena *req_arena,
struct Connection_Ping_res *res,
struct nk_arena *res_arena)
{
ObjectImpl *impl = (ObjectImpl *)self;
/**
* Значение value, пришедшее в запросе от клиента, инкрементируем на
* величину шага step и помещаем в аргумент result, который будет
* отправлен клиенту в составе ответа от сервера.
*/
res->result = req->value + (unsigned int)impl->step;
return NK_EOK;
}
/* Реализация метода Pong. */
static nk_err_t Pong_impl(
struct Connection *self,
const struct Connection_Pong_req *req,
const struct nk_arena *req_arena,
struct Connection_Pong_res *res,
struct nk_arena *res_arena)
{
ObjectImpl *impl = (ObjectImpl *)self;
/**
* Значение value, пришедшее в запросе от клиента, инкрементируем на
* величину шага step и помещаем в аргумент result, который будет
* отправлен клиенту в составе ответа от сервера.
*/
res->result = req->value + (unsigned int)impl->step;
return NK_EOK;
}
/**
* Конструктор объекта Ping.
* step - шаг, то есть число, на которое будет увеличиваться входящее значение.
*/
static struct Connection *CreateObjectImpl(int step)
{
/* Таблица реализаций методов интерфейса Connection. */
static const struct Connection_ops ops = {.Ping = Ping_impl, .Pong = Pong_impl};
/* Объект, реализующий интерфейс. */
static struct ObjectImpl impl = {.base = {&ops}};
impl.step = step;
return &impl.base;
}
/* Точка входа в сервер. */
int main(void)
{
NkKosTransport transport;
ServiceId iid;
/* Регистрируем соединение и получаем дескриптор для него. */
Handle handle = ServiceLocatorRegister("server_connection", NULL, 0, &iid);
if (INVALID_HANDLE == handle)
{
fprintf(stderr, "%s Failed to register service locator\n", Tag);
return EXIT_FAILURE;
}
/* Инициализируем транспорт до клиента. */
NkKosTransport_Init(&transport, handle, NK_NULL, 0);
/* Подготавливаем структуры запроса: фиксированную часть и арену. */
union Server_entity_req req;
char req_buffer[Server_entity_req_arena_size];
struct nk_arena req_arena = NK_ARENA_INITIALIZER(req_buffer, req_buffer + sizeof(req_buffer));
/* Подготавливаем структуры ответа: фиксированную часть и арену. */
union Server_entity_res res;
char res_buffer[Server_entity_res_arena_size];
struct nk_arena res_arena = NK_ARENA_INITIALIZER(res_buffer, res_buffer + sizeof(res_buffer));
/**
* Инициализируем диспетчер компонента Control. INCREMENT_STEP – значение "шага",
* которое будет прибавляться к входному аргументу value.
**/
struct Control_component component;
Control_component_init(&component, CreateObjectImpl(INCREMENT_STEP));
/* Инициализируем диспетчер сущности Server. */
struct Server_entity entity;
Server_entity_init(&entity, &component);
fprintf(stderr, "Hello I'm server\n");
/* Реализация цикла обработки запросов. */
do
{
/* Сбрасываем буферы с запросом и ответом. */
nk_req_reset(&req);
nk_arena_reset(&req_arena);
nk_arena_reset(&res_arena);
/* Ожидаем запрос от клиента. */
if (nk_transport_recv(&transport.base, &req.base_, &req_arena) != NK_EOK)
{
fprintf(stderr, "%s nk_transport_recv error\n", Tag);
}
else
{
/**
* Обрабатываем полученный запрос, вызывая реализацию connectionimpl
* запрошенного интерфейсного метода Ping.
*/
Server_entity_dispatch(&entity, &req.base_, &req_arena, &res.base_, &res_arena);
}
/* Отправляем ответ. */
if (nk_transport_reply(&transport.base, &res.base_, &res_arena) != NK_EOK)
{
fprintf(stderr, "%s nk_transport_reply error\n", Tag);
}
} while (true);
return EXIT_SUCCESS;
}
Файлы описаний в примере ping
Описание сущности Client
Сущность Client
не реализует ни одного интерфейса, поэтому в EDL-описании достаточно объявить имя сущности.
Client.edl
/* Описание сущности Client. */
entity ping.Client
Описание сущности Server
Сущность Server
реализует интерфейс Connection
, содержащий два метода – Ping
и Pong
. Как и в примере echo, требуется объявить отдельный компонент (например Control
)
, содержащий реализацию интерфейса Connection
.
В EDL-описании сущности Server
необходимо указать, что она содержит экземпляр компонента Control
:
Server.edl
/* Описание сущности Server. */
entity ping.Server
/* controlimpl - именованный экземпляр компонента ping.Control. */
components {
controlimpl : ping.Control
}
В CDL-описании компонента Control
необходимо указать, что он содержит реализацию интерфейса Connection
:
Control.cdl
/* Описание компонента Control. */
component ping.Control
/* connectionimpl - реализация интерфейса ping.Connection. */
interfaces {
connectionimpl : ping.Connection
}
В пакете Connection
необходимо объявить интерфейс Connection
, содержащий два метода – Ping
и Pong
:
Connection.idl
/* Описание пакета Connection. */
package ping.Connection
interface {
Ping(in UInt32 value, out UInt32 result);
Pong(in UInt32 value, out UInt32 result);
}
Init-описание
Чтобы сущность Client
могла вызвать метод сущности Server
, между ними требуется создать IPC-канал.
init.yaml
entities:
- name: ping.Client
connections:
- target: ping.Server
id: server_connection
- name: ping.Server
Канал имеет имя server_connection
. С помощью локатора сервисов можно получить дескриптор этого канала.
Политика безопасности решения в примере ping
Политика безопасности решения в этом примере разрешает запуск всех сущностей и позволяет любой сущности обращаться к сущностям Core
и Server
. При этом обращениями к сущности Server
управляют методы модели безопасности Flow.
Конечный автомат, описанный в конфигурации объекта request_state
модели безопасности Flow, имеет два состояния: ping_next
и pong_next
. Исходное состояние – ping_next
. Разрешены только переходы из ping_next
в pong_next
и обратно.
При вызове методов Ping
и Pong
проверяется текущее состояние объекта request_state
. В состоянии ping_next
разрешен только вызов Ping
, при этом состояние изменится на pong_next
. Аналогично, в состоянии pong_next
разрешен только вызов Pong
, при этом состояние изменится на ping_next
.
Таким образом, методы Ping
и Pong
разрешено вызывать только по очереди.
security.psl
/* Политика безопасности решения для демонстрации использования модели
* безопасности Flow в примере ping */
/* Включение PSL-файлов с формальными представлениями моделей безопасности
* Base и Flow */
use nk.base._
use nk.flow._
/* Создание объекта модели безопасности Flow */
policy object request_state : Flow {
type States = "ping_next" | "pong_next"
config = {
states : ["ping_next" , "pong_next"],
initial : "ping_next",
transitions : {
"ping_next" : ["pong_next"],
"pong_next" : ["ping_next"]
}
}
}
/* Запуск любых сущностей разрешен. */
execute {
grant ()
}
/* Любые запросы разрешены. */
request {
grant ()
}
/* Любые ответы разрешены. */
response {
grant ()
}
/* Включение EDL-файлов */
use EDL kl.core.Core
use EDL ping.Client
use EDL ping.Server
use EDL Einit
/* При запуске сущности Server инициировать эту сущность с конечным автоматом */
execute dst=ping.Server {
request_state.init {sid: dst_sid}
}
/* При вызове метода Ping проверить, что конечный автомат находится в состоянии ping_next.
Если это так, разрешить вызов метода Ping и перевести конечный автомат в состояние pong_next. */
request dst=ping.Server, endpoint=controlimpl.connectionimpl, method=Ping {
request_state.allow {sid: dst_sid, states: ["ping_next"]}
request_state.enter {sid: dst_sid, state: "pong_next"}
}
/* При вызове метода Pong проверить, что конечный автомат находится в состоянии pong_next.
Если это так, разрешить вызов метода Pong и перевести конечный автомат в состояние ping_next. */
request dst=ping.Server, endpoint=controlimpl.connectionimpl, method=Pong {
request_state.allow {sid: dst_sid, states: ["pong_next"]}
request_state.enter {sid: dst_sid, state: "ping_next"}
}
Тестирование политики безопасности решения на языке Policy Assertion Language (PAL)
Базовый сценарий использования Policy Assertion Language (PAL) – это создание тестовых сценариев для проверки политик безопасности решения, написанных с использованием PSL.
Язык PAL позволяет формировать и отправлять запросы в модуль безопасности, проверяя полученные решения на соответствие ожидаемым решениям. При этом для запуска тестовых сценариев, написанных на PAL, нет необходимости генерировать код клиент-серверных взаимодействий, так как PAL работает на уровне абстракции модуля безопасности.
Общий синтаксис
Тестовый сценарий является последовательностью запросов к модулю безопасности, для каждого из которых указано ожидаемое решение.
Тестовые сценарии можно объединять в группы. Группа сценариев может также содержать секции setup
и finally
, которые будут выполняться соответственно перед и после выполнения каждого сценария в этой группе. Это можно использовать для задания общих стартовых условий или для проверки общих инвариантов.
Для объявления группы тестовых сценариев используется блочная декларация assert
:
assert "имя группы сценариев" {
setup {}
sequence "имя сценария 1" {}
sequence "имя сценария 2" {}
...
finally {}
}
Синтаксис запросов
Для конфигурирования запросов внутри тестовых сценариев используются декларации следующего вида:
<ожидание> <заголовок> <операция> <селекторы события> {сообщение}
Здесь:
<ожидание>
– ожидаемое решение:grant
,deny
илиany
.При ожидании
any
решение модуля безопасности игнорируется, но ошибка при выполнении запроса пометит тестовый сценарий как неудачный.Если ожидаемое решение не указано явно, ожидается решение
grant
.<заголовок>
– опциональный параметр, содержащий текстовый заголовок описываемого запроса.<операция>
– один из видов обращения к модулю безопасности:execute
,security
,request
илиresponse
.<селекторы события>
– допустимые селекторы события совпадают с селекторами, использующимися при привязке методов моделей безопасности к событиям безопасности. Например можно указать сущность-получатель сообщения или вызываемый метод.{сообщение}
– параметр, содержащий значение аргументов вызываемого метода. Значение этого параметра должно соответствовать операции и селекторам запроса. По умолчанию передается пустое количество аргументов{}
.
Пример:
assert "some tests" {
sequence "first sequence" {
// При вызове сущностью Client метода Ping реализации интерфейса pingComp.pingImpl сущности Server ожидается решение grant
// При этом в аргументе value метода Ping передается значение 100
grant "Client calls Ping" request src=Client dst=Server endpoint=pingComp.pingImpl method=Ping {value: 100}
// Ожидается, что сущности Server запрещено отвечать на запросы сущности Client
deny "Server cannot respond" response src=Server dst=Client
}
}
Сокращенная форма запросов
Для удобства можно также применять следующие сокращенные формы запросов:
- При выполнении операции
execute
, можно сохранить дескриптор запускаемой сущности в переменную с помощью оператора<-
. - Сокращенная форма для операции
security
:<сущность> ! <путь.к.методу> {сообщение}
При выполнении разворачивается в полную форму:
security src=<сущность> method=<путь.к.методу> {сообщение}
- Сокращенная форма для операции
request
:<клиент> ~> <сервер> : <путь.к.имплементации.метода> {сообщение}
При выполнении разворачивается в полную форму:
request src=<клиент> dst=<сервер> endpoint=<путь.к.имплементации> method=<метод> {сообщение}
- Сокращенная форма для операции
response
:<клиент> <~ <сервер> : <путь.к.имплементации.метода> {сообщение}
При выполнении разворачивается в полную форму:
response src=<сервер> dst=<клиент> endpoint=<путь.к.имплементации> method=<метод> {сообщение}
Пример:
assert "ping test"{
setup {
// переменная s содержит указатель на запущенный экземпляр сущности Server
s <- execute dst=ping.Server
// переменная c содержит указатель на запущенный экземпляр сущности Client
c <- execute dst=ping.Client
}
sequence "ping ping is denied" {
// При вызове сущностью Client метода Ping реализации интерфейса pingComp.pingImpl сущности Server ожидается решение grant
// При этом в аргументе value метода Ping передается значение 100
c ~> s : pingComp.pingImpl.Ping {value: 100 }
// При повторном вызове ожидается решение deny
deny c ~> s : pingComp.pingImpl.Ping {value: 100 }
}
sequence "normal" {
// При последовательном вызове методов Ping и Pong ожидаются решения grant
c ~> s : pingComp.pingImpl.Ping { value: 100 }
c ~> s : pingComp.pingImpl.Pong { value: 100 }
}
}
Запуск тестов
Чтобы запустить написанные на PAL тестовые сценарии, необходимо использовать флаг --tests run
при запуске компилятора nk-psl-gen-c:
$ nk-psl-gen-c --tests run <другие параметры> ./security.psl
Компилятор nk-psl-gen-c
сгенерирует код модуля безопасности и код тестовых сценариев, а затем скомпилирует их с помощью gcc и запустит.
Чтобы сгенерировать код тестовых сценариев, но не компилировать и запускать их, необходимо использовать флаг --tests generate
.