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