app_confbridge: Fix reference to cfg in menu_template_handler
authorGeorge Joseph <gjoseph@digium.com>
Thu, 4 May 2017 21:04:46 +0000 (15:04 -0600)
committerGeorge Joseph <gjoseph@digium.com>
Fri, 5 May 2017 01:13:55 +0000 (20:13 -0500)
menu_template_handler wasn't properly accounting for the fact that
it might be called both during a load/reload (which isn't really
valid but not prevented) and by a dialplan function.  In both cases
it was attempting to use the "pending" config which wasn't valid in
the latter case.  aco_process_config is also partly to blame because
it wasn't properly cleaning "pending" up when a reload was done and
no changes were made.  Both of these contributed to a crash if
CONFBRIDGE(menu,template) was called in a dialplan after a reload.

* aco_process_config now sets info->internal->pending to NULL
  after it unrefs it although this isn't strictly necessary in the
  context of this fix.
* menu_template_handler now uses the "current" config and silently
  ignores any attempt to be called as a result of someone uses the
  "template" parameter in the conf file.

Luckily there's no other place in the codebase where
aco_pending_config is used outside of aco_process_config.

ASTERISK-25506 #close
Reported-by: Frederic LE FOLL

Change-Id: Ib349a17d3d088f092480b19addd7122fcaac21a7

apps/confbridge/conf_config_parser.c
main/config_options.c

index 4729139..3e4075b 100644 (file)
@@ -2077,7 +2077,7 @@ static int conf_menu_profile_copy(struct conf_menu *dst, struct conf_menu *src)
 static int menu_template_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
 {
        struct conf_menu *dst_menu = obj;
-       struct confbridge_cfg *cfg = aco_pending_config(&cfg_info);
+       RAII_VAR(struct confbridge_cfg *, cfg, ao2_global_obj_ref(cfg_handle), ao2_cleanup);
        RAII_VAR(struct conf_menu *, src_menu, NULL, ao2_cleanup);
 
        if (!cfg) {
@@ -2112,6 +2112,7 @@ static int verify_default_profiles(void)
        RAII_VAR(struct user_profile *, user_profile, NULL, ao2_cleanup);
        RAII_VAR(struct bridge_profile *, bridge_profile, NULL, ao2_cleanup);
        RAII_VAR(struct conf_menu *, menu_profile, NULL, ao2_cleanup);
+       /* We can only be called as a result of an aco_process_config so this is safe */
        struct confbridge_cfg *cfg = aco_pending_config(&cfg_info);
 
        if (!cfg) {
@@ -2213,6 +2214,7 @@ int conf_load_config(void)
 
        /* Menu options */
        aco_option_register(&cfg_info, "type", ACO_EXACT, menu_types, NULL, OPT_NOOP_T, 0, 0);
+       /* This option should only be used with the CONFBRIDGE dialplan function */
        aco_option_register_custom(&cfg_info, "template", ACO_EXACT, menu_types, NULL, menu_template_handler, 0);
        aco_option_register_custom(&cfg_info, "^[0-9A-D*#]+$", ACO_REGEX, menu_types, NULL, menu_option_handler, 0);
 
index 18b04ff..c807779 100644 (file)
@@ -586,10 +586,13 @@ enum aco_process_status aco_process_ast_config(struct aco_info *info, struct aco
        };
 
        ao2_cleanup(info->internal->pending);
+       info->internal->pending = NULL;
        return ACO_PROCESS_OK;
 
 error:
        ao2_cleanup(info->internal->pending);
+       info->internal->pending = NULL;
+
        return ACO_PROCESS_ERROR;
 }
 
@@ -702,6 +705,8 @@ try_alias:
 
 end:
        ao2_cleanup(info->internal->pending);
+       info->internal->pending = NULL;
+
        return res;
 }
 int aco_process_var(struct aco_type *type, const char *cat, struct ast_variable *var, void *obj)