tor

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

restrict.c (10174B)


      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 restrict.c
      8 * \brief Drop privileges from the current process.
      9 **/
     10 
     11 #include "orconfig.h"
     12 #include "lib/process/restrict.h"
     13 #include "lib/intmath/cmp.h"
     14 #include "lib/log/log.h"
     15 #include "lib/log/util_bug.h"
     16 #include "lib/net/socket.h"
     17 
     18 #ifdef HAVE_SYS_MMAN_H
     19 #include <sys/mman.h>
     20 #endif
     21 #include <errno.h>
     22 #include <stdlib.h>
     23 #include <string.h>
     24 
     25 /* We only use the linux prctl for now. There is no Win32 support; this may
     26 * also work on various BSD systems and Mac OS X - send testing feedback!
     27 *
     28 * On recent Gnu/Linux kernels it is possible to create a system-wide policy
     29 * that will prevent non-root processes from attaching to other processes
     30 * unless they are the parent process; thus gdb can attach to programs that
     31 * they execute but they cannot attach to other processes running as the same
     32 * user. The system wide policy may be set with the sysctl
     33 * kernel.yama.ptrace_scope or by inspecting
     34 * /proc/sys/kernel/yama/ptrace_scope and it is 1 by default on Ubuntu 11.04.
     35 *
     36 * This ptrace scope will be ignored on Gnu/Linux for users with
     37 * CAP_SYS_PTRACE and so it is very likely that root will still be able to
     38 * attach to the Tor process.
     39 */
     40 /** Attempt to disable debugger attachment: return 1 on success, -1 on
     41 * failure, and 0 if we don't know how to try on this platform. */
     42 int
     43 tor_disable_debugger_attach(void)
     44 {
     45  int r = -1;
     46  log_debug(LD_CONFIG,
     47            "Attempting to disable debugger attachment to Tor for "
     48            "unprivileged users.");
     49 #if defined(__linux__) && defined(HAVE_SYS_PRCTL_H) \
     50  && defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE)
     51 #define TRIED_TO_DISABLE
     52  r = prctl(PR_SET_DUMPABLE, 0);
     53 #elif defined(__APPLE__) && defined(PT_DENY_ATTACH)
     54 #define TRIED_TO_ATTACH
     55  r = ptrace(PT_DENY_ATTACH, 0, 0, 0);
     56 #endif /* defined(__linux__) && defined(HAVE_SYS_PRCTL_H) ... || ... */
     57 
     58  // XXX: TODO - Mac OS X has dtrace and this may be disabled.
     59  // XXX: TODO - Windows probably has something similar
     60 #ifdef TRIED_TO_DISABLE
     61  if (r == 0) {
     62    log_debug(LD_CONFIG,"Debugger attachment disabled for "
     63              "unprivileged users.");
     64    return 1;
     65  } else {
     66    log_warn(LD_CONFIG, "Unable to disable debugger attaching: %s",
     67             strerror(errno));
     68  }
     69 #endif /* defined(TRIED_TO_DISABLE) */
     70 #undef TRIED_TO_DISABLE
     71  return r;
     72 }
     73 
     74 #if defined(HAVE_MLOCKALL) && HAVE_DECL_MLOCKALL && defined(RLIMIT_MEMLOCK)
     75 #define HAVE_UNIX_MLOCKALL
     76 #endif
     77 
     78 #ifdef HAVE_UNIX_MLOCKALL
     79 /** Attempt to raise the current and max rlimit to infinity for our process.
     80 * This only needs to be done once and can probably only be done when we have
     81 * not already dropped privileges.
     82 */
     83 static int
     84 tor_set_max_memlock(void)
     85 {
     86  /* Future consideration for Windows is probably SetProcessWorkingSetSize
     87   * This is similar to setting the memory rlimit of RLIMIT_MEMLOCK
     88   * https://msdn.microsoft.com/en-us/library/ms686234(VS.85).aspx
     89   */
     90 
     91  struct rlimit limit;
     92 
     93  /* RLIM_INFINITY is -1 on some platforms. */
     94  limit.rlim_cur = RLIM_INFINITY;
     95  limit.rlim_max = RLIM_INFINITY;
     96 
     97  if (setrlimit(RLIMIT_MEMLOCK, &limit) == -1) {
     98    if (errno == EPERM) {
     99      log_warn(LD_GENERAL, "You appear to lack permissions to change memory "
    100                           "limits. Are you root?");
    101    }
    102    log_warn(LD_GENERAL, "Unable to raise RLIMIT_MEMLOCK: %s",
    103             strerror(errno));
    104    return -1;
    105  }
    106 
    107  return 0;
    108 }
    109 #endif /* defined(HAVE_UNIX_MLOCKALL) */
    110 
    111 /** Attempt to lock all current and all future memory pages.
    112 * This should only be called once and while we're privileged.
    113 * Like mlockall() we return 0 when we're successful and -1 when we're not.
    114 * Unlike mlockall() we return 1 if we've already attempted to lock memory.
    115 */
    116 int
    117 tor_mlockall(void)
    118 {
    119  static int memory_lock_attempted = 0;
    120 
    121  if (memory_lock_attempted) {
    122    return 1;
    123  }
    124 
    125  memory_lock_attempted = 1;
    126 
    127  /*
    128   * Future consideration for Windows may be VirtualLock
    129   * VirtualLock appears to implement mlock() but not mlockall()
    130   *
    131   * https://msdn.microsoft.com/en-us/library/aa366895(VS.85).aspx
    132   */
    133 
    134 #ifdef HAVE_UNIX_MLOCKALL
    135  if (tor_set_max_memlock() == 0) {
    136    log_debug(LD_GENERAL, "RLIMIT_MEMLOCK is now set to RLIM_INFINITY.");
    137  }
    138 
    139  if (mlockall(MCL_CURRENT|MCL_FUTURE) == 0) {
    140    log_info(LD_GENERAL, "Insecure OS paging is effectively disabled.");
    141    return 0;
    142  } else {
    143    if (errno == ENOSYS) {
    144      /* Apple - it's 2009! I'm looking at you. Grrr. */
    145      log_notice(LD_GENERAL, "It appears that mlockall() is not available on "
    146                             "your platform.");
    147    } else if (errno == EPERM) {
    148      log_notice(LD_GENERAL, "It appears that you lack the permissions to "
    149                             "lock memory. Are you root?");
    150    }
    151    log_notice(LD_GENERAL, "Unable to lock all current and future memory "
    152                           "pages: %s", strerror(errno));
    153    return -1;
    154  }
    155 #else /* !defined(HAVE_UNIX_MLOCKALL) */
    156  log_warn(LD_GENERAL, "Unable to lock memory pages. mlockall() unsupported?");
    157  return -1;
    158 #endif /* defined(HAVE_UNIX_MLOCKALL) */
    159 }
    160 
    161 /** Number of extra file descriptors to keep in reserve beyond those that we
    162 * tell Tor it's allowed to use. */
    163 #define ULIMIT_BUFFER 32 /* keep 32 extra fd's beyond ConnLimit_ */
    164 
    165 /** Learn the maximum allowed number of file descriptors, and tell the
    166 * system we want to use up to that number. (Some systems have a low soft
    167 * limit, and let us set it higher.)  We compute this by finding the largest
    168 * number that we can use.
    169 *
    170 * If the limit is below the reserved file descriptor value (ULIMIT_BUFFER),
    171 * return -1 and <b>max_out</b> is untouched.
    172 *
    173 * If we can't find a number greater than or equal to <b>limit</b>, then we
    174 * fail by returning -1 and <b>max_out</b> is untouched.
    175 *
    176 * If we are unable to set the limit value because of setrlimit() failing,
    177 * return 0 and <b>max_out</b> is set to the current maximum value returned
    178 * by getrlimit().
    179 *
    180 * Otherwise: return 0, store the maximum we found inside <b>max_out</b>,
    181 * and call set_max_sockets() with that value as well.*/
    182 int
    183 set_max_file_descriptors(rlim_t limit, int *max_out)
    184 {
    185  if (limit < ULIMIT_BUFFER) {
    186    log_warn(LD_CONFIG,
    187             "ConnLimit must be at least %d. Failing.", ULIMIT_BUFFER);
    188    return -1;
    189  }
    190 
    191  /* Define some maximum connections values for systems where we cannot
    192   * automatically determine a limit. Re Cygwin, see
    193   * https://archives.seul.org/or/talk/Aug-2006/msg00210.html
    194   * For an iPhone, 9999 should work. For Windows and all other unknown
    195   * systems we use 15000 as the default. */
    196 #ifndef HAVE_GETRLIMIT
    197 #if defined(CYGWIN) || defined(__CYGWIN__)
    198  const char *platform = "Cygwin";
    199  const unsigned long MAX_CONNECTIONS = 3200;
    200 #elif defined(_WIN32)
    201  const char *platform = "Windows";
    202  const unsigned long MAX_CONNECTIONS = 15000;
    203 #else
    204  const char *platform = "unknown platforms with no getrlimit()";
    205  const unsigned long MAX_CONNECTIONS = 15000;
    206 #endif /* defined(CYGWIN) || defined(__CYGWIN__) || ... */
    207  log_fn(LOG_INFO, LD_NET,
    208         "This platform is missing getrlimit(). Proceeding.");
    209  if (limit > MAX_CONNECTIONS) {
    210    log_warn(LD_CONFIG,
    211             "We do not support more than %lu file descriptors "
    212             "on %s. Tried to raise to %lu.",
    213             (unsigned long)MAX_CONNECTIONS, platform, (unsigned long)limit);
    214    return -1;
    215  }
    216  limit = MAX_CONNECTIONS;
    217 #else /* defined(HAVE_GETRLIMIT) */
    218  struct rlimit rlim;
    219 
    220  if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) {
    221    log_warn(LD_NET, "Could not get maximum number of file descriptors: %s",
    222             strerror(errno));
    223    return -1;
    224  }
    225  if (rlim.rlim_max < limit) {
    226    log_warn(LD_CONFIG,"We need %lu file descriptors available, and we're "
    227             "limited to %lu. Please change your ulimit -n.",
    228             (unsigned long)limit, (unsigned long)rlim.rlim_max);
    229    return -1;
    230  }
    231 
    232  if (rlim.rlim_max > rlim.rlim_cur) {
    233    log_info(LD_NET,"Raising max file descriptors from %lu to %lu.",
    234             (unsigned long)rlim.rlim_cur, (unsigned long)rlim.rlim_max);
    235  }
    236  /* Set the current limit value so if the attempt to set the limit to the
    237   * max fails at least we'll have a valid value of maximum sockets. */
    238  *max_out = (int)rlim.rlim_cur - ULIMIT_BUFFER;
    239  set_max_sockets(*max_out);
    240  rlim.rlim_cur = rlim.rlim_max;
    241 
    242  if (setrlimit(RLIMIT_NOFILE, &rlim) != 0) {
    243    int couldnt_set = 1;
    244    const int setrlimit_errno = errno;
    245 #ifdef OPEN_MAX
    246    uint64_t try_limit = OPEN_MAX - ULIMIT_BUFFER;
    247    if (errno == EINVAL && try_limit < (uint64_t) rlim.rlim_cur) {
    248      /* On some platforms, OPEN_MAX is the real limit, and getrlimit() is
    249       * full of nasty lies.  I'm looking at you, OSX 10.5.... */
    250      rlim.rlim_cur = MIN((rlim_t) try_limit, rlim.rlim_cur);
    251      if (setrlimit(RLIMIT_NOFILE, &rlim) == 0) {
    252        if (rlim.rlim_cur < (rlim_t)limit) {
    253          log_warn(LD_CONFIG, "We are limited to %lu file descriptors by "
    254                   "OPEN_MAX (%lu), and ConnLimit is %lu.  Changing "
    255                   "ConnLimit; sorry.",
    256                   (unsigned long)try_limit, (unsigned long)OPEN_MAX,
    257                   (unsigned long)limit);
    258        } else {
    259          log_info(LD_CONFIG, "Dropped connection limit to %lu based on "
    260                   "OPEN_MAX (%lu); Apparently, %lu was too high and rlimit "
    261                   "lied to us.",
    262                   (unsigned long)try_limit, (unsigned long)OPEN_MAX,
    263                   (unsigned long)rlim.rlim_max);
    264        }
    265        couldnt_set = 0;
    266      }
    267    }
    268 #endif /* defined(OPEN_MAX) */
    269    if (couldnt_set) {
    270      log_warn(LD_CONFIG,"Couldn't set maximum number of file descriptors: %s",
    271               strerror(setrlimit_errno));
    272    }
    273  }
    274  /* leave some overhead for logs, etc, */
    275  limit = rlim.rlim_cur;
    276 #endif /* !defined(HAVE_GETRLIMIT) */
    277 
    278  if (limit > INT_MAX)
    279    limit = INT_MAX;
    280  tor_assert(max_out);
    281  *max_out = (int)limit - ULIMIT_BUFFER;
    282  set_max_sockets(*max_out);
    283 
    284  return 0;
    285 }