Merge remote-tracking branch 'ctoader/gsoc-cap-stage2'

Conflicts:
	src/common/sandbox.c
This commit is contained in:
Nick Mathewson 2013-09-13 12:31:41 -04:00
commit e0b2cd061b
12 changed files with 1618 additions and 96 deletions

View File

@ -402,7 +402,13 @@ save_CPPFLAGS="$CPPFLAGS"
LIBS="-levent $STATIC_LIBEVENT_FLAGS $TOR_LIB_WS32 $LIBS"
LDFLAGS="$TOR_LDFLAGS_libevent $LDFLAGS"
CPPFLAGS="$TOR_CPPFLAGS_libevent $CPPFLAGS"
AC_CHECK_FUNCS(event_get_version event_get_version_number event_get_method event_set_log_callback evdns_set_outgoing_bind_address event_base_loopexit)
AC_CHECK_FUNCS([event_get_version \
event_get_version_number \
event_get_method \
event_set_log_callback \
evdns_set_outgoing_bind_address \
evutil_secure_rng_set_urandom_device_file \
event_base_loopexit])
AC_CHECK_MEMBERS([struct event.min_heap_idx], , ,
[#include <event.h>
])

View File

@ -14,6 +14,7 @@
#include "address.h"
#include "torlog.h"
#include "container.h"
#include "sandbox.h"
#ifdef _WIN32
#include <process.h>
@ -234,7 +235,7 @@ tor_addr_lookup(const char *name, uint16_t family, tor_addr_t *addr)
memset(&hints, 0, sizeof(hints));
hints.ai_family = family;
hints.ai_socktype = SOCK_STREAM;
err = getaddrinfo(name, NULL, &hints, &res);
err = sandbox_getaddrinfo(name, NULL, &hints, &res);
if (!err) {
best = NULL;
for (res_p = res; res_p; res_p = res_p->ai_next) {

View File

@ -110,6 +110,7 @@
#include "util.h"
#include "container.h"
#include "address.h"
#include "sandbox.h"
/* Inline the strl functions if the platform doesn't have them. */
#ifndef HAVE_STRLCPY
@ -126,6 +127,7 @@ tor_open_cloexec(const char *path, int flags, unsigned mode)
{
int fd;
#ifdef O_CLOEXEC
path = sandbox_intern_string(path);
fd = open(path, flags|O_CLOEXEC, mode);
if (fd >= 0)
return fd;

View File

@ -56,6 +56,7 @@
#include "../common/util.h"
#include "container.h"
#include "compat.h"
#include "sandbox.h"
#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(0,9,8)
#error "We require OpenSSL >= 0.9.8"
@ -2349,7 +2350,7 @@ crypto_strongest_rand(uint8_t *out, size_t out_len)
return 0;
#else
for (i = 0; filenames[i]; ++i) {
fd = open(filenames[i], O_RDONLY, 0);
fd = open(sandbox_intern_string(filenames[i]), O_RDONLY, 0);
if (fd<0) continue;
log_info(LD_CRYPTO, "Reading entropy from \"%s\"", filenames[i]);
n = read_all(fd, (char*)out, out_len, 0);

File diff suppressed because it is too large Load Diff

View File

@ -12,6 +12,9 @@
#ifndef SANDBOX_H_
#define SANDBOX_H_
#include "orconfig.h"
#include "torint.h"
#ifndef SYS_SECCOMP
/**
@ -22,13 +25,99 @@
#endif
#if defined(HAVE_SECCOMP_H) && defined(__linux__)
#define USE_LIBSECCOMP
#endif
struct sandbox_cfg_elem;
/** Typedef to structure used to manage a sandbox configuration. */
typedef struct sandbox_cfg_elem sandbox_cfg_t;
/**
* Linux definitions
*/
#ifdef __linux__
#ifdef USE_LIBSECCOMP
#ifndef __USE_GNU
#define __USE_GNU
#endif
#include <sys/ucontext.h>
#include <seccomp.h>
#include <netdb.h>
#define PARAM_PTR 0
#define PARAM_NUM 1
/**
* Enum used to manage the type of the implementation for general purpose.
*/
typedef enum {
/** Libseccomp implementation based on seccomp2*/
LIBSECCOMP2 = 0
} SB_IMPL;
/**
* Configuration parameter structure associated with the LIBSECCOMP2
* implementation.
*/
typedef struct smp_param {
/** syscall associated with parameter. */
int syscall;
/** parameter index. */
int pindex;
/** parameter value. */
intptr_t value;
/** parameter flag (0 = not protected, 1 = protected). */
int prot;
} smp_param_t;
/**
* Structure used to manage a sandbox configuration.
*
* It is implemented as a linked list of parameters. Currently only controls
* parameters for open, openat, execve, stat64.
*/
struct sandbox_cfg_elem {
/** Sandbox implementation which dictates the parameter type. */
SB_IMPL implem;
/** Configuration parameter. */
void *param;
/** Next element of the configuration*/
struct sandbox_cfg_elem *next;
};
/**
* Structure used for keeping a linked list of getaddrinfo pre-recorded
* results.
*/
struct sb_addr_info_el {
/** Name of the address info result. */
char *name;
/** Pre-recorded getaddrinfo result. */
struct addrinfo *info;
/** Next element in the list. */
struct sb_addr_info_el *next;
};
/** Typedef to structure used to manage an addrinfo list. */
typedef struct sb_addr_info_el sb_addr_info_t;
/** Function pointer defining the prototype of a filter function.*/
typedef int (*sandbox_filter_func_t)(scmp_filter_ctx ctx,
sandbox_cfg_t *filter);
/** Type that will be used in step 3 in order to manage multiple sandboxes.*/
typedef struct {
/** function pointers associated with the filter */
sandbox_filter_func_t *filter_func;
/** filter function pointer parameters */
sandbox_cfg_t *filter_dynamic;
} sandbox_t;
/**
* Linux 32 bit definitions
@ -46,10 +135,116 @@
#endif
#endif // __linux__
#endif // USE_LIBSECCOMP
#ifdef USE_LIBSECCOMP
/** Pre-calls getaddrinfo in order to pre-record result. */
int sandbox_add_addrinfo(const char *addr);
struct addrinfo;
/** Replacement for getaddrinfo(), using pre-recorded results. */
int sandbox_getaddrinfo(const char *name, const char *servname,
const struct addrinfo *hints,
struct addrinfo **res);
#else
#define sandbox_getaddrinfo(name, servname, hints, res) \
getaddrinfo((name),(servname), (hints),(res))
#define sandbox_add_addrinfo(name) \
((void)(name))
#endif
/** Use <b>fd</b> to log non-survivable sandbox violations. */
void sandbox_set_debugging_fd(int fd);
int tor_global_sandbox(void);
#ifdef USE_LIBSECCOMP
/** Returns a registered protected string used with the sandbox, given that
* it matches the parameter.
*/
const char* sandbox_intern_string(const char *param);
#else
#define sandbox_intern_string(s) (s)
#endif
/** Creates an empty sandbox configuration file.*/
sandbox_cfg_t * sandbox_cfg_new(void);
/**
* Function used to add a open allowed filename to a supplied configuration.
* The (char*) specifies the path to the allowed file, fr = 1 tells the
* function that the char* needs to be free-ed, 0 means the pointer does not
* need to be free-ed.
*/
int sandbox_cfg_allow_open_filename(sandbox_cfg_t **cfg, char *file,
int fr);
/** Function used to add a series of open allowed filenames to a supplied
* configuration.
* @param cfg sandbox configuration.
* @param ... all future parameters are specified as pairs of <(char*), 1 / 0>
* the char* specifies the path to the allowed file, 1 tells the function
* that the char* needs to be free-ed, 0 means the pointer does not need to
* be free-ed; the final parameter needs to be <NULL, 0>.
*/
int sandbox_cfg_allow_open_filename_array(sandbox_cfg_t **cfg, ...);
/**
* Function used to add a openat allowed filename to a supplied configuration.
* The (char*) specifies the path to the allowed file, fr = 1 tells the
* function that the char* needs to be free-ed, 0 means the pointer does not
* need to be free-ed.
*/
int sandbox_cfg_allow_openat_filename(sandbox_cfg_t **cfg, char *file,
int fr);
/** Function used to add a series of openat allowed filenames to a supplied
* configuration.
* @param cfg sandbox configuration.
* @param ... all future parameters are specified as pairs of <(char*), 1 / 0>
* the char* specifies the path to the allowed file, 1 tells the function
* that the char* needs to be free-ed, 0 means the pointer does not need to
* be free-ed; the final parameter needs to be <NULL, 0>.
*/
int sandbox_cfg_allow_openat_filename_array(sandbox_cfg_t **cfg, ...);
/**
* Function used to add a execve allowed filename to a supplied configuration.
* The (char*) specifies the path to the allowed file, fr = 1 tells the
* function that the char* needs to be free-ed, 0 means the pointer does not
* need to be free-ed.
*/
int sandbox_cfg_allow_execve(sandbox_cfg_t **cfg, const char *com);
/** Function used to add a series of execve allowed filenames to a supplied
* configuration.
* @param cfg sandbox configuration.
* @param ... all future parameters are specified as pairs of <(char*), 1 / 0>
* the char* specifies the path to the allowed file, 1 tells the function
* that the char* needs to be free-ed, 0 means the pointer does not need to
* be free-ed; the final parameter needs to be <NULL, 0>.
*/
int sandbox_cfg_allow_execve_array(sandbox_cfg_t **cfg, ...);
/**
* Function used to add a stat/stat64 allowed filename to a configuration.
* The (char*) specifies the path to the allowed file, fr = 1 tells the
* function that the char* needs to be free-ed, 0 means the pointer does not
* need to be free-ed.
*/
int sandbox_cfg_allow_stat_filename(sandbox_cfg_t **cfg, char *file,
int fr);
/** Function used to add a series of stat64 allowed filenames to a supplied
* configuration.
* @param cfg sandbox configuration.
* @param ... all future parameters are specified as pairs of <(char*), 1 / 0>
* the char* specifies the path to the allowed file, 1 tells the function
* that the char* needs to be free-ed, 0 means the pointer does not need to
* be free-ed; the final parameter needs to be <NULL, 0>.
*/
int sandbox_cfg_allow_stat_filename_array(sandbox_cfg_t **cfg, ...);
/** Function used to initialise a sandbox configuration.*/
int sandbox_init(sandbox_cfg_t* cfg);
#endif /* SANDBOX_H_ */

View File

@ -24,6 +24,7 @@
#include "torint.h"
#include "container.h"
#include "address.h"
#include "../common/sandbox.h"
#ifdef _WIN32
#include <io.h>
@ -1799,7 +1800,7 @@ file_status(const char *fname)
int r;
f = tor_strdup(fname);
clean_name_for_stat(f);
r = stat(f, &st);
r = stat(sandbox_intern_string(f), &st);
tor_free(f);
if (r) {
if (errno == ENOENT) {
@ -1849,7 +1850,7 @@ check_private_dir(const char *dirname, cpd_check_t check,
tor_assert(dirname);
f = tor_strdup(dirname);
clean_name_for_stat(f);
r = stat(f, &st);
r = stat(sandbox_intern_string(f), &st);
tor_free(f);
if (r) {
if (errno != ENOENT) {
@ -3039,6 +3040,7 @@ smartlist_t *
tor_listdir(const char *dirname)
{
smartlist_t *result;
const char *prot_dname = sandbox_intern_string(dirname);
#ifdef _WIN32
char *pattern=NULL;
TCHAR tpattern[MAX_PATH] = {0};
@ -3082,7 +3084,7 @@ tor_listdir(const char *dirname)
#else
DIR *d;
struct dirent *de;
if (!(d = opendir(dirname)))
if (!(d = opendir(prot_dname)))
return NULL;
result = smartlist_new();

View File

@ -542,5 +542,7 @@ STATIC int format_helper_exit_status(unsigned char child_state,
const char *libor_get_digests(void);
#define ARRAY_LENGTH(x) (sizeof(x)) / sizeof(x[0])
#endif

View File

@ -6301,7 +6301,8 @@ remove_file_if_very_old(const char *fname, time_t now)
#define VERY_OLD_FILE_AGE (28*24*60*60)
struct stat st;
if (stat(fname, &st)==0 && st.st_mtime < now-VERY_OLD_FILE_AGE) {
if (stat(sandbox_intern_string(fname), &st)==0 &&
st.st_mtime < now-VERY_OLD_FILE_AGE) {
char buf[ISO_TIME_LEN+1];
format_local_iso_time(buf, st.st_mtime);
log_notice(LD_GENERAL, "Obsolete file %s hasn't been modified since %s. "

View File

@ -24,6 +24,7 @@
#include "relay.h"
#include "router.h"
#include "ht.h"
#include "../common/sandbox.h"
#ifdef HAVE_EVENT2_DNS_H
#include <event2/event.h>
#include <event2/dns.h>
@ -1443,13 +1444,14 @@ configure_nameservers(int force)
const or_options_t *options;
const char *conf_fname;
struct stat st;
int r;
int r, flags;
options = get_options();
conf_fname = options->ServerDNSResolvConfFile;
#ifndef _WIN32
if (!conf_fname)
conf_fname = "/etc/resolv.conf";
#endif
flags = DNS_OPTIONS_ALL;
if (!the_evdns_base) {
if (!(the_evdns_base = evdns_base_new(tor_libevent_get_base(), 0))) {
@ -1477,7 +1479,7 @@ configure_nameservers(int force)
evdns_set_log_fn(evdns_log_cb);
if (conf_fname) {
if (stat(conf_fname, &st)) {
if (stat(sandbox_intern_string(conf_fname), &st)) {
log_warn(LD_EXIT, "Unable to stat resolver configuration in '%s': %s",
conf_fname, strerror(errno));
goto err;
@ -1491,9 +1493,14 @@ configure_nameservers(int force)
evdns_base_search_clear(the_evdns_base);
evdns_base_clear_nameservers_and_suspend(the_evdns_base);
}
if (flags & DNS_OPTION_HOSTSFILE) {
flags ^= DNS_OPTION_HOSTSFILE;
evdns_base_load_hosts(the_evdns_base,
sandbox_intern_string("/etc/resolv.conf"));
}
log_info(LD_EXIT, "Parsing resolver configuration in '%s'", conf_fname);
if ((r = evdns_base_resolv_conf_parse(the_evdns_base,
DNS_OPTIONS_ALL, conf_fname))) {
if ((r = evdns_base_resolv_conf_parse(the_evdns_base, flags,
sandbox_intern_string(conf_fname)))) {
log_warn(LD_EXIT, "Unable to parse '%s', or no nameservers in '%s' (%d)",
conf_fname, conf_fname, r);
goto err;

View File

@ -2655,6 +2655,95 @@ find_flashcard_path(PWCHAR path, size_t size)
}
#endif
static void
init_addrinfo(void)
{
char hname[256];
// host name to sandbox
gethostname(hname, sizeof(hname));
sandbox_add_addrinfo(hname);
}
static sandbox_cfg_t*
sandbox_init_filter(void)
{
sandbox_cfg_t *cfg = sandbox_cfg_new();
sandbox_cfg_allow_openat_filename(&cfg,
get_datadir_fname("cached-status"), 1);
sandbox_cfg_allow_open_filename_array(&cfg,
get_datadir_fname("cached-certs"), 1,
get_datadir_fname("cached-certs.tmp"), 1,
get_datadir_fname("cached-consensus"), 1,
get_datadir_fname("unverified-consensus"), 1,
get_datadir_fname("unverified-consensus.tmp"), 1,
get_datadir_fname("cached-microdesc-consensus"), 1,
get_datadir_fname("cached-microdesc-consensus.tmp"), 1,
get_datadir_fname("cached-microdescs"), 1,
get_datadir_fname("cached-microdescs.tmp"), 1,
get_datadir_fname("cached-microdescs.new"), 1,
get_datadir_fname("cached-microdescs.new.tmp"), 1,
get_datadir_fname("unverified-microdesc-consensus"), 1,
get_datadir_fname("cached-descriptors"), 1,
get_datadir_fname("cached-descriptors.new"), 1,
get_datadir_fname("cached-descriptors.tmp"), 1,
get_datadir_fname("cached-descriptors.new.tmp"), 1,
get_datadir_fname("cached-descriptors.tmp.tmp"), 1,
get_datadir_fname("cached-extrainfo"), 1,
get_datadir_fname("state.tmp"), 1,
get_datadir_fname("unparseable-desc.tmp"), 1,
get_datadir_fname("unparseable-desc"), 1,
"/dev/srandom", 0,
"/dev/urandom", 0,
"/dev/random", 0,
NULL, 0
);
sandbox_cfg_allow_stat_filename_array(&cfg,
get_datadir_fname(NULL), 1,
get_datadir_fname("lock"), 1,
get_datadir_fname("state"), 1,
get_datadir_fname("router-stability"), 1,
get_datadir_fname("cached-extrainfo.new"), 1,
NULL, 0
);
// orport
if (server_mode(get_options())) {
sandbox_cfg_allow_open_filename_array(&cfg,
get_datadir_fname2("keys", "secret_id_key"), 1,
get_datadir_fname2("keys", "secret_onion_key"), 1,
get_datadir_fname2("keys", "secret_onion_key_ntor"), 1,
get_datadir_fname2("keys", "secret_onion_key_ntor.tmp"), 1,
get_datadir_fname2("keys", "secret_id_key.old"), 1,
get_datadir_fname2("keys", "secret_onion_key.old"), 1,
get_datadir_fname2("keys", "secret_onion_key_ntor.old"), 1,
get_datadir_fname2("keys", "secret_onion_key.tmp"), 1,
get_datadir_fname2("keys", "secret_id_key.tmp"), 1,
get_datadir_fname("fingerprint"), 1,
get_datadir_fname("fingerprint.tmp"), 1,
get_datadir_fname("cached-consensus"), 1,
get_datadir_fname("cached-consensus.tmp"), 1,
"/etc/resolv.conf", 0,
NULL, 0
);
sandbox_cfg_allow_stat_filename_array(&cfg,
get_datadir_fname("keys"), 1,
get_datadir_fname("stats/dirreq-stats"), 1,
NULL, 0
);
}
sandbox_cfg_allow_execve(&cfg, "/usr/local/bin/tor");
init_addrinfo();
return cfg;
}
/** Main entry point for the Tor process. Called from main(). */
/* This function is distinct from main() only so we can link main.c into
* the unittest binary without conflicting with the unittests' main. */
@ -2723,10 +2812,18 @@ tor_main(int argc, char *argv[])
return -1;
if (get_options()->Sandbox) {
if (tor_global_sandbox()) {
sandbox_cfg_t* cfg = sandbox_init_filter();
if (sandbox_init(cfg)) {
log_err(LD_BUG,"Failed to create syscall sandbox filter");
return -1;
}
// registering libevent rng
#ifdef HAVE_EVUTIL_SECURE_RNG_SET_URANDOM_DEVICE_FILE
evutil_secure_rng_set_urandom_device_file(
(char*) sandbox_intern_string("/dev/urandom"));
#endif
}
switch (get_options()->command) {

View File

@ -37,7 +37,7 @@
#include "routerlist.h"
#include "routerparse.h"
#include "routerset.h"
#include "../common/sandbox.h"
// #define DEBUG_ROUTERLIST
/****************************************************************************/