Я пытаюсь использовать API IPC общей памяти POSIX в C, который в основном соответствует шаблону shm_open() -> ftruncate() -> mmap() -> use -> munmap() -> shm_unlink()
(последние два являются необязательными IIUC). Я заметил, что первые два вызова требуют разных флагов, определяющих разрешения и параметры, но я не могу понять разницу. Со страниц руководства:
int shm_open(const char *name, int oflag, mode_t mode);
--------- -----------
FIRST SECOND
oflag is a bit mask created by ORing together exactly one of O_RDONLY or O_RDWR
O_RDONLY
Open the object for read access. A shared memory object opened in this way can be mmap(2)ed only for read (PROT_READ) access.
O_RDWR Open the object for read-write access.
O_CREAT
Create the shared memory object if it does not exist. The user and group ownership of the object are taken from the corresponding effec‐
tive IDs of the calling process, and the object's permission bits are set according to the low-order 9 bits of mode, except that those
bits set in the process file mode creation mask (see umask(2)) are cleared for the new object. A set of macro constants which can be used
to define mode is listed in open(2). (Symbolic definitions of these constants can be obtained by including <sys/stat.h>.)
а потом
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
--------
THIRD
The prot argument describes the desired memory protection of the mapping (and must not conflict with the open mode of the file). It is either
PROT_NONE or the bitwise OR of one or more of the following flags:
PROT_EXEC Pages may be executed.
PROT_READ Pages may be read.
PROT_WRITE Pages may be written.
PROT_NONE Pages may not be accessed.
У меня вопрос: в чем разница между разрешениями, указанными в трех выделенных местах?
Несколько вещей, которые я заметил:
O_RDONLY
в shm_open()
, но тогда для выделения некоторого места в виртуальном файле с помощью ftruncate()
вам все равно нужно иметь разрешения на запись (O_RDWR
), так какой в этом смысл?SECOND
в примере)After the mmap() call has returned, the file descriptor, fd, can be closed immediately without invalidating the mapping.
, поэтому я думаю, если вы хотите создать файл только для чтения (потому что другие процессы могут писать в него), вам нужно сначала открыть его с правами на запись , затем отобразить его в режиме только для чтения, а затем освободить fd?Запись файловой системы имеет права доступа, по крайней мере, три «группы» «авторизации» (чтение, запись, выполнение) для владельца, владельца группы и других. Они используются, когда процесс запрашивает доступ к этому объекту; запрошенные доступы проверяются на соответствие этим разрешениям.
Когда вы «открываете» что-то, вы запрашиваете намерение, это указывается в параметре oflag
(я хочу прочитать RD_ONLY
, или я хочу написать, или...). Иногда просишь открыть то, чего нет, и в то же время при необходимости создать это (O_CREAT
). В этом случае вам необходимо указать, какие будут права доступа, через параметр mode
.
Открыв этот объект, вы можете использовать его так, как вы заявили в начале. В случае объекта общей памяти вам необходимо сопоставить его с адресным пространством процесса, чтобы иметь возможность доступа к нему. В этом и состоит цель mmap
— отобразить этот объект в каком-то месте памяти вашего процесса. Любой фрагмент памяти адресного пространства также защищен; например, код вашего процесса (по умолчанию) защищен от записи и т. д. Таким образом, если вы сопоставляете объект общей памяти, вам необходимо указать, какова будет защита этой памяти, в этом и заключается цель параметра prot
.
@AlessandroBertulli shm_open
не знает, какую prot
ценность вы намерены передать mmap
. Он не может просто открыть чтение и запись по умолчанию, потому что текущие разрешения могут этого не допускать.
@AlessandroBertulli Вы можете получить дескриптор файла, который для вас открывает какая-то библиотека (представьте, в режиме открытия чтения/записи), но ваше намерение состоит в том, чтобы просто прочитать внутри сопоставления и убедиться в этом ==> PROT_READ. У вас также могут быть разные намерения в разное время для одного и того же объекта.
У меня нет ответа, кроме четкого ответа Жана-Батиста Юнеса и комментария Яна Эббота, однако есть некоторые аспекты, которые могут быть интересны и заслуживают изучения.
Поскольку разрешения относительно того, какие процессы могут открывать и отображать общую память, сосредоточены на разрешениях владельца, группы и других лиц, примечательно, что любой процесс с соответствующими разрешениями может свободно присоединиться (при условии, что он знает правильный путь к файлу). Таким образом, это направлено против того, чтобы сами приложения могли контролировать, какие процессы могут получить доступ к общей памяти. Это может быть или не быть неоптимальным для приложения. Однако общая память иногда может быть слишком открытой.
Например, уязвимость произвольного кода в веб-браузере, если она использована, позволяет злоумышленнику получить доступ к любой общей памяти, доступной любым процессам, запускаемым одним и тем же пользователем (если им известен путь).
Если подобные вещи вызывают беспокойство, то помогает объединение процессов в виде потоков внутри одного процесса; тогда вся память может быть внутри процесса и не доступна за пределами процесса. Конечно, многое зависит от приложения(й) и т.д.
Одна из возможностей — вместо использования shm использовать ZeroMQ
. Это может быть слишком радикальным переосмыслением архитектуры приложения, которое вы преследуете, но у него есть некоторые интересные свойства, которые могут представлять интерес.
Это структура модели актера, очень непохожая на общую память. Однако этот транспорт inproc
фактически представляет собой совместное использование памяти в процессе (ну, копирование) и поэтому, вероятно, довольно быстр.
Во-вторых, если единицы выполнения (потоки, процессы) обмениваются данными с помощью ZeroMQ, все остальные транспорты (ipc
, tcp
, vmci
и т. д.) могут быть задействованы и смешаны/сопоставлены. Таким образом, исполнительные блоки можно легко преобразовать в потоки, отдельные процессы или процессы на отдельных машинах без каких-либо реальных изменений исходного кода. Его встроенная библиотека шифрования/безопасности (я думаю, libsodium) означает, что, если рассматривать ее как отдельные процессы, в приложении может быть обеспечена конфиденциальность/безопасность без необходимости подвергать все воздействию любого процесса, запускаемого пользователем.
Стоит обратить внимание на скорость inproc
. Он копирует данные (сколько раз я не уверен, но, возможно, только один раз), тогда как использование общей памяти (через shm) не копирует данные. Стоит иметь в виду, что доступ к общей памяти из нескольких ядер (или, что еще хуже, из отдельных ЦП) сопряжен с некоторыми накладными расходами в микроэлектронике ЦП; между ядрами может происходить много разговоров по управлению кешем, и в зависимости от того, что именно делает приложение, может быть много промахов кеша. В общем, на современных процессорах, если это соответствует приложению, может иметь смысл иметь отдельную копию данных для разных потоков/процессов, опосредованную структурой модели актера, такой как ZeroMQ.
Спасибо, первое отличие, которое я упустил, заключалось в том, что флаги
mode
учитываются только при создании нового файла сO_CREAT
oflag
. Что касается второго: это тот же механизм, с помощью которого исполняемый файл, который я создаю, разрешен какuser=rwx
в файловой системе, но разделtext
того же файла в памяти защищен от записи? Но тогда зачем нам указывать намерение дляshm_open
oflag
, если общую память можно использовать только черезmmap
(которая тоже защищена)?