1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <errno.h>
4 #include <sys/stat.h>
5 #include <unistd.h>
6 #if HAVE_LINUX_MEMFD_H
7 #include <linux/memfd.h>
8 #endif
9 #include <stdio.h>
10 #include <sys/prctl.h>
11
12 #include "alloc-util.h"
13 #include "errno-util.h"
14 #include "fd-util.h"
15 #include "macro.h"
16 #include "memfd-util.h"
17 #include "missing_fcntl.h"
18 #include "missing_mman.h"
19 #include "missing_syscall.h"
20 #include "string-util.h"
21 #include "utf8.h"
22
memfd_new(const char * name)23 int memfd_new(const char *name) {
24 _cleanup_free_ char *g = NULL;
25
26 if (!name) {
27 char pr[17] = {};
28
29 /* If no name is specified we generate one. We include
30 * a hint indicating our library implementation, and
31 * add the thread name to it */
32
33 assert_se(prctl(PR_GET_NAME, (unsigned long) pr) >= 0);
34
35 if (isempty(pr))
36 name = "sd";
37 else {
38 _cleanup_free_ char *e = NULL;
39
40 e = utf8_escape_invalid(pr);
41 if (!e)
42 return -ENOMEM;
43
44 g = strjoin("sd-", e);
45 if (!g)
46 return -ENOMEM;
47
48 name = g;
49 }
50 }
51
52 return RET_NERRNO(memfd_create(name, MFD_ALLOW_SEALING | MFD_CLOEXEC));
53 }
54
memfd_map(int fd,uint64_t offset,size_t size,void ** p)55 int memfd_map(int fd, uint64_t offset, size_t size, void **p) {
56 void *q;
57 int sealed;
58
59 assert(fd >= 0);
60 assert(size > 0);
61 assert(p);
62
63 sealed = memfd_get_sealed(fd);
64 if (sealed < 0)
65 return sealed;
66
67 if (sealed)
68 q = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, offset);
69 else
70 q = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset);
71 if (q == MAP_FAILED)
72 return -errno;
73
74 *p = q;
75 return 0;
76 }
77
memfd_set_sealed(int fd)78 int memfd_set_sealed(int fd) {
79 assert(fd >= 0);
80
81 return RET_NERRNO(fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE | F_SEAL_SEAL));
82 }
83
memfd_get_sealed(int fd)84 int memfd_get_sealed(int fd) {
85 int r;
86
87 assert(fd >= 0);
88
89 r = fcntl(fd, F_GET_SEALS);
90 if (r < 0)
91 return -errno;
92
93 return r == (F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE | F_SEAL_SEAL);
94 }
95
memfd_get_size(int fd,uint64_t * sz)96 int memfd_get_size(int fd, uint64_t *sz) {
97 struct stat stat;
98
99 assert(fd >= 0);
100 assert(sz);
101
102 if (fstat(fd, &stat) < 0)
103 return -errno;
104
105 *sz = stat.st_size;
106 return 0;
107 }
108
memfd_set_size(int fd,uint64_t sz)109 int memfd_set_size(int fd, uint64_t sz) {
110 assert(fd >= 0);
111
112 return RET_NERRNO(ftruncate(fd, sz));
113 }
114
memfd_new_and_map(const char * name,size_t sz,void ** p)115 int memfd_new_and_map(const char *name, size_t sz, void **p) {
116 _cleanup_close_ int fd = -1;
117 int r;
118
119 assert(sz > 0);
120 assert(p);
121
122 fd = memfd_new(name);
123 if (fd < 0)
124 return fd;
125
126 r = memfd_set_size(fd, sz);
127 if (r < 0)
128 return r;
129
130 r = memfd_map(fd, 0, sz, p);
131 if (r < 0)
132 return r;
133
134 return TAKE_FD(fd);
135 }
136