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 */
8 * \brief Drop privileges from the current process.
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"
18 #ifdef HAVE_SYS_MMAN_H
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!
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.
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.
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. */
43 tor_disable_debugger_attach(void)
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) ... || ... */
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
62 log_debug(LD_CONFIG
,"Debugger attachment disabled for "
63 "unprivileged users.");
66 log_warn(LD_CONFIG
, "Unable to disable debugger attaching: %s",
69 #endif /* defined(TRIED_TO_DISABLE) */
70 #undef TRIED_TO_DISABLE
74 #if defined(HAVE_MLOCKALL) && HAVE_DECL_MLOCKALL && defined(RLIMIT_MEMLOCK)
75 #define HAVE_UNIX_MLOCKALL
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.
84 tor_set_max_memlock(void)
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
93 /* RLIM_INFINITY is -1 on some platforms. */
94 limit
.rlim_cur
= RLIM_INFINITY
;
95 limit
.rlim_max
= RLIM_INFINITY
;
97 if (setrlimit(RLIMIT_MEMLOCK
, &limit
) == -1) {
99 log_warn(LD_GENERAL
, "You appear to lack permissions to change memory "
100 "limits. Are you root?");
102 log_warn(LD_GENERAL
, "Unable to raise RLIMIT_MEMLOCK: %s",
109 #endif /* defined(HAVE_UNIX_MLOCKALL) */
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.
119 static int memory_lock_attempted
= 0;
121 if (memory_lock_attempted
) {
125 memory_lock_attempted
= 1;
128 * Future consideration for Windows may be VirtualLock
129 * VirtualLock appears to implement mlock() but not mlockall()
131 * https://msdn.microsoft.com/en-us/library/aa366895(VS.85).aspx
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.");
139 if (mlockall(MCL_CURRENT
|MCL_FUTURE
) == 0) {
140 log_info(LD_GENERAL
, "Insecure OS paging is effectively disabled.");
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 "
147 } else if (errno
== EPERM
) {
148 log_notice(LD_GENERAL
, "It appears that you lack the permissions to "
149 "lock memory. Are you root?");
151 log_notice(LD_GENERAL
, "Unable to lock all current and future memory "
152 "pages: %s", strerror(errno
));
155 #else /* !defined(HAVE_UNIX_MLOCKALL) */
156 log_warn(LD_GENERAL
, "Unable to lock memory pages. mlockall() unsupported?");
158 #endif /* defined(HAVE_UNIX_MLOCKALL) */
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_ */
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.
170 * If the limit is below the reserved file descriptor value (ULIMIT_BUFFER),
171 * return -1 and <b>max_out</b> is untouched.
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.
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
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.*/
183 set_max_file_descriptors(rlim_t limit
, int *max_out
)
185 if (limit
< ULIMIT_BUFFER
) {
187 "ConnLimit must be at least %d. Failing.", ULIMIT_BUFFER
);
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;
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
) {
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
);
216 limit
= MAX_CONNECTIONS
;
217 #else /* defined(HAVE_GETRLIMIT) */
220 if (getrlimit(RLIMIT_NOFILE
, &rlim
) != 0) {
221 log_warn(LD_NET
, "Could not get maximum number of file descriptors: %s",
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
);
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
);
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
;
242 if (setrlimit(RLIMIT_NOFILE
, &rlim
) != 0) {
244 const int setrlimit_errno
= errno
;
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 "
256 (unsigned long)try_limit
, (unsigned long)OPEN_MAX
,
257 (unsigned long)limit
);
259 log_info(LD_CONFIG
, "Dropped connection limit to %lu based on "
260 "OPEN_MAX (%lu); Apparently, %lu was too high and rlimit "
262 (unsigned long)try_limit
, (unsigned long)OPEN_MAX
,
263 (unsigned long)rlim
.rlim_max
);
268 #endif /* defined(OPEN_MAX) */
270 log_warn(LD_CONFIG
,"Couldn't set maximum number of file descriptors: %s",
271 strerror(setrlimit_errno
));
274 /* leave some overhead for logs, etc, */
275 limit
= rlim
.rlim_cur
;
276 #endif /* !defined(HAVE_GETRLIMIT) */
281 *max_out
= (int)limit
- ULIMIT_BUFFER
;
282 set_max_sockets(*max_out
);