Главная » 2017 » Ноябрь » 21 » man 2 memfd_create
00:51
man 2 memfd_create

SEO sprint - Всё для максимальной раскрутки!





ИМЯ


memfd_create - создаёт анонимный файл



ОБЗОР


#include <sys/memfd.h>

int memfd_create(const char *name, unsigned int flags);

Замечание: В glibc нет обёрточной функции для данного системного вызова; смотрите
ЗАМЕЧАНИЯ.



ОПИСАНИЕ


Вызов memfd_create() создаёт анонимный файл и возвращает ссылающийся на него
файловый дескриптор. Анонимный файл и ведёт себя как обычный файл и может быть
изменён, обрезан, отображён в памятью и т.д. Однако в отличие от обычного файла он
располагается в ОЗУ и не имеет энергонезависимого хранилища. Как только все ссылки
на файл удаляются, он автоматически исчезает. Анонимные файлы располагаются в
анонимной памяти. Поэтому у файлов, создаваемых memfd_create(), такая же семантика
как и областей анонимной памяти, выделяемой с помощью mmap(2) с флагом
MAP_ANONYMOUS.

Первоначально, размер файла равен 0. После этого вызова нужно задать размер файла
с помощью ftruncate(2) (или заполнить файл с помощью write(2) или подобными).

Имя, указанное в name, используется в качестве имени файла и будет показываться
как цель соответствующей символьной ссылки в каталоге. /proc/self/fd/.
Отображаемое имя всегда начинается с memfd: и служит только для отладки. Имена не
влияют на поведение файлового дескриптора и поэтому несколько файлов могут иметь
одно имя без каких-либо последствий.

Для изменения поведения memfd_create() можно использовать следующие значения flags
(через OR):

MFD_CLOEXEC
Устанавливает флаг close-on-exec (FD_CLOEXEC) для нового открытого
файлового дескриптора. Смотрите описание флага O_CLOEXEC в open(2) для
того, чтобы узнать как это может пригодиться.

MFD_ALLOW_SEALING
Разрешает операции опечатывания (sealing) файла. Описание операций
F_ADD_SEALS и F_GET_SEALS смотрите в fcntl(2), а также в ЗАМЕЧАНИЯ ниже.
Первоначально набор печатей пуст. Если этот флаг не установлен, то
начальным набором печатей будет F_SEAL_SEAL, означающий запрещение
установки печатей на файл.

MFD_HUGETLB (начиная с Linux 4.14)
В файловой системе hugetlbfs, использующей огромные страницы, будет создан
анонимный файл. В файле исходного кода Linux
Documentation/vm/hugetlbpage.txt дана подробная информация о hugetlbfs.
Файловая система hugetlbfs не поддерживает операции запечатывания файла.
Поэтому одновременное указание MFD_HUGETLB и MFD_ALLOW_SEALING в flags
запрещено.

MFD_HUGE_2MB, MFD_HUGE_1GB, ...
Используется как дополнение к MFD_HUGETLB для выбора размера страницы
hugetlb (соответственно, 2 МБ, 1 ГБ, …) в системах, которые поддерживают
различные размеры страниц hugetlb. Определения размеров огромных страниц

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

При вызове fork(2) и execve(2) с файловым дескриптором, созданным memfd_create(),
применяется обычная семантика. Копия файлового дескриптора наследуется потомком,
созданным fork(2), указывает на тот же файл. Файловый дескриптор сохраняется при
после execve(2), если не установлен флаг close-on-exec.



ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ


При успешном выполнении memfd_create() возвращает новый файловый дескриптор. При
ошибке возвращается -1, и errno устанавливается в соответствующее значение.



ОШИБКИ


EFAULT Некорректный адрес в name.

EINVAL В flags указаны неизвестные биты.

EINVAL Значение name было слишком длинным (ограничено 249 байтами, не считая
конечный байт null).

EINVAL В flags указаны MFD_HUGETLB и MFD_ALLOW_SEALING одновременно.

EMFILE Было достигнуто ограничение по количеству открытых файловых дескрипторов на
процесс.

ENFILE Достигнуто максимальное количество открытых файлов в системе.

ENOMEM Недостаточно памяти для создания нового анонимного файла.



ВЕРСИИ


Системный вызов memfd_create() впервые появился в Linux 3.17.



СООТВЕТСТВИЕ СТАНДАРТАМ


Системный вызов memfd_create() есть только в Linux.



ЗАМЕЧАНИЯ


В glibc нет обёртки для данного системного вызова; запускайте его с помощью
syscall(2).

Системный вызов memfd_create() предоставляет простую альтернативу ручному
монтированию файловой системы tmpfs(5), созданию и открытию файла в этой файловой
системе. Основным предназначением memfd_create() является создание файлов и
соответствующих файловых дескрипторов, которые используются с программным
интерфейсом опечатывания файлов, предоставляемым fcntl(2).

Системный вызов memfd_create() также используется и без опечатывания файла (вот
почему опечатывание файлов отключено, если этого не запросить явно с помощью флага
MFD_ALLOW_SEALING). В частности, он может использоваться как альтернатива созданию
файлов в tmp или использованию open(2) с O_TMPFILE в случаях, когда не требуется
реальная ссылка на конечный файл в файловой системе.

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

В примере использования механизма опечатывания происходит следующее:

1. Первый процесс создаёт файл tmpfs(5) с помощью memfd_create(). Вызов возвращает
файловый дескриптор, используемый далее.

2. Первый процесс задаёт размер файла, созданного ранее, с помощью ftruncate(2),
отображает его с помощью mmap(2) и заполняется общую память нужными данными.

3. Первый процесс использует fcntl(2) с операцией F_ADD_SEALS для установки одной
или более печатей на файл, чтобы в дальнейшем ограничить изменение файла (если
устанавливается печать F_SEAL_WRITE, то сначала нужно удалить общее доступное
на запись отображение, созданное ранее).

4. Второй процесс получает файловый дескриптор файла tmpfs(5) и отображает его.
Варианты того, как это можно сделать:

* Процесс, вызвавший memfd_create(), может переслать полученный файловый
дескриптор второму процессу через доменный сокет UNIX (смотрите unix(7) и
cmsg(3)). Второй процесс затем отображает файл с помощью mmap(2).

* Второй процесс создаётся с помощью fork(2) и, таким образом, наследует
файловый дескриптор и отображение (заметим, что в этом случае и следующем
образуется природное доверие между двумя процессами, так как они работают с
правами одного пользовательского идентификатора. Поэтому опечатывание файла
здесь не нужно).

* Второй процесс открывает файл /proc/<pid>/fd/<fd>, где <pid> — PID первого
процесса (вызвавшего memfd_create()), а <fd> — номер файлового дескриптора,
возвращённого вызовом memfd_create() в этом процессе. Затем второй процесс
отображает файл с помощью mmap(2).

5. Второй процесс использует fcntl(2) с операцией F_GET_SEALS для получения
битовой маски печатей, которые были применены к файлу. Данная маска
проверяется, чтобы определить какие ограничения наложены на изменения файла.
Если требуется, то второй процесс может наложить дополнительные печати, что ещё
ограничить действия (возможно до тех пор, пока не будет наложена печать
F_SEAL_SEAL).



ПРИМЕР


Далее показано два примера программы, в которых продемонстрировано использование
memfd_create() и программный интерфейс опечатывания файла.

Первая программа, t_memfd_create.c, создаёт файл tmpfs(5) с помощью
memfd_create(), изменяет его размер, отображает в память и, возможно, накладывает
несколько печатей на файл. Программа принимает не более трёх аргументов командной
строки, два первых обязательные. Первым аргументом задаётся имя файла, во втором —
размер файла, а в необязательном третьем — строка символов, задающих
устанавливаемые печати на файл.

Вторая программа, t_get_seals.c, может использоваться для открытия существующего
файла, созданного memfd_create(), и проверки набора печатей, применённых к файлу.

Следующий пример сеанса показывает как использовать программу. Сначала создаётся
файл tmpfs(5) и накладываются печати:
/proc/[pid]/fd и использовать программу t_get_seals для просмотра печатей, которые
установлены на файл:

$ readlink /proc/11775/fd/3
/memfd:my_memfd_file (удалён)
$ ./t_get_seals /proc/11775/fd/3
Наложенные печати: WRITE SHRINK

Исходный код программы: t_memfd_create.c

#include <sys/memfd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>

#define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \
} while (0)

int
main(int argc, char *argv[])
{
int fd;
unsigned int seals;
char *addr;
char *name, *seals_arg;
ssize_t len;

if (argc < 3) {
fprintf(stderr, "%s имя размер [печати]\n", argv[0]);
fprintf(stderr, "\t в 'печати' могут быть "
"следующие символы:\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\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)
errExit("memfd_create");

/* Размер файл как указано в командной строке */

if (ftruncate(fd, len) == -1)
errExit("truncate");

printf("PID: %ld; fd: %d; /proc/%ld/fd/%d\n",

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, 'S') != NULL)
seals |= F_SEAL_SEAL;

if (fcntl(fd, F_ADD_SEALS, seals) == -1)
errExit("fcntl");
}

/* Продолжаем выполнение для того, чтобы файл, созданный memfd_create(),
продолжал существовать */

pause();

exit(EXIT_SUCCESS);
}

Исходный код программы: t_get_seals.c

#include <sys/memfd.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \
} while (0)

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)
errExit("open");

seals = fcntl(fd, F_GET_SEALS);
if (seals == -1)
errExit("fcntl");

printf("Наложенные печати:");
if (seals & F_SEAL_SEAL)
printf(" SEAL");
if (seals & F_SEAL_GROW)
exit(EXIT_SUCCESS);
}



СМОТРИТЕ ТАКЖЕ


fcntl(2), ftruncate(2), mmap(2), shmget(2), shm_open(3)



Категория: (2) Системные вызовы ядра (функции языка Си) | Просмотров: 360 | Добавил: Администратор | Рейтинг: 0.0/0
Всего комментариев: 0
avatar