diff options
author | Nick Mathewson <nickm@torproject.org> | 2019-10-25 08:10:39 -0400 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2019-10-25 08:10:39 -0400 |
commit | e7993dc046a099075bc5f9f65a7bb1601686d03c (patch) | |
tree | d927b8a7675d340fd79340f1a414a938e777a13c /src/app | |
parent | 0ae530c8f617fbc512bdf112530d5ec85281e0a8 (diff) | |
parent | 63f2a310cbeb5908a202ba17da7e66535c77c894 (diff) | |
download | tor-e7993dc046a099075bc5f9f65a7bb1601686d03c.tar.gz tor-e7993dc046a099075bc5f9f65a7bb1601686d03c.zip |
Merge branch 'ticket31241_v3'
Diffstat (limited to 'src/app')
-rw-r--r-- | src/app/config/config.c | 190 | ||||
-rw-r--r-- | src/app/config/config.h | 13 | ||||
-rw-r--r-- | src/app/config/statefile.c | 47 |
3 files changed, 144 insertions, 106 deletions
diff --git a/src/app/config/config.c b/src/app/config/config.c index 187c275598..f2db0e5250 100644 --- a/src/app/config/config.c +++ b/src/app/config/config.c @@ -822,10 +822,10 @@ static const config_deprecation_t option_deprecation_notes_[] = { #ifdef _WIN32 static char *get_windows_conf_root(void); #endif -static int options_act_reversible(const or_options_t *old_options, char **msg); -static int options_transition_allowed(const or_options_t *old, - const or_options_t *new, - char **msg); + +static int options_check_transition_cb(const void *old, + const void *new, + char **msg); static int options_transition_affects_workers( const or_options_t *old_options, const or_options_t *new_options); static int options_transition_affects_descriptor( @@ -858,25 +858,28 @@ static int options_validate_cb(const void *old_options, void *options, static void cleanup_protocol_warning_severity_level(void); static void set_protocol_warning_severity_level(int warning_severity); static void options_clear_cb(const config_mgr_t *mgr, void *opts); +static setopt_err_t options_validate_and_set(const or_options_t *old_options, + or_options_t *new_options, + char **msg_out); /** Magic value for or_options_t. */ #define OR_OPTIONS_MAGIC 9090909 /** Configuration format for or_options_t. */ static const config_format_t options_format = { - sizeof(or_options_t), - { + .size = sizeof(or_options_t), + .magic = { "or_options_t", OR_OPTIONS_MAGIC, offsetof(or_options_t, magic_), }, - option_abbrevs_, - option_deprecation_notes_, - option_vars_, - options_validate_cb, - options_clear_cb, - NULL, - offsetof(or_options_t, subconfigs_), + .abbrevs = option_abbrevs_, + .deprecations = option_deprecation_notes_, + .vars = option_vars_, + .legacy_validate_fn = options_validate_cb, + .check_transition_fn = options_check_transition_cb, + .clear_fn = options_clear_cb, + .config_suite_offset = offsetof(or_options_t, subconfigs_), }; /* @@ -918,6 +921,10 @@ get_options_mgr(void) return options_mgr; } +#define CHECK_OPTIONS_MAGIC(opt) STMT_BEGIN \ + config_check_toplevel_magic(get_options_mgr(), (opt)); \ + STMT_END + /** Return the contents of our frontpage string, or NULL if not configured. */ MOCK_IMPL(const char*, get_dirportfrontpage, (void)) @@ -1024,6 +1031,7 @@ static void options_clear_cb(const config_mgr_t *mgr, void *opts) { (void)mgr; + CHECK_OPTIONS_MAGIC(opts); or_options_t *options = opts; routerset_free(options->ExcludeExitNodesUnion_); @@ -1425,8 +1433,8 @@ static int have_low_ports = -1; * * Return 0 if all goes well, return -1 if things went badly. */ -static int -options_act_reversible(const or_options_t *old_options, char **msg) +MOCK_IMPL(STATIC int, +options_act_reversible,(const or_options_t *old_options, char **msg)) { smartlist_t *new_listeners = smartlist_new(); or_options_t *options = get_options_mutable(); @@ -1854,8 +1862,8 @@ options_transition_affects_dirauth_timing(const or_options_t *old_options, * Note: We haven't moved all the "act on new configuration" logic * here yet. Some is still in do_hup() and other places. */ -STATIC int -options_act(const or_options_t *old_options) +MOCK_IMPL(STATIC int, +options_act,(const or_options_t *old_options)) { config_line_t *cl; or_options_t *options = get_options_mutable(); @@ -2685,37 +2693,9 @@ options_trial_assign(config_line_t *list, unsigned flags, char **msg) or_options_free(trial_options); return r; } + const or_options_t *cur_options = get_options(); - setopt_err_t rv; - or_options_t *cur_options = get_options_mutable(); - - in_option_validation = 1; - - if (options_validate(cur_options, trial_options, - msg) < 0) { - or_options_free(trial_options); - rv = SETOPT_ERR_PARSE; /*XXX make this a separate return value. */ - goto done; - } - - if (options_transition_allowed(cur_options, trial_options, msg) < 0) { - or_options_free(trial_options); - rv = SETOPT_ERR_TRANSITION; - goto done; - } - in_option_validation = 0; - - if (set_options(trial_options, msg)<0) { - or_options_free(trial_options); - rv = SETOPT_ERR_SETTING; - goto done; - } - - /* we liked it. put it in place. */ - rv = SETOPT_OK; - done: - in_option_validation = 0; - return rv; + return options_validate_and_set(cur_options, trial_options, msg); } /** Print a usage message for tor. */ @@ -3240,15 +3220,68 @@ compute_publishserverdescriptor(or_options_t *options) * */ #define RECOMMENDED_MIN_CIRCUIT_BUILD_TIMEOUT (10) -static int -options_validate_cb(const void *old_options, void *options, char **msg) +/** + * Validate <b>new_options</b>. If it is valid, and it is a reasonable + * replacement for <b>old_options</b>, replace the previous value of the + * global options, and return return SETOPT_OK. + * + * If it is not valid, then free <b>new_options</b>, set *<b>msg_out</b> to a + * newly allocated error message, and return an error code. + */ +static setopt_err_t +options_validate_and_set(const or_options_t *old_options, + or_options_t *new_options, + char **msg_out) { + setopt_err_t rv; + validation_status_t vs; + in_option_validation = 1; - int rv = options_validate(old_options, options, msg); + vs = config_validate(get_options_mgr(), old_options, new_options, msg_out); + + if (vs == VSTAT_TRANSITION_ERR) { + rv = SETOPT_ERR_TRANSITION; + goto err; + } else if (vs < 0) { + rv = SETOPT_ERR_PARSE; + goto err; + } in_option_validation = 0; + + if (set_options(new_options, msg_out)) { + rv = SETOPT_ERR_SETTING; + goto err; + } + + rv = SETOPT_OK; + new_options = NULL; /* prevent free */ + err: + in_option_validation = 0; + tor_assert(new_options == NULL || rv != SETOPT_OK); + or_options_free(new_options); return rv; } +#ifdef TOR_UNIT_TESTS +/** + * Return 0 if every setting in <b>options</b> is reasonable, is a + * permissible transition from <b>old_options</b>, and none of the + * testing-only settings differ from <b>default_options</b> unless in + * testing mode. Else return -1. Should have no side effects, except for + * normalizing the contents of <b>options</b>. + * + * On error, tor_strdup an error explanation into *<b>msg</b>. + */ +int +options_validate(const or_options_t *old_options, or_options_t *options, + char **msg) +{ + validation_status_t vs; + vs = config_validate(get_options_mgr(), old_options, options, msg); + return vs < 0 ? -1 : 0; +} +#endif + #define REJECT(arg) \ STMT_BEGIN *msg = tor_strdup(arg); return -1; STMT_END #if defined(__GNUC__) && __GNUC__ <= 3 @@ -3432,18 +3465,19 @@ options_validate_single_onion(or_options_t *options, char **msg) return 0; } -/** Return 0 if every setting in <b>options</b> is reasonable, is a - * permissible transition from <b>old_options</b>, and none of the - * testing-only settings differ from <b>default_options</b> unless in - * testing mode. Else return -1. Should have no side effects, except for - * normalizing the contents of <b>options</b>. - * - * On error, tor_strdup an error explanation into *<b>msg</b>. +/** + * Legacy validation/normalization callback for or_options_t. See + * legacy_validate_fn_t for more information. */ -STATIC int -options_validate(const or_options_t *old_options, or_options_t *options, - char **msg) +static int +options_validate_cb(const void *old_options_, void *options_, char **msg) { + if (old_options_) + CHECK_OPTIONS_MAGIC(old_options_); + CHECK_OPTIONS_MAGIC(options_); + const or_options_t *old_options = old_options_; + or_options_t *options = options_; + config_line_t *cl; const char *uname = get_uname(); int n_ports=0; @@ -4791,11 +4825,17 @@ opt_streq(const char *s1, const char *s2) /** Check if any of the previous options have changed but aren't allowed to. */ static int -options_transition_allowed(const or_options_t *old, - const or_options_t *new_val, - char **msg) +options_check_transition_cb(const void *old_, + const void *new_val_, + char **msg) { - if (!old) + CHECK_OPTIONS_MAGIC(old_); + CHECK_OPTIONS_MAGIC(new_val_); + + const or_options_t *old = old_; + const or_options_t *new_val = new_val_; + + if (BUG(!old)) return 0; #define BAD_CHANGE_TO(opt, how) do { \ @@ -5523,25 +5563,12 @@ options_init_from_string(const char *cf_defaults, const char *cf, } newoptions->IncludeUsed = cf_has_include; - in_option_validation = 1; newoptions->FilesOpenedByIncludes = opened_files; + opened_files = NULL; // prevent double-free. - /* Validate newoptions */ - if (options_validate(oldoptions, newoptions, msg) < 0) { - err = SETOPT_ERR_PARSE; /*XXX make this a separate return value.*/ - goto err; - } - - if (options_transition_allowed(oldoptions, newoptions, msg) < 0) { - err = SETOPT_ERR_TRANSITION; + err = options_validate_and_set(oldoptions, newoptions, msg); + if (err < 0) goto err; - } - in_option_validation = 0; - - if (set_options(newoptions, msg)) { - err = SETOPT_ERR_SETTING; - goto err; /* frees and replaces old options */ - } or_options_free(global_default_options); global_default_options = newdefaultoptions; @@ -5554,9 +5581,6 @@ options_init_from_string(const char *cf_defaults, const char *cf, SMARTLIST_FOREACH(opened_files, char *, f, tor_free(f)); smartlist_free(opened_files); } - // may have been set to opened_files, avoid double free - newoptions->FilesOpenedByIncludes = NULL; - or_options_free(newoptions); or_options_free(newdefaultoptions); if (*msg) { char *old_msg = *msg; diff --git a/src/app/config/config.h b/src/app/config/config.h index dbba30e9c9..9cc77e2c69 100644 --- a/src/app/config/config.h +++ b/src/app/config/config.h @@ -264,7 +264,9 @@ int options_any_client_port_set(const or_options_t *options); #define CL_PORT_IS_UNIXSOCKET (1u<<6) #define CL_PORT_DFLT_GROUP_WRITABLE (1u<<7) -STATIC int options_act(const or_options_t *old_options); +MOCK_DECL(STATIC int, options_act,(const or_options_t *old_options)); +MOCK_DECL(STATIC int, options_act_reversible,(const or_options_t *old_options, + char **msg)); struct config_mgr_t; STATIC const struct config_mgr_t *get_options_mgr(void); @@ -277,9 +279,6 @@ STATIC void port_cfg_free_(port_cfg_t *port); STATIC void or_options_free_(or_options_t *options); STATIC int options_validate_single_onion(or_options_t *options, char **msg); -STATIC int options_validate(const or_options_t *old_options, - or_options_t *options, - char **msg); STATIC int parse_transport_line(const or_options_t *options, const char *line, int validate_only, int server); @@ -311,6 +310,12 @@ STATIC int open_and_add_file_log(const log_severity_list_t *severity, STATIC int options_init_logs(const or_options_t *old_options, or_options_t *options, int validate_only); +#ifdef TOR_UNIT_TESTS +int options_validate(const or_options_t *old_options, + or_options_t *options, + char **msg); +#endif + #endif /* defined(CONFIG_PRIVATE) */ #endif /* !defined(TOR_CONFIG_H) */ diff --git a/src/app/config/statefile.c b/src/app/config/statefile.c index 5c2e37490b..834ad93ed7 100644 --- a/src/app/config/statefile.c +++ b/src/app/config/statefile.c @@ -157,19 +157,17 @@ static struct_member_t state_extra_var = { /** Configuration format for or_state_t. */ static const config_format_t state_format = { - sizeof(or_state_t), - { + .size = sizeof(or_state_t), + .magic = { "or_state_t", OR_STATE_MAGIC, offsetof(or_state_t, magic_), }, - state_abbrevs_, - NULL, - state_vars_, - or_state_validate_cb, - NULL, - &state_extra_var, - offsetof(or_state_t, substates_), + .abbrevs = state_abbrevs_, + .vars = state_vars_, + .legacy_validate_fn = or_state_validate_cb, + .extra = &state_extra_var, + .config_suite_offset = offsetof(or_state_t, substates_), }; /* A global configuration manager for state-file objects */ @@ -186,6 +184,10 @@ get_state_mgr(void) return state_mgr; } +#define CHECK_STATE_MAGIC(s) STMT_BEGIN \ + config_check_toplevel_magic(get_state_mgr(), (s)); \ + STMT_END + /** Persistent serialized state. */ static or_state_t *global_state = NULL; @@ -267,16 +269,6 @@ validate_transports_in_state(or_state_t *state) return 0; } -static int -or_state_validate_cb(const void *old_state, void *state, char **msg) -{ - /* We don't use these; only options do. Still, we need to match that - * signature. */ - (void) old_state; - - return or_state_validate(state, msg); -} - /** Return 0 if every setting in <b>state</b> is reasonable, and a * permissible transition from <b>old_state</b>. Else warn and return -1. * Should have no side effects, except for normalizing the contents of @@ -285,6 +277,23 @@ or_state_validate_cb(const void *old_state, void *state, char **msg) static int or_state_validate(or_state_t *state, char **msg) { + return config_validate(get_state_mgr(), NULL, state, msg); +} + +/** + * Legacy validation/normalization callback for or_state_t. See + * legacy_validate_fn_t for more information. + */ +static int +or_state_validate_cb(const void *old_state, void *state_, char **msg) +{ + /* There is not a meaningful concept of a state-to-state transition, + * since we do not reload the state after we start. */ + (void) old_state; + CHECK_STATE_MAGIC(state_); + + or_state_t *state = state_; + if (entry_guards_parse_state(state, 0, msg)<0) return -1; |