Skip to content

Commit dadf574

Browse files
committed
validation BUGFIX avoid accessing reallocated memory
Getnext items are directly stored in a HT, which could be resized while it was used.
1 parent 631ccc5 commit dadf574

File tree

3 files changed

+31
-27
lines changed

3 files changed

+31
-27
lines changed

src/tree_data_new.c

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1916,11 +1916,10 @@ lyd_new_implicit(struct lyd_node *parent, struct lyd_node **first, const struct
19161916
uint32_t impl_opts, struct ly_ht *getnext_ht, struct lyd_node **diff)
19171917
{
19181918
LY_ERR ret;
1919-
const struct lysc_node *snode;
1919+
const struct lysc_node *snode, **choices, **snodes;
19201920
struct lyd_node *node = NULL;
19211921
struct lyd_value **dflts;
19221922
LY_ARRAY_COUNT_TYPE u;
1923-
const struct lyd_val_getnext *getnext;
19241923
uint32_t i;
19251924

19261925
assert(first && (parent || sparent || mod));
@@ -1930,11 +1929,11 @@ lyd_new_implicit(struct lyd_node *parent, struct lyd_node **first, const struct
19301929
}
19311930

19321931
/* get cached getnext schema nodes */
1933-
LY_CHECK_RET(lyd_val_getnext_get(sparent, mod, impl_opts & LYD_IMPLICIT_OUTPUT, getnext_ht, &getnext));
1932+
LY_CHECK_RET(lyd_val_getnext_get(sparent, mod, impl_opts & LYD_IMPLICIT_OUTPUT, getnext_ht, &choices, &snodes));
19341933

19351934
/* choice nodes */
1936-
for (i = 0; getnext->choices && getnext->choices[i]; ++i) {
1937-
snode = getnext->choices[i];
1935+
for (i = 0; choices && choices[i]; ++i) {
1936+
snode = choices[i];
19381937

19391938
if ((impl_opts & LYD_IMPLICIT_NO_STATE) && (snode->flags & LYS_CONFIG_R)) {
19401939
continue;
@@ -1956,8 +1955,8 @@ lyd_new_implicit(struct lyd_node *parent, struct lyd_node **first, const struct
19561955
}
19571956

19581957
/* container, leaf, leaf-list nodes */
1959-
for (i = 0; getnext->snodes && getnext->snodes[i]; ++i) {
1960-
snode = getnext->snodes[i];
1958+
for (i = 0; snodes && snodes[i]; ++i) {
1959+
snode = snodes[i];
19611960

19621961
if ((impl_opts & LYD_IMPLICIT_NO_STATE) && (snode->flags & LYS_CONFIG_R)) {
19631962
continue;

src/validation.c

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -103,17 +103,17 @@ lyd_val_getnext_ht_free(struct ly_ht *getnext_ht)
103103

104104
LY_ERR
105105
lyd_val_getnext_get(const struct lysc_node *sparent, const struct lys_module *mod, ly_bool output,
106-
struct ly_ht *getnext_ht, const struct lyd_val_getnext **getnext_p)
106+
struct ly_ht *getnext_ht, const struct lysc_node ***choices, const struct lysc_node ***snodes)
107107
{
108108
LY_ERR rc = LY_SUCCESS;
109-
struct lyd_val_getnext val = {0};
109+
struct lyd_val_getnext val = {0}, *getnext = NULL;
110110
const struct lysc_node *snode = NULL;
111111
uint32_t getnext_opts, snode_count = 0, choice_count = 0;
112112

113113
/* try to find the entry for this schema parent */
114114
val.sparent = sparent;
115-
if (!lyht_find(getnext_ht, &val, (uintptr_t)sparent, (void **)getnext_p)) {
116-
return LY_SUCCESS;
115+
if (!lyht_find(getnext_ht, &val, (uintptr_t)sparent, (void **)&getnext)) {
116+
goto cleanup;
117117
}
118118

119119
/* traverse all the children using getnext and store them */
@@ -143,14 +143,17 @@ lyd_val_getnext_get(const struct lysc_node *sparent, const struct lys_module *mo
143143
}
144144

145145
/* add into the hash table */
146-
if ((rc = lyht_insert(getnext_ht, &val, (uintptr_t)sparent, (void **)getnext_p))) {
146+
if ((rc = lyht_insert(getnext_ht, &val, (uintptr_t)sparent, (void **)&getnext))) {
147147
goto cleanup;
148148
}
149149

150150
cleanup:
151151
if (rc) {
152152
free(val.snodes);
153153
free(val.choices);
154+
} else {
155+
*choices = getnext->choices;
156+
*snodes = getnext->snodes;
154157
}
155158
return rc;
156159
}
@@ -901,23 +904,23 @@ lyd_validate_choice_r(struct lyd_node **first, const struct lysc_node *sparent,
901904
uint32_t val_opts, uint32_t int_opts, struct ly_ht *getnext_ht, struct lyd_node **diff)
902905
{
903906
LY_ERR r, rc = LY_SUCCESS;
904-
const struct lyd_val_getnext *getnext;
907+
const struct lysc_node **choices, **snodes;
905908
uint32_t i;
906909

907910
/* get cached getnext schema nodes */
908-
rc = lyd_val_getnext_get(sparent, mod, int_opts & LYD_INTOPT_REPLY, getnext_ht, &getnext);
911+
rc = lyd_val_getnext_get(sparent, mod, int_opts & LYD_INTOPT_REPLY, getnext_ht, &choices, &snodes);
909912
LY_CHECK_GOTO(rc, cleanup);
910-
if (!getnext->choices) {
913+
if (!choices) {
911914
goto cleanup;
912915
}
913916

914-
for (i = 0; *first && getnext->choices[i]; ++i) {
917+
for (i = 0; *first && choices[i]; ++i) {
915918
/* check case duplicites */
916-
r = lyd_validate_cases(first, mod, (struct lysc_node_choice *)getnext->choices[i], diff);
919+
r = lyd_validate_cases(first, mod, (struct lysc_node_choice *)choices[i], diff);
917920
LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
918921

919922
/* check for nested choice */
920-
r = lyd_validate_choice_r(first, getnext->choices[i], mod, val_opts, int_opts, getnext_ht, diff);
923+
r = lyd_validate_choice_r(first, choices[i], mod, val_opts, int_opts, getnext_ht, diff);
921924
LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
922925
}
923926

@@ -1495,18 +1498,17 @@ lyd_validate_siblings_schema_r(const struct lyd_node *first, const struct lyd_no
14951498
struct ly_ht *getnext_ht)
14961499
{
14971500
LY_ERR r, rc = LY_SUCCESS;
1498-
const struct lyd_val_getnext *getnext;
1499-
const struct lysc_node *snode, *scase;
1501+
const struct lysc_node *snode, *scase, **choices, **snodes;
15001502
struct lysc_node_list *slist;
15011503
struct lysc_node_leaflist *sllist;
15021504
uint32_t i;
15031505

15041506
/* get cached getnext schema nodes */
1505-
rc = lyd_val_getnext_get(sparent, mod, int_opts & LYD_INTOPT_REPLY, getnext_ht, &getnext);
1507+
rc = lyd_val_getnext_get(sparent, mod, int_opts & LYD_INTOPT_REPLY, getnext_ht, &choices, &snodes);
15061508
LY_CHECK_GOTO(rc, cleanup);
15071509

1508-
for (i = 0; getnext->choices && getnext->choices[i]; ++i) {
1509-
snode = getnext->choices[i];
1510+
for (i = 0; choices && choices[i]; ++i) {
1511+
snode = choices[i];
15101512

15111513
if ((val_opts & LYD_VALIDATE_NO_STATE) && (snode->flags & LYS_CONFIG_R)) {
15121514
/* skip state nodes */
@@ -1530,8 +1532,8 @@ lyd_validate_siblings_schema_r(const struct lyd_node *first, const struct lyd_no
15301532
}
15311533
}
15321534

1533-
for (i = 0; getnext->snodes && getnext->snodes[i]; ++i) {
1534-
snode = getnext->snodes[i];
1535+
for (i = 0; snodes && snodes[i]; ++i) {
1536+
snode = snodes[i];
15351537

15361538
if ((val_opts & LYD_VALIDATE_NO_STATE) && (snode->flags & LYS_CONFIG_R)) {
15371539
/* skip state nodes */

src/validation.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,15 +54,18 @@ void lyd_val_getnext_ht_free(struct ly_ht *getnext_ht);
5454
/**
5555
* @brief Get the schema children of a schema parent.
5656
*
57+
* Getnext structure cannot be returned because the pointer may become invalid on HT resize.
58+
*
5759
* @param[in] sparent Schema parent to use.
5860
* @param[in] mod Module to use.
5961
* @param[in] output Whether to traverse operation output instead of input nodes.
6062
* @param[in,out] getnext_ht Getnext HT to use, new @p sparent is added to it.
61-
* @param[out] getnext_p Filled getnext structure.
63+
* @param[out] choices Array of getnext choices of @p sparent.
64+
* @param[out] snodes Array of getnext schema nodes except for choices of @p sparent.
6265
* @return LY_ERR value.
6366
*/
6467
LY_ERR lyd_val_getnext_get(const struct lysc_node *sparent, const struct lys_module *mod, ly_bool output,
65-
struct ly_ht *getnext_ht, const struct lyd_val_getnext **getnext_p);
68+
struct ly_ht *getnext_ht, const struct lysc_node ***choices, const struct lysc_node ***snodes);
6669

6770
/**
6871
* @brief Add new changes into a diff. They are always merged.

0 commit comments

Comments
 (0)