It is easy to craft a config file that loads a profile recursively. To prevent this, not only check the depth of the current inclusion but also ignore already-seen profile names.
Unified · Split
| @@ -986,8 +986,14 @@ static struct m_profile *find_check_profile(struct m_config *config, char *name) · 985 unmodified lines | ||
| 986 | 986 | MP_WARN(config, "Unknown profile '%s'.\n", name); |
| 987 | 987 | return NULL; |
| 988 | 988 | } |
| 989 | − if (config->profile_depth > MAX_PROFILE_DEPTH) { | |
| 990 | − MP_WARN(config, "WARNING: Profile inclusion too deep.\n"); | |
| 989 | + for (size_t i = 0; i < config->profile_stack_depth; ++i) { | |
| 990 | + if (strcmp(config->profile_stack[i], name)) | |
| 991 | + continue; | |
| 992 | + MP_WARN(config, "Profile '%s' has already been applied.\n", name); | |
| 993 | + return NULL; | |
| 994 | + } | |
| 995 | + if (config->profile_stack_depth > MAX_PROFILE_DEPTH) { | |
| 996 | + MP_WARN(config, "Profile inclusion too deep.\n"); | |
| 991 | 997 | return NULL; |
| 992 | 998 | } |
| 993 | 999 | return p; |
| @@ -995,11 +1001,6 @@ static struct m_profile *find_check_profile(struct m_config *config, char *name) · 1 unmodified line | ||
| 995 | 1001 | |
| 996 | 1002 | int m_config_set_profile(struct m_config *config, char *name, int flags) |
| 997 | 1003 | { |
| 998 | − if ((flags & M_SETOPT_FROM_CONFIG_FILE) && !strcmp(name, "default")) { | |
| 999 | − MP_WARN(config, "Ignoring profile=%s from config file.\n", name); | |
| 1000 | − return 0; | |
| 1001 | − } | |
| 1002 | − | |
| 1003 | 1004 | MP_VERBOSE(config, "Applying profile '%s'...\n", name); |
| 1004 | 1005 | struct m_profile *p = find_check_profile(config, name); |
| 1005 | 1006 | if (!p) |
| @@ -1010,14 +1011,18 @@ int m_config_set_profile(struct m_config *config, char *name, int flags) · 4 unmodified lines | ||
| 1010 | 1011 | config->profile_backup_flags = p->restore_mode == 2 ? BACKUP_NVAL : 0; |
| 1011 | 1012 | } |
| 1012 | 1013 | |
| 1013 | − config->profile_depth++; | |
| 1014 | + char *profile_name = talloc_strdup(NULL, name); | |
| 1015 | + // Note that we don't check if profile applied correctly, it doesn't matter. | |
| 1016 | + MP_TARRAY_APPEND(config, config->profile_stack, config->profile_stack_depth, profile_name); | |
| 1017 | + talloc_steal(config->profile_stack, profile_name); | |
| 1014 | 1018 | for (int i = 0; i < p->num_opts; i++) { |
| 1015 | 1019 | m_config_set_option_cli(config, |
| 1016 | 1020 | bstr0(p->opts[2 * i]), |
| 1017 | 1021 | bstr0(p->opts[2 * i + 1]), |
| 1018 | 1022 | flags | M_SETOPT_FROM_CONFIG_FILE); |
| 1019 | 1023 | } |
| 1020 | − config->profile_depth--; | |
| 1024 | + if (MP_TARRAY_POP(config->profile_stack, config->profile_stack_depth, &profile_name)) | |
| 1025 | + talloc_free(profile_name); | |
| 1021 | 1026 | |
| 1022 | 1027 | if (config->profile_backup_tmp == &p->backups) { |
| 1023 | 1028 | config->profile_backup_tmp = NULL; |
| @@ -69,6 +69,8 @@ typedef struct m_config { · 68 unmodified lines | ||
| 69 | 69 | struct m_profile *profiles; |
| 70 | 70 | // Depth when recursively including profiles. |
| 71 | 71 | int profile_depth; |
| 72 | + char **profile_stack; | |
| 73 | + size_t profile_stack_depth; | |
| 72 | 74 | // Temporary during profile application. |
| 73 | 75 | struct m_opt_backup **profile_backup_tmp; |
| 74 | 76 | int profile_backup_flags; |