Передать данные через общего клиента
#include <sys/neutrino.h>int MsgKeyData( int rcvid,int op,uint32_t key,uint32_t *key2,const iov_t *msg,int parts );int MsgKeyData_r( int rcvid,int op,uint32_t key,uint32_t *key2,const iov_t *msg,int parts );
libc
Функции MsgKeyData() и MsgKeyData_r() kernel позволяют двум привилегированным процессам передавать данные через общего клиента и верифицировать, что клиент не модифицировал эти данные. Использование этой функции иллюстрируется в примере ниже.
Данные функции идентичны за исключением способа возврата ошибок.
Программа вызывает open(), указав имя файла. Функция open() шлёт сообщение менеджеру процессов, который управляет пространством имен.
Менеджер процессов определяет полное сетевое имя и идентификатор (pid) процесса, к которому нужно направить запрос open(). Эта информация возвращается клиенту.
Далее клиент посылает сообщение процессу, имеющему указанный в ответе менеджера процессов pid. В качестве параметра передаётся полученное полное сетевое имя.
Следует обратить внимание, что клиент может изменить путевое имя перед отправкой сообщения менеджеру файловой системы. На самом деле он вообще может не обращаться к менеджеру процессов и сформировать какое угодно путевое имя. Менеджер файловой системы всегда проверяет права доступа клиента. Поэтому возможные запросы произвольных путевых имен не является проблемой, за исключением одного случая: функция chroot() позволяет задать префикс, который будет добавляться ко всем путевым именам.
В рассмотренном выше примере клиент мог вызвать chroot() с именем /net/node2/home/dan
. В результате процесс будет работать только с файлами в каталоге /net/node2/home/dan
. Например:
Путь пользователя | мапируется на путь chroot() |
---|---|
/bin/ls | /net/node2/home/dan/bin/ls |
/ | /net/node2/home/dan |
Корневой файловой системой для процесса станет заданный подкаталог, ограничивая возможности процесса по доступу к файлам. Чтобы это ограничение работало, необходимо исключить возможность изменения путевых имен клиентом.
![]() | В ЗОСРВ «Нейтрино» обработку запросов chroot() выполняет менеджер процессов. Менеджеры ресурсов выполняются в отдельных адресных пространствах. Более того, они могут выполняться на разных ЭВМ. |
Для решения этой задачи используется MsgKeyData(). Когда менеджер процессов получает сообщение, отправленное функцией open(), он формирует данные для ответа. Прежде чем отвечать, менеджер процессов вызывает MsgKeyData() со следующими аргументами:
_NTO_KEYDATA_CALCULATE
Затем клиент посылает сообщение файловому менеджеру. При получении сообщения файловый менеджер вызывает MsgKeyData() с теми же аргументами, как выше, за исключением:
_NTO_KEYDATA_VERIFY
Если целостность сообщения не нарушена, то MsgKeyData() устанавливает значение ключа по ссылке key2 в ноль.
Обратите внимание, что на самом деле используется два ключа. Публичный ключ, который возращается клиенту и приватный ключ, который генерируется менеджером процессов. Алгорит верификации использует оба эти ключа.
Отсутствует.
-1
, код ошибки записывается в errno. Любое другое возвращенное значение считается успешным завершением.EOK
возвращается при успешном завершении. Функция НЕ устанавливает errno. При возникновении ошибки функция возвращает один из представленных ниже кодов.
/** Эта программа демонстрирует использование MsgKeyData() при* пересылке клиентом данных от исходного сервера (назовем его "source server"* на целевой сервер ("destination server"). Если клиент искажает данные, то* целевой сервер будет об этом знать.*/#include <errno.h>#include <pthread.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <time.h>#include <unistd.h>#include <sys/neutrino.h>typedef struct {int public_key;char text[10];} IPC_t;int chid_src, chid_dst;void * server_src_thread( void* parm );void * server_dst_thread( void* parm );int main(){pthread_t tid[2];IPC_t msg;int coid;int status;pthread_create( &tid[0], NULL, server_src_thread, NULL );pthread_create( &tid[1], NULL, server_dst_thread, NULL );sleep( 3 );/* Дадим время на сорздание каналов. Это не элегантный способ, но простой *//** Послать некоторые данные целевому серверу server_src_thread.* Данные будут включать некоторый текст и публичный ключ* для контроля целостности этого текста.*/coid = ConnectAttach( 0, 0, chid_src, 0, 0 );MsgSend( coid, NULL, 0, &msg, sizeof( msg ) );ConnectDetach( coid );/** Затем отправляем целевому серверу server_dst_thread ответ,* полученный от server_src_thread. Не модифицируем 'text', поэтому* должен прийти ответ об успешной пересылке текста. Обратите внимание,* что мы включили в сообщение публичный ключ.*/coid = ConnectAttach( 0, 0, chid_dst, 0, 0 );status = MsgSend( coid, &msg, sizeof( msg ), &msg, sizeof( msg ) );printf( "Sent unmodified text to server_dst_thread.Replied with %s\n", status == EOK ? "EOK" : "EINVAL" );/** Теперь модифицируем данные 'text' (чего нам делать не позволено)* и снова отправляем на сервер server_dst_thread вместе с публичным ключом.* Поскольку данные 'text' искажены сервер server_dst_thread должен* вернуть ошибку.*/strcpy( msg.text, "NEWDATA" );status = MsgSend( coid, &msg, sizeof( msg ), &msg, sizeof( msg ) );printf( "Sent modified text to server_dst_thread.Replied with %s\n", status == EOK ? "EOK" : "EINVAL" );return (0);}void * server_src_thread( void *parm ){int rcvid;int private_key; /* the kernel keeps this */iov_t keyed_area_iov;IPC_t msg;struct timespec t;chid_src = ChannelCreate( 0 );while ( 1 ){rcvid = MsgReceive( chid_src, &msg, sizeof( msg ), NULL );/** Передаем в MsgKeyData() приватный ключ, при этом функция сгенерирует* публичный ключ для поля 'text' сообщения. Ядро сохранит приватный ключ* и мы ответим отправим в ответ публичный ключ.* Обратите внимание, что мы используем количество наносекунд последней секунды* для получения 32-разрядного псевдослучайного числа для приватного ключа.*/clock_gettime( CLOCK_REALTIME, &t );private_key = t.tv_nsec; /* nanoseconds since last second */strcpy( msg.text, "OKDATA" );SETIOV( &keyed_area_iov, &msg.text, sizeof( msg.text ) );MsgKeyData( rcvid, _NTO_KEYDATA_CALCULATE, private_key,&msg.public_key, &keyed_area_iov, 1 );MsgReply( rcvid, 0, &msg, sizeof( msg ) );}return (NULL);}void * server_dst_thread( void *parm ){int rcvid, tampered, status;iov_t keyed_area_iov;IPC_t msg;chid_dst = ChannelCreate( 0 );while ( 1 ){rcvid = MsgReceive( chid_dst, &msg, sizeof( msg ), NULL );/** Проверяем целостность данных с помощью публичного ключа.*/SETIOV( &keyed_area_iov, &msg.text, sizeof( msg.text ) );MsgKeyData( rcvid, _NTO_KEYDATA_VERIFY, msg.public_key,&tampered, &keyed_area_iov, 1 );if ( tampered )status = EINVAL; /* ответ: 'text' изменён */elsestatus = EOK; /* ответ: 'text' в порядке */MsgReply( rcvid, status, &msg, sizeof( msg ) );}return (NULL);}
ЗОСРВ «Нейтрино»
iov_t, chroot(), MsgReceive(), MsgReceivev(), open(), rand()
Предыдущий раздел: Описание API системной библиотеки