tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

map_anon.c (7439B)


      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 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
    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
    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 *
    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
    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 }