Unix: обмен уже отображенной памятью между процессами

У меня есть встроенная библиотека пользовательского пространства, которая имеет API по строкам

void getBuffer (void **ppBuf, unsigned long *pSize);
void bufferFilled (void *pBuf, unsigned long size);

Идея состоит в том, что мой код запрашивает буфер из библиотеки lib, заполняет его материалом, а затем передает его обратно в lib.

Я хочу, чтобы другой процесс мог заполнить этот буфер. Я могу сделать это, создав новый общий буфер с помощью shm */shm_ * API, попробуем выполнить другой процесс, а затем скопируем его в буфер lib в локальном процессе lib, но у этого есть накладные расходы дополнительного (потенциально большого) копия.

Есть ли способ обмена памятью, которая УЖЕ была отображена для процесса? например, что-то вроде:

[local lib process]
getBuffer (&myLocalBuf, &mySize);
shmName = shareThisMemory (myLocalBuf, mySize);

[other process]
myLocalBuf = openTheSharedMemory (shmName);

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

Ответ 1

Есть веские причины не допускать эту функциональность, особенно с точки зрения безопасности. API-интерфейс "share this mem" может подорвать систему разрешений доступа.

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

Не подходит для вашего использования, признается, но скорее оправдан с точки зрения целостности системы/приложения. Попробуйте найти в Интернете уязвимость /proc/pid/mem mmap для некоторых объяснений, почему этот вид доступа не нужен (в общем).

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

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

Посмотрите на это с последней точки зрения, два процесса, не открывающие его O_EXCL, будут делиться доступом к файлу. Но если один процесс уже открыл его O_EXCL, тогда единственный способ "сделать его общим" (открытый для другого процесса) - это close() сначала, а затем open() снова без O_EXCL. Нет другого способа "удалить" эксклюзивный доступ из файла, который вы открыли как такового, кроме как закрыть его в первую очередь.
Так же как нет способа удалить эксклюзивный доступ к области памяти, отображаемой как таковой, кроме как сначала отменить ее, а для памяти процесса, MAP_PRIVATE по умолчанию по умолчанию.

Дополнительно: буфер с общей памятью процесса не сильно отличается от общего файла процесса; используя семантику стиля SysV-IPC, вы имеете:

              | SysV IPC shared memory            Files
==============+===================================================================
creation      | id = shmget(key,..., IPC_CREAT);  fd = open("name",...,O_CREAT);
lookup        | id = shmget(key,...);             fd = open("name",...);
access        | addr = shmat(id,...);             addr = mmap(...,fd,...);
              |
global handle | IPC key                           filename
local handle  | SHM ID number                     filedescriptor number
mem location  | created by shmat()                created by mmap()

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

Ответ 2

Более современный способ обмена памятью между процессами - использовать POSIX shm_open() API.

По сути, это переносимый способ размещения файлов на ramdisk (tmpfs). Таким образом, в одном процессе используется shm_open plus ftruncate plus mmap. Другой использует shm_open (с тем же именем) плюс mmap плюс shm_unlink. (С более чем двумя процессами, последний в mmap это может отменить связь.)

Таким образом, общая память будет автоматически исправлена ​​при выходе последнего процесса; нет необходимости явно удалять общий сегмент (как в случае с общей памятью SysV).

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

Ответ 3

В теории, по крайней мере, вы можете записать адрес памяти буфера, который вы получили из своей библиотеки, и иметь другой файл mmap/proc/$PID_OF_FIRST_PROCCESS/mem с адресом в качестве смещения.

Я не тестировал его, и я не уверен /proc/PID/mem на самом деле имеет файл mmap op, и есть тонна соображений безопасности, но это может сработать. Удачи: -)