xref: /freebsd-src/lib/libc/gen/memfd_create.c (revision c96772227b7dfcaf4eec4d07acb5c916643aca3a)
1c3207e2dSBrooks Davis /*
2c3207e2dSBrooks Davis  * SPDX-License-Identifier: BSD-2-Clause
3c3207e2dSBrooks Davis  *
4c3207e2dSBrooks Davis  * Copyright (c) 2019 Kyle Evans <kevans@FreeBSD.org>
5c3207e2dSBrooks Davis  *
6c3207e2dSBrooks Davis  * Redistribution and use in source and binary forms, with or without
7c3207e2dSBrooks Davis  * modification, are permitted provided that the following conditions
8c3207e2dSBrooks Davis  * are met:
9c3207e2dSBrooks Davis  * 1. Redistributions of source code must retain the above copyright
10c3207e2dSBrooks Davis  *    notice(s), this list of conditions and the following disclaimer as
11c3207e2dSBrooks Davis  *    the first lines of this file unmodified other than the possible
12c3207e2dSBrooks Davis  *    addition of one or more copyright notices.
13c3207e2dSBrooks Davis  * 2. Redistributions in binary form must reproduce the above copyright
14c3207e2dSBrooks Davis  *    notice(s), this list of conditions and the following disclaimer in
15c3207e2dSBrooks Davis  *    the documentation and/or other materials provided with the
16c3207e2dSBrooks Davis  *    distribution.
17c3207e2dSBrooks Davis  *
18c3207e2dSBrooks Davis  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
19c3207e2dSBrooks Davis  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20c3207e2dSBrooks Davis  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21c3207e2dSBrooks Davis  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
22c3207e2dSBrooks Davis  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23c3207e2dSBrooks Davis  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24c3207e2dSBrooks Davis  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
25c3207e2dSBrooks Davis  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26c3207e2dSBrooks Davis  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
27c3207e2dSBrooks Davis  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
28c3207e2dSBrooks Davis  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29c3207e2dSBrooks Davis  */
30c3207e2dSBrooks Davis 
31c3207e2dSBrooks Davis #include <sys/param.h>
32c3207e2dSBrooks Davis #include <sys/filio.h>
33c3207e2dSBrooks Davis #include <sys/mman.h>
34c3207e2dSBrooks Davis 
35c3207e2dSBrooks Davis #include <errno.h>
36c3207e2dSBrooks Davis #include <fcntl.h>
37c3207e2dSBrooks Davis #include <stdio.h>
38c3207e2dSBrooks Davis #include <string.h>
39c3207e2dSBrooks Davis #include <unistd.h>
40c3207e2dSBrooks Davis 
41c3207e2dSBrooks Davis #include "libc_private.h"
42c3207e2dSBrooks Davis 
43c3207e2dSBrooks Davis #define	MEMFD_NAME_PREFIX	"memfd:"
44c3207e2dSBrooks Davis 
45c3207e2dSBrooks Davis /*
46c3207e2dSBrooks Davis  * The path argument is passed to the kernel, but the kernel doesn't currently
47c3207e2dSBrooks Davis  * do anything with it.  Linux exposes it in linprocfs for debugging purposes
48c3207e2dSBrooks Davis  * only, but our kernel currently will not do the same.
49c3207e2dSBrooks Davis  */
50c3207e2dSBrooks Davis int
memfd_create(const char * name,unsigned int flags)51c3207e2dSBrooks Davis memfd_create(const char *name, unsigned int flags)
52c3207e2dSBrooks Davis {
53c3207e2dSBrooks Davis 	char memfd_name[NAME_MAX + 1];
54*c9677222SBrooks Davis 	size_t pgs[MAXPAGESIZES];
55*c9677222SBrooks Davis 	size_t namelen, pgsize;
56c3207e2dSBrooks Davis 	struct shm_largepage_conf slc;
57c3207e2dSBrooks Davis 	int error, fd, npgs, oflags, pgidx, saved_errno, shmflags;
58c3207e2dSBrooks Davis 
59c3207e2dSBrooks Davis 	if (name == NULL) {
60c3207e2dSBrooks Davis 		errno = EBADF;
61c3207e2dSBrooks Davis 		return (-1);
62c3207e2dSBrooks Davis 	}
63c3207e2dSBrooks Davis 	namelen = strlen(name);
64c3207e2dSBrooks Davis 	if (namelen + sizeof(MEMFD_NAME_PREFIX) - 1 > NAME_MAX) {
65c3207e2dSBrooks Davis 		errno = EINVAL;
66c3207e2dSBrooks Davis 		return (-1);
67c3207e2dSBrooks Davis 	}
68c3207e2dSBrooks Davis 	if ((flags & ~(MFD_CLOEXEC | MFD_ALLOW_SEALING | MFD_HUGETLB |
69c3207e2dSBrooks Davis 	    MFD_HUGE_MASK)) != 0) {
70c3207e2dSBrooks Davis 		errno = EINVAL;
71c3207e2dSBrooks Davis 		return (-1);
72c3207e2dSBrooks Davis 	}
73c3207e2dSBrooks Davis 	/* Size specified but no HUGETLB. */
74c3207e2dSBrooks Davis 	if ((flags & MFD_HUGE_MASK) != 0 && (flags & MFD_HUGETLB) == 0) {
75c3207e2dSBrooks Davis 		errno = EINVAL;
76c3207e2dSBrooks Davis 		return (-1);
77c3207e2dSBrooks Davis 	}
78c3207e2dSBrooks Davis 
79c3207e2dSBrooks Davis 	/* We've already validated that we're sufficiently sized. */
80c3207e2dSBrooks Davis 	snprintf(memfd_name, NAME_MAX + 1, "%s%s", MEMFD_NAME_PREFIX, name);
81c3207e2dSBrooks Davis 	oflags = O_RDWR;
82c3207e2dSBrooks Davis 	shmflags = 0;
83c3207e2dSBrooks Davis 	if ((flags & MFD_CLOEXEC) != 0)
84c3207e2dSBrooks Davis 		oflags |= O_CLOEXEC;
85c3207e2dSBrooks Davis 	if ((flags & MFD_ALLOW_SEALING) != 0)
86c3207e2dSBrooks Davis 		shmflags |= SHM_ALLOW_SEALING;
87c3207e2dSBrooks Davis 	if ((flags & MFD_HUGETLB) != 0)
88c3207e2dSBrooks Davis 		shmflags |= SHM_LARGEPAGE;
89c3207e2dSBrooks Davis 	else
90c3207e2dSBrooks Davis 		shmflags |= SHM_GROW_ON_WRITE;
91c3207e2dSBrooks Davis 	fd = __sys_shm_open2(SHM_ANON, oflags, 0, shmflags, memfd_name);
92c3207e2dSBrooks Davis 	if (fd == -1 || (flags & MFD_HUGETLB) == 0)
93c3207e2dSBrooks Davis 		return (fd);
94c3207e2dSBrooks Davis 
95*c9677222SBrooks Davis 	npgs = getpagesizes(pgs, nitems(pgs));
96c3207e2dSBrooks Davis 	if (npgs == -1)
97c3207e2dSBrooks Davis 		goto clean;
98c3207e2dSBrooks Davis 	pgsize = (size_t)1 << ((flags & MFD_HUGE_MASK) >> MFD_HUGE_SHIFT);
99c3207e2dSBrooks Davis 	for (pgidx = 0; pgidx < npgs; pgidx++) {
100c3207e2dSBrooks Davis 		if (pgsize == pgs[pgidx])
101c3207e2dSBrooks Davis 			break;
102c3207e2dSBrooks Davis 	}
103c3207e2dSBrooks Davis 	if (pgidx == npgs) {
104c3207e2dSBrooks Davis 		errno = EOPNOTSUPP;
105c3207e2dSBrooks Davis 		goto clean;
106c3207e2dSBrooks Davis 	}
107c3207e2dSBrooks Davis 
108c3207e2dSBrooks Davis 	memset(&slc, 0, sizeof(slc));
109c3207e2dSBrooks Davis 	slc.psind = pgidx;
110c3207e2dSBrooks Davis 	slc.alloc_policy = SHM_LARGEPAGE_ALLOC_DEFAULT;
111c3207e2dSBrooks Davis 	error = ioctl(fd, FIOSSHMLPGCNF, &slc);
112c3207e2dSBrooks Davis 	if (error == -1)
113c3207e2dSBrooks Davis 		goto clean;
114c3207e2dSBrooks Davis 	return (fd);
115c3207e2dSBrooks Davis 
116c3207e2dSBrooks Davis clean:
117c3207e2dSBrooks Davis 	saved_errno = errno;
118c3207e2dSBrooks Davis 	close(fd);
119c3207e2dSBrooks Davis 	errno = saved_errno;
120c3207e2dSBrooks Davis 	return (-1);
121c3207e2dSBrooks Davis }
122