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

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

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

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

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

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

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

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

API task.h позволяет родительскому процессу передавать дескрипторы дочернему процессу, который еще не запущен.

В IDL-описании сигнатуры интерфейсных методов для передачи дескрипторов имеют входные (in) и/или выходные (out) параметры типа Handle или array с элементами типа Handle. Через входные параметры одного метода можно передать до 255 дескрипторов. Столько же дескрипторов можно получить через выходные параметры.

Пример 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 генерирует в структурах IPC-запросов *_req и/или IPC-ответов *_res поле типа nk_handle_desc_t (далее также транспортный контейнер дескриптора). Этот тип объявлен в заголовочном файле sysroot-*-kos/include/nk/types.h из состава KasperskyOS SDK и представляет собой структуру, состоящую из трех полей: поля дескриптора handle, поля маски прав дескриптора rights и поля контекста передачи ресурса badge.

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

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

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

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

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

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

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

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

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

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

Чтобы упаковать дескриптор, маску прав дескриптора и дескриптор объекта контекста передачи ресурса в транспортный контейнер дескриптора, нужно использовать макрос nk_handle_desc(), который определен в заголовочном файле sysroot-*-kos/include/nk/types.h из состава KasperskyOS SDK. Этот макрос принимает переменное число параметров.

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

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

Чтобы извлечь дескриптор, маску прав дескриптора и указатель на контекст передачи ресурса из транспортного контейнера дескриптора, нужно использовать соответственно функции nk_get_handle(), nk_get_rights() и nk_get_badge_op() (или nk_get_badge()), которые определены в заголовочном файле sysroot-*-kos/include/nk/types.h из состава KasperskyOS SDK. Функции nk_get_badge_op() и nk_get_badge() нужно использовать только при разыменовании дескрипторов.

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

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

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

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

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

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

Сведения о функциях API

Функции handle_api.h

Функция

Сведения о функции

KnHandleCreateBadge()

Назначение

Создает объект контекста передачи ресурса и настраивает механизм уведомлений для контроля жизненного цикла этого объекта.

Параметры

  • [in] notice – идентификатор приемника уведомлений.
  • [in] eventId – идентификатор записи вида "ресурс – маска событий" в приемнике уведомлений.
  • [in,optional] context – указатель на данные, которые нужно ассоциировать с передачей дескриптора, или RTL_NULL, если эта ассоциация не требуется.
  • [out] handle – указатель на дескриптор объекта контекста передачи ресурса.

Возвращаемые значения

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

Дополнительные сведения

Приемник уведомлений настраивается на получение уведомлений о событиях, которые соответствуют флагам маски событий EVENT_OBJECT_DESTROYED и EVENT_BADGE_CLOSED.

В начало