KasperskyOS Community Edition 1.2

IDL-описание

IDL-описания помещаются в отдельные файлы *.idl и содержат декларации на языке IDL (Interface Definition Language):

  1. Имя пакета. Используется декларация:
    package <имя пакета>
  2. [Опционально] Пакеты, из которых импортируются типы данных для параметров интерфейсных методов. Используется декларация:
    import <имя пакета>
  3. [Опционально] Определения типов данных для параметров интерфейсных методов.
  4. [Опционально] Сигнатуры интерфейсных методов. Используется декларация:
    interface { <имя интерфейсного метода([параметры])>; [...] }

    Каждая сигнатура метода указывается отдельной строкой. Имя метода не может содержать символов подчеркивания _. Каждый метод в списке имеет уникальное имя. Параметры методов разделяются на входные (in), выходные (out) и параметры для передачи сведений об ошибках (error). Порядок описания параметров важен: сначала указываются входные, затем выходные и, далее, error-параметры. Методы интерфейса безопасности не могут иметь выходные и error-параметры.

    Входные и выходные параметры передаются в IPC-запросах и IPC-ответах соответственно. Error-параметры передаются в IPC-ответах, если сервер не может корректно обработать соответствующие IPC-запросы.

    Сервер может информировать клиента об ошибках обработки IPC-запросов как через error-параметры, так и через выходные параметры интерфейсных методов. Если при возникновении ошибки сервер устанавливает флаг ошибки в IPC-ответе, то этот IPC-ответ содержит error-параметры и не содержит выходных параметров. В противном случае этот IPC-ответ содержит выходные параметры так же, как и при корректной обработке запросов. (Для установки флага ошибки в IPC-ответах используется макрос nk_err_reset(), определенный в заголовочном файле nk/types.h из состава KasperskyOS SDK.)

    Отправка IPC-ответа с установленным флагом ошибки и отправка IPC-ответа со снятым флагом ошибки являются разными видами событий для модуля безопасности Kaspersky Security Module. При описании политики безопасности решения это позволяет удобно разделять обработку событий, которые связаны с корректным и некорректным выполнением IPC-запросов. Если сервер не устанавливает флаг ошибки в IPC-ответах, то для обработки событий, связанных с некорректным выполнением IPC-запросов, модулю безопасности требуется проверять значения выходных параметров, которые сигнализируют об ошибках. (Клиент может проверить состояние флага ошибки в IPC-ответе, даже если соответствующий интерфейсный метод не содержит error-параметров. Для этого клиент использует макрос nk_msg_check_err(), определенный в заголовочном файле nk/types.h из состава KasperskyOS SDK.)

    Сигнатуры интерфейсных методов не могут импортироваться из других IDL-файлов.

Язык IDL чувствителен к регистру символов.

В IDL-описании могут использоваться однострочные и многострочные комментарии.

В IDL-описании используется как минимум одна опциональная декларация. Если в IDL-описании не использовать ни одной опциональной декларации, то этому описанию будет соответствовать "пустой" пакет, который не задает ни интерфейсных методов, ни типов данных (в том числе из других IDL-описаний).

Некоторые IDL-файлы из состава KasperskyOS SDK не описывают интерфейсные методы, а только содержат определения типов данных. Такие IDL-файлы используются только как экспортеры типов данных.

Если пакет содержит описание интерфейсных методов, то имя интерфейса соответствует имени пакета.

Примеры IDL-файлов

Env.idl

package kl.Env // Определения типов данных для параметров интерфейсного метода typedef string<128> Name; typedef string<256> Arg; typedef sequence<Arg,256> Args; // Интерфейс включает один метод. interface { Read(in Name name, out Args args, out Args envs); }

Kpm.idl

package kl.Kpm // Импорт типов данных для параметров интерфейсных методов import kl.core.Types // Определение типа данных для параметров интерфейсных методов typedef string<64> String; /* Интерфейс включает несколько методов. * Часть методов не имеет параметров. */ interface { Shutdown(); Reboot(); PowerButtonPressedWait(); TerminationSignalWait(in UInt32 entityId, in String entityName); EntityTerminated(in UInt32 entityId); Terminate(in UInt32 callingEntityId); }

MessageBusSubs.idl

package kl.MessageBusSubs // Импорт типов данных для параметров интерфейсного метода import kl.MessageBusTypes /* Интерфейс включает метод, который имеет * входной и выходные параметры, а также * error-параметр.*/ interface { Wait(in ClientId id, out Message topic, out BundleId dataId, error ResultCode result); }

WaylandTypes.idl

// Пакет содержит только определения типов данных. package kl.WaylandTypes typedef UInt32 ClientId; typedef bytes<8192> Buffer; typedef string<4096> ConnectionId; typedef SInt32 SsizeT; typedef UInt32 SizeT; typedef SInt32 ShmFd; typedef SInt32 ShmId; typedef bytes<16384000> ShmBuffer;

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

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

Целочисленные выражения в языке IDL

В начало
[Topic ice_idl]

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

В языке IDL поддерживаются как примитивные, так и составные типы данных. Набор поддерживаемых составных типов включает объединения, структуры, массивы и последовательности.

Примитивные типы

В языке IDL поддерживаются следующие примитивные типы:

  • SInt8, SInt16, SInt32, SInt64 – знаковое целое число.
  • UInt8, UInt16, UInt32, UInt64 –беззнаковое целое число.
  • Handle – значение, двоичное представление которого состоит из нескольких полей, включая поле дескриптора и поле маски прав дескриптора.
  • bytes<<размер в байтах>> – байтовый буфер, представляющий собой область памяти с размером, не превышающим заданного числа байт.
  • string<<размер в байтах>> – строковый буфер, представляющий собой байтовый буфер, последний байт которого является терминирующим нулем. Максимальный размер строкового буфера на единицу больше заданного из-за наличия дополнительного байта с терминирующим нулем.

Целочисленные литералы можно указывать в десятичном, шестнадцатеричном (например, 0x2f, 0X2f, 0x2F, 0X2F) или восьмеричном (например, 0O123, 0o123) представлении.

С помощью ключевого слова const можно определять именованные целочисленные константы, задавая их значения целочисленными литералами или целочисленными выражениями.

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

const UInt32 DeviceNameMax = 0o100; const UInt32 HandleTypeUserLast = 0x0001FFFF; const UInt32 MaxLogMessageSize = (2 << 3) ** 2; const UInt32 MaxLogMessageCount = 100; const UInt64 MaxLen = (MaxLogMessageSize + 4) * MaxLogMessageCount;

Именованные целочисленные константы можно использовать, чтобы избежать проблемы "магических чисел". К примеру, если в IDL-описании определены именованные целочисленные константы для кодов возврата интерфейсного метода, то при описании политики можно интерпретировать эти коды без дополнительных сведений. Также именованные целочисленные константы и целочисленные выражения могут применяться в определениях байтовых и строковых буферов, а также составных типов, чтобы задать размер данных или число элементов данных.

Конструкции bytes<<размер в байтах>> и string<<размер в байтах>> используются в определениях составных типов, сигнатурах интерфейсных методов и при создании псевдонимов типов, так как сами по себе они определяют анонимные типы (типы без имени).

Объединения

Объединение позволяет хранить данные разных типов в одной области памяти. В IPC-сообщении объединение снабжается дополнительным полем tag, позволяющим определить, какой именно член объединения используется.

Для определения объединения используется следующая конструкция:

union <имя типа> { <тип члена> <имя члена>; [...] }

Пример определения объединения:

union ExitInfo { UInt32 code; ExceptionInfo exc; }

Структуры

Для определения структуры используется следующая конструкция:

struct <имя типа> { <тип поля> <имя поля>; [...] }

Пример определения структуры:

struct SessionEvqParams { UInt32 count; UInt32 align; UInt32 size; }

Массивы

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

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

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

Тип Handle можно использовать в качестве типа элементов массива, если этот массив не входит в другой составной тип данных. При этом суммарное число дескрипторов в IPC-сообщении не может превышать 255.

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

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

Для определения последовательности используется следующая конструкция:

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

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

Тип Handle нельзя использовать в качестве типа элементов последовательности.

Типы переменного и фиксированного размера

Типы bytes, string и sequence являются типами переменного размера, то есть при определении этих типов задается максимальное число элементов, а фактически может использоваться меньше, в том числе ноль. Данные типов bytes, string и sequence хранятся в арене IPC-сообщений. Остальные типы являются типами фиксированного размера. Данные типов фиксированного размера хранятся в фиксированной части IPC-сообщений.

Типы на основе составных типов

На основе составных типов могут быть определены другие составные типы. При этом определение массива или последовательности может быть вложено в определение другого типа.

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

const UInt32 MessageSize = 64; struct BazInfo { array<UInt8, 100> a; sequence<sequence<UInt32, MessageSize>, ((2 << 2) + 2 ** 2) * MessageSize> b; string<100> c; bytes<4096> d; UInt64 e; }

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

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

union foo { UInt32 value1; UInt8 value2; } struct bar { UInt32 a; UInt8 b; } struct BazInfo { foo x; bar y; }

Создание псевдонимов типов

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

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

typedef <имя типа/определение анонимного типа> <псевдоним типа>

Пример создания мнемонических псевдонимов:

typedef UInt64 ApplicationId; typedef Handle PortHandle;

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

typedef array<UInt8, 4> IP4;

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

const UInt32 MaxDevices = 8; struct Device { string<32> DeviceName; UInt8 DeviceID; } typedef sequence<Device, MaxDevices> Devices;

Пример создания псевдонима определению объединения:

union foo { UInt32 value1; UInt8 value2; } typedef foo bar;

Определение анонимных типов в сигнатурах интерфейсных методов

Анонимные типы могут быть определены в сигнатурах интерфейсных методов.

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

const UInt8 DeviceCount = 8; interface { Poll(in UInt32 timeout, out sequence<UInt32, DeviceCount / 2> report, out UInt32 count, out UInt32 rc); }
В начало
[Topic ice_idl_data_types]

Целочисленные выражения в языке IDL

Целочисленные выражения в языке IDL составляются из именованных целочисленных констант, целочисленных литералов, операторов (см. таблицу ниже) и группирующих круглых скобок.

Пример использования целочисленных выражений:

const UInt8 itemHeaderLen = 2; const UInt8 itemBlockLen = 4; const UInt8 maxItemCount = 0X10; const UInt64 maxLen = (2 << 3) + (itemHeaderLen + itemBlockLen * 4) * maxItemCount; interface { CopyPage(in array<UInt8, 4 * maxLen> page); }

Если при вычислении выражения возникнет целочисленное переполнение, генератор исходного кода, использующий IDL-файл, завершит работу с ошибкой.

Сведения об операторах целочисленных выражений в языке IDL

Синтаксис

Операция

Приоритет

Ассоциативность

Особенности

-a

Смена знака

1

Нет

Нет.

~a

Побитовое отрицание

1

Нет

Нет.

a ** b

Возведение в степень

2

Нет

Имеет следующие особенности:

  • Из-за отсутствия ассоциативности нужно использовать скобки при указании нескольких операторов подряд, чтобы задать порядок выполнения операций.

    Пример:

    (a ** b) ** c

    a ** (b ** c)

  • Показатель степени не должен быть отрицательным.

a * b

Умножение

3

Левая

Нет.

a / b

Целочисленное деление

3

Левая

Имеет следующие особенности:

  • Результатом операции является значение, полученное округлением вещественного результата деления до ближайшего меньшего целого. Например, 4 / 3 = 1, -4 / 3 = -2.
  • Делитель не должен быть нулевым.

a % b

Остаток от деления

3

Левая

Имеет следующие особенности:

  • Знак результата операции соответствует знаку делителя. Например, -5 % 2 = 1, 5 % -2 = -1.
  • Делитель не должен быть нулевым.

a + b

Сложение

4

Левая

Нет.

a - b

Вычитание

4

Левая

Нет.

a << b

Битовый сдвиг влево

2*

Нет

Имеет следующие особенности:

  • Приоритет ниже, чем у унарных операций, но несравним с приоритетами бинарных арифметических операций, поэтому в выражениях с бинарными арифметическими операциями нужно использовать скобки, чтобы задать порядок выполнения операций.

    Пример:

    a << (b + c)

    (a << b) ** c

  • Из-за отсутствия ассоциативности нужно использовать скобки при указании нескольких операторов подряд, чтобы задать порядок выполнения операций.

    Пример:

    (a << b) << c

    a << (b << c)

  • Значение сдвига должно быть в промежутке [0; 63].

a >> b

Битовый сдвиг вправо

2*

Нет

Имеет следующие особенности:

  • Приоритет ниже, чем у унарных операций, но несравним с приоритетами бинарных арифметических операций, поэтому в выражениях с бинарными арифметическими операциями нужно использовать скобки, чтобы задать порядок выполнения операций.

    Пример:

    a >> (b * c)

    (a >> b) / c

  • Из-за отсутствия ассоциативности нужно использовать скобки при указании нескольких операторов подряд, чтобы задать порядок выполнения операций.

    Пример:

    (a >> b) >> c

    a >> (b >> c)

  • Значение сдвига должно быть в промежутке [0; 63].

В начало
[Topic ice_idl_int_expres]