Tor  0.4.7.0-alpha-dev
restrict.c
Go to the documentation of this file.
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
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
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 and store the maximum we found inside <b>max_out</b>
181  * and set <b>max_sockets</b> 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__) || ... */
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 }
Macro definitions for MIN, MAX, and CLAMP.
Headers for log.c.
#define log_fn(severity, domain, args,...)
Definition: log.h:283
#define LD_NET
Definition: log.h:66
#define LD_GENERAL
Definition: log.h:62
#define LD_CONFIG
Definition: log.h:68
#define LOG_INFO
Definition: log.h:45
int set_max_file_descriptors(rlim_t limit, int *max_out)
Definition: restrict.c:183
#define ULIMIT_BUFFER
Definition: restrict.c:163
int tor_disable_debugger_attach(void)
Definition: restrict.c:43
int tor_mlockall(void)
Definition: restrict.c:117
Header for restrict.c.
void set_max_sockets(int n)
Definition: socket.c:105
Header for socket.c.
Macros to manage assertions, fatal and non-fatal.
#define tor_assert(expr)
Definition: util_bug.h:102