memfd_create(2) | System Calls Manual | memfd_create(2) |
memfd_create - создаёт анонимный файл
Standard C library (libc, -lc)
#define _GNU_SOURCE /* Смотрите feature_test_macros(7) */ #include <sys/mman.h>
int memfd_create(const char *name, unsigned int flags);
Вызов memfd_create() создаёт анонимный файл и возвращает ссылающийся на него файловый дескриптор. Анонимный файл ведёт себя как обычный файл и может быть изменён, обрезан, отображён в память и т.д. Однако в отличие от обычного файла он располагается в ОЗУ и не имеет энергонезависимого хранилища. Как только все ссылки на файл удаляются, он автоматически исчезает. Анонимные файлы располагаются в анонимной памяти. Поэтому у файлов, создаваемых memfd_create(), такая же семантика как и областей анонимной памяти, выделяемой с помощью mmap(2) с флагом MAP_ANONYMOUS.
Первоначально, размер файла равен 0. После этого вызова нужно задать размер файла с помощью ftruncate(2) (или заполнить файл с помощью write(2) или подобными).
Имя, указанное в name, используется в качестве имени файла и будет показываться как цель соответствующей символьной ссылки в каталоге. /proc/self/fd/. Отображаемое имя всегда начинается с memfd: и служит только для отладки. Имена не влияют на поведение файлового дескриптора и поэтому несколько файлов могут иметь одно имя без каких-либо последствий.
Для изменения поведения memfd_create() можно использовать следующие значения flags (через OR):
Неиспользуемые биты в flags должны быть равны 0.
В качестве возвращаемого значения memfd_create() возвращает новый файловый дескриптор, который можно использовать для обращения к файлу. Данный файловый дескриптор открыт на чтение и запись (O_RDWR) и в файловом дескрипторе установлен флаг O_LARGEFILE.
При вызове fork(2) и execve(2) с файловым дескриптором, созданным memfd_create(), применяется обычная семантика. Копия файлового дескриптора наследуется потомком, созданным fork(2), указывает на тот же файл. Файловый дескриптор сохраняется при после execve(2), если не установлен флаг close-on-exec.
При успешном выполнении memfd_create() возвращает новый файловый дескриптор. При ошибке возвращается -1, и errno устанавливается в соответствующее значение.
The memfd_create() system call first appeared in Linux 3.17; glibc support was added in glibc 2.27.
Системный вызов memfd_create() есть только в Linux.
Системный вызов memfd_create() предоставляет простую альтернативу ручному монтированию файловой системы tmpfs(5), созданию и открытию файла в этой файловой системе. Основным предназначением memfd_create() является создание файлов и соответствующих файловых дескрипторов, которые используются с программным интерфейсом опечатывания файлов, предоставляемым fcntl(2).
Системный вызов memfd_create() также используется и без опечатывания файла (вот почему опечатывание файлов отключено, если этого не запросить явно с помощью флага MFD_ALLOW_SEALING). В частности, он может использоваться как альтернатива созданию файлов в tmp или использованию open(2) с O_TMPFILE в случаях, когда не требуется реальная ссылка на конечный файл в файловой системе.
Ели файл не опечатан, то процессы, которые связываются через общую память, должны или доверять друг другу, или учитывать возможность того, что недоверенная сторона может работать с общей памятью проблемным способом. Например, недоверенная сторона может изменить содержимое общей памяти в любое время или уменьшить область общей памяти. Первая возможность делает локальный процесс уязвимым к состязательности условий «момент проверки — момент использования» (обычно решается копированием данных из области общей памяти перед проверкой и использованием). Последняя возможность делает локальный процесс уязвимым к сигналам SIGBUS, которые возникают при попытке получить доступ к теперь несуществующему расположению в области общей памяти (решается использованием обработчика сигнала SIGBUS).
Взаимодействие с недоверенными сторонами приводит к усложнению кода для работы с общей памятью. Опечатывание памяти позволяет устранить эту сложность, позволяя процессу безопасно работать, зная что его партнёр не может изменить общую память нежелательным способом.
В примере использования механизма опечатывания происходит следующее:
Далее показано два примера программы, в которых продемонстрировано использование memfd_create() и программный интерфейс опечатывания файла.
Первая программа, t_memfd_create.c, создаёт файл tmpfs(5) с помощью memfd_create(), изменяет его размер, отображает в память и, возможно, накладывает несколько печатей на файл. Программа принимает не более трёх аргументов командной строки, два первых обязательные. Первым аргументом задаётся имя файла, во втором — размер файла, а в необязательном третьем — строка символов, задающих устанавливаемые печати на файл.
Вторая программа, t_get_seals.c, может использоваться для открытия существующего файла, созданного memfd_create(), и проверки набора печатей, применённых к файлу.
Следующий пример сеанса показывает как использовать программу. Сначала создаётся файл tmpfs(5) и накладываются печати:
$ ./t_memfd_create my_memfd_file 4096 sw & [1] 11775 PID: 11775; fd: 3; /proc/11775/fd/3
После этого программа t_memfd_create продолжает выполняться в фоновом режиме. Из другой программы можно получить дескриптор файла, созданный memfd_create(), открыв файл /proc/pid/fd, который соответствует файловому дескриптору, открытому memfd_create(). Используя это имя, можно просмотреть содержимое символьной ссылки /proc/pid/fd и использовать программу t_get_seals для просмотра печатей, которые установлены на файл:
$ readlink /proc/11775/fd/3 /memfd:my_memfd_file (удалён) $ ./t_get_seals /proc/11775/fd/3 Наложенные печати: WRITE SHRINK
#define _GNU_SOURCE #include <err.h> #include <fcntl.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/mman.h> #include <unistd.h> int main(int argc, char *argv[]) {
int fd;
char *name, *seals_arg;
ssize_t len;
unsigned int seals;
if (argc < 3) {
fprintf(stderr, "%s name size [seals]\n", argv[0]);
fprintf(stderr, "\t'seals' can contain any of the "
"following characters:\n");
fprintf(stderr, "\t\tg - F_SEAL_GROW\n");
fprintf(stderr, "\t\ts - F_SEAL_SHRINK\n");
fprintf(stderr, "\t\tw - F_SEAL_WRITE\n");
fprintf(stderr, "\t\tW - F_SEAL_FUTURE_WRITE\n");
fprintf(stderr, "\t\tS - F_SEAL_SEAL\n");
exit(EXIT_FAILURE);
}
name = argv[1];
len = atoi(argv[2]);
seals_arg = argv[3];
/* Создаётся анонимный файл в tmpfs; на файл
накладываются указанные печати. */
fd = memfd_create(name, MFD_ALLOW_SEALING);
if (fd == -1)
err(EXIT_FAILURE, "memfd_create");
/* Размер файл как указано в командной строке. */
if (ftruncate(fd, len) == -1)
err(EXIT_FAILURE, "truncate");
printf("PID: %jd; fd: %d; /proc/%jd/fd/%d\n",
(intmax_t) getpid(), fd, (intmax_t) getpid(), fd);
/* Здесь может быть код для отображения файла и заполнения данными. */
/* If a 'seals' command-line argument was supplied, set some
seals on the file. */
if (seals_arg != NULL) {
seals = 0;
if (strchr(seals_arg, 'g') != NULL)
seals |= F_SEAL_GROW;
if (strchr(seals_arg, 's') != NULL)
seals |= F_SEAL_SHRINK;
if (strchr(seals_arg, 'w') != NULL)
seals |= F_SEAL_WRITE;
if (strchr(seals_arg, 'W') != NULL)
seals |= F_SEAL_FUTURE_WRITE;
if (strchr(seals_arg, 'S') != NULL)
seals |= F_SEAL_SEAL;
if (fcntl(fd, F_ADD_SEALS, seals) == -1)
err(EXIT_FAILURE, "fcntl");
}
/* Продолжаем выполнение для того, чтобы файл, созданный memfd_create(),
продолжал существовать. */
pause();
exit(EXIT_SUCCESS); }
#define _GNU_SOURCE #include <err.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) {
int fd;
unsigned int seals;
if (argc != 2) {
fprintf(stderr, "%s /proc/PID/fd/FD\n", argv[0]);
exit(EXIT_FAILURE);
}
fd = open(argv[1], O_RDWR);
if (fd == -1)
err(EXIT_FAILURE, "open");
seals = fcntl(fd, F_GET_SEALS);
if (seals == -1)
err(EXIT_FAILURE, "fcntl");
printf("Наложенные печати:");
if (seals & F_SEAL_SEAL)
printf(" SEAL");
if (seals & F_SEAL_GROW)
printf(" GROW");
if (seals & F_SEAL_WRITE)
printf(" WRITE");
if (seals & F_SEAL_FUTURE_WRITE)
printf(" FUTURE_WRITE");
if (seals & F_SEAL_SHRINK)
printf(" SHRINK");
printf("\n");
/* Здесь может быть код для отображения и доступа к содержимому файла. */
exit(EXIT_SUCCESS); }
fcntl(2), ftruncate(2), memfd_secret(2), mmap(2), shmget(2), shm_open(3)
Русский перевод этой страницы руководства был сделан aereiae <aereiae@gmail.com>, Alexey <a.chepugov@gmail.com>, Azamat Hackimov <azamat.hackimov@gmail.com>, Dmitriy S. Seregin <dseregin@59.ru>, Dmitry Bolkhovskikh <d20052005@yandex.ru>, ITriskTI <ITriskTI@gmail.com>, Max Is <ismax799@gmail.com>, Yuri Kozlov <yuray@komyakino.ru>, Иван Павлов <pavia00@gmail.com> и Малянов Евгений Викторович <maljanow@outlook.com>
Этот перевод является бесплатной документацией; прочитайте Стандартную общественную лицензию GNU версии 3 или более позднюю, чтобы узнать об условиях авторского права. Мы не несем НИКАКОЙ ОТВЕТСТВЕННОСТИ.
Если вы обнаружите ошибки в переводе этой страницы руководства, пожалуйста, отправьте электронное письмо на man-pages-ru-talks@lists.sourceforge.net.
5 февраля 2023 г. | Linux man-pages 6.03 |