mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-20 02:09:24 +01:00
Implement DisableAllSwap to avoid putting secret info in page files.
This commit implements a new config option: 'DisableAllSwap' This option probably only works properly when Tor is started as root. We added two new functions: tor_mlockall() and tor_set_max_memlock(). tor_mlockall() attempts to mlock() all current and all future memory pages. For tor_mlockall() to work properly we set the process rlimits for memory to RLIM_INFINITY (and beyond) inside of tor_set_max_memlock(). We behave differently from mlockall() by only allowing tor_mlockall() to be called one single time. All other calls will result in a return code of 1. It is not possible to change DisableAllSwap while running. A sample configuration item was added to the torrc.complete.in config file. A new item in the man page for DisableAllSwap was added. Thanks to Moxie Marlinspike and Chris Palmer for their feedback on this patch. Please note that we make no guarantees about the quality of your OS and its mlock/mlockall implementation. It is possible that this will do nothing at all. It is also possible that you can ulimit the mlock properties of a given user such that root is not required. This has not been extensively tested and is unsupported. I have included some comments for possible ways we can handle this on win32.
This commit is contained in:
parent
56c2385157
commit
2aac39a779
10
ChangeLog
10
ChangeLog
@ -14,6 +14,16 @@ Changes in version 0.2.2.6-alpha - 2009-10-??
|
|||||||
algorithms for signatures and resource selection. Newer formats are
|
algorithms for signatures and resource selection. Newer formats are
|
||||||
signed with SHA256, with a possibility for moving to a better hash
|
signed with SHA256, with a possibility for moving to a better hash
|
||||||
algorithm in the future.
|
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:
|
o Code simplifications and refactorings:
|
||||||
- Numerous changes, bugfixes, and workarounds from Nathan Freitas
|
- Numerous changes, bugfixes, and workarounds from Nathan Freitas
|
||||||
|
13
doc/tor.1.in
13
doc/tor.1.in
@ -234,6 +234,19 @@ the default hidden service authorities, but not the directory or
|
|||||||
bridge authorities.
|
bridge authorities.
|
||||||
.LP
|
.LP
|
||||||
.TP
|
.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
|
\fBFetchDirInfoEarly \fR\fB0\fR|\fB1\fR\fP
|
||||||
If set to 1, Tor will always fetch directory information like other
|
If set to 1, Tor will always fetch directory information like other
|
||||||
directory caches, even if you don't meet the normal criteria for
|
directory caches, even if you don't meet the normal criteria for
|
||||||
|
@ -2204,6 +2204,105 @@ tor_threads_init(void)
|
|||||||
}
|
}
|
||||||
#endif
|
#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 */
|
/** Identity of the "main" thread */
|
||||||
static unsigned long main_thread_id = -1;
|
static unsigned long main_thread_id = -1;
|
||||||
|
|
||||||
|
@ -509,6 +509,8 @@ typedef struct tor_mutex_t {
|
|||||||
#endif
|
#endif
|
||||||
} tor_mutex_t;
|
} tor_mutex_t;
|
||||||
|
|
||||||
|
int tor_mlockall(void);
|
||||||
|
|
||||||
#ifdef TOR_IS_MULTITHREADED
|
#ifdef TOR_IS_MULTITHREADED
|
||||||
tor_mutex_t *tor_mutex_new(void);
|
tor_mutex_t *tor_mutex_new(void);
|
||||||
void tor_mutex_init(tor_mutex_t *m);
|
void tor_mutex_init(tor_mutex_t *m);
|
||||||
|
@ -79,6 +79,9 @@
|
|||||||
#DirServer moria2 v1 18.244.0.114:80 719B E45D E224 B607 C537 07D0 E214 3E2D 423E 74CF
|
#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
|
#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.
|
## On startup, setgid to this user.
|
||||||
#Group GID
|
#Group GID
|
||||||
|
|
||||||
|
@ -195,6 +195,7 @@ static config_var_t _option_vars[] = {
|
|||||||
OBSOLETE("DirRecordUsageSaveInterval"),
|
OBSOLETE("DirRecordUsageSaveInterval"),
|
||||||
V(DirReqStatistics, BOOL, "0"),
|
V(DirReqStatistics, BOOL, "0"),
|
||||||
VAR("DirServer", LINELIST, DirServers, NULL),
|
VAR("DirServer", LINELIST, DirServers, NULL),
|
||||||
|
V(DisableAllSwap, BOOL, "0"),
|
||||||
V(DNSPort, UINT, "0"),
|
V(DNSPort, UINT, "0"),
|
||||||
V(DNSListenAddress, LINELIST, NULL),
|
V(DNSListenAddress, LINELIST, NULL),
|
||||||
V(DownloadExtraInfo, BOOL, "0"),
|
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 "
|
{ "DirServer", "Tor only trusts directories signed with one of these "
|
||||||
"servers' keys. Used to override the standard list of directory "
|
"servers' keys. Used to override the standard list of directory "
|
||||||
"authorities." },
|
"authorities." },
|
||||||
|
{ "DisableAllSwap", "Tor will attempt a simple memory lock that "
|
||||||
|
"will prevent leaking of all information in memory to the swap file." },
|
||||||
/* { "FastFirstHopPK", "" }, */
|
/* { "FastFirstHopPK", "" }, */
|
||||||
/* FetchServerDescriptors, FetchHidServDescriptors,
|
/* FetchServerDescriptors, FetchHidServDescriptors,
|
||||||
* FetchUselessDescriptors */
|
* FetchUselessDescriptors */
|
||||||
@ -1115,6 +1118,15 @@ options_act_reversible(or_options_t *old_options, char **msg)
|
|||||||
}
|
}
|
||||||
#endif
|
#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 */
|
/* Setuid/setgid as appropriate */
|
||||||
if (options->User) {
|
if (options->User) {
|
||||||
if (switch_id(options->User) != 0) {
|
if (switch_id(options->User) != 0) {
|
||||||
@ -3834,6 +3846,12 @@ options_transition_allowed(or_options_t *old, or_options_t *new_val,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (old->DisableAllSwap != new_val->DisableAllSwap) {
|
||||||
|
*msg = tor_strdup("While Tor is running, changing DisableAllSwap "
|
||||||
|
"is not allowed.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2287,6 +2287,9 @@ typedef struct {
|
|||||||
* stop building circuits? */
|
* stop building circuits? */
|
||||||
int StrictEntryNodes; /**< Boolean: When none of our EntryNodes are up, do we
|
int StrictEntryNodes; /**< Boolean: When none of our EntryNodes are up, do we
|
||||||
* stop building circuits? */
|
* 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,
|
routerset_t *ExcludeNodes;/**< Structure containing nicknames, digests,
|
||||||
* country codes and IP address patterns of ORs
|
* country codes and IP address patterns of ORs
|
||||||
* not to use in circuits. */
|
* not to use in circuits. */
|
||||||
|
Loading…
Reference in New Issue
Block a user