Merge branch 'maint-0.4.5' into release-0.4.5
[tor.git] / src / lib / malloc / map_anon.c
blob628966012a2f9bdf0a53baa008cbfc9f432cf7bb
1 /* Copyright (c) 2003-2004, Roger Dingledine
2 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
3 * Copyright (c) 2007-2020, The Tor Project, Inc. */
4 /* See LICENSE for licensing information */
6 /**
7 * \file map_anon.c
8 * \brief Manage anonymous mappings.
9 **/
11 #include "orconfig.h"
12 #include "lib/malloc/map_anon.h"
13 #include "lib/malloc/malloc.h"
14 #include "lib/err/torerr.h"
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
26 #ifdef _WIN32
27 #include <windows.h>
28 #endif
30 #include <string.h>
31 #include <errno.h>
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.
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
44 /* Here we define a MINHERIT macro that is minherit() or madvise(), depending
45 * on what we actually want.
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.
51 #if defined(HAVE_MINHERIT)
52 #define MINHERIT minherit
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) || ... */
67 #elif defined(HAVE_MADVISE)
69 #define MINHERIT madvise
71 #ifdef MADV_WIPEONFORK
72 #define FLAG_ZERO MADV_WIPEONFORK
73 #endif
74 #ifdef MADV_DONTFORK
75 #define FLAG_NOINHERIT MADV_DONTFORK
76 #endif
78 #endif /* defined(HAVE_MINHERIT) || ... */
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
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.
90 static int
91 lock_mem(void *mem, size_t sz)
93 #ifdef _WIN32
94 return VirtualLock(mem, sz) ? 0 : -1;
95 #elif defined(HAVE_MLOCK)
96 return mlock(mem, sz);
97 #else
98 (void) mem;
99 (void) sz;
101 return 0;
102 #endif /* defined(_WIN32) || ... */
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.
110 static int
111 nodump_mem(void *mem, size_t sz)
113 #if defined(MADV_DONTDUMP)
114 int rv = madvise(mem, sz, MADV_DONTDUMP);
115 if (rv == 0) {
116 return 0;
117 } else if (errno == ENOSYS || errno == EINVAL) {
118 return 0; // syscall not supported, or flag not supported.
119 } else {
120 tor_log_err_sigsafe("Unexpected error from madvise: ",
121 strerror(errno),
122 NULL);
123 return -1;
125 #else /* !defined(MADV_DONTDUMP) */
126 (void) mem;
127 (void) sz;
128 return 0;
129 #endif /* defined(MADV_DONTDUMP) */
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.
139 * If we successfully make the memory uninheritable, adjust the value of
140 * *<b>inherit_result_out</b>.
142 static int
143 noinherit_mem(void *mem, size_t sz, inherit_res_t *inherit_result_out)
145 #ifdef FLAG_ZERO
146 int r = MINHERIT(mem, sz, FLAG_ZERO);
147 if (r == 0) {
148 *inherit_result_out = INHERIT_RES_ZERO;
149 return 0;
151 #endif /* defined(FLAG_ZERO) */
153 #ifdef FLAG_NOINHERIT
154 int r2 = MINHERIT(mem, sz, FLAG_NOINHERIT);
155 if (r2 == 0) {
156 *inherit_result_out = INHERIT_RES_DROP;
157 return 0;
159 #endif /* defined(FLAG_NOINHERIT) */
161 #if defined(FLAG_ZERO) || defined(FLAG_NOINHERIT)
162 /* At least one operation was tried, and neither succeeded. */
164 if (errno == ENOSYS || errno == EINVAL) {
165 /* Syscall not supported, or flag not supported. */
166 return 0;
167 } else {
168 tor_log_err_sigsafe("Unexpected error from minherit: ",
169 strerror(errno),
170 NULL);
171 return -1;
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) */
182 * Return a new anonymous memory mapping that holds <b>sz</b> bytes.
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.
188 * The "flags" argument may be zero or more of ANONMAP_PRIVATE and
189 * ANONMAP_NOINHERIT.
191 * Memory returned from this function must be released with
192 * tor_munmap_anonymous().
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.
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.]
202 void *
203 tor_mmap_anonymous(size_t sz, unsigned flags,
204 inherit_res_t *inherit_result_out)
206 void *ptr;
207 inherit_res_t itmp=0;
208 if (inherit_result_out == NULL) {
209 inherit_result_out = &itmp;
211 *inherit_result_out = INHERIT_RES_KEEP;
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 ptr = mmap(NULL, sz,
228 PROT_READ|PROT_WRITE,
229 MAP_ANON|MAP_PRIVATE,
230 -1, 0);
231 raw_assert(ptr != MAP_FAILED);
232 raw_assert(ptr != NULL);
233 #else
234 ptr = tor_malloc_zero(sz);
235 #endif /* defined(_WIN32) || ... */
237 if (flags & ANONMAP_PRIVATE) {
238 int lock_result = lock_mem(ptr, sz);
239 raw_assert(lock_result == 0);
240 int nodump_result = nodump_mem(ptr, sz);
241 raw_assert(nodump_result == 0);
244 if (flags & ANONMAP_NOINHERIT) {
245 int noinherit_result = noinherit_mem(ptr, sz, inherit_result_out);
246 raw_assert(noinherit_result == 0);
249 return ptr;
253 * Release <b>sz</b> bytes of memory that were previously mapped at
254 * <b>mapping</b> by tor_mmap_anonymous().
256 void
257 tor_munmap_anonymous(void *mapping, size_t sz)
259 if (!mapping)
260 return;
262 #if defined(_WIN32)
263 (void)sz;
264 UnmapViewOfFile(mapping);
265 #elif defined(HAVE_SYS_MMAN_H)
266 munmap(mapping, sz);
267 #else
268 (void)sz;
269 tor_free(mapping);
270 #endif /* defined(_WIN32) || ... */