Передача дескрипторов

Общие сведения

Передача дескрипторов между программами осуществляется для того, чтобы клиенты (программы, которые используют ресурсы) получали доступ к требуемым ресурсам. По причине локальности дескрипторов передача дескриптора инициирует на стороне принимающей программы создание дескриптора из ее пространства дескрипторов. Этот дескриптор регистрируется как потомок отправленного дескриптора и идентифицирует тот же ресурс.

Один дескриптор может быть передан многократно одной или нескольким программам. Каждая передача порождает нового потомка переданного дескриптора на стороне принимающей программы. Программа может передавать дескрипторы, которые она получила от других программ или ядра KasperskyOS (при создании дескрипторов системных ресурсов). Поэтому у дескриптора может быть несколько поколений потомков. Иерархия порождения дескрипторов для каждого ресурса хранится в ядре KasperskyOS в виде дерева наследования дескрипторов.

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

Условия для передачи дескрипторов

Чтобы программы могли передавать дескрипторы между собой, должны выполняться следующие условия:

  1. Между программами создан IPC-канал.
  2. Политика безопасности решения (security.psl) разрешает взаимодействие программ.
  3. Реализованы интерфейсные методы для передачи дескрипторов.
  4. Программа-клиент получила идентификатор службы (RIID) программы-сервера с методами для передачи дескрипторов.

Интерфейсные методы для передачи дескрипторов объявляются в IDL-описании с входными (in) и/или выходными (out) параметрами типа Handle. Методы с входными параметрами типа Handle предназначены для передачи дескрипторов от программы-клиента программе-серверу. Методы с выходными параметрами типа Handle предназначены для передачи дескрипторов от программы-сервера программе-клиенту. Для одного метода может быть объявлено не более семи входных и семи выходных параметров типа Handle.

Пример IDL-описания, где объявлены интерфейсные методы для передачи дескрипторов:

package IpcTransfer

interface {

PublishResource1(in Handle handle, out UInt32 result);

PublishResource7(in Handle handle1, in Handle handle2,

in Handle handle3, in Handle handle4,

in Handle handle5, in Handle handle6,

in Handle handle7, out UInt32 result);

OpenResource(in UInt32 ID, out Handle handle);

}

Для каждого параметра типа Handle компилятор NK генерирует в структурах запросов *_req и/или ответов *_res поле типа nk_handle_desc_t (далее также транспортный контейнер дескриптора). Этот тип объявлен в заголовочном файле nk/types.h и представляет собой структуру, состоящую из трех полей: поля дескриптора handle, поля маски прав дескриптора rights и поля контекста передачи ресурса badge.

Контекст передачи ресурса

Контекст передачи ресурса – данные, позволяющие программе-серверу идентифицировать ресурс и его состояние, когда запрашивается доступ к ресурсу через потомков переданного дескриптора. В общем случае это набор разнотипных данных (структура). Например, для файла контекст передачи может включать имя, путь, положение курсора. Программа-сервер получает указатель на контекст передачи ресурса при разыменовании дескриптора.

Программа-сервер независимо от того, является ли она поставщиком ресурса или нет, может ассоциировать каждую передачу дескриптора с отдельным контекстом передачи ресурса. Этот контекст передачи ресурса связывается только с теми потомками дескриптора (поддеревом наследования дескриптора), которые порождены в результате конкретной его передачи. Это позволяет определять состояние ресурса по отношению к отдельной передаче дескриптора этого ресурса. Например, в случае множественного доступа к одному файлу контекст передачи файла позволяет определить, какому именно открытию этого файла соответствует полученный запрос.

Если программа-сервер является поставщиком ресурса, то по умолчанию каждая передача дескриптора этого ресурса ассоциируется с контекстом пользовательского ресурса. То есть контекст пользовательского ресурса используется в качестве контекста передачи ресурса для каждой передачи дескриптора, если эта передача не ассоциируется с отдельным контекстом передачи ресурса.

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

Если программа-клиент использует несколько разнотипных ресурсов программы-сервера, контексты передачи ресурсов (или контексты пользовательских ресурсов, если они используются в качестве контекстов передачи ресурсов) должны быть типизированными объектами KosObject. Это нужно, чтобы программа-сервер могла проверить, что программа-клиент при использовании ресурса передала в интерфейсный метод дескриптор того ресурса, который соответствует этому методу. Такая проверка требуется, поскольку программа-клиент может ошибочно передать в интерфейсный метод дескриптор ресурса, который не соответствует этому методу. Например, программа-клиент получила дескриптор файла и передала его в интерфейсный метод для работы с томами.

Чтобы ассоциировать передачу дескриптора с контекстом передачи ресурса, программа-сервер помещает в поле badge структуры nk_handle_desc_t дескриптор объекта контекста передачи ресурса. Объект контекста передачи ресурса – объект, в котором хранится указатель на контекст передачи ресурса. Объект контекста передачи ресурса создается функцией KnHandleCreateBadge(), которая объявлена в заголовочном файле coresrv/handle/handle_api.h. Работа этой функции связана с подсистемой уведомлений о состоянии ресурсов, так как программе-серверу нужно знать, когда объект контекста передачи ресурса будет закрыт и прекратит свое существование. Эти сведения требуются программе-серверу, чтобы освободить или использовать повторно память, которая отведена для хранения контекста передачи ресурса.

Объект контекста передачи ресурса будет закрыт, когда будут удалены или отозваны потомки дескриптора (см. "Удаление дескрипторов", "Отзыв дескрипторов"), которые порождены его передачей в ассоциации с этим объектом. (Переданный дескриптор может быть удален не только целенаправленно, но и, например, при неожиданном завершении работы принимающей программы-клиента.) Получив уведомление о закрытии объекта контекста передачи ресурса, программа-сервер удаляет дескриптор этого объекта. После этого объект контекста передачи ресурса прекращает свое существование. Получив уведомление, что объект контекста передачи ресурса прекратил свое существование, программа-сервер освобождает или использует повторно память, которая отведена для хранения контекста передачи ресурса.

Один объект контекста передачи ресурса может быть ассоциирован только с одной передачей дескриптора.

handle_api.h (фрагмент)

/**

* Функция создает объект контекста передачи ресурса для

* контекста передачи ресурса context и настраивает

* приемник уведомлений notice на прием уведомлений об

* этом объекте. Приемник уведомлений настраивается на

* прием уведомлений о событиях, которые соответствуют

* флагам маски событий OBJECT_DESTROYED и EVENT_BADGE_CLOSED.

* Входной параметр eventId задает идентификатор записи

* вида "ресурс – маска событий" в приемнике уведомлений.

* Выходной параметр handle содержит дескриптор объекта

* контекста передачи ресурса.

* В случае успеха функция возвращает rcOk, иначе возвращает код ошибки.

*/

Retcode KnHandleCreateBadge(Notice notice, rtl_uintptr_t eventId,

void *context, Handle *handle);

Упаковка данных в транспортный контейнер дескриптора

Для упаковки дескриптора, маски прав дескриптора и дескриптора объекта контекста передачи ресурса в транспортный контейнер дескриптора используется макрос nk_handle_desc(), который определен в заголовочном файле nk/types.h. Этот макрос принимает переменное число аргументов.

Если не передавать макросу ни одного аргумента, то в поле дескриптора handle структуры nk_handle_desc_t будет записано значение NK_INVALID_HANDLE.

Если передать макросу один аргумент, то этот аргумент интерпретируется как дескриптор.

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

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

Извлечение данных из транспортного контейнера дескриптора

Для извлечения дескриптора, маски прав дескриптора и указателя на контекст передачи ресурса из транспортного контейнера дескриптора используются соответственно функции nk_get_handle(), nk_get_rights() и nk_get_badge_op() (или nk_get_badge()), которые определены в заголовочном файле nk/types.h. Функции nk_get_badge_op() и nk_get_badge() используются только при разыменовании дескрипторов.

Сценарии передачи дескрипторов

Сценарий передачи дескрипторов от программы-клиента программе-серверу включает следующие шаги:

  1. Передающая программа-клиент упаковывает дескрипторы и маски прав дескрипторов в поля структуры запросов *_req типа nk_handle_desc_t.
  2. Передающая программа-клиент вызывает интерфейсный метод для передачи дескрипторов программе-серверу. Этот метод выполняет системный вызов Call().
  3. Принимающая программа-сервер получает запрос, выполняя системный вызов Recv().
  4. Диспетчер на стороне принимающей программы-сервера вызывает метод, который соответствует запросу. Этот метод извлекает дескрипторы и маски прав дескрипторов из полей структуры запросов *_req типа nk_handle_desc_t.

Сценарий передачи дескрипторов от программы-сервера программе-клиенту включает следующие шаги:

  1. Принимающая программа-клиент вызывает интерфейсный метод для получения дескрипторов от программы-сервера. Этот метод выполняет системный вызов Call().
  2. Передающая программа-сервер получает запрос, выполняя системный вызов Recv().
  3. Диспетчер на стороне передающей программы-сервера вызывает метод, который соответствует запросу. Этот метод упаковывает дескрипторы, маски прав дескрипторов и дескрипторы объектов контекстов передачи ресурсов в поля структуры ответов *_res типа nk_handle_desc_t.
  4. Передающая программа-сервер отвечает на запрос, выполняя системный вызов Reply().
  5. На стороне принимающей программы-клиента интерфейсный метод возвращает управление. После этого принимающая программа-клиент извлекает дескрипторы и маски прав дескрипторов из полей структуры ответов *_res типа nk_handle_desc_t.

Если передающая программа задает в передаваемой маске прав дескриптора больше прав доступа, чем задано для передаваемого дескриптора (владельцем которого она является), то передача не осуществляется. В этом случае выполнение системного вызова Call() передающей или принимающей программой-клиентом, а также выполнение системного вызова Reply() передающей программой-сервером завершается с ошибкой rcSecurityDisallow.

В начало