From cc178f6b5624a9b7442fc2b7599e739411f9a47c Mon Sep 17 00:00:00 2001 From: aravindor Date: Sat, 7 Nov 2026 16:27:23 +0530 Subject: [PATCH] schema diff, types, parsers REFACTOR bound the remaining string writes The schema diff tree, the decimal64 / ipv4-prefix / ipv6-prefix canonical value printers, the date/time helpers, the unique-constraint error builder, schema-mount context copying and the YANG/YIN pattern and revision-date parsers still built strings with sprintf()/strcpy() sized by hand. Each buffer is already large enough, but the writes were unbounded. Convert them to snprintf() bounded by the buffer (sizeof or the allocation size), memcpy() of the measured length, or strdup(). Output is unchanged. With #2625 this removes the last hand-sized unbounded string writes from the library sources. --- src/parser_yang.c | 2 +- src/parser_yin.c | 5 +-- src/plugins_exts/schema_mount.c | 6 ++- src/plugins_types/decimal64.c | 6 +-- src/plugins_types/ipv4_address_prefix.c | 2 +- src/plugins_types/ipv6_address_prefix.c | 2 +- src/schema_diff_tree.c | 60 ++++++++++++------------- src/tree_data_common.c | 4 +- src/tree_schema.c | 2 +- src/validation.c | 2 +- 10 files changed, 46 insertions(+), 45 deletions(-) diff --git a/src/parser_yang.c b/src/parser_yang.c index df9982906..e885034a9 100644 --- a/src/parser_yang.c +++ b/src/parser_yang.c @@ -2208,7 +2208,7 @@ parse_type_pattern_modifier(struct lysp_yang_ctx *ctx, struct lysp_restr *restr) /* replace the value in the dictionary */ buf = malloc(strlen(restr->arg.str) + 1); LY_CHECK_ERR_GOTO(!buf, LOGMEM(PARSER_CTX(ctx)); ret = LY_EMEM, cleanup); - strcpy(buf, restr->arg.str); + memcpy(buf, restr->arg.str, strlen(restr->arg.str) + 1); lysdict_remove(PARSER_CTX(ctx), restr->arg.str); assert(buf[0] == LYSP_RESTR_PATTERN_ACK); diff --git a/src/parser_yin.c b/src/parser_yin.c index cf8890502..12f1046ea 100644 --- a/src/parser_yin.c +++ b/src/parser_yin.c @@ -1005,9 +1005,8 @@ yin_parse_modifier(struct lysp_yin_ctx *ctx, const void *parent, const char **pa lysdict_remove(ctx->xmlctx->ctx, temp_val); /* allocate new value */ - modified_val = malloc(strlen(*pat) + 1); + modified_val = strdup(*pat); LY_CHECK_ERR_RET(!modified_val, LOGMEM(ctx->xmlctx->ctx), LY_EMEM); - strcpy(modified_val, *pat); lysdict_remove(ctx->xmlctx->ctx, *pat); /* modify the new value */ @@ -1994,7 +1993,7 @@ yin_parse_revision_date(struct lysp_yin_ctx *ctx, char *rev, struct lysp_ext_ins LY_CHECK_ERR_RET(lys_check_date(PARSER_CTX(ctx), temp_rev, strlen(temp_rev), "revision-date") != LY_SUCCESS, lysdict_remove(ctx->xmlctx->ctx, temp_rev), LY_EVALID); - strcpy(rev, temp_rev); + memcpy(rev, temp_rev, LY_REV_SIZE); lysdict_remove(ctx->xmlctx->ctx, temp_rev); LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), rev, LY_STMT_REVISION_DATE, NULL, exts)); diff --git a/src/plugins_exts/schema_mount.c b/src/plugins_exts/schema_mount.c index 48723f6b9..f62b027a2 100644 --- a/src/plugins_exts/schema_mount.c +++ b/src/plugins_exts/schema_mount.c @@ -1522,12 +1522,14 @@ schema_mount_compiled_print(const struct lysc_ext_instance *orig_ext, struct lys sm_data->shared->schemas[i].ctx = ctx_mem; /* mount_point */ - strcpy(*mem, orig_sm_data->shared->schemas[i].mount_point); + memcpy(*mem, orig_sm_data->shared->schemas[i].mount_point, + strlen(orig_sm_data->shared->schemas[i].mount_point) + 1); sm_data->shared->schemas[i].mount_point = *mem; *mem = (char *)*mem + LY_CTXP_MEM_SIZE(strlen(sm_data->shared->schemas[i].mount_point) + 1); /* content_id */ - strcpy(*mem, orig_sm_data->shared->schemas[i].content_id); + memcpy(*mem, orig_sm_data->shared->schemas[i].content_id, + strlen(orig_sm_data->shared->schemas[i].content_id) + 1); sm_data->shared->schemas[i].content_id = *mem; *mem = (char *)*mem + LY_CTXP_MEM_SIZE(strlen(sm_data->shared->schemas[i].content_id) + 1); } diff --git a/src/plugins_types/decimal64.c b/src/plugins_types/decimal64.c index a678abfc8..bc5168535 100644 --- a/src/plugins_types/decimal64.c +++ b/src/plugins_types/decimal64.c @@ -53,14 +53,14 @@ decimal64_num2str(int64_t num, struct lysc_type_dec *type, char **str) LY_CHECK_RET(!ret, LY_EMEM); if (num) { - int count = sprintf(ret, "%" PRId64 " ", num); + int count = snprintf(ret, LY_NUMBER_MAXLEN, "%" PRId64 " ", num); if (((num > 0) && ((count - 1) <= type->fraction_digits)) || ((count - 2) <= type->fraction_digits)) { /* we have 0. value, print the value with the leading zeros * (one for 0. and also keep the correct with of num according * to fraction-digits value) * for (num < 0) - extra character for '-' sign */ - count = sprintf(ret, "%0*" PRId64 " ", (num > 0) ? (type->fraction_digits + 1) : (type->fraction_digits + 2), num); + count = snprintf(ret, LY_NUMBER_MAXLEN, "%0*" PRId64 " ", (num > 0) ? (type->fraction_digits + 1) : (type->fraction_digits + 2), num); } for (uint8_t i = type->fraction_digits, j = 1; i > 0; i--) { if (j && (i > 1) && (ret[count - 2] == '0')) { @@ -75,7 +75,7 @@ decimal64_num2str(int64_t num, struct lysc_type_dec *type, char **str) ret[count - 1] = '.'; } else { /* zero */ - sprintf(ret, "0.0"); + snprintf(ret, LY_NUMBER_MAXLEN, "0.0"); } *str = ret; diff --git a/src/plugins_types/ipv4_address_prefix.c b/src/plugins_types/ipv4_address_prefix.c index 350b1a3ae..150e867ac 100644 --- a/src/plugins_types/ipv4_address_prefix.c +++ b/src/plugins_types/ipv4_address_prefix.c @@ -275,7 +275,7 @@ lyplg_type_print_ipv4_address_prefix(const struct ly_ctx *ctx, const struct lyd_ } /* add the prefix */ - sprintf(ret + strlen(ret), "/%" PRIu8, val->prefix); + snprintf(ret + strlen(ret), INET_ADDRSTRLEN + 4 - strlen(ret), "/%" PRIu8, val->prefix); /* store it */ if (lydict_insert_zc(ctx, ret, (const char **)&value->_canonical)) { diff --git a/src/plugins_types/ipv6_address_prefix.c b/src/plugins_types/ipv6_address_prefix.c index bf9f828f9..2bdcce8a2 100644 --- a/src/plugins_types/ipv6_address_prefix.c +++ b/src/plugins_types/ipv6_address_prefix.c @@ -289,7 +289,7 @@ lyplg_type_print_ipv6_address_prefix(const struct ly_ctx *ctx, const struct lyd_ } /* add the prefix */ - sprintf(ret + strlen(ret), "/%" PRIu8, val->prefix); + snprintf(ret + strlen(ret), INET6_ADDRSTRLEN + 4 - strlen(ret), "/%" PRIu8, val->prefix); /* store it */ if (lydict_insert_zc(ctx, ret, (const char **)&value->_canonical)) { diff --git a/src/schema_diff_tree.c b/src/schema_diff_tree.c index 82cce7b69..3c0089d6d 100644 --- a/src/schema_diff_tree.c +++ b/src/schema_diff_tree.c @@ -316,7 +316,7 @@ schema_diff_pnode_path(const struct lysp_node *node) path = ly_realloc(path, new_len + 1); LY_CHECK_ERR_GOTO(!path, LOGMEM(NULL), cleanup); - sprintf(path + path_len, "/%s%s%s", node_pre ? node_pre : "", nodes[i]->name, node_post ? node_post : ""); + snprintf(path + path_len, new_len + 1 - path_len, "/%s%s%s", node_pre ? node_pre : "", nodes[i]->name, node_post ? node_post : ""); path_len = new_len; } while (i); @@ -491,11 +491,11 @@ schema_diff_ext_inst_substmts_bitenums(const struct ly_ctx *ctx, const struct ly /* value/position */ if (items[u].flags & LYS_IS_ENUM) { - sprintf(num_str, "%" PRId32, items[u].value); + snprintf(num_str, sizeof num_str, "%" PRId32, items[u].value); LY_CHECK_GOTO(rc = schema_diff_ext_inst_substmts_child_add(ctx, "value", num_str, &bitenum_node->child), cleanup); } else { - sprintf(num_str, "%" PRIu32, items[u].position); + snprintf(num_str, sizeof num_str, "%" PRIu32, items[u].position); LY_CHECK_GOTO(rc = schema_diff_ext_inst_substmts_child_add(ctx, "position", num_str, &bitenum_node->child), cleanup); } @@ -611,16 +611,16 @@ schema_diff_range2str(struct lysc_range_part *parts, ly_bool is_signed, char **s LYA_FOR(parts, u) { if (is_signed) { - sprintf(num_min_str, "%" PRId64, parts[u].min_64); + snprintf(num_min_str, sizeof num_min_str, "%" PRId64, parts[u].min_64); if (parts[u].min_64 < parts[u].max_64) { - sprintf(num_max_str, "%" PRId64, parts[u].max_64); + snprintf(num_max_str, sizeof num_max_str, "%" PRId64, parts[u].max_64); } else { num_max_str[0] = '\0'; } } else { - sprintf(num_min_str, "%" PRIu64, parts[u].min_u64); + snprintf(num_min_str, sizeof num_min_str, "%" PRIu64, parts[u].min_u64); if (parts[u].min_u64 < parts[u].max_u64) { - sprintf(num_max_str, "%" PRIu64, parts[u].max_u64); + snprintf(num_max_str, sizeof num_max_str, "%" PRIu64, parts[u].max_u64); } else { num_max_str[0] = '\0'; } @@ -630,7 +630,7 @@ schema_diff_range2str(struct lysc_range_part *parts, ly_bool is_signed, char **s s = ly_realloc(s, new_len + 1); LY_CHECK_ERR_GOTO(!s, LOGMEM(NULL); rc = LY_EMEM, cleanup); - sprintf(s + s_len, "%s%s%s%s", s_len ? "|" : "", num_min_str, num_max_str[0] ? ".." : "", + snprintf(s + s_len, new_len + 1 - s_len, "%s%s%s%s", s_len ? "|" : "", num_min_str, num_max_str[0] ? ".." : "", num_max_str[0] ? num_max_str : ""); s_len = new_len; } @@ -877,7 +877,7 @@ schema_diff_ext_inst_substmts_type(const struct ly_ctx *ctx, const struct lysc_t type_dec = (const struct lysc_type_dec *)type; /* fraction-digits */ - sprintf(num_str, "%" PRIu8, type_dec->fraction_digits); + snprintf(num_str, sizeof num_str, "%" PRIu8, type_dec->fraction_digits); LY_CHECK_GOTO(rc = schema_diff_ext_inst_substmts_child_add(ctx, "fraction-digits", num_str, child_p), cleanup); /* range */ @@ -1099,12 +1099,12 @@ schema_diff_ext_inst_substmts_nodes_r(const struct lysc_node *sibling, struct ly max = llist->max; } if (min > 0) { - sprintf(num_str, "%" PRIu32, min); + snprintf(num_str, sizeof num_str, "%" PRIu32, min); LY_CHECK_GOTO(rc = schema_diff_ext_inst_substmts_child_add(ctx, "min-elements", num_str, &node->child), cleanup); } if (max < UINT32_MAX) { - sprintf(num_str, "%" PRIu32, max); + snprintf(num_str, sizeof num_str, "%" PRIu32, max); LY_CHECK_GOTO(rc = schema_diff_ext_inst_substmts_child_add(ctx, "max-elements", num_str, &node->child), cleanup); } @@ -1221,7 +1221,7 @@ schema_diff_ext_inst_substmts(const struct ly_ctx *ctx, const struct lysc_ext_su /* uint8 number */ if (*(substmts[u].storage_p)) { - sprintf(num_str, "%" PRIu8, *(uint8_t *)substmts[u].storage_p); + snprintf(num_str, sizeof num_str, "%" PRIu8, *(uint8_t *)substmts[u].storage_p); LY_CHECK_GOTO(rc = schema_diff_ext_inst_substmts_child_add(ctx, lys_stmt_str(substmts[u].stmt), num_str, child_p), cleanup); } @@ -1253,7 +1253,7 @@ schema_diff_ext_inst_substmts(const struct ly_ctx *ctx, const struct lysc_ext_su /* uint32 number */ if (*(uint32_t *)substmts[u].storage_p < UINT32_MAX) { - sprintf(num_str, "%" PRIu32, *(uint32_t *)substmts[u].storage_p); + snprintf(num_str, sizeof num_str, "%" PRIu32, *(uint32_t *)substmts[u].storage_p); LY_CHECK_GOTO(rc = schema_diff_ext_inst_substmts_child_add(ctx, "max-elements", num_str, child_p), cleanup); } @@ -1264,7 +1264,7 @@ schema_diff_ext_inst_substmts(const struct ly_ctx *ctx, const struct lysc_ext_su /* uint32 number */ if (*(uint32_t *)substmts[u].storage_p > 0) { - sprintf(num_str, "%" PRIu32, *(uint32_t *)substmts[u].storage_p); + snprintf(num_str, sizeof num_str, "%" PRIu32, *(uint32_t *)substmts[u].storage_p); LY_CHECK_GOTO(rc = schema_diff_ext_inst_substmts_child_add(ctx, "min-elements", num_str, child_p), cleanup); } @@ -1290,7 +1290,7 @@ schema_diff_ext_inst_substmts(const struct ly_ctx *ctx, const struct lysc_ext_su char num_str[21]; /* uint64 number */ - sprintf(num_str, "%" PRIu64, *(uint64_t *)substmts[u].storage_p); + snprintf(num_str, sizeof num_str, "%" PRIu64, *(uint64_t *)substmts[u].storage_p); LY_CHECK_GOTO(rc = schema_diff_ext_inst_substmts_child_add(ctx, "position", num_str, child_p), cleanup); break; } @@ -1334,7 +1334,7 @@ schema_diff_ext_inst_substmts(const struct ly_ctx *ctx, const struct lysc_ext_su char num_str[21]; /* int64 number */ - sprintf(num_str, "%" PRId64, *(int64_t *)substmts[u].storage_p); + snprintf(num_str, sizeof num_str, "%" PRId64, *(int64_t *)substmts[u].storage_p); LY_CHECK_GOTO(rc = schema_diff_ext_inst_substmts_child_add(ctx, "value", num_str, child_p), cleanup); break; } @@ -1958,11 +1958,11 @@ schema_diff_parsed_enum(const struct lysp_type_enum *enm, ly_bool is_bit, struct if (is_bit) { /* position */ - sprintf(str, "%" PRIu64, (uint64_t)enm->value); + snprintf(str, sizeof str, "%" PRIu64, (uint64_t)enm->value); LY_CHECK_GOTO(rc = lyd_new_term(enum_list, NULL, "position", str, LYD_NEW_VAL_CANON, NULL), cleanup); } else { /* value */ - sprintf(str, "%" PRId64, enm->value); + snprintf(str, sizeof str, "%" PRId64, enm->value); LY_CHECK_GOTO(rc = lyd_new_term(enum_list, NULL, "value", str, LYD_NEW_VAL_CANON, NULL), cleanup); } @@ -2011,7 +2011,7 @@ schema_diff_parsed_type(const struct lysp_type *type, struct lyd_node *cont) /* fraction-digits */ if (type->flags & LYS_SET_FRDIGITS) { - sprintf(str, "%" PRIu8, type->fraction_digits); + snprintf(str, sizeof str, "%" PRIu8, type->fraction_digits); LY_CHECK_GOTO(rc = lyd_new_term(cont, NULL, "fraction-digits", str, LYD_NEW_VAL_CANON, NULL), cleanup); } @@ -2264,7 +2264,7 @@ schema_diff_pnode(const struct lysp_node *pnode, struct lyd_node *change_cont) /* min-elements */ if (min_set) { - sprintf(buf, "%" PRIu32, min); + snprintf(buf, sizeof buf, "%" PRIu32, min); if ((rc = lyd_new_term(change_cont, NULL, "min-elements", buf, 0, NULL))) { goto cleanup; } @@ -2272,7 +2272,7 @@ schema_diff_pnode(const struct lysp_node *pnode, struct lyd_node *change_cont) /* max-elements */ if (max_set) { - sprintf(buf, "%" PRIu32, max); + snprintf(buf, sizeof buf, "%" PRIu32, max); if ((rc = lyd_new_term(change_cont, NULL, "max-elements", buf, 0, NULL))) { goto cleanup; } @@ -2405,7 +2405,7 @@ schema_diff_refine(const struct lysp_refine *refine, struct lyd_node *change_con /* min-elements */ if (refine->flags & LYS_SET_MIN) { - sprintf(buf, "%" PRIu32, refine->min); + snprintf(buf, sizeof buf, "%" PRIu32, refine->min); if ((rc = lyd_new_term(change_cont, NULL, "min-elements", buf, 0, NULL))) { goto cleanup; } @@ -2413,7 +2413,7 @@ schema_diff_refine(const struct lysp_refine *refine, struct lyd_node *change_con /* max-elements */ if (refine->flags & LYS_SET_MAX) { - sprintf(buf, "%" PRIu32, refine->max); + snprintf(buf, sizeof buf, "%" PRIu32, refine->max); if ((rc = lyd_new_term(change_cont, NULL, "max-elements", buf, 0, NULL))) { goto cleanup; } @@ -3122,7 +3122,7 @@ schema_diff_deviation(const struct lysp_deviation *dev, struct lyd_node *change_ /* min-elements */ if (flags & LYS_SET_MIN) { - sprintf(buf, "%" PRIu32, min); + snprintf(buf, sizeof buf, "%" PRIu32, min); if ((rc = lyd_new_term(dev_list, NULL, "min-elements", buf, 0, NULL))) { goto cleanup; } @@ -3130,7 +3130,7 @@ schema_diff_deviation(const struct lysp_deviation *dev, struct lyd_node *change_ /* max-elements */ if (flags & LYS_SET_MAX) { - sprintf(buf, "%" PRIu32, max); + snprintf(buf, sizeof buf, "%" PRIu32, max); if ((rc = lyd_new_term(dev_list, NULL, "max-elements", buf, 0, NULL))) { goto cleanup; } @@ -3523,10 +3523,10 @@ schema_diff_node_type_bitenums(const struct lysc_type_bitenum_item *items, struc /* value/position */ if (items[u].flags & LYS_IS_ENUM) { - sprintf(buf, "%" PRId32, items[u].value); + snprintf(buf, sizeof buf, "%" PRId32, items[u].value); LY_CHECK_GOTO(rc = lyd_new_term(par_list, NULL, "value", buf, 0, NULL), cleanup); } else { - sprintf(buf, "%" PRIu32, items[u].position); + snprintf(buf, sizeof buf, "%" PRIu32, items[u].position); LY_CHECK_GOTO(rc = lyd_new_term(par_list, NULL, "position", buf, 0, NULL), cleanup); } @@ -3625,7 +3625,7 @@ schema_diff_node_type(const struct lysc_type *type, struct lyd_node *type_par) type_dec = (const struct lysc_type_dec *)type; /* fraction-digits */ - sprintf(buf, "%" PRIu8, type_dec->fraction_digits); + snprintf(buf, sizeof buf, "%" PRIu8, type_dec->fraction_digits); LY_CHECK_GOTO(rc = lyd_new_term(type_par, NULL, "fraction-digits", buf, 0, NULL), cleanup); /* range */ @@ -3828,13 +3828,13 @@ schema_diff_node_stmts(const struct lysc_node *node, ly_bool gen_local, struct l max = llist->max; } if (min > 0) { - sprintf(buf, "%" PRIu32, min); + snprintf(buf, sizeof buf, "%" PRIu32, min); if ((rc = lyd_new_term(change_cont, NULL, "min-elements", buf, 0, NULL))) { goto cleanup; } } if (max < UINT32_MAX) { - sprintf(buf, "%" PRIu32, max); + snprintf(buf, sizeof buf, "%" PRIu32, max); if ((rc = lyd_new_term(change_cont, NULL, "max-elements", buf, 0, NULL))) { goto cleanup; } diff --git a/src/tree_data_common.c b/src/tree_data_common.c index 9fc0159d0..6089b6559 100644 --- a/src/tree_data_common.c +++ b/src/tree_data_common.c @@ -1648,7 +1648,7 @@ ly_time_time2str(time_t time, const char *fractions_s, char **str) zonediff_s = ly_time_tz_offset_at(time); zonediff_h = zonediff_s / 60 / 60; zonediff_m = zonediff_s / 60 % 60; - sprintf(zoneshift, "%+03d:%02d", zonediff_h, zonediff_m < 0 ? -zonediff_m : zonediff_m); + snprintf(zoneshift, sizeof zoneshift, "%+03d:%02d", zonediff_h, zonediff_m < 0 ? -zonediff_m : zonediff_m); /* print */ if (asprintf(str, "%04d-%02d-%02dT%02d:%02d:%02d%s%s%s", @@ -1698,7 +1698,7 @@ ly_time_ts2str(const struct timespec *ts, char **str) /* convert nanoseconds to fractions of a second */ if (ts->tv_nsec) { - sprintf(frac_buf, "%09ld", ts->tv_nsec); + snprintf(frac_buf, sizeof frac_buf, "%09ld", ts->tv_nsec); } return ly_time_time2str(ts->tv_sec, ts->tv_nsec ? frac_buf : NULL, str); diff --git a/src/tree_schema.c b/src/tree_schema.c index 85b8833fa..bcf0f17ae 100644 --- a/src/tree_schema.c +++ b/src/tree_schema.c @@ -1000,7 +1000,7 @@ lysc_path_until(const struct lysc_node *node, const struct lysc_node *parent, LY path = NULL; } else if (len == 0) { if (buffer) { - strcpy(buffer, "/"); + snprintf(buffer, buflen, "/"); } else { free(path); path = strdup("/"); diff --git a/src/validation.c b/src/validation.c index 850bb0c67..babc112d0 100644 --- a/src/validation.c +++ b/src/validation.c @@ -1578,7 +1578,7 @@ lyd_val_uniq_list_equal(void *val1_p, void *val2_p, ly_bool UNUSED(mod), void *c ptr = uniq_str; LYA_FOR(slist->uniques[u], v) { if (v) { - strcpy(ptr, " "); + memcpy(ptr, " ", 2); ++ptr; } ptr = lysc_path_until((struct lysc_node *)slist->uniques[u][v], &slist->node, LYSC_PATH_LOG,