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
lock_mem(void * mem,size_t sz)91 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   (void) mem;
99   (void) sz;
100 
101   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
nodump_mem(void * mem,size_t sz)111 nodump_mem(void *mem, size_t sz)
112 {
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;
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
noinherit_mem(void * mem,size_t sz,inherit_res_t * inherit_result_out)143 noinherit_mem(void *mem, size_t sz, inherit_res_t *inherit_result_out)
144 {
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;
150   }
151 #endif /* defined(FLAG_ZERO) */
152 
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;
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   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;
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 *
tor_mmap_anonymous(size_t sz,unsigned flags,inherit_res_t * inherit_result_out)203 tor_mmap_anonymous(size_t sz, unsigned flags,
204                    inherit_res_t *inherit_result_out)
205 {
206   void *ptr;
207   inherit_res_t itmp=0;
208   if (inherit_result_out == NULL) {
209     inherit_result_out = &itmp;
210   }
211   *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   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) || ... */
236 
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);
242   }
243 
244   if (flags & ANONMAP_NOINHERIT) {
245     int noinherit_result = noinherit_mem(ptr, sz, inherit_result_out);
246     raw_assert(noinherit_result == 0);
247   }
248 
249   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
tor_munmap_anonymous(void * mapping,size_t sz)257 tor_munmap_anonymous(void *mapping, size_t sz)
258 {
259   if (!mapping)
260     return;
261 
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) || ... */
271 }
272