From 23a5a8569be5042a5317e62cc8361d0c99ca70fc Mon Sep 17 00:00:00 2001 From: Jakub Jelen Date: Mon, 13 Nov 2023 14:52:56 +0100 Subject: [PATCH] pkcs15init: Find reference loops in all the macro values For some reason the macro value is a linked list and the reference loop was checked only in the first value, but the evaluation was taking into the account all the values in the linked list. The following input would cause stack overflow in the past macros { e =1 o =$e e =-$e } filesystem { DF { size =$o Thanks oss-fuzz https://oss-fuzz.com/testcase-detail/5289592319508480 --- src/pkcs15init/profile.c | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/src/pkcs15init/profile.c b/src/pkcs15init/profile.c index ba2b22ee56..de8caae857 100644 --- a/src/pkcs15init/profile.c +++ b/src/pkcs15init/profile.c @@ -2013,27 +2013,36 @@ get_inner_word(char *str, char word[WORD_SIZE]) { * Function returns 1 if a reference loop is detected, 0 otherwise. */ static int -check_macro_reference_loop(const char *start_name, sc_macro_t *macro, sc_profile_t *profile, int depth) { - char *macro_value = NULL; +check_macro_reference_loop(const char *start_name, sc_macro_t *macro, sc_profile_t *profile, int depth) +{ + scconf_list *value; char *name = NULL; + sc_macro_t *m; char word[WORD_SIZE]; if (!start_name || !macro || !profile || depth == 16) return 1; - /* Find name in macro value */ - macro_value = macro->value->data; - if (!(name = strchr(macro_value, '$'))) - return 0; - /* Extract the macro name from the string */ - get_inner_word(name + 1, word); - /* Find whether name corresponds to some other macro */ - if (!(macro = find_macro(profile, word))) - return 0; - /* Check for loop */ - if (!strcmp(macro->name, start_name)) - return 1; - return check_macro_reference_loop(start_name, macro, profile, depth + 1); + /* For some reason, the macro value is a list where we need to check for references */ + for (value = macro->value; value != NULL; value = value->next) { + /* Find name in macro value */ + char *macro_value = value->data; + if (!(name = strchr(macro_value, '$'))) + continue; + /* Extract the macro name from the string */ + get_inner_word(name + 1, word); + /* Find whether name corresponds to some other macro */ + if (!(m = find_macro(profile, word))) + continue; + /* Check for loop */ + if (!strcmp(m->name, start_name)) + return 1; + /* Reference loop was found to the original macro name */ + if (check_macro_reference_loop(start_name, m, profile, depth + 1) == 1) { + return 1; + } + } + return 0; } static int