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