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