summaryrefslogtreecommitdiff
path: root/src/common/compat.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/compat.c')
-rw-r--r--src/common/compat.c261
1 files changed, 112 insertions, 149 deletions
diff --git a/src/common/compat.c b/src/common/compat.c
index af61f024ef..836b3813e0 100644
--- a/src/common/compat.c
+++ b/src/common/compat.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2016, The Tor Project, Inc. */
+ * Copyright (c) 2007-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -12,17 +12,6 @@
* the platform.
**/
-/* This is required on rh7 to make strptime not complain.
- * We also need it to make memmem get defined (where available)
- */
-/* XXXX024 We should just use AC_USE_SYSTEM_EXTENSIONS in our autoconf,
- * and get this (and other important stuff!) automatically. Once we do that,
- * make sure to also change the extern char **environ detection in
- * configure.ac, because whether that is declared or not depends on whether
- * we have _GNU_SOURCE defined! Maybe that means that once we take this out,
- * we can also take out the configure check. */
-#define _GNU_SOURCE
-
#define COMPAT_PRIVATE
#include "compat.h"
@@ -44,6 +33,12 @@
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
+#ifdef HAVE_UTIME_H
+#include <utime.h>
+#endif
+#ifdef HAVE_SYS_UTIME_H
+#include <sys/utime.h>
+#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
@@ -100,12 +95,6 @@ SecureZeroMemory(PVOID ptr, SIZE_T cnt)
#include "tor_readpassphrase.h"
#endif
-#ifndef HAVE_GETTIMEOFDAY
-#ifdef HAVE_FTIME
-#include <sys/timeb.h>
-#endif
-#endif
-
/* Includes for the process attaching prevention */
#if defined(HAVE_SYS_PRCTL_H) && defined(__linux__)
/* Only use the linux prctl; the IRIX prctl is totally different */
@@ -127,12 +116,6 @@ SecureZeroMemory(PVOID ptr, SIZE_T cnt)
#ifdef HAVE_SIGNAL_H
#include <signal.h>
#endif
-#ifdef HAVE_UTIME_H
-#include <utime.h>
-#endif
-#ifdef HAVE_SYS_UTIME_H
-#include <sys/utime.h>
-#endif
#ifdef HAVE_SYS_MMAN_H
#include <sys/mman.h>
#endif
@@ -142,12 +125,6 @@ SecureZeroMemory(PVOID ptr, SIZE_T cnt)
#ifdef HAVE_SYS_FILE_H
#include <sys/file.h>
#endif
-#ifdef TOR_UNIT_TESTS
-#if !defined(HAVE_USLEEP) && defined(HAVE_SYS_SELECT_H)
-/* as fallback implementation for tor_sleep_msec */
-#include <sys/select.h>
-#endif
-#endif
#include "torlog.h"
#include "util.h"
@@ -227,7 +204,15 @@ tor_rename(const char *path_old, const char *path_new)
sandbox_intern_string(path_new));
}
-#if defined(HAVE_SYS_MMAN_H) || defined(RUNNING_DOXYGEN)
+/* Some MinGW builds have sys/mman.h, but not the corresponding symbols.
+ * Other configs rename the symbols using macros (including getpagesize).
+ * So check for sys/mman.h and unistd.h, and a getpagesize declaration. */
+#if (defined(HAVE_SYS_MMAN_H) && defined(HAVE_UNISTD_H) && \
+ defined(HAVE_DECL_GETPAGESIZE))
+#define COMPAT_HAS_MMAN_AND_PAGESIZE
+#endif
+
+#if defined(COMPAT_HAS_MMAN_AND_PAGESIZE) || defined(RUNNING_DOXYGEN)
/** Try to create a memory mapping for <b>filename</b> and return it. On
* failure, return NULL. Sets errno properly, using ERANGE to mean
* "empty file". */
@@ -273,6 +258,12 @@ tor_mmap_file(const char *filename)
page_size = getpagesize();
size += (size%page_size) ? page_size-(size%page_size) : 0;
+ if (st.st_size > SSIZE_T_CEILING || (off_t)size < st.st_size) {
+ log_warn(LD_FS, "File \"%s\" is too large. Ignoring.",filename);
+ errno = EFBIG;
+ close(fd);
+ return NULL;
+ }
if (!size) {
/* Zero-length file. If we call mmap on it, it will succeed but
* return NULL, and bad things will happen. So just fail. */
@@ -525,8 +516,10 @@ tor_asprintf(char **strp, const char *fmt, ...)
r = tor_vasprintf(strp, fmt, args);
va_end(args);
if (!*strp || r < 0) {
+ /* LCOV_EXCL_START */
log_err(LD_BUG, "Internal error in asprintf");
tor_assert(0);
+ /* LCOV_EXCL_STOP */
}
return r;
}
@@ -553,7 +546,10 @@ tor_vasprintf(char **strp, const char *fmt, va_list args)
/* On Windows, _vsnprintf won't tell us the length of the string if it
* overflows, so we need to use _vcsprintf to tell how much to allocate */
int len, r;
- len = _vscprintf(fmt, args);
+ va_list tmp_args;
+ va_copy(tmp_args, args);
+ len = _vscprintf(fmt, tmp_args);
+ va_end(tmp_args);
if (len < 0) {
*strp = NULL;
return -1;
@@ -666,7 +662,7 @@ const uint32_t TOR_ISLOWER_TABLE[8] = { 0, 0, 0, 0x7fffffe, 0, 0, 0, 0 };
/** Upper-casing and lowercasing tables to map characters to upper/lowercase
* equivalents. Used by tor_toupper() and tor_tolower(). */
/**@{*/
-const char TOR_TOUPPER_TABLE[256] = {
+const uint8_t TOR_TOUPPER_TABLE[256] = {
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,
32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,
@@ -684,7 +680,7 @@ const char TOR_TOUPPER_TABLE[256] = {
224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,
};
-const char TOR_TOLOWER_TABLE[256] = {
+const uint8_t TOR_TOLOWER_TABLE[256] = {
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,
32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,
@@ -1131,8 +1127,8 @@ tor_close_socket_simple(tor_socket_t s)
/** As tor_close_socket_simple(), but keeps track of the number
* of open sockets. Returns 0 on success, -1 on failure. */
-int
-tor_close_socket(tor_socket_t s)
+MOCK_IMPL(int,
+tor_close_socket,(tor_socket_t s))
{
int r = tor_close_socket_simple(s);
@@ -1154,14 +1150,12 @@ tor_close_socket(tor_socket_t s)
--n_sockets_open;
#else
if (r != EBADF)
- --n_sockets_open;
+ --n_sockets_open; // LCOV_EXCL_LINE -- EIO and EINTR too hard to force.
#endif
r = -1;
}
- if (n_sockets_open < 0)
- log_warn(LD_BUG, "Our socket count is below zero: %d. Please submit a "
- "bug report.", n_sockets_open);
+ tor_assert_nonfatal(n_sockets_open >= 0);
socket_accounting_unlock();
return r;
}
@@ -1204,10 +1198,10 @@ tor_open_socket,(int domain, int type, int protocol))
/** Mockable wrapper for connect(). */
MOCK_IMPL(tor_socket_t,
-tor_connect_socket,(tor_socket_t socket,const struct sockaddr *address,
+tor_connect_socket,(tor_socket_t sock, const struct sockaddr *address,
socklen_t address_len))
{
- return connect(socket,address,address_len);
+ return connect(sock,address,address_len);
}
/** As socket(), but creates a nonblocking socket and
@@ -1382,31 +1376,31 @@ get_n_open_sockets(void)
/** Mockable wrapper for getsockname(). */
MOCK_IMPL(int,
-tor_getsockname,(tor_socket_t socket, struct sockaddr *address,
+tor_getsockname,(tor_socket_t sock, struct sockaddr *address,
socklen_t *address_len))
{
- return getsockname(socket, address, address_len);
+ return getsockname(sock, address, address_len);
}
/** Turn <b>socket</b> into a nonblocking socket. Return 0 on success, -1
* on failure.
*/
int
-set_socket_nonblocking(tor_socket_t socket)
+set_socket_nonblocking(tor_socket_t sock)
{
#if defined(_WIN32)
unsigned long nonblocking = 1;
- ioctlsocket(socket, FIONBIO, (unsigned long*) &nonblocking);
+ ioctlsocket(sock, FIONBIO, (unsigned long*) &nonblocking);
#else
int flags;
- flags = fcntl(socket, F_GETFL, 0);
+ flags = fcntl(sock, F_GETFL, 0);
if (flags == -1) {
log_warn(LD_NET, "Couldn't get file status flags: %s", strerror(errno));
return -1;
}
flags |= O_NONBLOCK;
- if (fcntl(socket, F_SETFL, flags) == -1) {
+ if (fcntl(sock, F_SETFL, flags) == -1) {
log_warn(LD_NET, "Couldn't set file status flags: %s", strerror(errno));
return -1;
}
@@ -1738,19 +1732,24 @@ set_max_file_descriptors(rlim_t limit, int *max_out)
if (setrlimit(RLIMIT_NOFILE, &rlim) != 0) {
int bad = 1;
#ifdef OPEN_MAX
- if (errno == EINVAL && OPEN_MAX < rlim.rlim_cur) {
+ uint64_t try_limit = OPEN_MAX - ULIMIT_BUFFER;
+ if (errno == EINVAL && try_limit < (uint64_t) rlim.rlim_cur) {
/* On some platforms, OPEN_MAX is the real limit, and getrlimit() is
* full of nasty lies. I'm looking at you, OSX 10.5.... */
- rlim.rlim_cur = OPEN_MAX;
+ rlim.rlim_cur = try_limit;
if (setrlimit(RLIMIT_NOFILE, &rlim) == 0) {
if (rlim.rlim_cur < (rlim_t)limit) {
log_warn(LD_CONFIG, "We are limited to %lu file descriptors by "
- "OPEN_MAX, and ConnLimit is %lu. Changing ConnLimit; sorry.",
- (unsigned long)OPEN_MAX, (unsigned long)limit);
+ "OPEN_MAX (%lu), and ConnLimit is %lu. Changing "
+ "ConnLimit; sorry.",
+ (unsigned long)try_limit, (unsigned long)OPEN_MAX,
+ (unsigned long)limit);
} else {
- log_info(LD_CONFIG, "Dropped connection limit to OPEN_MAX (%lu); "
- "Apparently, %lu was too high and rlimit lied to us.",
- (unsigned long)OPEN_MAX, (unsigned long)rlim.rlim_max);
+ log_info(LD_CONFIG, "Dropped connection limit to %lu based on "
+ "OPEN_MAX (%lu); Apparently, %lu was too high and rlimit "
+ "lied to us.",
+ (unsigned long)try_limit, (unsigned long)OPEN_MAX,
+ (unsigned long)rlim.rlim_max);
}
bad = 0;
}
@@ -1941,7 +1940,7 @@ tor_getpwnam(const char *username)
return NULL;
if (! strcmp(username, passwd_cached->pw_name))
- return passwd_cached;
+ return passwd_cached; // LCOV_EXCL_LINE - would need to make getpwnam flaky
return NULL;
}
@@ -1967,7 +1966,7 @@ tor_getpwuid(uid_t uid)
return NULL;
if (uid == passwd_cached->pw_uid)
- return passwd_cached;
+ return passwd_cached; // LCOV_EXCL_LINE - would need to make getpwnam flaky
return NULL;
}
@@ -2350,28 +2349,34 @@ get_parent_directory(char *fname)
static char *
alloc_getcwd(void)
{
- int saved_errno = errno;
-/* We use this as a starting path length. Not too large seems sane. */
-#define START_PATH_LENGTH 128
-/* Nobody has a maxpath longer than this, as far as I know. And if they
- * do, they shouldn't. */
-#define MAX_SANE_PATH_LENGTH 4096
- size_t path_length = START_PATH_LENGTH;
- char *path = tor_malloc(path_length);
-
- errno = 0;
- while (getcwd(path, path_length) == NULL) {
- if (errno == ERANGE && path_length < MAX_SANE_PATH_LENGTH) {
- path_length*=2;
- path = tor_realloc(path, path_length);
- } else {
- tor_free(path);
- path = NULL;
- break;
- }
+#ifdef HAVE_GET_CURRENT_DIR_NAME
+ /* Glibc makes this nice and simple for us. */
+ char *cwd = get_current_dir_name();
+ char *result = NULL;
+ if (cwd) {
+ /* We make a copy here, in case tor_malloc() is not malloc(). */
+ result = tor_strdup(cwd);
+ raw_free(cwd); // alias for free to avoid tripping check-spaces.
+ }
+ return result;
+#else
+ size_t size = 1024;
+ char *buf = NULL;
+ char *ptr = NULL;
+
+ while (ptr == NULL) {
+ buf = tor_realloc(buf, size);
+ ptr = getcwd(buf, size);
+
+ if (ptr == NULL && errno != ERANGE) {
+ tor_free(buf);
+ return NULL;
}
- errno = saved_errno;
- return path;
+
+ size *= 2;
+ }
+ return buf;
+#endif
}
#endif
@@ -2386,7 +2391,7 @@ make_path_absolute(char *fname)
/* We don't want to assume that tor_free can free a string allocated
* with malloc. On failure, return fname (it's better than nothing). */
char *absfname = tor_strdup(absfname_malloced ? absfname_malloced : fname);
- if (absfname_malloced) free(absfname_malloced);
+ if (absfname_malloced) raw_free(absfname_malloced);
return absfname;
#else
@@ -2402,11 +2407,13 @@ make_path_absolute(char *fname)
tor_asprintf(&absfname, "%s/%s", path, fname);
tor_free(path);
} else {
+ /* LCOV_EXCL_START Can't make getcwd fail. */
/* If getcwd failed, the best we can do here is keep using the
* relative path. (Perhaps / isn't readable by this UID/GID.) */
log_warn(LD_GENERAL, "Unable to find current working directory: %s",
strerror(errno));
absfname = tor_strdup(fname);
+ /* LCOV_EXCL_STOP */
}
}
return absfname;
@@ -2610,8 +2617,12 @@ tor_inet_pton(int af, const char *src, void *dst)
char *next;
ssize_t len;
long r = strtol(src, &next, 16);
- tor_assert(next != NULL);
- tor_assert(next != src);
+ if (next == NULL || next == src) {
+ /* The 'next == src' error case can happen on versions of openbsd
+ * which treat "0xfoo" as an error, rather than as "0" followed by
+ * "xfoo". */
+ return 0;
+ }
len = *next == '\0' ? eow - src : next - src;
if (len > 4)
@@ -2695,7 +2706,8 @@ static int uname_result_is_set = 0;
/** Return a pointer to a description of our platform.
*/
-MOCK_IMPL(const char *, get_uname, (void))
+MOCK_IMPL(const char *,
+get_uname,(void))
{
#ifdef HAVE_UNAME
struct utsname u;
@@ -2770,7 +2782,9 @@ MOCK_IMPL(const char *, get_uname, (void))
}
#endif
#else
+ /* LCOV_EXCL_START -- can't provoke uname failure */
strlcpy(uname_result, "Unknown platform", sizeof(uname_result));
+ /* LCOV_EXCL_STOP */
#endif
}
uname_result_is_set = 1;
@@ -2844,59 +2858,19 @@ compute_num_cpus(void)
if (num_cpus == -2) {
num_cpus = compute_num_cpus_impl();
tor_assert(num_cpus != -2);
- if (num_cpus > MAX_DETECTABLE_CPUS)
+ if (num_cpus > MAX_DETECTABLE_CPUS) {
+ /* LCOV_EXCL_START */
log_notice(LD_GENERAL, "Wow! I detected that you have %d CPUs. I "
"will not autodetect any more than %d, though. If you "
"want to configure more, set NumCPUs in your torrc",
num_cpus, MAX_DETECTABLE_CPUS);
+ num_cpus = MAX_DETECTABLE_CPUS;
+ /* LCOV_EXCL_STOP */
+ }
}
return num_cpus;
}
-/** Set *timeval to the current time of day. On error, log and terminate.
- * (Same as gettimeofday(timeval,NULL), but never returns -1.)
- */
-void
-tor_gettimeofday(struct timeval *timeval)
-{
-#ifdef _WIN32
- /* Epoch bias copied from perl: number of units between windows epoch and
- * Unix epoch. */
-#define EPOCH_BIAS U64_LITERAL(116444736000000000)
-#define UNITS_PER_SEC U64_LITERAL(10000000)
-#define USEC_PER_SEC U64_LITERAL(1000000)
-#define UNITS_PER_USEC U64_LITERAL(10)
- union {
- uint64_t ft_64;
- FILETIME ft_ft;
- } ft;
- /* number of 100-nsec units since Jan 1, 1601 */
- GetSystemTimeAsFileTime(&ft.ft_ft);
- if (ft.ft_64 < EPOCH_BIAS) {
- log_err(LD_GENERAL,"System time is before 1970; failing.");
- exit(1);
- }
- ft.ft_64 -= EPOCH_BIAS;
- timeval->tv_sec = (unsigned) (ft.ft_64 / UNITS_PER_SEC);
- timeval->tv_usec = (unsigned) ((ft.ft_64 / UNITS_PER_USEC) % USEC_PER_SEC);
-#elif defined(HAVE_GETTIMEOFDAY)
- if (gettimeofday(timeval, NULL)) {
- log_err(LD_GENERAL,"gettimeofday failed.");
- /* If gettimeofday dies, we have either given a bad timezone (we didn't),
- or segfaulted.*/
- exit(1);
- }
-#elif defined(HAVE_FTIME)
- struct timeb tb;
- ftime(&tb);
- timeval->tv_sec = tb.time;
- timeval->tv_usec = tb.millitm * 1000;
-#else
-#error "No way to get time."
-#endif
- return;
-}
-
#if !defined(_WIN32)
/** Defined iff we need to add locks when defining fake versions of reentrant
* versions of time-related functions. */
@@ -2923,6 +2897,7 @@ correct_tm(int islocal, const time_t *timep, struct tm *resultbuf,
r->tm_mon = 11;
r->tm_mday = 31;
r->tm_yday = 364;
+ r->tm_wday = 6;
r->tm_hour = 23;
r->tm_min = 59;
r->tm_sec = 59;
@@ -2931,6 +2906,7 @@ correct_tm(int islocal, const time_t *timep, struct tm *resultbuf,
r->tm_mon = 0;
r->tm_mday = 1;
r->tm_yday = 0;
+ r->tm_wday = 0;
r->tm_hour = 0;
r->tm_min = 0;
r->tm_sec = 0;
@@ -2948,6 +2924,7 @@ correct_tm(int islocal, const time_t *timep, struct tm *resultbuf,
r->tm_mon = 0;
r->tm_mday = 1;
r->tm_yday = 0;
+ r->tm_wday = 0;
r->tm_hour = 0;
r->tm_min = 0 ;
r->tm_sec = 0;
@@ -2961,6 +2938,7 @@ correct_tm(int islocal, const time_t *timep, struct tm *resultbuf,
r->tm_mon = 11;
r->tm_mday = 31;
r->tm_yday = 364;
+ r->tm_wday = 6;
r->tm_hour = 23;
r->tm_min = 59;
r->tm_sec = 59;
@@ -2971,11 +2949,12 @@ correct_tm(int islocal, const time_t *timep, struct tm *resultbuf,
/* If we get here, then gmtime/localtime failed without getting an extreme
* value for *timep */
-
+ /* LCOV_EXCL_START */
tor_fragile_assert();
r = resultbuf;
memset(resultbuf, 0, sizeof(struct tm));
outcome="can't recover";
+ /* LCOV_EXCL_STOP */
done:
log_warn(LD_BUG, "%s("I64_FORMAT") failed with error %s: %s",
islocal?"localtime":"gmtime",
@@ -3301,7 +3280,7 @@ format_win32_error(DWORD err)
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, err,
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),
(LPVOID)&str,
0, NULL);
@@ -3369,9 +3348,11 @@ get_total_system_memory_impl(void)
return result * 1024;
err:
+ /* LCOV_EXCL_START Can't reach this unless proc is broken. */
tor_free(s);
close(fd);
return 0;
+ /* LCOV_EXCL_STOP */
#elif defined (_WIN32)
/* Windows has MEMORYSTATUSEX; pretty straightforward. */
MEMORYSTATUSEX ms;
@@ -3420,6 +3401,7 @@ get_total_system_memory(size_t *mem_out)
static size_t mem_cached=0;
uint64_t m = get_total_system_memory_impl();
if (0 == m) {
+ /* LCOV_EXCL_START -- can't make this happen without mocking. */
/* We couldn't find our memory total */
if (0 == mem_cached) {
/* We have no cached value either */
@@ -3429,6 +3411,7 @@ get_total_system_memory(size_t *mem_out)
*mem_out = mem_cached;
return 0;
+ /* LCOV_EXCL_STOP */
}
#if SIZE_MAX != UINT64_MAX
@@ -3445,26 +3428,6 @@ get_total_system_memory(size_t *mem_out)
return 0;
}
-#ifdef TOR_UNIT_TESTS
-/** Delay for <b>msec</b> milliseconds. Only used in tests. */
-void
-tor_sleep_msec(int msec)
-{
-#ifdef _WIN32
- Sleep(msec);
-#elif defined(HAVE_USLEEP)
- sleep(msec / 1000);
- /* Some usleep()s hate sleeping more than 1 sec */
- usleep((msec % 1000) * 1000);
-#elif defined(HAVE_SYS_SELECT_H)
- struct timeval tv = { msec / 1000, (msec % 1000) * 1000};
- select(0, NULL, NULL, NULL, &tv);
-#else
- sleep(CEIL_DIV(msec, 1000));
-#endif
-}
-#endif
-
/** Emit the password prompt <b>prompt</b>, then read up to <b>buflen</b>
* bytes of passphrase into <b>output</b>. Return the number of bytes in
* the passphrase, excluding terminating NUL.