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 }