Line data Source code
1 : /* Copyright (c) 2003-2004, Roger Dingledine
2 : * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
3 : * Copyright (c) 2007-2021, The Tor Project, Inc. */
4 : /* See LICENSE for licensing information */
5 :
6 : /**
7 : * \file map_anon.c
8 : * \brief Manage anonymous mappings.
9 : **/
10 :
11 : #include "orconfig.h"
12 : #include "lib/malloc/map_anon.h"
13 : #include "lib/malloc/malloc.h"
14 : #include "lib/err/torerr.h"
15 :
16 : #ifdef HAVE_SYS_MMAN_H
17 : #include <sys/mman.h>
18 : #endif
19 : #ifdef HAVE_SYS_TYPES_H
20 : #include <sys/types.h>
21 : #endif
22 : #ifdef HAVE_MACH_VM_INHERIT_H
23 : #include <mach/vm_inherit.h>
24 : #endif
25 :
26 : #ifdef _WIN32
27 : #include <windows.h>
28 : #endif
29 :
30 : #include <string.h>
31 : #include <errno.h>
32 :
33 : /**
34 : * Macro to get the high bytes of a size_t, if there are high bytes.
35 : * Windows needs this; other operating systems define a size_t that does
36 : * what it should.
37 : */
38 : #if SIZEOF_SIZE_T > 4
39 : #define HIGH_SIZE_T_BYTES(sz) ((sz) >> 32)
40 : #else
41 : #define HIGH_SIZE_T_BYTES(sz) (0)
42 : #endif
43 :
44 : /* Here we define a MINHERIT macro that is minherit() or madvise(), depending
45 : * on what we actually want.
46 : *
47 : * If there's a flag that sets pages to zero after fork, we define FLAG_ZERO
48 : * to be that flag. If there's a flag unmaps pages after fork, we define
49 : * FLAG_NOINHERIT to be that flag.
50 : */
51 : #if defined(HAVE_MINHERIT)
52 : #define MINHERIT minherit
53 :
54 : #ifdef INHERIT_ZERO
55 : #define FLAG_ZERO INHERIT_ZERO
56 : #elif defined(MAP_INHERIT_ZERO)
57 : #define FLAG_ZERO MAP_INHERIT_ZERO
58 : #endif
59 : #ifdef INHERIT_NONE
60 : #define FLAG_NOINHERIT INHERIT_NONE
61 : #elif defined(VM_INHERIT_NONE)
62 : #define FLAG_NOINHERIT VM_INHERIT_NONE
63 : #elif defined(MAP_INHERIT_NONE)
64 : #define FLAG_NOINHERIT MAP_INHERIT_NONE
65 : #endif /* defined(INHERIT_NONE) || ... */
66 :
67 : #elif defined(HAVE_MADVISE)
68 :
69 : #define MINHERIT madvise
70 :
71 : #ifdef MADV_WIPEONFORK
72 : #define FLAG_ZERO MADV_WIPEONFORK
73 : #endif
74 : #ifdef MADV_DONTFORK
75 : #define FLAG_NOINHERIT MADV_DONTFORK
76 : #endif
77 :
78 : #endif /* defined(HAVE_MINHERIT) || ... */
79 :
80 : #if defined(HAVE_MINHERIT) && !defined(FLAG_ZERO) && !defined(FLAG_NOINHERIT)
81 : #warning "minherit() is defined, but FLAG_ZERO/NOINHERIT are not."
82 : #warning "This is probably a bug in Tor's support for this platform."
83 : #endif
84 :
85 : /**
86 : * Helper: try to prevent the <b>sz</b> bytes at <b>mem</b> from being swapped
87 : * to disk. Return 0 on success or if the facility is not available on this
88 : * OS; return -1 on failure.
89 : */
90 : static int
91 171 : lock_mem(void *mem, size_t sz)
92 : {
93 : #ifdef _WIN32
94 : return VirtualLock(mem, sz) ? 0 : -1;
95 : #elif defined(HAVE_MLOCK)
96 : return mlock(mem, sz);
97 : #else
98 171 : (void) mem;
99 171 : (void) sz;
100 :
101 171 : return 0;
102 : #endif /* defined(_WIN32) || ... */
103 : }
104 :
105 : /**
106 : * Helper: try to prevent the <b>sz</b> bytes at <b>mem</b> from appearing in
107 : * a core dump. Return 0 on success or if the facility is not available on
108 : * this OS; return -1 on failure.
109 : */
110 : static int
111 171 : nodump_mem(void *mem, size_t sz)
112 : {
113 : #if defined(MADV_DONTDUMP)
114 171 : int rv = madvise(mem, sz, MADV_DONTDUMP);
115 171 : if (rv == 0) {
116 : return 0;
117 0 : } else if (errno == ENOSYS || errno == EINVAL) {
118 : return 0; // syscall not supported, or flag not supported.
119 : } else {
120 0 : tor_log_err_sigsafe("Unexpected error from madvise: ",
121 : strerror(errno),
122 : NULL);
123 0 : return -1;
124 : }
125 : #else /* !defined(MADV_DONTDUMP) */
126 : (void) mem;
127 : (void) sz;
128 : return 0;
129 : #endif /* defined(MADV_DONTDUMP) */
130 : }
131 :
132 : /**
133 : * Helper: try to prevent the <b>sz</b> bytes at <b>mem</b> from being
134 : * accessible in child processes -- ideally by having them set to 0 after a
135 : * fork, and if that doesn't work, by having them unmapped after a fork.
136 : * Return 0 on success or if the facility is not available on this OS; return
137 : * -1 on failure.
138 : *
139 : * If we successfully make the memory uninheritable, adjust the value of
140 : * *<b>inherit_result_out</b>.
141 : */
142 : static int
143 172 : noinherit_mem(void *mem, size_t sz, inherit_res_t *inherit_result_out)
144 : {
145 : #ifdef FLAG_ZERO
146 172 : int r = MINHERIT(mem, sz, FLAG_ZERO);
147 172 : if (r == 0) {
148 172 : *inherit_result_out = INHERIT_RES_ZERO;
149 172 : return 0;
150 : }
151 : #endif /* defined(FLAG_ZERO) */
152 :
153 : #ifdef FLAG_NOINHERIT
154 0 : int r2 = MINHERIT(mem, sz, FLAG_NOINHERIT);
155 0 : if (r2 == 0) {
156 0 : *inherit_result_out = INHERIT_RES_DROP;
157 0 : return 0;
158 : }
159 : #endif /* defined(FLAG_NOINHERIT) */
160 :
161 : #if defined(FLAG_ZERO) || defined(FLAG_NOINHERIT)
162 : /* At least one operation was tried, and neither succeeded. */
163 :
164 0 : if (errno == ENOSYS || errno == EINVAL) {
165 : /* Syscall not supported, or flag not supported. */
166 : return 0;
167 : } else {
168 0 : tor_log_err_sigsafe("Unexpected error from minherit: ",
169 : strerror(errno),
170 : NULL);
171 0 : return -1;
172 : }
173 : #else /* !(defined(FLAG_ZERO) || defined(FLAG_NOINHERIT)) */
174 : (void)inherit_result_out;
175 : (void)mem;
176 : (void)sz;
177 : return 0;
178 : #endif /* defined(FLAG_ZERO) || defined(FLAG_NOINHERIT) */
179 : }
180 :
181 : /**
182 : * Return a new anonymous memory mapping that holds <b>sz</b> bytes.
183 : *
184 : * Memory mappings are unlike the results from malloc() in that they are
185 : * handled separately by the operating system, and as such can have different
186 : * kernel-level flags set on them.
187 : *
188 : * The "flags" argument may be zero or more of ANONMAP_PRIVATE and
189 : * ANONMAP_NOINHERIT.
190 : *
191 : * Memory returned from this function must be released with
192 : * tor_munmap_anonymous().
193 : *
194 : * If <b>inherit_result_out</b> is non-NULL, set it to one of
195 : * INHERIT_RES_KEEP, INHERIT_RES_DROP, or INHERIT_RES_ZERO, depending on the
196 : * properties of the returned memory.
197 : *
198 : * [Note: OS people use the word "anonymous" here to mean that the memory
199 : * isn't associated with any file. This has *nothing* to do with the kind of
200 : * anonymity that Tor is trying to provide.]
201 : */
202 : void *
203 174 : tor_mmap_anonymous(size_t sz, unsigned flags,
204 : inherit_res_t *inherit_result_out)
205 : {
206 174 : void *ptr;
207 174 : inherit_res_t itmp=0;
208 174 : if (inherit_result_out == NULL) {
209 0 : inherit_result_out = &itmp;
210 : }
211 174 : *inherit_result_out = INHERIT_RES_KEEP;
212 :
213 : #if defined(_WIN32)
214 : HANDLE mapping = CreateFileMapping(INVALID_HANDLE_VALUE,
215 : NULL, /*attributes*/
216 : PAGE_READWRITE,
217 : HIGH_SIZE_T_BYTES(sz),
218 : sz & 0xffffffff,
219 : NULL /* name */);
220 : raw_assert(mapping != NULL);
221 : ptr = MapViewOfFile(mapping, FILE_MAP_WRITE,
222 : 0, 0, /* Offset */
223 : 0 /* Extend to end of mapping */);
224 : raw_assert(ptr);
225 : CloseHandle(mapping); /* mapped view holds a reference */
226 : #elif defined(HAVE_SYS_MMAN_H)
227 174 : ptr = mmap(NULL, sz,
228 : PROT_READ|PROT_WRITE,
229 : MAP_ANON|MAP_PRIVATE,
230 : -1, 0);
231 174 : raw_assert(ptr != MAP_FAILED);
232 174 : raw_assert(ptr != NULL);
233 : #else
234 : ptr = tor_malloc_zero(sz);
235 : #endif /* defined(_WIN32) || ... */
236 :
237 174 : if (flags & ANONMAP_PRIVATE) {
238 171 : int lock_result = lock_mem(ptr, sz);
239 171 : raw_assert(lock_result == 0);
240 171 : int nodump_result = nodump_mem(ptr, sz);
241 171 : raw_assert(nodump_result == 0);
242 : }
243 :
244 174 : if (flags & ANONMAP_NOINHERIT) {
245 172 : int noinherit_result = noinherit_mem(ptr, sz, inherit_result_out);
246 172 : raw_assert(noinherit_result == 0);
247 : }
248 :
249 174 : return ptr;
250 : }
251 :
252 : /**
253 : * Release <b>sz</b> bytes of memory that were previously mapped at
254 : * <b>mapping</b> by tor_mmap_anonymous().
255 : **/
256 : void
257 32 : tor_munmap_anonymous(void *mapping, size_t sz)
258 : {
259 32 : if (!mapping)
260 : return;
261 :
262 : #if defined(_WIN32)
263 : (void)sz;
264 : UnmapViewOfFile(mapping);
265 : #elif defined(HAVE_SYS_MMAN_H)
266 31 : munmap(mapping, sz);
267 : #else
268 : (void)sz;
269 : tor_free(mapping);
270 : #endif /* defined(_WIN32) || ... */
271 : }
|