Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 31 additions & 12 deletions src/in.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,23 @@ ly_in_type(const struct ly_in *in)
return in->type;
}

static LY_ERR
ly_in_check_read(const struct ly_in *in, size_t count)
{
size_t offset;

if (!in->bounded) {
return LY_SUCCESS;
}

offset = in->current - in->start;
if ((offset > in->length) || (count > in->length - offset)) {
return LY_EDENIED;
}

return LY_SUCCESS;
}

LIBYANG_API_DEF LY_ERR
ly_in_reset(struct ly_in *in)
{
Expand Down Expand Up @@ -78,6 +95,7 @@ ly_in_new_fd(int fd, struct ly_in **in)
(*in)->current = (*in)->start = (*in)->func_start = addr;
(*in)->line = 1;
(*in)->length = length;
(*in)->bounded = 1;

return LY_SUCCESS;
}
Expand Down Expand Up @@ -106,6 +124,7 @@ ly_in_fd(struct ly_in *in, int fd)
in->current = in->start = addr;
in->line = 1;
in->length = length;
in->bounded = 1;
}

return prev_fd;
Expand Down Expand Up @@ -179,6 +198,8 @@ ly_in_memory(struct ly_in *in, const char *str)
if (str) {
in->start = in->current = str;
in->line = 1;
in->length = 0;
in->bounded = 0;
}

return data;
Expand Down Expand Up @@ -299,12 +320,12 @@ ly_in_free(struct ly_in *in, ly_bool destroy)
LIBYANG_API_DEF LY_ERR
ly_in_read(struct ly_in *in, void *buf, size_t count)
{
size_t read_count;

LY_CHECK_ARG_RET(NULL, in, buf, LY_EINVAL);

if (in->length && (in->length - (in->current - in->start) < count)) {
/* EOF */
return LY_EDENIED;
}
read_count = (count && in->peeked) ? count - 1 : count;
LY_CHECK_RET(ly_in_check_read(in, read_count));

if (count && in->peeked) {
/* read the peeked byte */
Expand All @@ -328,13 +349,11 @@ ly_in_peek(struct ly_in *in, uint8_t *peek)
{
LY_CHECK_ARG_RET(NULL, in, peek, LY_EINVAL);

if (in->length && (in->length - (in->current - in->start) < 1)) {
/* EOF */
return LY_EDENIED;
} else if (in->peeked) {
if (in->peeked) {
/* unsupported */
return LY_ENOT;
}
LY_CHECK_RET(ly_in_check_read(in, 1));

memcpy(&in->peek, in->current, 1);
in->current += 1;
Expand All @@ -347,12 +366,12 @@ ly_in_peek(struct ly_in *in, uint8_t *peek)
LIBYANG_API_DEF LY_ERR
ly_in_skip(struct ly_in *in, size_t count)
{
size_t skip_count;

LY_CHECK_ARG_RET(NULL, in, LY_EINVAL);

if (in->length && (in->length - (in->current - in->start) < count)) {
/* EOF */
return LY_EDENIED;
}
skip_count = (count && in->peeked) ? count - 1 : count;
LY_CHECK_RET(ly_in_check_read(in, skip_count));

if (count && in->peeked) {
/* skip the peeked byte */
Expand Down
3 changes: 2 additions & 1 deletion src/in_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ struct ly_in {
const char *current; /**< Current position in the input data */
const char *func_start; /**< Input data position when the last parser function was executed */
const char *start; /**< Input data start */
size_t length; /**< mmap() length (if used) */
size_t length; /**< input data length (if bounded) */
ly_bool bounded; /**< whether @ref length limits reads from @ref start */

ly_bool peeked; /**< whether a byte was peeked */
uint8_t peek; /**< peeked byte, if any */
Expand Down
21 changes: 11 additions & 10 deletions src/parser_data.h
Original file line number Diff line number Diff line change
Expand Up @@ -266,21 +266,22 @@ LIBYANG_API_DECL LY_ERR lyd_parse_data_mem(const struct ly_ctx *ctx, const char
uint32_t validate_options, struct lyd_node **tree);

/**
* @brief Parse data from a memory buffer with a specified length.
* @brief Parse (and validate) input data as a YANG data tree from a bounded memory buffer.
*
* This function parses the provided data buffer of a given length and returns the resulting data tree.
* Wrapper around ::lyd_parse_data() hiding work with the input handler and some obscure options.
* Unlike ::lyd_parse_data_mem(), @p data may contain NULL bytes and the parser will not read past @p data_len bytes.
*
* @param[in] ctx libyang context for parsing.
* @param[in] data Pointer to the memory buffer containing the data to parse.
* @param[in] data_len Length of the memory buffer.
* @param[in] format Data format (e.g., XML, JSON, LYD_LYB).
* @param[in] ctx Context to connect with the tree being built here.
* @param[in] data The input data in the specified @p format to parse (and validate).
* @param[in] data_len Number of readable bytes in @p data.
* @param[in] format Format of the input data to be parsed.
* @param[in] parse_options Options for parser, see @ref dataparseroptions.
* @param[in] validate_options Options for the validation phase, see @ref datavalidationoptions.
* @param[in] ctx_node Optional context node for parsing (can be NULL).
* @param[out] tree Pointer to the resulting data tree (set on success).
* @return LY_ERR value indicating success or error reason.
* @param[out] tree Full parsed data tree, note that NULL can be a valid tree.
* @return LY_SUCCESS in case of successful parsing (and validation).
* @return LY_ERR value in case of error. Additional error information can be obtained from the context using ly_err* functions.
*/
LIBYANG_API_DECL LY_ERR lyd_parse_data_mem_len(const struct ly_ctx *ctx, const char *data, size_t data_len, LYD_FORMAT format,
LIBYANG_API_DECL LY_ERR lyd_parse_data_mem_len(const struct ly_ctx *ctx, const char *data, uint32_t data_len, LYD_FORMAT format,
uint32_t parse_options, uint32_t validate_options, struct lyd_node **tree);

/**
Expand Down
24 changes: 15 additions & 9 deletions src/parser_lyb.c
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,8 @@ lyb_read(void *buf, uint64_t count_bits, struct lylyb_parse_ctx *lybctx)
return LY_SUCCESS;

eof:
LOGERR(lybctx->ctx, LY_EDENIED, "Unexpected LYB read EOF.");
return LY_EDENIED;
LOGERR(lybctx->ctx, LY_EVALID, "Unexpected end of LYB data.");
return LY_EVALID;
}

/**
Expand Down Expand Up @@ -210,8 +210,8 @@ lyb_read_count(uint32_t *count, struct lylyb_parse_ctx *lybctx)
break;
default:
/* invalid */
LOGINT(lybctx->ctx);
return LY_EINT;
LOGERR(lybctx->ctx, LY_EVALID, "Invalid LYB count prefix.");
return LY_EVALID;
}

/* correct byte order */
Expand Down Expand Up @@ -269,8 +269,8 @@ lyb_read_size(uint32_t *size, struct lylyb_parse_ctx *lybctx)
break;
default:
/* invalid */
LOGINT(lybctx->ctx);
return LY_EINT;
LOGERR(lybctx->ctx, LY_EVALID, "Invalid LYB size prefix.");
return LY_EVALID;
}

/* correct byte order */
Expand Down Expand Up @@ -351,7 +351,7 @@ lyb_read_value(const struct lysc_type *type, uint8_t **val, uint64_t *val_size_b
*val_size_bits = fixed_size_bits;
} else {
/* parse value size in bits or bytes, uint32_t is enough because larger sizes will be stored as bytes */
lyb_read_size(&lyb_size_bits, lybctx);
LY_CHECK_RET(lyb_read_size(&lyb_size_bits, lybctx));
*val_size_bits = lyb_size_bits;
if (size_type == LYPLG_LYB_SIZE_VARIABLE_BYTES) {
*val_size_bits *= 8;
Expand Down Expand Up @@ -873,9 +873,15 @@ lyb_read_hashes(struct lylyb_parse_ctx *lybctx, LYB_HASH *hash, uint8_t *hash_co
LY_CHECK_RET(lyb_read(&hash[j - 1], sizeof *hash * 8, lybctx));

/* correct collision ID */
assert(hash[j - 1] & (LYB_HASH_COLLISION_ID >> (j - 1)));
if (!(hash[j - 1] & (LYB_HASH_COLLISION_ID >> (j - 1)))) {
LOGERR(lybctx->ctx, LY_EVALID, "Invalid LYB schema hash collision ID.");
return LY_EVALID;
}
/* preceded with zeros */
assert(!(hash[j - 1] & (LYB_HASH_MASK << (LYB_HASH_BITS - (j - 1)))));
if (hash[j - 1] & (LYB_HASH_MASK << (LYB_HASH_BITS - (j - 1)))) {
LOGERR(lybctx->ctx, LY_EVALID, "Invalid LYB schema hash prefix.");
return LY_EVALID;
}
}

*hash_count = i + 1;
Expand Down
5 changes: 3 additions & 2 deletions src/tree_data.c
Original file line number Diff line number Diff line change
Expand Up @@ -220,14 +220,15 @@ lyd_parse_data(const struct ly_ctx *ctx, struct lyd_node *parent, struct ly_in *
}

LIBYANG_API_DEF LY_ERR
lyd_parse_data_mem_len(const struct ly_ctx *ctx, const char *data, size_t data_len, LYD_FORMAT format,
lyd_parse_data_mem_len(const struct ly_ctx *ctx, const char *data, uint32_t data_len, LYD_FORMAT format,
uint32_t parse_options, uint32_t validate_options, struct lyd_node **tree)
{
LY_ERR ret;
struct ly_in *in;

LY_CHECK_RET(ly_in_new_memory(data, &in));
in->length = data_len; // Set the length for the input
in->length = data_len;
in->bounded = 1;

ret = lyd_parse_data(ctx, NULL, in, format, parse_options, validate_options, tree);

Expand Down
26 changes: 4 additions & 22 deletions tests/fuzz/lyd_parse_lyb.c
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
#define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <stdint.h>

#include "libyang.h"

int LLVMFuzzerTestOneInput(uint8_t const *buf, size_t len)
{
struct ly_ctx *ctx = NULL;
struct lyd_node *tree = NULL;
FILE *input = NULL;
static bool log = false;
const char *schema =
"module fuzz-lyb {namespace urn:tests:fuzz-lyb;prefix fl;"
Expand All @@ -31,26 +26,13 @@ int LLVMFuzzerTestOneInput(uint8_t const *buf, size_t len)
goto cleanup;
}

input = tmpfile();
if (!input) {
goto cleanup;
if (len <= UINT32_MAX) {
lyd_parse_data_mem_len(ctx, (const char *)buf, (uint32_t)len, LYD_LYB, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT,
&tree);
}

if (len && (fwrite(buf, 1, len, input) != len)) {
goto cleanup;
}
fflush(input);
if (lseek(fileno(input), 0, SEEK_SET) == -1) {
goto cleanup;
}

lyd_parse_data_fd(ctx, fileno(input), LYD_LYB, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, &tree);

cleanup:
lyd_free_all(tree);
if (input) {
fclose(input);
}
ly_ctx_destroy(ctx);
return 0;
}
6 changes: 3 additions & 3 deletions tests/utests/data/test_cbor.c
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ test_node(void **state)
lyd_free_all(tree);

assert_int_equal(LY_SUCCESS, lyd_parse_data_mem_len(((struct utest_context *)*state)->ctx, buffer,
ly_out_printed(out), LYD_CBOR, LYD_PARSE_ONLY, 0, &tree));
(uint32_t)ly_out_printed(out), LYD_CBOR, LYD_PARSE_ONLY, 0, &tree));

ly_out_free(out, NULL, 0);
free(buffer);
Expand Down Expand Up @@ -244,7 +244,7 @@ test_schema_mount(void **state)
tree = NULL;

assert_int_equal(LY_SUCCESS, lyd_parse_data_mem_len(UTEST_LYCTX, cbor_buffer,
ly_out_printed(out_cbor), LYD_CBOR, LYD_PARSE_STRICT | LYD_PARSE_ONLY, 0, &tree));
(uint32_t)ly_out_printed(out_cbor), LYD_CBOR, LYD_PARSE_STRICT | LYD_PARSE_ONLY, 0, &tree));

ly_out_free(out_cbor, NULL, 0);
free(cbor_buffer);
Expand Down Expand Up @@ -280,7 +280,7 @@ test_opaque(void **state)
lyd_free_all(tree);

assert_int_equal(LY_SUCCESS, lyd_parse_data_mem_len(((struct utest_context *)*state)->ctx, buffer,
ly_out_printed(out), LYD_CBOR, LYD_PARSE_ONLY | LYD_PARSE_OPAQ, 0, &tree));
(uint32_t)ly_out_printed(out), LYD_CBOR, LYD_PARSE_ONLY | LYD_PARSE_OPAQ, 0, &tree));

ly_out_free(out, NULL, 0);
free(buffer);
Expand Down
Loading