From 878cc3488630201a361dda87438fde58c6f8d67c Mon Sep 17 00:00:00 2001 From: Michael Kerrisk Date: Fri, 9 Jan 2015 12:20:35 +0100 Subject: [PATCH] memfd_create.2: Add EXAMPLE programs Signed-off-by: Michael Kerrisk --- man2/memfd_create.2 | 199 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 195 insertions(+), 4 deletions(-) diff --git a/man2/memfd_create.2 b/man2/memfd_create.2 index 0ff49e89b..e5eb70716 100644 --- a/man2/memfd_create.2 +++ b/man2/memfd_create.2 @@ -1,5 +1,5 @@ -.\" Copyright (C) 2014 David Herrmann -.\" and Copyright (C) 2014 Michael Kerrisk +.\" Copyright (C) 2014 Michael Kerrisk +.\" and Copyright (C) 2014 David Herrmann .\" .\" %%%LICENSE_START(GPLv2+_SW_3_PARA) .\" @@ -268,8 +268,199 @@ If desired, the second process can apply further seals to impose additional restrictions (so long as the .BR F_SEAL_SEAL seal has not yet been applied). -.\" -.\" FIXME Do we have any nice example program that could go in the man page? +.\" FIXME I added the EXAMPLE section below. Please review. +.SH EXAMPLE +Below are shown two example programs that demonstrate the use of +.BR memfd_create () +and the file sealing API. + +The first program, +.IR t_memfd_create.c , +creates a +.I tmpfs +file using +.BR memfd_create (), +sets a size for the file, maps it into memory, +and optionally places some seals on the file. +The program accepts up to three command-line arguments, +of which the first two are required. +The first argument is the name to associate with the file, +the second argument is the size to be set for the file, +and the optional third is a string of characters that specify +seals to be set on file. + +The second program, +.IR t_get_seals.c , +can be used to open an existing file that was created via +.BR memfd_create () +and inspect the set of seals that have been applied to that file. + +The following shell session demonstrates the use of these programs. +First we create a +.I tmpfs +file and set some seals on it: + +.in +4n +.nf +$ \fB./t_memfd_create my_memfd_file 4096 sw &\fP +[1] 11775 +PID: 11775; fd: 3; /proc/11775/fd/3 +.fi +.in + +At this point, the +.I t_memfd_create +program continues to run in the background. +From another program, we can obtain a file descriptor for the +memfd file by opening the +.IR /proc/PID/fd +file that corresponds to the descriptor opened by +.BR memfd_create (). +Using that pathname, we inspect the content of the +.IR /proc/PID/fd +symbolic link, and use our +.I t_get_seals +program to view the seals that have been placed on the file: + +.in +4n +.nf +$ \fBreadlink /proc/11775/fd/3\fP +/memfd:my_memfd_file (deleted) +$ \fB./t_get_seals /proc/11775/fd/3\fP +Existing seals: WRITE SHRINK +.fi +.in +.SS Program source: t_memfd_create.c +\& +.nf +#include +#include +#include +#include +#include +#include + +#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 name size [seals]\\n", argv[0]); + fprintf(stderr, "\\t\(aqseals\(aq 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\\tS \- F_SEAL_SEAL\\n"); + exit(EXIT_FAILURE); + } + + name = argv[1]; + len = atoi(argv[2]); + seals_arg = argv[3]; + + /* Create an anonymous file in tmpfs; allow seals to be + placed on the file */ + + fd = memfd_create(name, MFD_ALLOW_SEALING); + if (fd == \-1) + errExit("memfd_create"); + + /* Size the file as specified on the command line */ + + if (ftruncate(fd, len) == \-1) + errExit("truncate"); + + printf("PID: %ld; fd: %d; /proc/%ld/fd/%d\\n", + (long) getpid(), fd, (long) getpid(), fd); + + /* Code to map the file and populate the mapping with data + omitted */ + + /* If a \(aqseals\(aq command\-line argument was supplied, set some + seals on the file */ + + if (seals_arg != NULL) { + seals = 0; + + if (strchr(seals_arg, \(aqg\(aq) != NULL) + seals |= F_SEAL_GROW; + if (strchr(seals_arg, \(aqs\(aq) != NULL) + seals |= F_SEAL_SHRINK; + if (strchr(seals_arg, \(aqw\(aq) != NULL) + seals |= F_SEAL_WRITE; + if (strchr(seals_arg, \(aqS\(aq) != NULL) + seals |= F_SEAL_SEAL; + + if (fcntl(fd, F_ADD_SEALS, seals) == \-1) + errExit("fcntl"); + } + + /* Keep running, so that the file created by memfd_create() + continues to exist */ + + pause(); + + exit(EXIT_SUCCESS); +} +.fi +.SS Program source: t_get_seals.c +\& +.nf +#include +#include +#include +#include +#include +#include + +#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("Existing seals:"); + 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_SHRINK) + printf(" SHRINK"); + printf("\\n"); + + /* Code to map the file and access the contents of the + resulting mapping omitted */ + + exit(EXIT_SUCCESS); +} +.fi .SH SEE ALSO .BR fcntl (2), .BR ftruncate (2),