diff options
Diffstat (limited to 'src/lib')
40 files changed, 1047 insertions, 180 deletions
diff --git a/src/lib/buf/buffers.c b/src/lib/buf/buffers.c index a5031a47a6..23fc1e23a6 100644 --- a/src/lib/buf/buffers.c +++ b/src/lib/buf/buffers.c @@ -685,19 +685,22 @@ buf_move_to_buf(buf_t *buf_out, buf_t *buf_in, size_t *buf_flushlen) } /** Moves all data from <b>buf_in</b> to <b>buf_out</b>, without copying. + * Return the number of bytes that were moved. */ -void +size_t buf_move_all(buf_t *buf_out, buf_t *buf_in) { tor_assert(buf_out); if (!buf_in) - return; + return 0; if (buf_datalen(buf_in) == 0) - return; + return 0; if (BUG(buf_out->datalen > BUF_MAX_LEN || buf_in->datalen > BUF_MAX_LEN)) - return; + return 0; if (BUG(buf_out->datalen > BUF_MAX_LEN - buf_in->datalen)) - return; + return 0; + + size_t n_bytes_moved = buf_in->datalen; if (buf_out->head == NULL) { buf_out->head = buf_in->head; @@ -710,6 +713,8 @@ buf_move_all(buf_t *buf_out, buf_t *buf_in) buf_out->datalen += buf_in->datalen; buf_in->head = buf_in->tail = NULL; buf_in->datalen = 0; + + return n_bytes_moved; } /** Internal structure: represents a position in a buffer. */ diff --git a/src/lib/buf/buffers.h b/src/lib/buf/buffers.h index d8a77feb72..1361a02eba 100644 --- a/src/lib/buf/buffers.h +++ b/src/lib/buf/buffers.h @@ -46,7 +46,7 @@ void buf_add_printf(buf_t *buf, const char *format, ...) void buf_add_vprintf(buf_t *buf, const char *format, va_list args) CHECK_PRINTF(2, 0); int buf_move_to_buf(buf_t *buf_out, buf_t *buf_in, size_t *buf_flushlen); -void buf_move_all(buf_t *buf_out, buf_t *buf_in); +size_t buf_move_all(buf_t *buf_out, buf_t *buf_in); void buf_peek(const buf_t *buf, char *string, size_t string_len); void buf_drain(buf_t *buf, size_t n); int buf_get_bytes(buf_t *buf, char *string, size_t string_len); diff --git a/src/lib/crypt_ops/crypto_curve25519.h b/src/lib/crypt_ops/crypto_curve25519.h index 154a0b94bc..f1e5d1265d 100644 --- a/src/lib/crypt_ops/crypto_curve25519.h +++ b/src/lib/crypt_ops/crypto_curve25519.h @@ -9,6 +9,7 @@ #ifndef TOR_CRYPTO_CURVE25519_H #define TOR_CRYPTO_CURVE25519_H +#include <stdbool.h> #include "lib/testsupport/testsupport.h" #include "lib/cc/torint.h" #include "lib/crypt_ops/crypto_digest.h" @@ -77,7 +78,8 @@ STATIC int curve25519_basepoint_impl(uint8_t *output, const uint8_t *secret); int curve25519_public_from_base64(curve25519_public_key_t *pkey, const char *input); void curve25519_public_to_base64(char *output, - const curve25519_public_key_t *pkey); + const curve25519_public_key_t *pkey, + bool pad); void curve25519_set_impl_params(int use_ed); void curve25519_init(void); diff --git a/src/lib/crypt_ops/crypto_format.c b/src/lib/crypt_ops/crypto_format.c index 92b8b9372e..4483b7d2f5 100644 --- a/src/lib/crypt_ops/crypto_format.c +++ b/src/lib/crypt_ops/crypto_format.c @@ -131,9 +131,10 @@ crypto_read_tagged_contents_from_file(const char *fname, return r; } -/** Encode <b>pkey</b> as a base64-encoded string, including trailing "=" - * characters, in the buffer <b>output</b>, which must have at least - * CURVE25519_BASE64_PADDED_LEN+1 bytes available. +/** Encode <b>pkey</b> as a base64-encoded string in the buffer <b>output</b>. + * If <b>pad</b> is false do not include trailing "=" characters, otherwise + * include them. <b>output</b> must have at least + * CURVE25519_BASE64_PADDED_LEN+1 bytes available, even if <b>pad</b> is false. * Can not fail. * * Careful! CURVE25519_BASE64_PADDED_LEN is one byte longer than @@ -141,17 +142,25 @@ crypto_read_tagged_contents_from_file(const char *fname, */ void curve25519_public_to_base64(char *output, - const curve25519_public_key_t *pkey) + const curve25519_public_key_t *pkey, bool pad) { - char buf[128]; - int n = base64_encode(buf, sizeof(buf), - (const char*)pkey->public_key, - CURVE25519_PUBKEY_LEN, 0); + int n, expected_len; + if (pad) { + n = base64_encode(output, CURVE25519_BASE64_PADDED_LEN+1, + (const char*)pkey->public_key, + CURVE25519_PUBKEY_LEN, 0); + expected_len = CURVE25519_BASE64_PADDED_LEN; + } else { + n = base64_encode_nopad(output, CURVE25519_BASE64_PADDED_LEN+1, + (const uint8_t*)pkey->public_key, + CURVE25519_PUBKEY_LEN); + expected_len = CURVE25519_BASE64_LEN; + } + /* These asserts should always succeed, unless there is a bug in * base64_encode(). */ - tor_assert(n == CURVE25519_BASE64_PADDED_LEN); - tor_assert(buf[CURVE25519_BASE64_PADDED_LEN] == '\0'); - memcpy(output, buf, CURVE25519_BASE64_PADDED_LEN+1); + tor_assert(n == expected_len); + tor_assert(output[expected_len] == '\0'); } /** Try to decode a base64-encoded curve25519 public key from <b>input</b> @@ -162,11 +171,11 @@ curve25519_public_from_base64(curve25519_public_key_t *pkey, const char *input) { size_t len = strlen(input); - if (len == CURVE25519_BASE64_PADDED_LEN - 1) { + if (len == CURVE25519_BASE64_LEN) { /* not padded */ return digest256_from_base64((char*)pkey->public_key, input); } else if (len == CURVE25519_BASE64_PADDED_LEN) { - char buf[128]; + char buf[CURVE25519_BASE64_PADDED_LEN+1]; if (base64_decode(buf, sizeof(buf), input, len) != CURVE25519_PUBKEY_LEN) return -1; memcpy(pkey->public_key, buf, CURVE25519_PUBKEY_LEN); diff --git a/src/lib/defs/x25519_sizes.h b/src/lib/defs/x25519_sizes.h index acb08c5e6a..e650f5a350 100644 --- a/src/lib/defs/x25519_sizes.h +++ b/src/lib/defs/x25519_sizes.h @@ -36,6 +36,9 @@ /** Length of a Curve25519 key when encoded in base 64, with padding. */ #define CURVE25519_BASE64_PADDED_LEN 44 +/** Length of a Curve25519 key when encoded in base 64, without padding. */ +#define CURVE25519_BASE64_LEN 43 + /** Length of a Ed25519 key when encoded in base 64, without padding. */ #define ED25519_BASE64_LEN 43 /** Length of a Ed25519 signature when encoded in base 64, without padding. */ diff --git a/src/lib/fs/conffile.c b/src/lib/fs/conffile.c index 9583093c12..f1f6d8ae5f 100644 --- a/src/lib/fs/conffile.c +++ b/src/lib/fs/conffile.c @@ -21,6 +21,8 @@ #include "lib/malloc/malloc.h" #include "lib/string/printf.h" +#include <stdbool.h> + static smartlist_t *config_get_file_list(const char *path, smartlist_t *opened_files); static int config_get_included_config(const char *path, int recursion_level, @@ -50,62 +52,109 @@ config_get_lines_include(const char *string, config_line_t **result, opened_lst, 1, NULL, config_process_include); } -/** Adds a list of configuration files present on <b>path</b> to - * <b>file_list</b>. <b>path</b> can be a file or a directory. If it is a file, - * only that file will be added to <b>file_list</b>. If it is a directory, - * all paths for files on that directory root (no recursion) except for files - * whose name starts with a dot will be added to <b>file_list</b>. - * <b>opened_files</b> will have a list of files opened by this function - * if provided. Return 0 on success, -1 on failure. Ignores empty files. - */ +/** Returns a list of paths obtained when expading globs in <b>pattern</b>. If + * <b>pattern</b> has no globs, returns a list with <b>pattern</b> if it is an + * existing path or NULL otherwise. If <b>opened_files</b> is provided, adds + * paths opened by glob to it. Returns NULL on failure. */ static smartlist_t * -config_get_file_list(const char *path, smartlist_t *opened_files) +expand_glob(const char *pattern, smartlist_t *opened_files) { - smartlist_t *file_list = smartlist_new(); + smartlist_t *matches = tor_glob(pattern); + if (!matches) { + return NULL; + } - if (opened_files) { - smartlist_add_strdup(opened_files, path); + // if it is not a glob, return error when the path is missing + if (!has_glob(pattern) && smartlist_len(matches) == 0) { + smartlist_free(matches); + return NULL; } - file_status_t file_type = file_status(path); - if (file_type == FN_FILE) { - smartlist_add_strdup(file_list, path); - return file_list; - } else if (file_type == FN_DIR) { - smartlist_t *all_files = tor_listdir(path); - if (!all_files) { - smartlist_free(file_list); + if (opened_files) { + smartlist_t *glob_opened = get_glob_opened_files(pattern); + if (!glob_opened) { + SMARTLIST_FOREACH(matches, char *, f, tor_free(f)); + smartlist_free(matches); return NULL; } - smartlist_sort_strings(all_files); - SMARTLIST_FOREACH_BEGIN(all_files, char *, f) { - if (f[0] == '.') { - tor_free(f); - continue; - } + smartlist_add_all(opened_files, glob_opened); + smartlist_free(glob_opened); + } + smartlist_sort_strings(matches); + return matches; +} + +/** Returns a list of configuration files present on paths that match + * <b>pattern</b>. The pattern is expanded and then all the paths are + * processed. A path can be a file or a directory. If it is a file, that file + * will be added to the list to be returned. If it is a directory, + * all paths for files on that directory root (no recursion) except for files + * whose name starts with a dot will be added to the list to be returned. + * <b>opened_files</b> will have a list of files opened by this function + * if provided. Return NULL on failure. Ignores empty files. + */ +static smartlist_t * +config_get_file_list(const char *pattern, smartlist_t *opened_files) +{ + smartlist_t *glob_matches = expand_glob(pattern, opened_files); + if (!glob_matches) { + return NULL; + } - char *fullname; - tor_asprintf(&fullname, "%s"PATH_SEPARATOR"%s", path, f); - tor_free(f); + bool error_found = false; + smartlist_t *file_list = smartlist_new(); + SMARTLIST_FOREACH_BEGIN(glob_matches, char *, path) { + if (opened_files) { + smartlist_add_strdup(opened_files, path); + } - if (opened_files) { - smartlist_add_strdup(opened_files, fullname); + file_status_t file_type = file_status(path); + if (file_type == FN_FILE) { + smartlist_add_strdup(file_list, path); + } else if (file_type == FN_DIR) { + smartlist_t *all_files = tor_listdir(path); + if (!all_files) { + error_found = true; + break; } - - if (file_status(fullname) != FN_FILE) { - tor_free(fullname); + smartlist_sort_strings(all_files); + SMARTLIST_FOREACH_BEGIN(all_files, char *, f) { + if (f[0] == '.') { + continue; + } + + char *fullname; + tor_asprintf(&fullname, "%s"PATH_SEPARATOR"%s", path, f); + + if (opened_files) { + smartlist_add_strdup(opened_files, fullname); + } + + if (file_status(fullname) != FN_FILE) { + tor_free(fullname); + continue; + } + smartlist_add(file_list, fullname); + } SMARTLIST_FOREACH_END(f); + SMARTLIST_FOREACH(all_files, char *, f, tor_free(f)); + smartlist_free(all_files); + } else if (file_type == FN_EMPTY) { continue; - } - smartlist_add(file_list, fullname); - } SMARTLIST_FOREACH_END(f); - smartlist_free(all_files); - return file_list; - } else if (file_type == FN_EMPTY) { - return file_list; - } else { + } else { + error_found = true; + break; + } + } SMARTLIST_FOREACH_END(path); + SMARTLIST_FOREACH(glob_matches, char *, f, tor_free(f)); + smartlist_free(glob_matches); + + if (error_found) { + SMARTLIST_FOREACH(file_list, char *, f, tor_free(f)); smartlist_free(file_list); - return NULL; + file_list = NULL; } + + return file_list; } /** Creates a list of config lines present on included <b>path</b>. @@ -133,19 +182,19 @@ config_get_included_config(const char *path, int recursion_level, int extended, return 0; } -/** Process an %include <b>path</b> in a config file. Set <b>list</b> to the +/** Process an %include <b>pattern</b> in a config file. Set <b>list</b> to the * list of configuration settings obtained and <b>list_last</b> to the last * element of the same list. <b>opened_lst</b> will have a list of opened * files if provided. Return 0 on success, -1 on failure. */ static int -config_process_include(const char *path, int recursion_level, int extended, +config_process_include(const char *pattern, int recursion_level, int extended, config_line_t **list, config_line_t **list_last, smartlist_t *opened_lst) { config_line_t *ret_list = NULL; config_line_t **next = &ret_list; - smartlist_t *config_files = config_get_file_list(path, opened_lst); + smartlist_t *config_files = config_get_file_list(pattern, opened_lst); if (!config_files) { return -1; } diff --git a/src/lib/fs/files.c b/src/lib/fs/files.c index aeaeb5daea..aff78db718 100644 --- a/src/lib/fs/files.c +++ b/src/lib/fs/files.c @@ -247,6 +247,22 @@ file_status(const char *fname) } } +/** Returns true if <b>file_type</b> represents an existing file (even if + * empty). Returns false otherwise. */ +bool +is_file(file_status_t file_type) +{ + return file_type != FN_ERROR && file_type != FN_NOENT && file_type != FN_DIR; +} + +/** Returns true if <b>file_type</b> represents an existing directory. Returns + * false otherwise. */ +bool +is_dir(file_status_t file_type) +{ + return file_type == FN_DIR; +} + /** Create a file named <b>fname</b> with the contents <b>str</b>. Overwrite * the previous <b>fname</b> if possible. Return 0 on success, -1 on failure. * @@ -607,6 +623,9 @@ read_file_to_str_until_eof(int fd, size_t max_bytes_to_read, size_t *sz_out) * If <b>flags</b> & RFTS_BIN, open the file in binary mode. * If <b>flags</b> & RFTS_IGNORE_MISSING, don't warn if the file * doesn't exist. + * + * Unless the RFTS_BIN flag is set in <b>flags</b>, this function will strip + * any CR characters in the return value on all platforms. */ /* * This function <em>may</em> return an erroneous result if the file @@ -685,7 +704,6 @@ read_file_to_str, (const char *filename, int flags, struct stat *stat_out)) } string[r] = '\0'; /* NUL-terminate the result. */ -#if defined(_WIN32) || defined(__CYGWIN__) if (!bin && strchr(string, '\r')) { log_debug(LD_FS, "We didn't convert CRLF to LF as well as we hoped " "when reading %s. Coping.", @@ -695,8 +713,7 @@ read_file_to_str, (const char *filename, int flags, struct stat *stat_out)) } if (!bin) { statbuf.st_size = (size_t) r; - } else -#endif /* defined(_WIN32) || defined(__CYGWIN__) */ + } else { if (r != statbuf.st_size) { /* Unless we're using text mode on win32, we'd better have an exact * match for size. */ @@ -708,6 +725,7 @@ read_file_to_str, (const char *filename, int flags, struct stat *stat_out)) errno = save_errno; return NULL; } + } close(fd); if (stat_out) { memcpy(stat_out, &statbuf, sizeof(struct stat)); @@ -716,6 +734,26 @@ read_file_to_str, (const char *filename, int flags, struct stat *stat_out)) return string; } +/** Attempt to read a file <b>fname</b>. If the file's contents is + * equal to the string <b>str</b>, return 0. Otherwise, attempt to + * overwrite the file with the contents of <b>str</b> and return + * the value of write_str_to_file(). + */ +int +write_str_to_file_if_not_equal(const char *fname, const char *str) +{ + char *fstr = read_file_to_str(fname, RFTS_IGNORE_MISSING, NULL); + int rv; + + if (!fstr || strcmp(str, fstr)) { + rv = write_str_to_file(fname, str, 0); + } else { + rv = 0; + } + tor_free(fstr); + return rv; +} + #if !defined(HAVE_GETDELIM) || defined(TOR_UNIT_TESTS) #include "ext/getdelim.c" #endif diff --git a/src/lib/fs/files.h b/src/lib/fs/files.h index a109cd6248..f0178e2b5b 100644 --- a/src/lib/fs/files.h +++ b/src/lib/fs/files.h @@ -55,6 +55,8 @@ MOCK_DECL(int,tor_unlink,(const char *pathname)); typedef enum { FN_ERROR, FN_NOENT, FN_FILE, FN_DIR, FN_EMPTY } file_status_t; file_status_t file_status(const char *filename); +bool is_file(file_status_t file_type); +bool is_dir(file_status_t file_type); int64_t tor_get_avail_disk_space(const char *path); @@ -91,6 +93,8 @@ int append_bytes_to_file(const char *fname, const char *str, size_t len, int write_bytes_to_new_file(const char *fname, const char *str, size_t len, int bin); +int write_str_to_file_if_not_equal(const char *fname, const char *str); + /** Flag for read_file_to_str: open the file in binary mode. */ #define RFTS_BIN 1 /** Flag for read_file_to_str: it's okay if the file doesn't exist. */ diff --git a/src/lib/fs/path.c b/src/lib/fs/path.c index 0d57be4b06..1a15969419 100644 --- a/src/lib/fs/path.c +++ b/src/lib/fs/path.c @@ -13,15 +13,34 @@ #include "lib/malloc/malloc.h" #include "lib/log/log.h" #include "lib/log/util_bug.h" +#include "lib/container/smartlist.h" +#include "lib/sandbox/sandbox.h" #include "lib/string/printf.h" #include "lib/string/util_string.h" #include "lib/string/compat_ctype.h" +#include "lib/string/compat_string.h" +#include "lib/fs/files.h" +#include "lib/fs/dir.h" #include "lib/fs/userdb.h" +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif #ifdef HAVE_UNISTD_H #include <unistd.h> #endif +#ifdef _WIN32 +#include <windows.h> +#include <shlwapi.h> +#else /* !(defined(_WIN32)) */ +#include <dirent.h> +#include <glob.h> +#endif /* defined(_WIN32) */ + #include <errno.h> #include <string.h> @@ -294,3 +313,357 @@ make_path_absolute(const char *fname) return absfname; #endif /* defined(_WIN32) */ } + +/* The code below implements tor_glob and get_glob_opened_files. Because it is + * not easy to understand it by looking at individual functions, the big + * picture explanation here should be read first. + * + * Purpose of the functions: + * - tor_glob - recevies a pattern and returns all the paths that result from + * its glob expansion, globs can be present on all path components. + * - get_glob_opened_files - receives a pattern and returns all the paths that + * are opened during its expansion (the paths before any path fragment that + * contains a glob as they have to be opened to check for glob matches). This + * is used to get the paths that have to be added to the seccomp sandbox + * allowed list. + * + * Due to OS API differences explained below, the implementation of tor_glob is + * completly different for Windows and POSIX systems, so we ended up with three + * different implementations: + * - tor_glob for POSIX - as POSIX glob does everything we need, we simply call + * it and process the results. This is completly implemented in tor_glob. + * - tor_glob for WIN32 - because the WIN32 API only supports expanding globs + * in the last path fragment, we need to expand the globs in each path + * fragment manually and call recursively to get the same behaviour as POSIX + * glob. When there are no globs in pattern, we know we are on the last path + * fragment and collect the full path. + * - get_glob_opened_files - because the paths before any path fragment with a + * glob will be opened to check for matches, we need to collect them and we + * need to expand the globs in each path fragments and call recursively until + * we find no more globs. + * + * As seen from the description above, both tor_glob for WIN32 and + * get_glob_opened_files receive a pattern and return a list of paths and have + * to expand all path fragments that contain globs and call themselves + * recursively. The differences are: + * - get_glob_opened_files collects paths before path fragments with globs + * while tor_glob for WIN32 collects full paths resulting from the expansion + * of all globs. + * - get_glob_opened_files can call tor_glob to expand path fragments with + * globs while tor_glob for WIN32 cannot because it IS tor_glob. For tor_glob + * for WIN32, an auxiliary function has to be used for this purpose. + * + * To avoid code duplication, the logic of tor_glob for WIN32 and + * get_glob_opened_files is implemented in get_glob_paths. The differences are + * configured by the extra function parameters: + * - final - if true, returns a list of paths obtained from expanding pattern + * (implements tor_glob). Otherwise, returns the paths before path fragments + * with globs (implements get_glob_opened_files). + * - unglob - function used to expand a path fragment. The function signature + * is defined by the unglob_fn typedef. Two implementations are available: + * - unglob_win32 - uses tor_listdir and PathMatchSpec (for tor_glob WIN32) + * - unglob_opened_files - uses tor_glob (for get_glob_opened_files) + */ + +/** Returns true if the character at position <b>pos</b> in <b>pattern</b> is + * considered a glob. Returns false otherwise. Takes escaping into account on + * systems where escaping globs is supported. */ +static inline bool +is_glob_char(const char *pattern, int pos) +{ + bool is_glob = pattern[pos] == '*' || pattern[pos] == '?'; +#ifdef _WIN32 + return is_glob; +#else /* !defined(_WIN32) */ + bool is_escaped = pos > 0 && pattern[pos-1] == '\\'; + return is_glob && !is_escaped; +#endif /* defined(_WIN32) */ +} + +/** Expands the first path fragment of <b>pattern</b> that contains globs. The + * path fragment is between <b>prev_sep</b> and <b>next_sep</b>. If the path + * fragment is the last fragment of <b>pattern</b>, <b>next_sep</b> will be the + * index of the last char. Returns a list of paths resulting from the glob + * expansion of the path fragment. Anything after <b>next_sep</b> is not + * included in the returned list. Returns NULL on failure. */ +typedef struct smartlist_t * unglob_fn(const char *pattern, int prev_sep, + int next_sep); + +/** Adds <b>path</b> to <b>result</b> if it exists and is a file type we can + * handle. Returns false if <b>path</b> is a file type we cannot handle, + * returns true otherwise. Used on tor_glob for WIN32. */ +static bool +add_non_glob_path(const char *path, struct smartlist_t *result) +{ + file_status_t file_type = file_status(path); + if (file_type == FN_ERROR) { + return false; + } else if (file_type != FN_NOENT) { + char *to_add = tor_strdup(path); + clean_fname_for_stat(to_add); + smartlist_add(result, to_add); + } + /* If WIN32 tor_glob is called with a non-existing path, we want it to + * return an empty list instead of error to match the regular version */ + return true; +} + +/** Auxiliary function used by get_glob_opened_files and WIN32 tor_glob. + * Returns a list of paths obtained from <b>pattern</b> using <b>unglob</b> to + * expand each path fragment. If <b>final</b> is true, the paths are the result + * of the glob expansion of <b>pattern</b> (implements tor_glob). Otherwise, + * the paths are the paths opened by glob while expanding <b>pattern</b> + * (implements get_glob_opened_files). Returns NULL on failure. */ +static struct smartlist_t * +get_glob_paths(const char *pattern, unglob_fn unglob, bool final) +{ + smartlist_t *result = smartlist_new(); + int i, prev_sep = -1, next_sep = -1; + bool is_glob = false, error_found = false, is_sep = false, is_last = false; + + // find first path fragment with globs + for (i = 0; pattern[i]; i++) { + is_glob = is_glob || is_glob_char(pattern, i); + is_last = !pattern[i+1]; + is_sep = pattern[i] == *PATH_SEPARATOR || pattern[i] == '/'; + if (is_sep || is_last) { + prev_sep = next_sep; + next_sep = i; // next_sep+1 is start of next fragment or end of string + if (is_glob) { + break; + } + } + } + + if (!is_glob) { // pattern fully expanded or no glob in pattern + if (final && !add_non_glob_path(pattern, result)) { + error_found = true; + goto end; + } + return result; + } + + if (!final) { + // add path before the glob to result + int len = prev_sep < 1 ? prev_sep + 1 : prev_sep; // handle /* + char *path_until_glob = tor_strndup(pattern, len); + smartlist_add(result, path_until_glob); + } + + smartlist_t *unglobbed_paths = unglob(pattern, prev_sep, next_sep); + if (!unglobbed_paths) { + error_found = true; + } else { + // for each path for current fragment, add the rest of the pattern + // and call recursively to get all expanded paths + SMARTLIST_FOREACH_BEGIN(unglobbed_paths, char *, current_path) { + char *next_path; + tor_asprintf(&next_path, "%s"PATH_SEPARATOR"%s", current_path, + &pattern[next_sep+1]); + smartlist_t *opened_next = get_glob_paths(next_path, unglob, final); + tor_free(next_path); + if (!opened_next) { + error_found = true; + break; + } + smartlist_add_all(result, opened_next); + smartlist_free(opened_next); + } SMARTLIST_FOREACH_END(current_path); + SMARTLIST_FOREACH(unglobbed_paths, char *, p, tor_free(p)); + smartlist_free(unglobbed_paths); + } + +end: + if (error_found) { + SMARTLIST_FOREACH(result, char *, p, tor_free(p)); + smartlist_free(result); + result = NULL; + } + return result; +} + +#ifdef _WIN32 +/** Expands globs in <b>pattern</b> for the path fragment between + * <b>prev_sep</b> and <b>next_sep</b> using the WIN32 API. Returns NULL on + * failure. Used by the WIN32 implementation of tor_glob. Implements unglob_fn, + * see its description for more details. */ +static struct smartlist_t * +unglob_win32(const char *pattern, int prev_sep, int next_sep) +{ + smartlist_t *result = smartlist_new(); + int len = prev_sep < 1 ? prev_sep + 1 : prev_sep; // handle /* + char *path_until_glob = tor_strndup(pattern, len); + + if (!is_file(file_status(path_until_glob))) { + smartlist_t *filenames = tor_listdir(path_until_glob); + if (!filenames) { + smartlist_free(result); + result = NULL; + } else { + SMARTLIST_FOREACH_BEGIN(filenames, char *, filename) { + TCHAR tpattern[MAX_PATH] = {0}; + TCHAR tfile[MAX_PATH] = {0}; + char *full_path; + tor_asprintf(&full_path, "%s"PATH_SEPARATOR"%s", + path_until_glob, filename); + char *path_curr_glob = tor_strndup(pattern, next_sep + 1); + // *\ must return only dirs, remove \ from the pattern so it matches + if (is_dir(file_status(full_path))) { + clean_fname_for_stat(path_curr_glob); + } +#ifdef UNICODE + mbstowcs(tpattern, path_curr_glob, MAX_PATH); + mbstowcs(tfile, full_path, MAX_PATH); +#else /* !defined(UNICODE) */ + strlcpy(tpattern, path_curr_glob, MAX_PATH); + strlcpy(tfile, full_path, MAX_PATH); +#endif /* defined(UNICODE) */ + if (PathMatchSpec(tfile, tpattern)) { + smartlist_add(result, full_path); + } else { + tor_free(full_path); + } + tor_free(path_curr_glob); + } SMARTLIST_FOREACH_END(filename); + SMARTLIST_FOREACH(filenames, char *, p, tor_free(p)); + smartlist_free(filenames); + } + } + tor_free(path_until_glob); + return result; +} +#elif HAVE_GLOB +/** Same as opendir but calls sandbox_intern_string before */ +static DIR * +prot_opendir(const char *name) +{ + return opendir(sandbox_intern_string(name)); +} + +/** Same as stat but calls sandbox_intern_string before */ +static int +prot_stat(const char *pathname, struct stat *buf) +{ + return stat(sandbox_intern_string(pathname), buf); +} + +/** Same as lstat but calls sandbox_intern_string before */ +static int +prot_lstat(const char *pathname, struct stat *buf) +{ + return lstat(sandbox_intern_string(pathname), buf); +} +/** As closedir, but has the right type for gl_closedir */ +static void +wrap_closedir(void *arg) +{ + closedir(arg); +} +#endif /* defined(HAVE_GLOB) */ + +/** Return a new list containing the paths that match the pattern + * <b>pattern</b>. Return NULL on error. On POSIX systems, errno is set by the + * glob function. + */ +struct smartlist_t * +tor_glob(const char *pattern) +{ + smartlist_t *result = NULL; + +#ifdef _WIN32 + // PathMatchSpec does not support forward slashes, change them to backslashes + char *pattern_normalized = tor_strdup(pattern); + tor_strreplacechar(pattern_normalized, '/', *PATH_SEPARATOR); + result = get_glob_paths(pattern_normalized, unglob_win32, true); + tor_free(pattern_normalized); +#elif HAVE_GLOB /* !(defined(_WIN32)) */ + glob_t matches; + int flags = GLOB_ERR | GLOB_NOSORT; +#ifdef GLOB_ALTDIRFUNC + /* use functions that call sandbox_intern_string */ + flags |= GLOB_ALTDIRFUNC; + typedef void *(*gl_opendir)(const char * name); + typedef struct dirent *(*gl_readdir)(void *); + typedef void (*gl_closedir)(void *); + matches.gl_opendir = (gl_opendir) &prot_opendir; + matches.gl_readdir = (gl_readdir) &readdir; + matches.gl_closedir = (gl_closedir) &wrap_closedir; + matches.gl_stat = &prot_stat; + matches.gl_lstat = &prot_lstat; +#endif /* defined(GLOB_ALTDIRFUNC) */ + int ret = glob(pattern, flags, NULL, &matches); + if (ret == GLOB_NOMATCH) { + return smartlist_new(); + } else if (ret != 0) { + return NULL; + } + + result = smartlist_new(); + size_t i; + for (i = 0; i < matches.gl_pathc; i++) { + char *match = tor_strdup(matches.gl_pathv[i]); + size_t len = strlen(match); + if (len > 0 && match[len-1] == *PATH_SEPARATOR) { + match[len-1] = '\0'; + } + smartlist_add(result, match); + } + globfree(&matches); +#else + (void)pattern; + return result; +#endif /* !defined(HAVE_GLOB) */ + + return result; +} + +/** Returns true if <b>s</b> contains characters that can be globbed. + * Returns false otherwise. */ +bool +has_glob(const char *s) +{ + int i; + for (i = 0; s[i]; i++) { + if (is_glob_char(s, i)) { + return true; + } + } + return false; +} + +/** Expands globs in <b>pattern</b> for the path fragment between + * <b>prev_sep</b> and <b>next_sep</b> using tor_glob. Returns NULL on + * failure. Used by get_glob_opened_files. Implements unglob_fn, see its + * description for more details. */ +static struct smartlist_t * +unglob_opened_files(const char *pattern, int prev_sep, int next_sep) +{ + (void)prev_sep; + smartlist_t *result = smartlist_new(); + // if the following fragments have no globs, we're done + if (has_glob(&pattern[next_sep+1])) { + // if there is a glob after next_sep, we know next_sep is a separator and + // not the last char and glob_path will have the path without the separator + char *glob_path = tor_strndup(pattern, next_sep); + smartlist_t *child_paths = tor_glob(glob_path); + tor_free(glob_path); + if (!child_paths) { + smartlist_free(result); + result = NULL; + } else { + smartlist_add_all(result, child_paths); + smartlist_free(child_paths); + } + } + return result; +} + +/** Returns a list of files that are opened by the tor_glob function when + * called with <b>pattern</b>. Returns NULL on error. The purpose of this + * function is to create a list of files to be added to the sandbox white list + * before the sandbox is enabled. */ +struct smartlist_t * +get_glob_opened_files(const char *pattern) +{ + return get_glob_paths(pattern, unglob_opened_files, false); +} diff --git a/src/lib/fs/path.h b/src/lib/fs/path.h index f0e253c556..425bd12516 100644 --- a/src/lib/fs/path.h +++ b/src/lib/fs/path.h @@ -12,6 +12,10 @@ #ifndef TOR_PATH_H #define TOR_PATH_H +#include <stdbool.h> +#ifdef _WIN32 +#include <windows.h> +#endif #include "lib/cc/compat_compiler.h" #ifdef _WIN32 @@ -26,5 +30,8 @@ int path_is_relative(const char *filename); void clean_fname_for_stat(char *name); int get_parent_directory(char *fname); char *make_path_absolute(const char *fname); +struct smartlist_t *tor_glob(const char *pattern); +bool has_glob(const char *s); +struct smartlist_t *get_glob_opened_files(const char *pattern); #endif /* !defined(TOR_PATH_H) */ diff --git a/src/lib/log/log.c b/src/lib/log/log.c index 9ee87c0668..cd848fdd73 100644 --- a/src/lib/log/log.c +++ b/src/lib/log/log.c @@ -1308,7 +1308,7 @@ log_level_to_string(int level) /** NULL-terminated array of names for log domains such that domain_list[dom] * is a description of <b>dom</b>. * - * Remember to update doc/tor.1.txt if you modify this list. + * Remember to update doc/man/tor.1.txt if you modify this list. * */ static const char *domain_list[] = { "GENERAL", "CRYPTO", "NET", "CONFIG", "FS", "PROTOCOL", "MM", diff --git a/src/lib/log/ratelim.c b/src/lib/log/ratelim.c index ac401fb398..8dfaee3384 100644 --- a/src/lib/log/ratelim.c +++ b/src/lib/log/ratelim.c @@ -11,6 +11,7 @@ #include "lib/log/ratelim.h" #include "lib/malloc/malloc.h" #include "lib/string/printf.h" +#include "lib/intmath/muldiv.h" /** If the rate-limiter <b>lim</b> is ready at <b>now</b>, return the number * of calls to rate_limit_is_ready (including this one!) since the last time @@ -42,19 +43,24 @@ rate_limit_log(ratelim_t *lim, time_t now) { int n; if ((n = rate_limit_is_ready(lim, now))) { + time_t started_limiting = lim->started_limiting; + lim->started_limiting = 0; if (n == 1) { return tor_strdup(""); } else { char *cp=NULL; const char *opt_over = (n >= RATELIM_TOOMANY) ? "over " : ""; - /* XXXX this is not exactly correct: the messages could have occurred - * any time between the old value of lim->allowed and now. */ + unsigned difference = (unsigned)(now - started_limiting); + difference = round_to_next_multiple_of(difference, 60); tor_asprintf(&cp, " [%s%d similar message(s) suppressed in last %d seconds]", - opt_over, n-1, lim->rate); + opt_over, n-1, (int)difference); return cp; } } else { + if (lim->started_limiting == 0) { + lim->started_limiting = now; + } return NULL; } } diff --git a/src/lib/log/ratelim.h b/src/lib/log/ratelim.h index e9b55d40dc..9e202028cf 100644 --- a/src/lib/log/ratelim.h +++ b/src/lib/log/ratelim.h @@ -40,13 +40,19 @@ </pre> */ typedef struct ratelim_t { + /** How many seconds must elapse between log messages? */ int rate; + /** When did this limiter last allow a message to appear? */ time_t last_allowed; + /** When did this limiter start suppressing messages? */ + time_t started_limiting; + /** How many messages has this limiter suppressed since it last allowed + * one to appear? */ int n_calls_since_last_time; } ratelim_t; #ifndef COCCI -#define RATELIM_INIT(r) { (r), 0, 0 } +#define RATELIM_INIT(r) { (r), 0, 0, 0 } #endif #define RATELIM_TOOMANY (16*1000*1000) diff --git a/src/lib/net/address.c b/src/lib/net/address.c index 6d46f9b955..ea6c29db9f 100644 --- a/src/lib/net/address.c +++ b/src/lib/net/address.c @@ -764,6 +764,15 @@ tor_addr_is_v4(const tor_addr_t *addr) return 0; /* Not IPv4 - unknown family or a full-blood IPv6 address */ } +/** Determine whether an address <b>addr</b> is an IPv6 (AF_INET6). Return + * true if so else false. */ +int +tor_addr_is_v6(const tor_addr_t *addr) +{ + tor_assert(addr); + return (tor_addr_family(addr) == AF_INET6); +} + /** Determine whether an address <b>addr</b> is null, either all zeroes or * belonging to family AF_UNSPEC. */ @@ -1217,20 +1226,28 @@ fmt_addr32(uint32_t addr) return buf; } -/** Return a string representing the family of <b>addr</b>. +/** Like fmt_addrport(), but takes <b>addr</b> as a host-order IPv4 + * addresses. Also not thread-safe, also clobbers its return buffer on + * repeated calls. */ +const char * +fmt_addr32_port(uint32_t addr, uint16_t port) +{ + static char buf[INET_NTOA_BUF_LEN + 6]; + snprintf(buf, sizeof(buf), "%s:%u", fmt_addr32(addr), port); + return buf; +} + +/** Return a string representing <b>family</b>. * * This string is a string constant, and must not be freed. * This function is thread-safe. */ const char * -fmt_addr_family(const tor_addr_t *addr) +fmt_af_family(sa_family_t family) { static int default_bug_once = 0; - IF_BUG_ONCE(!addr) - return "NULL pointer"; - - switch (tor_addr_family(addr)) { + switch (family) { case AF_INET6: return "IPv6"; case AF_INET: @@ -1242,7 +1259,7 @@ fmt_addr_family(const tor_addr_t *addr) default: if (!default_bug_once) { log_warn(LD_BUG, "Called with unknown address family %d", - (int)tor_addr_family(addr)); + (int)family); default_bug_once = 1; } return "unknown"; @@ -1250,6 +1267,20 @@ fmt_addr_family(const tor_addr_t *addr) //return "(unreachable code)"; } +/** Return a string representing the family of <b>addr</b>. + * + * This string is a string constant, and must not be freed. + * This function is thread-safe. + */ +const char * +fmt_addr_family(const tor_addr_t *addr) +{ + IF_BUG_ONCE(!addr) + return "NULL pointer"; + + return fmt_af_family(tor_addr_family(addr)); +} + /** Convert the string in <b>src</b> to a tor_addr_t <b>addr</b>. The string * may be an IPv4 address, or an IPv6 address surrounded by square brackets. * @@ -1700,8 +1731,8 @@ get_interface_address6,(int severity, sa_family_t family, tor_addr_t *addr)) /* Get a list of public or internal IPs in arbitrary order */ addrs = get_interface_address6_list(severity, family, 1); - /* Find the first non-internal address, or the last internal address - * Ideally, we want the default route, see #12377 for details */ + /* Find the first non-internal address, or the last internal address. + * Ideally, we want the default route; see #12377 for details. */ SMARTLIST_FOREACH_BEGIN(addrs, tor_addr_t *, a) { tor_addr_copy(addr, a); const bool is_internal = tor_addr_is_internal(a, 0); @@ -2083,6 +2114,18 @@ tor_addr_port_eq(const tor_addr_port_t *a, return tor_addr_eq(&a->addr, &b->addr) && a->port == b->port; } +/** + * Copy a tor_addr_port_t from @a source to @a dest. + **/ +void +tor_addr_port_copy(tor_addr_port_t *dest, + const tor_addr_port_t *source) +{ + tor_assert(dest); + tor_assert(source); + memcpy(dest, source, sizeof(tor_addr_port_t)); +} + /** Return true if <b>string</b> represents a valid IPv4 adddress in * 'a.b.c.d' form. */ diff --git a/src/lib/net/address.h b/src/lib/net/address.h index e5016ee4fe..bc8ec7744f 100644 --- a/src/lib/net/address.h +++ b/src/lib/net/address.h @@ -95,6 +95,7 @@ static inline uint32_t tor_addr_to_ipv4n(const tor_addr_t *a); static inline uint32_t tor_addr_to_ipv4h(const tor_addr_t *a); static inline uint32_t tor_addr_to_mapped_ipv4h(const tor_addr_t *a); static inline sa_family_t tor_addr_family(const tor_addr_t *a); +static inline bool tor_addr_is_unspec(const tor_addr_t *a); static inline const struct in_addr *tor_addr_to_in(const tor_addr_t *a); static inline int tor_addr_eq_ipv4h(const tor_addr_t *a, uint32_t u); @@ -188,6 +189,15 @@ tor_addr_family(const tor_addr_t *a) return a->family; } +/** + * Return true if the address @a is in the UNSPEC family. + **/ +static inline bool +tor_addr_is_unspec(const tor_addr_t *a) +{ + return a->family == AF_UNSPEC; +} + /** Return an in_addr* equivalent to <b>a</b>, or NULL if <b>a</b> is not * an IPv4 address. */ static inline const struct in_addr * @@ -236,6 +246,8 @@ const char *fmt_addr_impl(const tor_addr_t *addr, int decorate); const char *fmt_addrport(const tor_addr_t *addr, uint16_t port); #define fmt_addrport_ap(ap) fmt_addrport(&(ap)->addr, (ap)->port) const char *fmt_addr32(uint32_t addr); +const char *fmt_addr32_port(uint32_t addr, uint16_t port); +const char *fmt_af_family(sa_family_t family); const char *fmt_addr_family(const tor_addr_t *addr); MOCK_DECL(int,get_interface_address6,(int severity, sa_family_t family, @@ -272,6 +284,7 @@ struct sipkey; uint64_t tor_addr_keyed_hash(const struct sipkey *key, const tor_addr_t *addr); int tor_addr_is_v4(const tor_addr_t *addr); +int tor_addr_is_v6(const tor_addr_t *addr); int tor_addr_is_internal_(const tor_addr_t *ip, int for_listening, const char *filename, int lineno); #define tor_addr_is_internal(addr, for_listening) \ @@ -381,6 +394,7 @@ get_interface_address_list(int severity, int include_internal) tor_addr_port_t *tor_addr_port_new(const tor_addr_t *addr, uint16_t port); int tor_addr_port_eq(const tor_addr_port_t *a, const tor_addr_port_t *b); +void tor_addr_port_copy(tor_addr_port_t *dest, const tor_addr_port_t *source); int string_is_valid_dest(const char *string); int string_is_valid_nonrfc_hostname(const char *string); diff --git a/src/lib/net/buffers_net.c b/src/lib/net/buffers_net.c index 4dbf491e1a..4a0eb3bf16 100644 --- a/src/lib/net/buffers_net.c +++ b/src/lib/net/buffers_net.c @@ -137,13 +137,12 @@ buf_read_from_fd(buf_t *buf, int fd, size_t at_most, } /** Helper for buf_flush_to_socket(): try to write <b>sz</b> bytes from chunk - * <b>chunk</b> of buffer <b>buf</b> onto file descriptor <b>fd</b>. On - * success, deduct the bytes written from *<b>buf_flushlen</b>. Return the - * number of bytes written on success, 0 on blocking, -1 on failure. + * <b>chunk</b> of buffer <b>buf</b> onto file descriptor <b>fd</b>. Return + * the number of bytes written on success, 0 on blocking, -1 on failure. */ static inline int flush_chunk(tor_socket_t fd, buf_t *buf, chunk_t *chunk, size_t sz, - size_t *buf_flushlen, bool is_socket) + bool is_socket) { ssize_t write_result; @@ -168,7 +167,6 @@ flush_chunk(tor_socket_t fd, buf_t *buf, chunk_t *chunk, size_t sz, log_debug(LD_NET,"write() would block, returning."); return 0; } else { - *buf_flushlen -= write_result; buf_drain(buf, write_result); tor_assert(write_result <= BUF_MAX_LEN); return (int)write_result; @@ -176,27 +174,22 @@ flush_chunk(tor_socket_t fd, buf_t *buf, chunk_t *chunk, size_t sz, } /** Write data from <b>buf</b> to the file descriptor <b>fd</b>. Write at most - * <b>sz</b> bytes, decrement *<b>buf_flushlen</b> by - * the number of bytes actually written, and remove the written bytes + * <b>sz</b> bytes, and remove the written bytes * from the buffer. Return the number of bytes written on success, * -1 on failure. Return 0 if write() would block. */ static int buf_flush_to_fd(buf_t *buf, int fd, size_t sz, - size_t *buf_flushlen, bool is_socket) + bool is_socket) { /* XXXX It's stupid to overload the return values for these functions: * "error status" and "number of bytes flushed" are not mutually exclusive. */ int r; size_t flushed = 0; - tor_assert(buf_flushlen); tor_assert(SOCKET_OK(fd)); - if (BUG(*buf_flushlen > buf->datalen)) { - *buf_flushlen = buf->datalen; - } - if (BUG(sz > *buf_flushlen)) { - sz = *buf_flushlen; + if (BUG(sz > buf->datalen)) { + sz = buf->datalen; } check(); @@ -208,7 +201,7 @@ buf_flush_to_fd(buf_t *buf, int fd, size_t sz, else flushlen0 = buf->head->datalen; - r = flush_chunk(fd, buf, buf->head, flushlen0, buf_flushlen, is_socket); + r = flush_chunk(fd, buf, buf->head, flushlen0, is_socket); check(); if (r < 0) return r; @@ -228,10 +221,9 @@ buf_flush_to_fd(buf_t *buf, int fd, size_t sz, * -1 on failure. Return 0 if write() would block. */ int -buf_flush_to_socket(buf_t *buf, tor_socket_t s, size_t sz, - size_t *buf_flushlen) +buf_flush_to_socket(buf_t *buf, tor_socket_t s, size_t sz) { - return buf_flush_to_fd(buf, s, sz, buf_flushlen, true); + return buf_flush_to_fd(buf, s, sz, true); } /** Read from socket <b>s</b>, writing onto end of <b>buf</b>. Read at most @@ -254,10 +246,9 @@ buf_read_from_socket(buf_t *buf, tor_socket_t s, size_t at_most, * -1 on failure. Return 0 if write() would block. */ int -buf_flush_to_pipe(buf_t *buf, int fd, size_t sz, - size_t *buf_flushlen) +buf_flush_to_pipe(buf_t *buf, int fd, size_t sz) { - return buf_flush_to_fd(buf, fd, sz, buf_flushlen, false); + return buf_flush_to_fd(buf, fd, sz, false); } /** Read from pipe <b>fd</b>, writing onto end of <b>buf</b>. Read at most diff --git a/src/lib/net/buffers_net.h b/src/lib/net/buffers_net.h index a45c23a273..556575c3dc 100644 --- a/src/lib/net/buffers_net.h +++ b/src/lib/net/buffers_net.h @@ -21,14 +21,12 @@ int buf_read_from_socket(struct buf_t *buf, tor_socket_t s, size_t at_most, int *reached_eof, int *socket_error); -int buf_flush_to_socket(struct buf_t *buf, tor_socket_t s, size_t sz, - size_t *buf_flushlen); +int buf_flush_to_socket(struct buf_t *buf, tor_socket_t s, size_t sz); int buf_read_from_pipe(struct buf_t *buf, int fd, size_t at_most, int *reached_eof, int *socket_error); -int buf_flush_to_pipe(struct buf_t *buf, int fd, size_t sz, - size_t *buf_flushlen); +int buf_flush_to_pipe(struct buf_t *buf, int fd, size_t sz); #endif /* !defined(TOR_BUFFERS_NET_H) */ diff --git a/src/lib/osinfo/include.am b/src/lib/osinfo/include.am index 84bd7feb00..df8c98500c 100644 --- a/src/lib/osinfo/include.am +++ b/src/lib/osinfo/include.am @@ -7,7 +7,8 @@ endif # ADD_C_FILE: INSERT SOURCES HERE. src_lib_libtor_osinfo_a_SOURCES = \ - src/lib/osinfo/uname.c + src/lib/osinfo/uname.c \ + src/lib/osinfo/libc.c src_lib_libtor_osinfo_testing_a_SOURCES = \ $(src_lib_libtor_osinfo_a_SOURCES) @@ -16,4 +17,5 @@ src_lib_libtor_osinfo_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) # ADD_C_FILE: INSERT HEADERS HERE. noinst_HEADERS += \ - src/lib/osinfo/uname.h + src/lib/osinfo/uname.h \ + src/lib/osinfo/libc.h diff --git a/src/lib/osinfo/libc.c b/src/lib/osinfo/libc.c new file mode 100644 index 0000000000..32cbad0fa2 --- /dev/null +++ b/src/lib/osinfo/libc.c @@ -0,0 +1,66 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2020, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file libc.c + * @brief Functions to get the name and version of the system libc. + **/ + +#include "orconfig.h" +#include "lib/osinfo/libc.h" +#include <stdlib.h> + +#ifdef HAVE_GNU_LIBC_VERSION_H +#include <gnu/libc-version.h> +#endif + +#ifdef HAVE_GNU_LIBC_VERSION_H +#ifdef HAVE_GNU_GET_LIBC_VERSION +#define CHECK_LIBC_VERSION +#endif +#endif + +#define STR_IMPL(x) #x +#define STR(x) STR_IMPL(x) + +/** Return the name of the compile time libc. Returns NULL if we + * cannot identify the libc. */ +const char * +tor_libc_get_name(void) +{ +#ifdef __GLIBC__ + return "Glibc"; +#else /* !defined(__GLIBC__) */ + return NULL; +#endif /* defined(__GLIBC__) */ +} + +/** Return a string representation of the version of the currently running + * version of Glibc. */ +const char * +tor_libc_get_version_str(void) +{ +#ifdef CHECK_LIBC_VERSION + const char *version = gnu_get_libc_version(); + if (version == NULL) + return "N/A"; + return version; +#else /* !defined(CHECK_LIBC_VERSION) */ + return "N/A"; +#endif /* defined(CHECK_LIBC_VERSION) */ +} + +/** Return a string representation of the version of Glibc that was used at + * compilation time. */ +const char * +tor_libc_get_header_version_str(void) +{ +#ifdef __GLIBC__ + return STR(__GLIBC__) "." STR(__GLIBC_MINOR__); +#else + return "N/A"; +#endif /* defined(__GLIBC__) */ +} diff --git a/src/lib/osinfo/libc.h b/src/lib/osinfo/libc.h new file mode 100644 index 0000000000..f4303f8c9c --- /dev/null +++ b/src/lib/osinfo/libc.h @@ -0,0 +1,19 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2020, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file libc.h + * @brief Header for lib/osinfo/libc.c + **/ + +#ifndef TOR_LIB_OSINFO_LIBC_H +#define TOR_LIB_OSINFO_LIBC_H + +const char *tor_libc_get_name(void); +const char *tor_libc_get_version_str(void); +const char *tor_libc_get_header_version_str(void); + +#endif /* !defined(TOR_LIB_OSINFO_LIBC_H) */ diff --git a/src/lib/process/process_unix.c b/src/lib/process/process_unix.c index 2b47e1874d..82b2630a5d 100644 --- a/src/lib/process/process_unix.c +++ b/src/lib/process/process_unix.c @@ -418,7 +418,7 @@ process_unix_write(process_t *process, buf_t *buffer) /* We have data to write and the kernel have told us to write it. */ return buf_flush_to_pipe(buffer, process_get_unix_process(process)->stdin_handle.fd, - max_to_write, &buffer_flush_len); + max_to_write); } /** Read data from the given process's standard output and put it into diff --git a/src/lib/sandbox/sandbox.c b/src/lib/sandbox/sandbox.c index d4f0da8397..8d467c516e 100644 --- a/src/lib/sandbox/sandbox.c +++ b/src/lib/sandbox/sandbox.c @@ -204,6 +204,8 @@ static int filter_nopar_gen[] = { #ifdef __NR__llseek SCMP_SYS(_llseek), #endif + // glob uses this.. + SCMP_SYS(lstat), SCMP_SYS(mkdir), SCMP_SYS(mlockall), #ifdef __NR_mmap @@ -997,7 +999,7 @@ sb_epoll_ctl(scmp_filter_ctx ctx, sandbox_cfg_t *filter) * the seccomp filter sandbox. * * NOTE: if multiple filters need to be added, the PR_SECCOMP parameter needs - * to be whitelisted in this function. + * to be allowlisted in this function. */ static int sb_prctl(scmp_filter_ctx ctx, sandbox_cfg_t *filter) diff --git a/src/lib/string/compat_string.h b/src/lib/string/compat_string.h index f05265bdcc..5c9bf05ebd 100644 --- a/src/lib/string/compat_string.h +++ b/src/lib/string/compat_string.h @@ -42,7 +42,7 @@ static inline int strcasecmp(const char *a, const char *b) { * (If --enable-fragile-hardening is passed to configure, we use the hardened * variants, which do not suffer from this issue.) * - * See https://trac.torproject.org/projects/tor/ticket/15205 + * See https://bugs.torproject.org/tpo/core/tor/15205. */ #undef strlcat #undef strlcpy diff --git a/src/lib/string/util_string.c b/src/lib/string/util_string.c index c8f12d780e..ba5f9f2203 100644 --- a/src/lib/string/util_string.c +++ b/src/lib/string/util_string.c @@ -143,6 +143,15 @@ tor_strupper(char *s) } } +/** Replaces <b>old</b> with <b>replacement</b> in <b>s</b> */ +void +tor_strreplacechar(char *s, char find, char replacement) +{ + for (s = strchr(s, find); s; s = strchr(s + 1, find)) { + *s = replacement; + } +} + /** Return 1 if every character in <b>s</b> is printable, else return 0. */ int diff --git a/src/lib/string/util_string.h b/src/lib/string/util_string.h index e89233df88..15d35415fe 100644 --- a/src/lib/string/util_string.h +++ b/src/lib/string/util_string.h @@ -31,6 +31,7 @@ int tor_digest256_is_zero(const char *digest); #define HEX_CHARACTERS "0123456789ABCDEFabcdef" void tor_strlower(char *s); void tor_strupper(char *s); +void tor_strreplacechar(char *s, char find, char replacement); int tor_strisprint(const char *s); int tor_strisnonupper(const char *s); int tor_strisspace(const char *s); diff --git a/src/lib/tls/buffers_tls.c b/src/lib/tls/buffers_tls.c index b92a14d6a1..de0e9cb4ef 100644 --- a/src/lib/tls/buffers_tls.c +++ b/src/lib/tls/buffers_tls.c @@ -59,6 +59,9 @@ read_to_chunk_tls(buf_t *buf, chunk_t *chunk, tor_tls_t *tls, * Second, the TLS stream's events do not correspond directly to network * events: sometimes, before a TLS stream can read, the network must be * ready to write -- or vice versa. + * + * On success, return the number of bytes read. On error, a TOR_TLS_* negative + * code is returned (expect any of them except TOR_TLS_DONE). */ int buf_read_from_tls(buf_t *buf, tor_tls_t *tls, size_t at_most) @@ -92,8 +95,6 @@ buf_read_from_tls(buf_t *buf, tor_tls_t *tls, size_t at_most) return r; /* Error */ tor_assert(total_read+r <= BUF_MAX_LEN); total_read += r; - if ((size_t)r < readlen) /* eof, block, or no more to read. */ - break; } return (int)total_read; } @@ -105,8 +106,7 @@ buf_read_from_tls(buf_t *buf, tor_tls_t *tls, size_t at_most) * written on success, and a TOR_TLS error code on failure or blocking. */ static inline int -flush_chunk_tls(tor_tls_t *tls, buf_t *buf, chunk_t *chunk, - size_t sz, size_t *buf_flushlen) +flush_chunk_tls(tor_tls_t *tls, buf_t *buf, chunk_t *chunk, size_t sz) { int r; size_t forced; @@ -125,13 +125,9 @@ flush_chunk_tls(tor_tls_t *tls, buf_t *buf, chunk_t *chunk, r = tor_tls_write(tls, data, sz); if (r < 0) return r; - if (*buf_flushlen > (size_t)r) - *buf_flushlen -= r; - else - *buf_flushlen = 0; buf_drain(buf, r); - log_debug(LD_NET,"flushed %d bytes, %d ready to flush, %d remain.", - r,(int)*buf_flushlen,(int)buf->datalen); + log_debug(LD_NET,"flushed %d bytes, %d remain.", + r,(int)buf->datalen); return r; } @@ -139,18 +135,13 @@ flush_chunk_tls(tor_tls_t *tls, buf_t *buf, chunk_t *chunk, * more than <b>flushlen</b> bytes. */ int -buf_flush_to_tls(buf_t *buf, tor_tls_t *tls, size_t flushlen, - size_t *buf_flushlen) +buf_flush_to_tls(buf_t *buf, tor_tls_t *tls, size_t flushlen) { int r; size_t flushed = 0; ssize_t sz; - tor_assert(buf_flushlen); - IF_BUG_ONCE(*buf_flushlen > buf->datalen) { - *buf_flushlen = buf->datalen; - } - IF_BUG_ONCE(flushlen > *buf_flushlen) { - flushlen = *buf_flushlen; + IF_BUG_ONCE(flushlen > buf->datalen) { + flushlen = buf->datalen; } sz = (ssize_t) flushlen; @@ -169,7 +160,7 @@ buf_flush_to_tls(buf_t *buf, tor_tls_t *tls, size_t flushlen, flushlen0 = 0; } - r = flush_chunk_tls(tls, buf, buf->head, flushlen0, buf_flushlen); + r = flush_chunk_tls(tls, buf, buf->head, flushlen0); if (r < 0) return r; flushed += r; diff --git a/src/lib/tls/buffers_tls.h b/src/lib/tls/buffers_tls.h index 587426801d..ed391cefbd 100644 --- a/src/lib/tls/buffers_tls.h +++ b/src/lib/tls/buffers_tls.h @@ -18,6 +18,6 @@ struct tor_tls_t; int buf_read_from_tls(struct buf_t *buf, struct tor_tls_t *tls, size_t at_most); int buf_flush_to_tls(struct buf_t *buf, struct tor_tls_t *tls, - size_t sz, size_t *buf_flushlen); + size_t sz); #endif /* !defined(TOR_BUFFERS_TLS_H) */ diff --git a/src/lib/trace/.may_include b/src/lib/trace/.may_include index 45cd13676b..1ed533cc7a 100644 --- a/src/lib/trace/.may_include +++ b/src/lib/trace/.may_include @@ -1,3 +1,4 @@ orconfig.h lib/log/*.h lib/trace/*.h +lib/subsys/*.h diff --git a/src/lib/trace/debug.h b/src/lib/trace/debug.h index 87b3074e0b..84a2867a6d 100644 --- a/src/lib/trace/debug.h +++ b/src/lib/trace/debug.h @@ -6,8 +6,10 @@ * \brief Macros for debugging our event-trace support. **/ -#ifndef TOR_TRACE_LOG_DEBUG_H -#define TOR_TRACE_LOG_DEBUG_H +#ifndef TOR_TRACE_DEBUG_H +#define TOR_TRACE_DEBUG_H + +#ifdef USE_TRACING_INSTRUMENTATION_LOG_DEBUG #include "lib/log/log.h" @@ -17,14 +19,20 @@ /* Send every event to a debug log level. This is useful to debug new trace * events without implementing them for a specific event tracing framework. - * Note that the arguments are ignored since at this step we do not know the - * types and amount there is. */ + * + * NOTE: arguments can't be used becaue there is no easy generic ways to learn + * their type and amount. It is probably doable with massive C pre-processor + * trickery but this is meant to be simple. */ + +#define TOR_TRACE_LOG_DEBUG(subsystem, event_name, ...) \ + log_debug(LD_GENERAL, "Tracepoint \"" XSTR(event_name) "\" from " \ + "subsystem \"" XSTR(subsystem) "\" hit.") + +#else /* defined(USE_TRACING_INSTRUMENTATION_LOG_DEBUG) */ + +/* NOP the debug event. */ +#define TOR_TRACE_LOG_DEBUG(subsystem, name, ...) -/* Example on how to map a tracepoint to log_debug(). */ -#undef tor_trace -#define tor_trace(subsystem, name, args...) \ - log_debug(LD_GENERAL, "Trace event \"" XSTR(name) "\" from " \ - "\"" XSTR(subsystem) "\" hit. " \ - "(line "XSTR(__LINE__) ")") +#endif /* defined(USE_TRACING_INSTRUMENTATION_LOG_DEBUG) */ -#endif /* !defined(TOR_TRACE_LOG_DEBUG_H) */ +#endif /* !defined(TOR_TRACE_DEBUG_H) */ diff --git a/src/lib/trace/events.h b/src/lib/trace/events.h index 368f85dd02..ce1604de22 100644 --- a/src/lib/trace/events.h +++ b/src/lib/trace/events.h @@ -3,43 +3,75 @@ /** * \file events.h - * \brief Header file for Tor event tracing. + * \brief Header file for Tor tracing instrumentation definition. **/ -#ifndef TOR_TRACE_EVENTS_H -#define TOR_TRACE_EVENTS_H +#ifndef TOR_LIB_TRACE_EVENTS_H +#define TOR_LIB_TRACE_EVENTS_H + +#include "orconfig.h" /* - * The following defines a generic event tracing function name that has to be - * used to trace events in the code base. + * A tracepoint signature is defined as follow: + * + * tor_trace(<subsystem>, <event_name>, <args>...) + * + * If tracing is enabled, the tor_trace() macro is mapped to all possible + * instrumentations (defined below). Each instrumentation type MUST define a + * top level macro (TOR_TRACE_<type>) so it can be inserted into each + * tracepoint. + * + * In case no tracing is enabled (HAVE_TRACING), tracepoints are NOP and thus + * have no execution cost. * - * That generic function is then defined by a event tracing framework. For - * instance, the "log debug" framework sends all trace events to log_debug() - * which is defined in src/trace/debug.h which can only be enabled at compile - * time (--enable-event-tracing-debug). + * Currently, three types of instrumentation are supported: * - * By default, every trace events in the code base are replaced by a NOP. See - * doc/HACKING/Tracing.md for more information on how to use event tracing or - * add events. + * log-debug: Every tracepoints is mapped to a log_debug() statement. + * + * User Statically-Defined Tracing (USDT): Probes that can be used with perf, + * dtrace, SystemTap, DTrace and BPF Compiler Collection (BCC). + * + * LTTng-UST: Probes for the LTTng Userspace Tracer. If USDT interface + * (sdt.h) is available, the USDT probes are also generated by LTTng thus + * enabling this instrumentation provides both probes. */ -#ifdef TOR_EVENT_TRACING_ENABLED -/* Map every trace event to a per subsystem macro. */ -#define tor_trace(subsystem, name, ...) \ - tor_trace_##subsystem(name, __VA_ARGS__) +/** Helper to disambiguate these identifiers in the code base. They should + * only be used with tor_trace() like so: + * + * tor_trace(TR_SUBSYS(circuit), TR_EV(opened), ...); + */ + +#define TR_SUBSYS(name) tor_ ## name +#define TR_EV(name) name + +#ifdef HAVE_TRACING -/* Enable event tracing for the debug framework where all trace events are - * mapped to a log_debug(). */ -#ifdef USE_EVENT_TRACING_DEBUG +#define tor_trace(subsystem, event_name, ...) \ + do { \ + TOR_TRACE_LOG_DEBUG(subsystem, event_name); \ + TOR_TRACE_USDT(subsystem, event_name, ## __VA_ARGS__); \ + TOR_TRACE_LTTNG(subsystem, event_name, ## __VA_ARGS__); \ + } while (0) + +/* This corresponds to the --enable-tracing-instrumentation-log-debug + * configure option which maps all tracepoints to a log_debug() statement. */ #include "lib/trace/debug.h" -#endif -#else /* !defined(TOR_EVENT_TRACING_ENABLED) */ +/* This corresponds to the --enable-tracing-instrumentation-usdt configure + * option which will generate USDT probes for each tracepoints. */ +#include "lib/trace/usdt/usdt.h" + +/* This corresponds to the --enable-tracing-instrumentation-lttng configure + * option which will generate LTTng probes for each tracepoints. */ +#include "lib/trace/lttng/lttng.h" + +#else /* !defined(HAVE_TRACING) */ -/* Reaching this point, we NOP every event declaration because event tracing - * is not been enabled at compile time. */ -#define tor_trace(subsystem, name, args...) +/* Reaching this point, tracing is disabled thus we NOP every tracepoints + * declaration so we have no execution cost at runtime. */ +#define tor_trace(subsystem, name, ...) -#endif /* defined(TOR_EVENT_TRACING_ENABLED) */ +#endif /* defined(HAVE_TRACING) */ -#endif /* !defined(TOR_TRACE_EVENTS_H) */ +#endif /* !defined(TOR_LIB_TRACE_EVENTS_H) */ diff --git a/src/lib/trace/include.am b/src/lib/trace/include.am index 98098c87f4..6fe1365652 100644 --- a/src/lib/trace/include.am +++ b/src/lib/trace/include.am @@ -2,18 +2,34 @@ noinst_LIBRARIES += \ src/lib/libtor-trace.a +# ADD_C_FILE: INSERT SOURCES HERE. +LIBTOR_TRACE_A_SOURCES = \ + src/lib/trace/trace.c \ + src/lib/trace/trace_sys.c + # ADD_C_FILE: INSERT HEADERS HERE. TRACEHEADERS = \ - src/lib/trace/trace.h \ + src/lib/trace/trace.h \ + src/lib/trace/trace_sys.h \ src/lib/trace/events.h -if USE_EVENT_TRACING_DEBUG +if USE_TRACING_INSTRUMENTATION_LOG_DEBUG TRACEHEADERS += \ src/lib/trace/debug.h endif -# ADD_C_FILE: INSERT SOURCES HERE. -src_lib_libtor_trace_a_SOURCES = \ - src/lib/trace/trace.c +if USE_TRACING_INSTRUMENTATION_USDT +include src/lib/trace/usdt/include.am +endif + +if USE_TRACING_INSTRUMENTATION_LTTNG +include src/lib/trace/lttng/include.am +endif + +if USE_TRACING +src_lib_libtor_trace_a_SOURCES = $(LIBTOR_TRACE_A_SOURCES) +else +src_lib_libtor_trace_a_SOURCES = src/lib/trace/trace_stub.c +endif noinst_HEADERS+= $(TRACEHEADERS) diff --git a/src/lib/trace/lttng/include.am b/src/lib/trace/lttng/include.am new file mode 100644 index 0000000000..4495ce0900 --- /dev/null +++ b/src/lib/trace/lttng/include.am @@ -0,0 +1,3 @@ +# ADD_C_FILE: INSERT HEADERS HERE. +TRACEHEADERS += \ + src/lib/trace/lttng/lttng.h diff --git a/src/lib/trace/lttng/lttng.h b/src/lib/trace/lttng/lttng.h new file mode 100644 index 0000000000..8ede98bb02 --- /dev/null +++ b/src/lib/trace/lttng/lttng.h @@ -0,0 +1,28 @@ +/* Copyright (c) 2020, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file lttng.h + * \brief Header file for lttng.c. + **/ + +#ifndef TOR_TRACE_LTTNG_LTTNG_H +#define TOR_TRACE_LTTNG_LTTNG_H + +#ifdef USE_TRACING_INSTRUMENTATION_LTTNG + +#include <lttng/tracepoint.h> + +/* Map event to an LTTng tracepoint. */ +#define TOR_TRACE_LTTNG(subsystem, event_name, ...) \ + tracepoint(subsystem, event_name, ## __VA_ARGS__) + +#else /* !defined(USE_TRACING_INSTRUMENTATION_LTTNG) */ + +/* NOP event. */ +#define TOR_TRACE_LTTNG(subsystem, event_name, ...) + +#endif /* !defined(USE_TRACING_INSTRUMENTATION_LTTNG) */ + +#endif /* TOR_TRACE_LTTNG_LTTNG_H */ + diff --git a/src/lib/trace/trace.c b/src/lib/trace/trace.c index 4e5c66b4c6..10d11c17c5 100644 --- a/src/lib/trace/trace.c +++ b/src/lib/trace/trace.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2020, The Tor Project, Inc. */ +/* Copyright (c) 2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -15,3 +15,9 @@ void tor_trace_init(void) { } + +/** Free all the tracing library. */ +void +tor_trace_free_all(void) +{ +} diff --git a/src/lib/trace/trace.h b/src/lib/trace/trace.h index 5e24678c3c..22589dbe94 100644 --- a/src/lib/trace/trace.h +++ b/src/lib/trace/trace.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2020, The Tor Project, Inc. */ +/* Copyright (c) 2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -6,9 +6,31 @@ * \brief Header for trace.c **/ -#ifndef TOR_TRACE_TRACE_H -#define TOR_TRACE_TRACE_H +#ifndef TOR_LIB_TRACE_TRACE_H +#define TOR_LIB_TRACE_TRACE_H + +#include "orconfig.h" void tor_trace_init(void); +void tor_trace_free_all(void); + +#ifdef HAVE_TRACING + +#include "lib/log/log.h" + +static inline void +tracing_log_warning(void) +{ + log_warn(LD_GENERAL, + "Tracing capabilities have been built in. If this is NOT on " + "purpose, your tor is NOT safe to run."); +} + +#else + +/* NOP it. */ +#define tracing_log_warning() + +#endif /* defined(HAVE_TRACING) */ -#endif /* !defined(TOR_TRACE_TRACE_H) */ +#endif /* !defined(TOR_LIB_TRACE_TRACE_H) */ diff --git a/src/lib/trace/trace_stub.c b/src/lib/trace/trace_stub.c new file mode 100644 index 0000000000..9043efe360 --- /dev/null +++ b/src/lib/trace/trace_stub.c @@ -0,0 +1,19 @@ +/* Copyright (c) 2020, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file trace_stub.c + * \brief Stub declaratinos for use when trace library is disabled. + **/ + +#include "lib/subsys/subsys.h" + +#include "lib/trace/trace_sys.h" + +const subsys_fns_t sys_tracing = { + SUBSYS_DECLARE_LOCATION(), + + .name = "tracing", + .supported = false, + .level = TRACE_SUBSYS_LEVEL, +}; diff --git a/src/lib/trace/trace_sys.c b/src/lib/trace/trace_sys.c new file mode 100644 index 0000000000..2ba0258407 --- /dev/null +++ b/src/lib/trace/trace_sys.c @@ -0,0 +1,36 @@ +/* Copyright (c) 2018-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file log_sys.c + * \brief Setup and tear down the tracing module. + **/ + +#include "lib/subsys/subsys.h" + +#include "lib/trace/trace.h" +#include "lib/trace/trace_sys.h" + +static int +subsys_tracing_initialize(void) +{ + tor_trace_init(); + return 0; +} + +static void +subsys_tracing_shutdown(void) +{ + tor_trace_free_all(); +} + +const subsys_fns_t sys_tracing = { + SUBSYS_DECLARE_LOCATION(), + + .name = "tracing", + .supported = true, + .level = TRACE_SUBSYS_LEVEL, + + .initialize = subsys_tracing_initialize, + .shutdown = subsys_tracing_shutdown, +}; diff --git a/src/lib/trace/trace_sys.h b/src/lib/trace/trace_sys.h new file mode 100644 index 0000000000..d4da5a9701 --- /dev/null +++ b/src/lib/trace/trace_sys.h @@ -0,0 +1,22 @@ +/* Copyright (c) 2018-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file log_sys.h + * \brief Declare subsystem object for the logging module. + **/ + +#ifndef TOR_TRACE_SYS_H +#define TOR_TRACE_SYS_H + +extern const struct subsys_fns_t sys_tracing; + +/** + * Subsystem level for the tracing system. + * + * Defined here so that it can be shared between the real and stub + * definitions. + **/ +#define TRACE_SUBSYS_LEVEL (-85) + +#endif /* !defined(TOR_TRACE_SYS_H) */ diff --git a/src/lib/trace/usdt/include.am b/src/lib/trace/usdt/include.am new file mode 100644 index 0000000000..4e7e04c326 --- /dev/null +++ b/src/lib/trace/usdt/include.am @@ -0,0 +1,3 @@ +# ADD_C_FILE: INSERT HEADERS HERE. +TRACEHEADERS += \ + src/lib/trace/usdt/usdt.h diff --git a/src/lib/trace/usdt/usdt.h b/src/lib/trace/usdt/usdt.h new file mode 100644 index 0000000000..0b5fd6c444 --- /dev/null +++ b/src/lib/trace/usdt/usdt.h @@ -0,0 +1,33 @@ +/* Copyright (c) 2020, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file trace.h + * \brief Header for usdt.h + **/ + +#ifndef TOR_TRACE_USDT_USDT_H +#define TOR_TRACE_USDT_USDT_H + +#ifdef USE_TRACING_INSTRUMENTATION_USDT + +#ifdef HAVE_SYS_SDT_H +#define SDT_USE_VARIADIC +#include <sys/sdt.h> +#define TOR_STAP_PROBEV STAP_PROBEV +#else /* defined(HAVE_SYS_SDT_H) */ +#define TOR_STAP_PROBEV(...) +#endif + +/* Map events to an USDT probe. */ +#define TOR_TRACE_USDT(subsystem, event_name, ...) \ + TOR_STAP_PROBEV(subsystem, event_name, ## __VA_ARGS__); + +#else /* !defined(USE_TRACING_INSTRUMENTATION_USDT) */ + +/* NOP event. */ +#define TOR_TRACE_USDT(subsystem, event_name, ...) + +#endif /* !defined(USE_TRACING_INSTRUMENTATION_USDT) */ + +#endif /* !defined(TOR_TRACE_USDT_USDT_H) */ |