KasperskyOS Community Edition 1.0

Содержание

Часть 3. Политика безопасности решения

В предыдущих частях руководства показано, как реализовать взаимодействие между сущностями. При этом для простоты все решения собирались без модуля безопасности (ksm.module), которым представлена подсистема Kaspersky Security System.

Между тем, именно подсистема Kaspersky Security System контролирует обращения сущностей друг к другу и другие события. Это значит, что решение можно разделить на сущности, управлять их взаимодействиями и, как следствие, повысить безопасность решения.

В этой части руководства рассматриваются:;

  • синтаксис языка PSL;
  • модели безопасности, поддерживаемые в Kaspersky Security System;
  • пример политики безопасности решения.

В этом разделе справки

Общие сведения об описании политики безопасности решения

Синтаксис языка PSL

Модели безопасности

Пример ping

Тестирование политики безопасности решения на языке Policy Assertion Language (PAL)

В начало

Общие сведения об описании политики безопасности решения

В упрощенном представлении описание политики безопасности решения состоит из привязок, которые ассоциируют описания событий безопасности с вызовами методов, предоставляемых объектами моделей безопасности. Объект модели безопасности – это экземпляр класса, определение которого является формальным представлением модели безопасности (в 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

Базовые правила

  1. Декларации могут располагаться в файле в любом порядке.
  2. Одна декларация может быть записана в одну или несколько строк. Вторая и последующие строки декларации должны быть записаны с отступами относительно первой строки. Закрывающая фигурная скобка, которая завершает декларацию, может быть записана на уровне первой строки.
  3. В многострочной декларации используются отступы разных размеров, чтобы отразить вложенность конструкций, составляющих эту декларацию. Строки многострочной конструкции, заключенные в фигурные скобки, и открывающая фигурная скобка должны быть записаны с отступом относительно первой строки этой конструкции. Закрывающая фигурная скобка многострочной конструкции может быть записана с отступом или на уровне первой строки конструкции.
  4. Поддерживаются однострочные и многострочные комментарии:

    /* Это комментарий

    И это тоже */

    // Ещё один комментарий

Типы деклараций

В языке PSL есть следующие типы деклараций:

  • описание глобальных параметров политики безопасности решения;
  • включение PSL-файлов;
  • включение EDL-файлов;
  • создание объектов моделей безопасности;
  • привязка методов моделей безопасности к событиям безопасности;
  • описание профилей аудита безопасности.

В этом разделе

Описание глобальных параметров политики безопасности решения

Включение PSL-файлов

Включение EDL-файлов

Создание объектов моделей безопасности

Привязка методов моделей безопасности к событиям безопасности

Описание профилей аудита безопасности

Типы данных в языке PSL

Пример простейшей политики безопасности решения

В начало

Описание глобальных параметров политики безопасности решения

Глобальными являются следующие параметры политики безопасности решения:

  • 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

Обозначения типов

Описание типов

UInt8, UInt16, UInt32, UInt64

Беззнаковое целое число

SInt8, SInt16, SInt32, SInt64

Знаковое целое число

Boolean

Логический тип

Логический тип включает два значения: true и false.

Text

Текстовый тип

()

Тип Unit

Тип Unit включает одно неизменяемое значение. Используется как заглушка в случаях, когда синтаксис языка PSL требует указать какие-либо данные, но фактически эти данные не требуются. Например, тип Unit можно использовать, чтобы объявить метод, который не имеет параметров (аналогично тому, как тип void используется в C/C++).

"<тип>"

Текстовый литерал

Текстовый литерал включает одно неизменяемое текстовое значение.

Примеры определений текстовых литералов:

""

"granted"

<тип>

Целочисленный литерал

Целочисленный литерал включает одно неизменяемое целочисленное значение.

Примеры определений числовых литералов:

12

-5

0xFFFF

<тип 1 | тип 2> [|]...

Вариантный тип

Вариантный тип объединяет два и более типов и может выступать в роли любого из них.

Примеры определений вариантных типов:

Boolean | ()

UInt8 | UInt16 | UInt32 | UInt64

"granted" | "denied"

{ [имя поля : тип поля]

[,] ...

...

}

Словарь

Словарь состоит из полей одного или нескольких типов. Словарь может быть пустым.

Примеры определений словарей:

{}

{ handle : Handle

, rights : UInt32

}

[[тип] [,] ...]

Кортеж

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

Примеры определений кортежей:

[]

["granted"]

[Boolean, Boolean]

Set<<тип элементов>>

Множество

Множество включает ноль и более уникальных элементов одного типа.

Примеры определений множеств:

Set<"granted" | "denied">

Set<Text>

List<<тип элементов>>

Список

Список включает ноль и более элементов одного типа.

Примеры определений списков:

List<Boolean>

List<Text | ()>

Map<<тип ключа, тип значения>>

Ассоциативный массив

Ассоциативный массив включает ноль и более записей типа "ключ-значение" с уникальными ключами.

Пример определения ассоциативного массива:

Map<UInt32, UInt32>

Array<<тип элементов, число элементов>>

Массив

Массив включает заданное число элементов одного типа.

Пример определения массива:

Array<UInt8, 42>

Sequence<<тип элементов, число элементов>>

Последовательность

Последовательность включает от ноля до заданного числа элементов одного типа.

Пример определения последовательности:

Sequence<SInt64, 58>

Псевдонимы некоторых типов PSL

В файле nk/base.psl из состава KasperskyOS SDK определены типы данных, которые используются как типы параметров (или структурных элементов параметров) и возвращаемых значений для методов разных моделей безопасности. Псевдонимы и определения этих типов приведены в таблице ниже.

Псевдонимы и определения некоторых типов данных в языке PSL

Псевдоним типа

Определение типа

Unsigned

Беззнаковое целое число

UInt8 | UInt16 | UInt32 | UInt64

Signed

Знаковое целое число

SInt8 | SInt16 | SInt32 | SInt64

Number

Целое число

Unsigned | Signed

ScalarLiteral

Скалярный литерал

() | Boolean | Number

Literal

Литерал

ScalarLiteral | Text

Sid

Тип идентификатора безопасности SID

UInt32

Handle

Тип идентификатора безопасности SID

Sid

HandleDesc

Словарь, содержащий поля для SID и маски прав дескриптора

{ handle : Handle

, rights : UInt32

}

Cases

Тип данных, принимаемых выражениями моделей безопасности, вызываемыми в конструкции choice для проверки выполнения условий

List<Text | ()>

KSSAudit

Тип данных, задающих условия выполнения аудита безопасности

Set<"granted" | "denied">

Отображение типов 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

Правило init модели безопасности HashSet

Правило fini модели безопасности HashSet

Правило add модели безопасности HashSet

Правило remove модели безопасности HashSet

Выражение contains модели безопасности HashSet

В начало

Объект модели безопасности 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

Правило init модели безопасности StaticMap

Правило fini модели безопасности StaticMap

Правило set модели безопасности StaticMap

Правило commit модели безопасности StaticMap

Правило rollback модели безопасности StaticMap

Выражение get модели безопасности StaticMap

Выражение get_uncommited модели безопасности StaticMap

В начало

Объект модели безопасности 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

Правило init модели безопасности Flow

Правило fini модели безопасности Flow

Правило enter модели безопасности Flow

Правило allow модели безопасности Flow

Выражение query модели безопасности Flow

В начало

Объект модели безопасности 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"]

}

}

}

finite_state_machine_example

Диаграмма состояний конечного автомата в примере

Объект модели безопасности 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

Реализация сущности Client в примере ping

Реализация сущности Server в примере ping

Файлы описаний в примере ping

Политика безопасности решения в примере 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

#include <stdio.h>

#include <stdlib.h>

#include <stdint.h>

/* Файлы, необходимые для инициализации транспорта. */

#include <coresrv/nk/transport-kos.h>

#include <coresrv/sl/sl_api.h>

/* Описание интерфейса сервера, по которому обращается клиентская сущность. */

#include <ping/Connection.idl.h>

#define EXAMPLE_VALUE_TO_SEND 777

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

#include <stdio.h>

#include <stdlib.h>

#include <stdbool.h>

/* Файлы, необходимые для инициализации транспорта. */

#include <coresrv/nk/transport-kos.h>

#include <coresrv/sl/sl_api.h>

/* Описания сущности-сервера на языках EDL, CDL, IDL. */

#include <ping/Connection.idl.h>

#include <ping/Control.cdl.h>

#include <ping/Server.edl.h>

#define INCREMENT_STEP 3

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"}

}

В начало

Сборка и запуск примера ping

См. "Сборка и запуск примеров".

В начало

Тестирование политики безопасности решения на языке 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.

В начало