Unix: разделение уже отображенной памяти между процессами - PullRequest
14 голосов
/ 23 июня 2011

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

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

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

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

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

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

[other process]
myLocalBuf = openTheSharedMemory (shmName);

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

Ответы [ 3 ]

9 голосов
/ 23 июня 2011

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

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

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

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

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

Посмотрите нас последней точки зрения, два процесса , а не , открывающие его O_EXCL, будут совместно использовать доступ к файлу.Но если один процесс уже открыл его O_EXCL, то единственный способ «сделать его общим» (доступным для другого процесса) - это close() it сначала , затем open() it снова без 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Затем соединение может использовать этот ключ, чтобы проверить, существует ли общий ресурс, а также при доступе (прикрепить к дескриптору) содержимого, хотя бы этого.

5 голосов
/ 23 июня 2011

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

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

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

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

0 голосов
/ 23 июня 2011

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

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

...