Skip to content

Commit

Permalink
data: option to loosen json data type validation
Browse files Browse the repository at this point in the history
Prior to v1.0.212 the default behavior was to allow numbers
and boolean values to be in quotes, which is technically a
violation of the spec.

This adds a new `LY_CTX_LOOSE_JSON_DATATYPES` context option
which will restore the prior behavior when enabled.

SONiC is using v1.0.73 currently and has a large installed base which
may be in violation of the new behavior, so adding such a flag is
required for this usecase.

Signed-off-by: Brad House <[email protected]>
  • Loading branch information
bradh352 committed Feb 6, 2025
1 parent 03e294d commit a74e422
Show file tree
Hide file tree
Showing 24 changed files with 37 additions and 29 deletions.
4 changes: 4 additions & 0 deletions src/context.h
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,10 @@ struct ly_ctx;
loaded except for built-in YANG types so all derived types will use these and
for all purposes behave as the base type. The option can be used for cases when
invalid data needs to be stored in YANG node values. */
#define LY_CTX_LOOSE_JSON_DATATYPES 0x1000 /**< By default, JSON data values are validated to be in the proper format. For
instance numbers are expected to not be enclosed in quotes, nor are boolean
values. Setting this context option will disable this validation. Prior to
v1.0.212 this was the default behavior. */

/** @} contextoptions */

Expand Down
13 changes: 8 additions & 5 deletions src/plugins_types.c
Original file line number Diff line number Diff line change
Expand Up @@ -666,8 +666,8 @@ type_get_hints_base(uint32_t hints)
}

LIBYANG_API_DEF LY_ERR
lyplg_type_check_hints(uint32_t hints, const char *value, size_t value_len, LY_DATA_TYPE type, int *base,
struct ly_err_item **err)
lyplg_type_check_hints(const struct ly_ctx *ctx, uint32_t hints, const char *value, size_t value_len,
LY_DATA_TYPE type, int *base, struct ly_err_item **err)
{
LY_CHECK_ARG_RET(NULL, value || !value_len, err, LY_EINVAL);

Expand All @@ -685,7 +685,8 @@ lyplg_type_check_hints(uint32_t hints, const char *value, size_t value_len, LY_D
case LY_TYPE_INT32:
LY_CHECK_ARG_RET(NULL, base, LY_EINVAL);

if (!(hints & (LYD_VALHINT_DECNUM | LYD_VALHINT_OCTNUM | LYD_VALHINT_HEXNUM))) {
if (!(hints & (LYD_VALHINT_DECNUM | LYD_VALHINT_OCTNUM | LYD_VALHINT_HEXNUM)) &&
!(ly_ctx_get_options(ctx) & LY_CTX_LOOSE_JSON_DATATYPES)) {
return ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "Invalid non-number-encoded %s value \"%.*s\".",
lys_datatype2str(type), (int)value_len, value);
}
Expand All @@ -695,7 +696,8 @@ lyplg_type_check_hints(uint32_t hints, const char *value, size_t value_len, LY_D
case LY_TYPE_INT64:
LY_CHECK_ARG_RET(NULL, base, LY_EINVAL);

if (!(hints & LYD_VALHINT_NUM64)) {
if (!(hints & LYD_VALHINT_NUM64) &&
!(ly_ctx_get_options(ctx) & LY_CTX_LOOSE_JSON_DATATYPES)) {
return ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "Invalid non-num64-encoded %s value \"%.*s\".",
lys_datatype2str(type), (int)value_len, value);
}
Expand All @@ -714,7 +716,8 @@ lyplg_type_check_hints(uint32_t hints, const char *value, size_t value_len, LY_D
}
break;
case LY_TYPE_BOOL:
if (!(hints & LYD_VALHINT_BOOLEAN)) {
if (!(hints & LYD_VALHINT_BOOLEAN) &&
!(ly_ctx_get_options(ctx) & LY_CTX_LOOSE_JSON_DATATYPES)) {
return ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "Invalid non-boolean-encoded %s value \"%.*s\".",
lys_datatype2str(type), (int)value_len, value);
}
Expand Down
5 changes: 3 additions & 2 deletions src/plugins_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@ LIBYANG_API_DECL void ly_err_free(void *ptr);
*
* Use only in implementations of ::lyplg_type_store_clb which provide all the necessary parameters for this function.
*
* @param[in] ctx libyang context.
* @param[in] hints Bitmap of [value hints](@ref lydvalhints) of all the allowed value types provided by parsers
* to ::lyplg_type_store_clb.
* @param[in] value Lexical representation of the value to be stored.
Expand All @@ -253,8 +254,8 @@ LIBYANG_API_DECL void ly_err_free(void *ptr);
* @param[out] err Pointer to store error information in case of failure.
* @return LY_ERR value
*/
LIBYANG_API_DECL LY_ERR lyplg_type_check_hints(uint32_t hints, const char *value, size_t value_len, LY_DATA_TYPE type,
int *base, struct ly_err_item **err);
LIBYANG_API_DECL LY_ERR lyplg_type_check_hints(const struct ly_ctx *ctx, uint32_t hints, const char *value,
size_t value_len, LY_DATA_TYPE type, int *base, struct ly_err_item **err);

/**
* @brief Check that the value of a type is allowed based on its status.
Expand Down
2 changes: 1 addition & 1 deletion src/plugins_types/binary.c
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ lyplg_type_store_binary(const struct ly_ctx *ctx, const struct lysc_type *type,
}

/* check hints */
ret = lyplg_type_check_hints(hints, value, value_len, type->basetype, NULL, err);
ret = lyplg_type_check_hints(ctx, hints, value, value_len, type->basetype, NULL, err);
LY_CHECK_GOTO(ret, cleanup);

if (format != LY_VALUE_CANON) {
Expand Down
2 changes: 1 addition & 1 deletion src/plugins_types/bits.c
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@ lyplg_type_store_bits(const struct ly_ctx *ctx, const struct lysc_type *type, co
}

/* check hints */
ret = lyplg_type_check_hints(hints, value, value_len, type->basetype, NULL, err);
ret = lyplg_type_check_hints(ctx, hints, value, value_len, type->basetype, NULL, err);
LY_CHECK_GOTO(ret, cleanup);

/* allocate the bitmap */
Expand Down
2 changes: 1 addition & 1 deletion src/plugins_types/boolean.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ lyplg_type_store_boolean(const struct ly_ctx *ctx, const struct lysc_type *type,
}

/* check hints */
ret = lyplg_type_check_hints(hints, value, value_len, type->basetype, NULL, err);
ret = lyplg_type_check_hints(ctx, hints, value, value_len, type->basetype, NULL, err);
LY_CHECK_GOTO(ret, cleanup);

/* validate and store the value */
Expand Down
2 changes: 1 addition & 1 deletion src/plugins_types/date_and_time.c
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ lyplg_type_store_date_and_time(const struct ly_ctx *ctx, const struct lysc_type
}

/* check hints */
ret = lyplg_type_check_hints(hints, value, value_len, type->basetype, NULL, err);
ret = lyplg_type_check_hints(ctx, hints, value, value_len, type->basetype, NULL, err);
LY_CHECK_GOTO(ret, cleanup);

/* convert to UNIX time and fractions of second, function must check for all the possible errors */
Expand Down
2 changes: 1 addition & 1 deletion src/plugins_types/decimal64.c
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ lyplg_type_store_decimal64(const struct ly_ctx *ctx, const struct lysc_type *typ
num = le64toh(num);
} else {
/* check hints */
ret = lyplg_type_check_hints(hints, value, value_len, type->basetype, NULL, err);
ret = lyplg_type_check_hints(ctx, hints, value, value_len, type->basetype, NULL, err);
LY_CHECK_GOTO(ret, cleanup);

/* parse decimal64 value */
Expand Down
2 changes: 1 addition & 1 deletion src/plugins_types/empty.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ lyplg_type_store_empty(const struct ly_ctx *ctx, const struct lysc_type *type, c
storage->realtype = type;

/* check hints */
ret = lyplg_type_check_hints(hints, value, value_len, type->basetype, NULL, err);
ret = lyplg_type_check_hints(ctx, hints, value, value_len, type->basetype, NULL, err);
LY_CHECK_GOTO(ret, cleanup);

/* validation */
Expand Down
2 changes: 1 addition & 1 deletion src/plugins_types/enumeration.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ lyplg_type_store_enum(const struct ly_ctx *ctx, const struct lysc_type *type, co
}

/* check hints */
ret = lyplg_type_check_hints(hints, value, value_len, type->basetype, NULL, err);
ret = lyplg_type_check_hints(ctx, hints, value, value_len, type->basetype, NULL, err);
LY_CHECK_GOTO(ret, cleanup);

/* find the matching enumeration value item */
Expand Down
2 changes: 1 addition & 1 deletion src/plugins_types/hex_string.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ lyplg_type_store_hex_string(const struct ly_ctx *ctx, const struct lysc_type *ty
storage->realtype = type;

/* check hints */
ret = lyplg_type_check_hints(hints, value, value_len, type->basetype, NULL, err);
ret = lyplg_type_check_hints(ctx, hints, value, value_len, type->basetype, NULL, err);
LY_CHECK_GOTO(ret, cleanup);

/* make a copy, it is needed for canonization */
Expand Down
2 changes: 1 addition & 1 deletion src/plugins_types/identityref.c
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ lyplg_type_store_identityref(const struct ly_ctx *ctx, const struct lysc_type *t
storage->realtype = type;

/* check hints */
ret = lyplg_type_check_hints(hints, value, value_len, type->basetype, NULL, err);
ret = lyplg_type_check_hints(ctx, hints, value, value_len, type->basetype, NULL, err);
LY_CHECK_GOTO(ret, cleanup);

/* find a matching identity */
Expand Down
2 changes: 1 addition & 1 deletion src/plugins_types/instanceid.c
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ lyplg_type_store_instanceid(const struct ly_ctx *ctx, const struct lysc_type *ty
storage->realtype = type;

/* check hints */
ret = lyplg_type_check_hints(hints, value, value_len, type->basetype, NULL, err);
ret = lyplg_type_check_hints(ctx, hints, value, value_len, type->basetype, NULL, err);
LY_CHECK_GOTO(ret, cleanup);

/* compile instance-identifier into path */
Expand Down
2 changes: 1 addition & 1 deletion src/plugins_types/instanceid_keys.c
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ lyplg_type_store_instanceid_keys(const struct ly_ctx *ctx, const struct lysc_typ
storage->realtype = type;

/* check hints */
ret = lyplg_type_check_hints(hints, value, value_len, type->basetype, NULL, err);
ret = lyplg_type_check_hints(ctx, hints, value, value_len, type->basetype, NULL, err);
LY_CHECK_GOTO(ret, cleanup);

/* length restriction of the string */
Expand Down
4 changes: 2 additions & 2 deletions src/plugins_types/integer.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ lyplg_type_store_int(const struct ly_ctx *ctx, const struct lysc_type *type, con
num = le64toh(num);
} else {
/* check hints */
ret = lyplg_type_check_hints(hints, value, value_len, type->basetype, &base, err);
ret = lyplg_type_check_hints(ctx, hints, value, value_len, type->basetype, &base, err);
LY_CHECK_GOTO(ret, cleanup);

/* parse the integer */
Expand Down Expand Up @@ -339,7 +339,7 @@ lyplg_type_store_uint(const struct ly_ctx *ctx, const struct lysc_type *type, co
num = le64toh(num);
} else {
/* check hints */
ret = lyplg_type_check_hints(hints, value, value_len, type->basetype, &base, err);
ret = lyplg_type_check_hints(ctx, hints, value, value_len, type->basetype, &base, err);
LY_CHECK_GOTO(ret, cleanup);

/* parse the integer */
Expand Down
2 changes: 1 addition & 1 deletion src/plugins_types/ipv4_address.c
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ lyplg_type_store_ipv4_address(const struct ly_ctx *ctx, const struct lysc_type *
}

/* check hints */
ret = lyplg_type_check_hints(hints, value, value_len, type->basetype, NULL, err);
ret = lyplg_type_check_hints(ctx, hints, value, value_len, type->basetype, NULL, err);
LY_CHECK_GOTO(ret, cleanup);

if (!(options & LYPLG_TYPE_STORE_ONLY)) {
Expand Down
2 changes: 1 addition & 1 deletion src/plugins_types/ipv4_address_no_zone.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ lyplg_type_store_ipv4_address_no_zone(const struct ly_ctx *ctx, const struct lys
}

/* check hints */
ret = lyplg_type_check_hints(hints, value, value_len, type->basetype, NULL, err);
ret = lyplg_type_check_hints(ctx, hints, value, value_len, type->basetype, NULL, err);
LY_CHECK_GOTO(ret, cleanup);

/* we always need a dynamic value */
Expand Down
2 changes: 1 addition & 1 deletion src/plugins_types/ipv4_prefix.c
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ lyplg_type_store_ipv4_prefix(const struct ly_ctx *ctx, const struct lysc_type *t
}

/* check hints */
ret = lyplg_type_check_hints(hints, value, value_len, type->basetype, NULL, err);
ret = lyplg_type_check_hints(ctx, hints, value, value_len, type->basetype, NULL, err);
LY_CHECK_GOTO(ret, cleanup);

if (!(options & LYPLG_TYPE_STORE_ONLY)) {
Expand Down
2 changes: 1 addition & 1 deletion src/plugins_types/ipv6_address.c
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ lyplg_type_store_ipv6_address(const struct ly_ctx *ctx, const struct lysc_type *
}

/* check hints */
ret = lyplg_type_check_hints(hints, value, value_len, type->basetype, NULL, err);
ret = lyplg_type_check_hints(ctx, hints, value, value_len, type->basetype, NULL, err);
LY_CHECK_GOTO(ret, cleanup);

if (!(options & LYPLG_TYPE_STORE_ONLY)) {
Expand Down
2 changes: 1 addition & 1 deletion src/plugins_types/ipv6_address_no_zone.c
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ lyplg_type_store_ipv6_address_no_zone(const struct ly_ctx *ctx, const struct lys
LY_CHECK_ERR_GOTO(!val, ret = LY_EMEM, cleanup);

/* check hints */
ret = lyplg_type_check_hints(hints, value, value_len, type->basetype, NULL, err);
ret = lyplg_type_check_hints(ctx, hints, value, value_len, type->basetype, NULL, err);
LY_CHECK_GOTO(ret, cleanup);

/* get the network-byte order address, validates the value */
Expand Down
2 changes: 1 addition & 1 deletion src/plugins_types/ipv6_prefix.c
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ lyplg_type_store_ipv6_prefix(const struct ly_ctx *ctx, const struct lysc_type *t
LY_CHECK_ERR_GOTO(!val, ret = LY_EMEM, cleanup);

/* check hints */
ret = lyplg_type_check_hints(hints, value, value_len, type->basetype, NULL, err);
ret = lyplg_type_check_hints(ctx, hints, value, value_len, type->basetype, NULL, err);
LY_CHECK_GOTO(ret, cleanup);

if (!(options & LYPLG_TYPE_STORE_ONLY)) {
Expand Down
2 changes: 1 addition & 1 deletion src/plugins_types/node_instanceid.c
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ lyplg_type_store_node_instanceid(const struct ly_ctx *ctx, const struct lysc_typ
storage->realtype = type;

/* check hints */
ret = lyplg_type_check_hints(hints, value, value_len, type->basetype, NULL, err);
ret = lyplg_type_check_hints(ctx, hints, value, value_len, type->basetype, NULL, err);
LY_CHECK_GOTO(ret, cleanup);

if ((((char *)value)[0] == '/') && (value_len == 1)) {
Expand Down
2 changes: 1 addition & 1 deletion src/plugins_types/string.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ lyplg_type_store_string(const struct ly_ctx *ctx, const struct lysc_type *type,
}

/* check hints */
ret = lyplg_type_check_hints(hints, value, value_len, type->basetype, NULL, err);
ret = lyplg_type_check_hints(ctx, hints, value, value_len, type->basetype, NULL, err);
LY_CHECK_GOTO(ret, cleanup);

/* store canonical value */
Expand Down
2 changes: 1 addition & 1 deletion src/plugins_types/xpath1.0.c
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ lyplg_type_store_xpath10(const struct ly_ctx *ctx, const struct lysc_type *type,
storage->realtype = type;

/* check hints */
ret = lyplg_type_check_hints(hints, value, value_len, type->basetype, NULL, err);
ret = lyplg_type_check_hints(ctx, hints, value, value_len, type->basetype, NULL, err);
LY_CHECK_GOTO(ret, cleanup);

/* parse */
Expand Down

0 comments on commit a74e422

Please sign in to comment.