From 6bb6faadc9b2560594b9a19a5238d6ac7ee9e098 Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Mon, 19 Jul 2021 08:14:10 +0200 Subject: [PATCH] * Fixed: mandatory leaf in a uses statement caused abort * Occurence was in ietf-yang-patch.yang --- CHANGELOG.md | 2 ++ lib/clixon/clixon_yang.h | 1 + lib/src/clixon_yang.c | 48 ++++++++++++++++++++++----------- lib/src/clixon_yang_parse_lib.c | 44 +++++++++++++++++++----------- 4 files changed, 64 insertions(+), 31 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c4b5c37d..627f204d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,6 +42,8 @@ Developers may need to change their code ### Corrected Bugs +* Fixed: mandatory leaf in a uses statement caused abort + * Occurence was in ietf-yang-patch.yang * Native RESTCONF fixes for http/1 or http/2 only modes * Memleak in http/1-only * Exit if http/1 request sent to http/2-only (bad client magic) diff --git a/lib/clixon/clixon_yang.h b/lib/clixon/clixon_yang.h index 5d25249e..8e482cad 100644 --- a/lib/clixon/clixon_yang.h +++ b/lib/clixon/clixon_yang.h @@ -198,6 +198,7 @@ char *yang_argument_get(yang_stmt *ys); int yang_argument_set(yang_stmt *ys, char *arg); cg_var *yang_cv_get(yang_stmt *ys); +int yang_cv_set(yang_stmt *ys, cg_var *cv); cvec *yang_cvec_get(yang_stmt *ys); int yang_cvec_set(yang_stmt *ys, cvec *cvv); uint16_t yang_flag_get(yang_stmt *ys, uint16_t flag); diff --git a/lib/src/clixon_yang.c b/lib/src/clixon_yang.c index 57f5bece..056dee6d 100644 --- a/lib/src/clixon_yang.c +++ b/lib/src/clixon_yang.c @@ -256,6 +256,18 @@ yang_cv_get(yang_stmt *ys) return ys->ys_cv; } +/*! Set yang statement CLIgen variable + * @param[in] ys Yang statement node + * @param[in] cv cligen variable + */ +int +yang_cv_set(yang_stmt *ys, + cg_var *cv) +{ + ys->ys_cv = cv; + return 0; +} + /*! Get yang statement CLIgen variable vector * @param[in] ys Yang statement node */ @@ -456,13 +468,14 @@ int ys_free1(yang_stmt *ys, int self) { + cg_var *cv; if (ys->ys_argument){ free(ys->ys_argument); ys->ys_argument = NULL; } - if (ys->ys_cv){ - cv_free(ys->ys_cv); - ys->ys_cv = NULL; + if ((cv = yang_cv_get(ys)) != NULL){ + cv_free(cv); + yang_cv_set(ys, NULL); } if (ys->ys_cvec){ cvec_free(ys->ys_cvec); @@ -601,6 +614,8 @@ ys_cp(yang_stmt *ynew, int i; yang_stmt *ycn; /* new child */ yang_stmt *yco; /* old child */ + cg_var *cvn; + cg_var *cvo; memcpy(ynew, yold, sizeof(*yold)); ynew->ys_parent = NULL; @@ -614,11 +629,13 @@ ys_cp(yang_stmt *ynew, clicon_err(OE_YANG, errno, "strdup"); goto done; } - if (yold->ys_cv) - if ((ynew->ys_cv = cv_dup(yold->ys_cv)) == NULL){ + if ((cvo = yang_cv_get(yold)) != NULL){ + if ((cvn = cv_dup(cvo)) == NULL){ clicon_err(OE_YANG, errno, "cv_dup"); goto done; } + yang_cv_set(ynew, cvn); + } if (yold->ys_cvec) if ((ynew->ys_cvec = cvec_dup(yold->ys_cvec)) == NULL){ clicon_err(OE_YANG, errno, "cvec_dup"); @@ -1770,8 +1787,7 @@ ys_populate_leaf(clicon_handle h, yparent = ys->ys_parent; /* Find parent: list/container */ /* 1. Find type specification and set cv type accordingly */ - if (yang_type_get(ys, &origtype, &yrestype, &options, NULL, NULL, NULL, &fraction_digits) - < 0) + if (yang_type_get(ys, &origtype, &yrestype, &options, NULL, NULL, NULL, &fraction_digits) < 0) goto done; restype = yrestype?yrestype->ys_argument:NULL; if (clicon_type2cv(origtype, restype, ys, &cvtype) < 0) /* This handles non-resolved also */ @@ -1828,7 +1844,7 @@ ys_populate_leaf(clicon_handle h, if ((ret = yang_key_match(yparent, ys->ys_argument)) < 0) goto done; } - ys->ys_cv = cv; + yang_cv_set(ys, cv); retval = 0; done: if (origtype) @@ -2241,7 +2257,7 @@ ys_populate_feature(clicon_handle h, cv_bool_set(cv, found); if (found) clicon_debug(1, "%s %s:%s", __FUNCTION__, module, feature); - ys->ys_cv = cv; + yang_cv_set(ys, cv); ok: retval = 0; done: @@ -2495,7 +2511,7 @@ yang_if_feature(clicon_handle h, yang_stmt *yfeat; /* feature yang node */ int opand = -1; /* -1:not set, 0:or, 1:and */ int enabled = 0; - + cg_var *cv; if ((vec = clicon_strsep(ys->ys_argument, " \t\r\n", &nvec)) == NULL) goto done; /* Two steps: first detect operators @@ -2584,7 +2600,8 @@ yang_if_feature(clicon_handle h, /* Check if this feature is enabled or not * Continue loop to catch unbound features and make verdict at end */ - if (yfeat->ys_cv == NULL || !cv_bool_get(yfeat->ys_cv)){ /* disabled */ + cv = yang_cv_get(yfeat); + if (cv == NULL || !cv_bool_get(cv)){ /* disabled */ /* if AND then this is permanently disabled */ if (opand && enabled) enabled = 0; @@ -3024,14 +3041,15 @@ int yang_mandatory(yang_stmt *ys) { yang_stmt *ym; + cg_var *cv; /* 1) A leaf, choice, anydata, or anyxml node with a "mandatory" * statement with the value "true". */ if (ys->ys_keyword == Y_LEAF || ys->ys_keyword == Y_CHOICE || ys->ys_keyword == Y_ANYDATA || ys->ys_keyword == Y_ANYXML){ if ((ym = yang_find(ys, Y_MANDATORY, NULL)) != NULL){ - if (ym->ys_cv != NULL) /* shouldnt happen */ - return cv_bool_get(ym->ys_cv); + if ((cv = yang_cv_get(ym)) != NULL) /* shouldnt happen */ + return cv_bool_get(cv); } } #if 0 /* See note above */ @@ -3071,9 +3089,9 @@ yang_config(yang_stmt *ys) yang_stmt *ym; if ((ym = yang_find(ys, Y_CONFIG, NULL)) != NULL){ - if (ym->ys_cv == NULL) /* shouldnt happen */ + if (yang_cv_get(ym) == NULL) /* shouldnt happen */ return 1; - return cv_bool_get(ym->ys_cv); + return cv_bool_get(yang_cv_get(ym)); } return 1; } diff --git a/lib/src/clixon_yang_parse_lib.c b/lib/src/clixon_yang_parse_lib.c index 6668be60..2548363b 100644 --- a/lib/src/clixon_yang_parse_lib.c +++ b/lib/src/clixon_yang_parse_lib.c @@ -1767,29 +1767,33 @@ cg_var * ys_parse(yang_stmt *ys, enum cv_type cvtype) { - int cvret; - char *reason = NULL; + int cvret; + char *reason = NULL; + cg_var *cv = NULL; - assert(yang_cv_get(ys) == NULL); /* Cv:s are parsed in different places, difficult to separate */ - if ((ys->ys_cv = cv_new(cvtype)) == NULL){ + if ((cv = yang_cv_get(ys)) != NULL){ + /* eg mandatory in uses is already set and then copied */ + cv_free(cv); + yang_cv_set(ys, NULL); + } + if ((cv = cv_new(cvtype)) == NULL){ clicon_err(OE_YANG, errno, "cv_new"); goto done; } - if ((cvret = cv_parse1(yang_argument_get(ys), ys->ys_cv, &reason)) < 0){ /* error */ + if ((cvret = cv_parse1(yang_argument_get(ys), cv, &reason)) < 0){ /* error */ clicon_err(OE_YANG, errno, "parsing cv"); - ys->ys_cv = NULL; goto done; } if (cvret == 0){ /* parsing failed */ clicon_err(OE_YANG, errno, "Parsing CV: %s", reason); - ys->ys_cv = NULL; goto done; } + yang_cv_set(ys, cv); /* cvret == 1 means parsing is OK */ done: if (reason) free(reason); - return ys->ys_cv; + return yang_cv_get(ys); } /*! First round yang syntactic statement specific checks. No context checks. @@ -1819,6 +1823,7 @@ ys_parse_sub(yang_stmt *ys, char *reason = NULL; int ret; uint32_t minmax; + cg_var *cv = NULL; arg = yang_argument_get(ys); keyword = yang_keyword_get(ys); @@ -1826,7 +1831,11 @@ ys_parse_sub(yang_stmt *ys, case Y_FRACTION_DIGITS: if (ys_parse(ys, CGV_UINT8) == NULL) goto done; - fd = cv_uint8_get(ys->ys_cv); + if ((cv = yang_cv_get(ys)) == NULL){ + clicon_err(OE_YANG, ENOENT, "Unexpected NULL cv"); + goto done; + } + fd = cv_uint8_get(cv); if (fd < 1 || fd > 18){ clicon_err(OE_YANG, errno, "%u: Out of range, should be [1:18]", fd); goto done; @@ -1841,11 +1850,12 @@ ys_parse_sub(yang_stmt *ys, case Y_REVISION_DATE: /* YYYY-MM-DD encoded as uint32 YYYYMMDD */ if (ys_parse_date_arg(arg, &date) < 0) goto done; - if ((ys->ys_cv = cv_new(CGV_UINT32)) == NULL){ + if ((cv = cv_new(CGV_UINT32)) == NULL){ clicon_err(OE_YANG, errno, "cv_new"); goto done; } - cv_uint32_set(ys->ys_cv, date); + yang_cv_set(ys, cv); + cv_uint32_set(cv, date); break; case Y_STATUS: /* RFC7950 7.21.2: "current", "deprecated", or "obsolete". */ if (strcmp(arg, "current") && @@ -1858,13 +1868,14 @@ ys_parse_sub(yang_stmt *ys, break; case Y_MAX_ELEMENTS: case Y_MIN_ELEMENTS: - if ((ys->ys_cv = cv_new(CGV_UINT32)) == NULL){ + if ((cv = cv_new(CGV_UINT32)) == NULL){ clicon_err(OE_YANG, errno, "cv_new"); goto done; } + yang_cv_set(ys, cv); if (keyword == Y_MAX_ELEMENTS && strcmp(arg, "unbounded") == 0) - cv_uint32_set(ys->ys_cv, 0); /* 0 means unbounded for max */ + cv_uint32_set(cv, 0); /* 0 means unbounded for max */ else{ if ((ret = parse_uint32(arg, &minmax, &reason)) < 0){ clicon_err(OE_YANG, errno, "parse_uint32"); @@ -1876,7 +1887,7 @@ ys_parse_sub(yang_stmt *ys, free(reason); goto done; } - cv_uint32_set(ys->ys_cv, minmax); + cv_uint32_set(cv, minmax); } break; case Y_MODIFIER: @@ -1888,11 +1899,12 @@ ys_parse_sub(yang_stmt *ys, case Y_UNKNOWN:{ /* save (optional) argument in ys_cv */ if (extra == NULL) break; - if ((ys->ys_cv = cv_new(CGV_STRING)) == NULL){ + if ((cv = cv_new(CGV_STRING)) == NULL){ clicon_err(OE_YANG, errno, "cv_new"); goto done; } - if ((ret = cv_parse1(extra, ys->ys_cv, &reason)) < 0){ /* error */ + yang_cv_set(ys, cv); + if ((ret = cv_parse1(extra, cv, &reason)) < 0){ /* error */ clicon_err(OE_YANG, errno, "parsing cv"); goto done; }