diff options
-rw-r--r-- | ChangeLog | 10 | ||||
-rw-r--r-- | doc/tor.1.in | 13 | ||||
-rw-r--r-- | src/common/compat.c | 99 | ||||
-rw-r--r-- | src/common/compat.h | 2 | ||||
-rw-r--r-- | src/config/torrc.complete.in | 3 | ||||
-rw-r--r-- | src/or/config.c | 18 | ||||
-rw-r--r-- | src/or/or.h | 3 |
7 files changed, 148 insertions, 0 deletions
@@ -14,6 +14,16 @@ Changes in version 0.2.2.6-alpha - 2009-10-?? algorithms for signatures and resource selection. Newer formats are signed with SHA256, with a possibility for moving to a better hash algorithm in the future. + - New DisableAllSwap option. If set to 1, Tor will attempt to lock all + current and future memory pages. On supported platforms, this should + effectively disable any and all attempts to page out memory. Under the + hood, DisableAllSwap uses mlockall() on unix-like platforms. Windows is + currently unsupported. We believe that this feature works on modern + Gnu/Linux distributions. Mac OS X appears to be broken by design. On + reasonable *BSD systems it should also be supported but this is untested. + This option requires that you start your Tor as root. If you use + DisableAllSwap, please consider using the User option to properly reduce + the privileges of your Tor. o Code simplifications and refactorings: - Numerous changes, bugfixes, and workarounds from Nathan Freitas diff --git a/doc/tor.1.in b/doc/tor.1.in index 739b889fb..1a71026aa 100644 --- a/doc/tor.1.in +++ b/doc/tor.1.in @@ -234,6 +234,19 @@ the default hidden service authorities, but not the directory or bridge authorities. .LP .TP +\fBDisableAllSwap \fR\fB0\fR|\fB1\fR\fP +If set to 1, Tor will attempt to lock all current and future memory pages. +On supported platforms, this should effectively disable any and all attempts +to page out memory. Under the hood, DisableAllSwap uses mlockall() on unix-like +platforms. Windows is currently unsupported. We believe that this feature works +on modern Gnu/Linux distributions. Mac OS X appears to be broken by design. On +reasonable *BSD systems it should also be supported but this is untested. This +option requires that you start your Tor as root. If you use DisableAllSwap, +please consider using the User option to properly reduce the privileges of +your Tor. +(Default: 0) +.LP +.TP \fBFetchDirInfoEarly \fR\fB0\fR|\fB1\fR\fP If set to 1, Tor will always fetch directory information like other directory caches, even if you don't meet the normal criteria for diff --git a/src/common/compat.c b/src/common/compat.c index e1a275de1..9e5dca352 100644 --- a/src/common/compat.c +++ b/src/common/compat.c @@ -2204,6 +2204,105 @@ tor_threads_init(void) } #endif +#ifdef HAVE_SYS_MMAN_H +/** Attempt to raise the current and max rlimit to infinity for our process. + * This only needs to be done once and can probably only be done when we have + * not already dropped privileges. + */ +static int +tor_set_max_memlock(void) +{ + /* Future consideration for Windows is probably SetProcessWorkingSetSize + * This is similar to setting the memory rlimit of RLIMIT_MEMLOCK + * http://msdn.microsoft.com/en-us/library/ms686234(VS.85).aspx + */ + + struct rlimit limit; + int ret; + + /* Do we want to report current limits first? This is not really needed. */ + ret = getrlimit(RLIMIT_MEMLOCK, &limit); + if (ret == -1) { + log_warn(LD_GENERAL, "Could not get RLIMIT_MEMLOCK: %s", strerror(errno)); + return -1; + } + + /* RLIM_INFINITY is -1 on some platforms. */ + limit.rlim_cur = RLIM_INFINITY; + limit.rlim_max = RLIM_INFINITY; + + ret = setrlimit(RLIMIT_MEMLOCK, &limit); + if (ret == -1) { + if (errno == EPERM) { + log_warn(LD_GENERAL, "You appear to lack permissions to change memory " + "limits. Are you root?"); + log_warn(LD_GENERAL, "Unable to raise RLIMIT_MEMLOCK: %s", + strerror(errno)); + } else { + log_warn(LD_GENERAL, "Could not raise RLIMIT_MEMLOCK: %s", + strerror(errno)); + } + return -1; + } + + return 0; +} +#endif + +/** Attempt to lock all current and all future memory pages. + * This should only be called once and while we're privileged. + * Like mlockall() we return 0 when we're successful and -1 when we're not. + * Unlike mlockall() we return 1 if we've already attempted to lock memory. + */ +int +tor_mlockall(void) +{ + static int memory_lock_attempted = 0; + int ret; + + if (memory_lock_attempted) { + return 1; + } + + memory_lock_attempted = 1; + + /* + * Future consideration for Windows may be VirtualLock + * VirtualLock appears to implement mlock() but not mlockall() + * + * http://msdn.microsoft.com/en-us/library/aa366895(VS.85).aspx + */ + +#ifdef HAVE_SYS_MMAN_H + ret = tor_set_max_memlock(); + if (ret == 0) { + /* Perhaps we only want to log this if we're in a verbose mode? */ + log_notice(LD_GENERAL, "RLIMIT_MEMLOCK is now set to RLIM_INFINITY."); + } + + ret = mlockall(MCL_CURRENT|MCL_FUTURE); + if (ret == 0) { + log_notice(LD_GENERAL, "Insecure OS paging is effectively disabled."); + return 0; + } else { + if (errno == ENOSYS) { + /* Apple - it's 2009! I'm looking at you. Grrr. */ + log_notice(LD_GENERAL, "It appears that mlockall() is not available on " + "your platform."); + } else if (errno == EPERM) { + log_notice(LD_GENERAL, "It appears that you lack the permissions to " + "lock memory. Are you root?"); + } + log_notice(LD_GENERAL, "Unable to lock all current and future memory " + "pages: %s", strerror(errno)); + return -1; + } +#else + log_warn(LD_GENERAL, "Unable to lock memory pages. mlockall() unsupported?"); + return -1; +#endif +} + /** Identity of the "main" thread */ static unsigned long main_thread_id = -1; diff --git a/src/common/compat.h b/src/common/compat.h index edd09d868..554ae8919 100644 --- a/src/common/compat.h +++ b/src/common/compat.h @@ -509,6 +509,8 @@ typedef struct tor_mutex_t { #endif } tor_mutex_t; +int tor_mlockall(void); + #ifdef TOR_IS_MULTITHREADED tor_mutex_t *tor_mutex_new(void); void tor_mutex_init(tor_mutex_t *m); diff --git a/src/config/torrc.complete.in b/src/config/torrc.complete.in index 2fbf494e5..6dbec2fbf 100644 --- a/src/config/torrc.complete.in +++ b/src/config/torrc.complete.in @@ -79,6 +79,9 @@ #DirServer moria2 v1 18.244.0.114:80 719B E45D E224 B607 C537 07D0 E214 3E2D 423E 74CF #DirServer tor26 v1 86.59.21.38:80 847B 1F85 0344 D787 6491 A548 92F9 0493 4E4E B85D +## Attempt to lock current and future memory pages and effectively disable swap +# DisableAllSwap 0|1 + ## On startup, setgid to this user. #Group GID diff --git a/src/or/config.c b/src/or/config.c index 5a0ced29d..b6a52a85d 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -195,6 +195,7 @@ static config_var_t _option_vars[] = { OBSOLETE("DirRecordUsageSaveInterval"), V(DirReqStatistics, BOOL, "0"), VAR("DirServer", LINELIST, DirServers, NULL), + V(DisableAllSwap, BOOL, "0"), V(DNSPort, UINT, "0"), V(DNSListenAddress, LINELIST, NULL), V(DownloadExtraInfo, BOOL, "0"), @@ -456,6 +457,8 @@ static config_var_description_t options_description[] = { { "DirServer", "Tor only trusts directories signed with one of these " "servers' keys. Used to override the standard list of directory " "authorities." }, + { "DisableAllSwap", "Tor will attempt a simple memory lock that " + "will prevent leaking of all information in memory to the swap file." }, /* { "FastFirstHopPK", "" }, */ /* FetchServerDescriptors, FetchHidServDescriptors, * FetchUselessDescriptors */ @@ -1115,6 +1118,15 @@ options_act_reversible(or_options_t *old_options, char **msg) } #endif + /* Attempt to lock all current and future memory with mlockall() only once */ + if (options->DisableAllSwap) { + if (tor_mlockall() == -1) { + *msg = tor_strdup("DisableAllSwap failure. Do you have proper " + "permissions?"); + goto done; + } + } + /* Setuid/setgid as appropriate */ if (options->User) { if (switch_id(options->User) != 0) { @@ -3834,6 +3846,12 @@ options_transition_allowed(or_options_t *old, or_options_t *new_val, return -1; } + if (old->DisableAllSwap != new_val->DisableAllSwap) { + *msg = tor_strdup("While Tor is running, changing DisableAllSwap " + "is not allowed."); + return -1; + } + return 0; } diff --git a/src/or/or.h b/src/or/or.h index bf415d839..767ad9572 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -2287,6 +2287,9 @@ typedef struct { * stop building circuits? */ int StrictEntryNodes; /**< Boolean: When none of our EntryNodes are up, do we * stop building circuits? */ + int DisableAllSwap; /**< Boolean: Attempt to call mlockall() on our + * process for all current and future memory. */ + routerset_t *ExcludeNodes;/**< Structure containing nicknames, digests, * country codes and IP address patterns of ORs * not to use in circuits. */ |