KasperskyOS Community Edition 1.2

Управление дескрипторами (handle_api.h)

API определен в заголовочном файле sysroot-*-kos/include/coresrv/handle/handle_api.h из состава KasperskyOS SDK.

API предназначен для выполнения операций с дескрипторами. Дескрипторы имеют тип Handle, который определен в заголовочном файле sysroot-*-kos/include/handle/handletype.h из состава KasperskyOS SDK.

Локальность дескрипторов

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

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

Маска прав дескриптора

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

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

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

Разыменование дескрипторов

Отзыв дескрипторов

Закрытие дескрипторов

Получение идентификатора безопасности (SID)

Пример использования OCap

В начало
[Topic handles_manage]

Маска прав дескриптора

Маска прав дескриптора имеет размер 32 бита и состоит из общей и специальной части. Общая часть описывает права, неспецифичные для любых ресурсов (флаги этих прав определены в заголовочном файле sysroot-*-kos/include/services/ocap.h из состава KasperskyOS SDK). Например, в общей части находится флаг OCAP_HANDLE_TRANSFER, который определяет право на передачу дескриптора. Специальная часть описывает права, специфичные для пользовательского или системного ресурса. Флаги прав специальной части для системных ресурсов определены в заголовочном файле ocap.h. Структура специальной части для пользовательских ресурсов определяется поставщиком ресурсов с использованием макроса OCAP_HANDLE_SPEC(), который определен в заголовочном файле ocap.h. Поставщику ресурсов необходимо экспортировать публичные заголовочные файлы с описанием флагов специальной части.

При создании дескриптора системного ресурса маска прав задается ядром KasperskyOS, которое применяет маски прав из заголовочного файла ocap.h. Применяются маски прав с именами вида OCAP_*_FULL (например, OCAP_IOPORT_FULL, OCAP_TASK_FULL, OCAP_FILE_FULL) и вида OCAP_IPC_* (например, OCAP_IPC_SERVER, OCAP_IPC_LISTENER, OCAP_IPC_CLIENT).

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

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

В начало
[Topic libkos_handles_rights]

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

Создание дескрипторов системных ресурсов

Дескрипторы системных ресурсов создаются при создании этих ресурсов, например, при регистрации прерывания или региона памяти MMIO, создании буфера DMA, потока исполнения или процесса.

Создание дескрипторов пользовательских ресурсов

Дескрипторы пользовательских ресурсов создаются поставщиками ресурсов с использованием функции KnHandleCreateUserObject() или KnHandleCreateUserObjectEx().

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

Через параметр rights нужно задать маску прав дескриптора.

Создание IPC-дескрипторов

IPC-дескриптор (англ. IPC handle) – это дескриптор, который идентифицирует IPC-канал. IPC-дескрипторы используются для выполнения системных вызовов. Клиентский IPC-дескриптор нужен для выполнения системного вызова Call(). Серверный IPC-дескриптор требуется для выполнения системных вызовов Recv() и Reply(). Серверный IPC-дескриптор, который имеет расширенные права, позволяющие добавлять IPC-каналы в набор идентифицируемых этим дескриптором IPC-каналов, называется слушающим дескриптором (англ. listener handle). Клиентский IPC-дескриптор, который идентифицирует одновременно IPC-канал до сервера и службу этого сервера, называется callable-дескриптором (англ. callable handle).

Сервер создает callable-дескриптор и передает его клиенту, чтобы клиент мог использовать службу сервера. Клиент инициализирует IPC-транспорт, используя полученный callable-дескриптор. При этом в функции инициализации прокси-объекта клиент указывает значение INVALID_RIID в качестве идентификатор службы (RIID). Чтобы создать callable-дескриптор, нужно вызвать функцию KnHandleCreateUserObjectEx(), указав в параметрах ipcChannel и riid серверный IPC-дескриптор и идентификатор службы (RIID) соответственно. Через параметр context можно задать данные для ассоциации с callable-дескриптором. Сервер сможет получить указатель на эти данные при разыменовании callable-дескриптора. (Несмотря на то что callable-дескриптор является IPC-дескриптором, он помещается ядром в поле base_.self фиксированной части IPC-запроса.)

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

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

Чтобы создать слушающий дескриптор, не связанный с клиентским и серверным IPC-дескрипторами, нужно вызвать функцию KnHandleCreateListener(). (Функции KnHandleConnect() и KnHandleConnectEx() создают слушающий дескриптор, связанный с клиентским и серверным IPC-дескрипторами.) Функцию KnHandleCreateListener() удобно использовать, чтобы создать слушающий дескриптор, с которым впоследствии будут связаны callable-дескрипторы.

Чтобы создать клиентский IPC-дескриптор для обращения к модулю безопасности Kaspersky Security Module через интерфейс безопасности, нужно вызвать функцию KnHandleSecurityConnect(). Эта функция вызывается библиотекой libkos при инициализации IPC-транспорта для обращения к модулю безопасности.

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

Функции handle_api.h

Функция

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

KnHandleCreateUserObject()

Назначение

Создает дескриптор.

Параметры

  • [in] type – тип дескриптора. Фиктивный параметр, который должен принимать значение от константы HANDLE_TYPE_USER_FIRST до константы HANDLE_TYPE_USER_LAST, определенных в заголовочном файле sysroot-*-kos/include/handle/handletype.h из состава KasperskyOS SDK.
  • [in] rights – маска прав дескриптора.
  • [in,optional] context – указатель на данные, которые нужно ассоциировать с дескриптором, или RTL_NULL, если эта ассоциация не требуется.
  • [out] handle – указатель на дескриптор.

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

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

KnHandleCreateUserObjectEx()

Назначение

Создает дескриптор.

Параметры

  • [in] type – тип дескриптора. Фиктивный параметр, который должен принимать значение от константы HANDLE_TYPE_USER_FIRST до константы HANDLE_TYPE_USER_LAST, определенных в заголовочном файле sysroot-*-kos/include/handle/handletype.h из состава KasperskyOS SDK.
  • [in] rights – маска прав дескриптора.
  • [in,optional] context – указатель на данные, которые нужно ассоциировать с дескриптором, или RTL_NULL, если эта ассоциация не требуется.
  • [in,optional] ipcChannel – серверный IPC-дескриптор или INVALID_HANDLE, если не требуется создавать callable-дескриптор.
  • [in,optional] riid – идентификатор службы (RIID) или INVALID_RIID, если не требуется создавать callable-дескриптор.
  • [out] handle – указатель на дескриптор.

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

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

KnHandleConnect()

Назначение

Создает и связывает между собой клиентский, серверный и слушающий IPC-дескрипторы.

Параметры

  • [in,optional] ls – слушающий дескриптор или INVALID_HANDLE, чтобы создать его.
  • [out,optional] outLs – указатель на слушающий дескриптор. Можно указать RTL_NULL, если через параметр ls задан слушающий дескриптор.
  • [out,optional] outSr – указатель на серверный IPC-дескриптор или RTL_NULL, чтобы не создавать серверный IPC-дескриптор, если через параметр ls задан слушающий дескриптор.
  • [out] outCl – указатель на клиентский IPC-дескриптор.

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

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

KnHandleConnectEx()

Назначение

Создает и связывает между собой клиентский, серверный и слушающий IPC-дескрипторы.

Параметры

  • [in] server – дескриптор серверного процесса.
  • [in,optional] srListener – слушающий дескриптор из пространства дескрипторов серверного процесса или INVALID_HANDLE, чтобы создать его.
  • [in] client – дескриптор клиентского процесса.
  • [out,optional] outSrListener – указатель на слушающий дескриптор из пространства дескрипторов серверного процесса. Можно указать RTL_NULL, если через параметр srListener задан слушающий дескриптор.
  • [out,optional] outSrEndpoint – указатель на серверный IPC-дескриптор из пространства дескрипторов серверного процесса или RTL_NULL, чтобы не создавать серверный IPC-дескриптор, если через параметр srListener задан слушающий дескриптор.
  • [out] outClEndpoint – указатель на клиентский IPC-дескриптор из пространства дескрипторов клиентского процесса.

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

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

KnHandleSecurityConnect()

Назначение

Создает клиентский IPC-дескриптор для обращения к модулю безопасности Kaspersky Security Module через интерфейс безопасности.

Параметры

  • [out] client – указатель на дескриптор.

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

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

KnHandleCreateListener()

Назначение

Создает слушающий дескриптор, не связанный с клиентским и серверным IPC-дескрипторами.

Параметры

  • [out] listener – указатель на слушающий дескриптор.

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

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

В начало
[Topic libkos_handles_create]

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

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

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

Один дескриптор может быть передан многократно одному или нескольким процессам. Каждая передача порождает нового потомка переданного дескриптора на стороне принимающего процесса. Процесс может передавать дескрипторы, которые он получил от других процессов или ядра 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.

В начало
[Topic libkos_handles_transfer]

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

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

Чтобы выполнить копирование дескриптора, нужно вызвать функцию KnHandleCopy(). При этом в маске прав дескриптора должен быть установлен флаг OCAP_HANDLE_COPY.

Сведения о функциях API приведены в таблице ниже.

Функции handle_api.h

Функция

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

KnHandleCopy()

Назначение

Копирует дескриптор.

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

Параметры

  • [in] inHandle – оригинальный дескриптор.
  • [in] newRightsMask – маска прав потомка дескриптора.
  • [in,optional] copyBadge – дескриптор объекта контекста передачи ресурса или INVALID_HANDLE, если не требуется ассоциировать копирование дескриптора с этим объектом.
  • [out] outHandle – указатель на потомка дескриптора.

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

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

В начало
[Topic libkos_handle_copy]

Разыменование дескрипторов

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

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

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

Для выполнения проверок сервер использует функции nk_is_handle_dereferenced() и nk_get_badge_op(), которые объявлены в заголовочном файле sysroot-*-kos/include/nk/types.h из состава KasperskyOS SDK.

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

/** * Функция возвращает отличное от нуля значение, если * дескриптор в транспортном контейнере дескриптора * desc получен в результате операции разыменования * дескриптора. Функция возвращает нуль, если дескриптор * в транспортном контейнере дескриптора desc получен * в результате операции передачи дескриптора. */ static inline nk_bool_t nk_is_handle_dereferenced(const nk_handle_desc_t *desc) /** * Функция извлекает указатель на контекст передачи ресурса * badge из транспортного контейнера дескриптора desc, * если в маске прав, которая помещена в транспортном * контейнере дескриптора desc, установлены флаги operation. * В случае успеха функция возвращает NK_EOK, иначе возвращает код ошибки. */ static inline nk_err_t nk_get_badge_op(const nk_handle_desc_t *desc, nk_rights_t operation, nk_badge_t *badge)

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

В начало
[Topic libkos_handles_dereference]

Отзыв дескрипторов

Процесс может отозвать потомков дескриптора, которым он владеет. Отзыв дескрипторов осуществляется на основе дерева наследования дескрипторов.

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

Чтобы отозвать потомков дескриптора, нужно вызвать функцию KnHandleRevoke() или KnHandleRevokeSubtree(). Функция KnHandleRevokeSubtree() использует объект контекста передачи ресурса, который создается при передаче дескрипторов.

Если каждый из дескрипторов системного ресурса во всех процессах, которые владеют этими дескрипторами, будет закрыт (см. "Закрытие дескрипторов") или отозван, то этот системный ресурс будет удален.

Сведения о функциях API приведены в таблице ниже.

Функции handle_api.h

Функция

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

KnHandleRevoke()

Назначение

Закрывает дескриптор и отзывает его потомков.

Параметры

  • [in] handle – дескриптор.

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

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

KnHandleRevokeSubtree()

Назначение

Отзывает дескрипторы, которые образуют поддерево наследования заданного дескриптора.

Параметры

  • [in] handle – дескриптор. Дескрипторы, образующие поддерево наследования этого дескриптора, отзываются.
  • [in] badge – дескриптор, идентифицирующий объект контекста передачи ресурса, который определяет поддерево наследования дескрипторов для отзыва. Корневым узлом этого поддерева является дескриптор, который порожден передачей или копированием дескриптора, заданного через параметр handle, в ассоциации с объектом контекста передачи ресурса.

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

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

В начало
[Topic libkos_handles_revoke]

Закрытие дескрипторов

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

Чтобы закрыть дескриптор, нужно вызвать функцию KnHandleClose().

Если каждый из дескрипторов системного ресурса во всех процессах, которые владеют этими дескрипторами, будет отозван (см. "Отзыв дескрипторов") или закрыт, то этот системный ресурс будет удален.

Сведения о функциях API приведены в таблице ниже.

Функции handle_api.h

Функция

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

KnHandleClose()

Назначение

Закрывает дескриптор.

Параметры

  • [in] handle – дескриптор.

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

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

В начало
[Topic libkos_handles_delete]

Получение идентификатора безопасности (SID)

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

Чтобы получить идентификатор безопасности по дескриптору, нужно вызвать функцию KnHandleGetSidByHandle(). При этом в маске прав дескриптора должен быть установлен флаг OCAP_HANDLE_GET_SID.

Сведения о функциях API приведены в таблице ниже.

Функции handle_api.h

Функция

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

KnHandleGetSidByHandle()

Назначение

Позволяет получить идентификатор безопасности (SID) по дескриптору.

Параметры

  • [in] handle – дескриптор.
  • [out] sid – указатель на идентификатор безопасности (SID).

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

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

В начало
[Topic libkos_handle_get_sid]

Пример использования OCap

В этом примере приведен сценарий использования OCap, в котором поставщик ресурсов предоставляет следующие методы доступа к своим ресурсам:

  • OpenResource() – открытие доступа к ресурсу;
  • UseResource() – использование ресурса;
  • CloseResource() – закрытие доступа к ресурсу.

Потребитель ресурсов использует эти методы.

IDL-описание:

package SimpleOCap interface { OpenResource(in UInt32 ID, out Handle handle); UseResource(in Handle handle, in UInt8 param, out UInt8 result); CloseResource(in Handle handle); }

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

  1. Поставщик ресурсов создает контекст пользовательского ресурса и вызывает функцию KnHandleCreateUserObject() для создания дескриптора ресурса. Поставщик ресурсов сохраняет дескриптор ресурса в контексте пользовательского ресурса.
  2. Потребитель ресурсов вызывает метод открытия доступа к ресурсу OpenResource().
    1. Поставщик ресурсов создает контекст передачи ресурса и вызывает функцию KnHandleCreateBadge() для создания объекта контекста передачи ресурса и настройки приемника уведомлений на получение уведомлений о закрытии и удалении объекта контекста передачи ресурса. Поставщик ресурсов сохраняет дескриптор объекта контекста передачи ресурса и указатель на контекст пользовательского ресурса в контексте передачи ресурса.
    2. Поставщик ресурсов, используя макрос nk_handle_desc(), упаковывает дескриптор ресурса, маску прав дескриптора и указатель на объект контекста передачи ресурса в транспортный контейнер дескриптора.
    3. Выполняется передача дескриптора от поставщика ресурсов к потребителю ресурсов, в результате которой потребитель ресурсов получает потомка дескриптора, которым владеет поставщик ресурсов.
    4. Вызов метода OpenResource() завершается успешно. Потребитель ресурсов извлекает дескриптор и маску прав дескриптора из транспортного контейнера дескриптора функциями nk_get_handle() и nk_get_rights() соответственно. Маска прав дескриптора не требуется потребителю ресурсов для обращения к ресурсу и передается, чтобы потребитель ресурсов мог узнать свои права доступа к ресурсу.
  3. Потребитель ресурсов вызывает метод использования ресурса UseResource().
    1. Дескриптор, который получен от поставщика ресурсов на шаге 2, используется в качестве параметра метода UseResource(). Перед вызовом этого метода потребитель ресурсов упаковывает дескриптор в транспортный контейнер дескриптора макросом nk_handle_desc().
    2. Выполняется разыменование дескриптора, в результате которого поставщик ресурсов получает указатель на контекст передачи ресурса.
    3. Поставщик ресурсов, используя функцию nk_is_handle_dereferenced(), проверяет, что выполнена операция разыменования, а не передача дескриптора.
    4. Поставщик ресурсов проверяет, что права доступа разыменованного дескриптора (который отправлен потребителем ресурсов) разрешают запрашиваемую операцию с ресурсом, и извлекает указатель на контекст передачи ресурса из транспортного контейнера дескриптора. Для этого поставщик ресурсов использует функцию nk_get_badge_op(), которая извлекает указатель на контекст передачи ресурса из транспортного контейнера дескриптора, если в полученной маске прав установлены флаги, соответствующие запрашиваемой операции.
    5. Поставщик ресурсов, используя контекст передачи ресурса и контекст пользовательского ресурса, выполняет запрашиваемую потребителем ресурсов операцию с ресурсом. Затем поставщик ресурсов отправляет потребителю ресурсов результат выполнения этой операции.
    6. Вызов метода UseResource() завершается успешно. Потребитель ресурсов получает результат выполнения операции с ресурсом.
  4. Потребитель ресурсов вызывает метод закрытия доступа к ресурсу CloseResource().
    1. Дескриптор, который получен от поставщика ресурсов на шаге 2, используется в качестве параметра метода CloseResource(). Перед вызовом этого метода потребитель ресурсов упаковывает дескриптор в транспортный контейнер дескриптора макросом nk_handle_desc(). После вызова метода CloseResource() потребитель ресурсов закрывает дескриптор функцией KnHandleClose().
    2. Выполняется разыменование дескриптора, в результате которого поставщик ресурсов получает указатель на контекст передачи ресурса.
    3. Поставщик ресурсов, используя функцию nk_is_handle_dereferenced(), проверяет, что выполнена операция разыменования, а не передача дескриптора.
    4. Поставщик ресурсов, используя функцию nk_get_badge(), извлекает указатель на контекст передачи ресурса из транспортного контейнера дескриптора.
    5. Поставщик ресурсов отзывает дескриптор, которым владеет потребитель ресурсов, функцией KnHandleRevokeSubtree(). В качестве параметров этой функции используются дескриптор ресурса, которым владеет поставщик ресурсов, и дескриптор объекта контекста передачи ресурса. Поставщик ресурсов получает доступ к этим дескрипторам через указатель на контекст передачи ресурса. (Технически не требуется отзывать дескриптор, которым владеет потребитель ресурсов, так как потребитель ресурсов его уже закрыл. Но поставщик ресурсов не может быть уверен в том, что потребитель ресурсов закрыл дескриптор, поэтому выполняется отзыв).
    6. Вызов метода CloseResource() завершается успешно.
  5. Поставщик ресурсов освобождает память, которая была выделена для контекста передачи ресурса и контекста пользовательского ресурса.
    1. Поставщик ресурсов вызовом функции KnNoticeGetEvent() получает уведомление, что объект контекста передачи ресурса закрыт, и закрывает дескриптор объекта контекста передачи ресурса функцией KnHandleClose().
    2. Поставщик ресурсов вызовом функции KnNoticeGetEvent() получает уведомление, что объект контекста передачи ресурса удален, и освобождает память, которая была выделена для контекста передачи ресурса.
    3. Поставщик ресурсов закрывает дескриптор ресурса функцией KnHandleClose() и освобождает память, которая была выделена для контекста пользовательского ресурса.
В начало
[Topic libkos_handles_simple_scenario]