Skip to content

Commit

Permalink
Merge pull request #260 from alpire/master
Browse files Browse the repository at this point in the history
Fix memory safety issues
  • Loading branch information
vstakhov committed Jan 6, 2022
2 parents 71f16a8 + 110428d commit 64557c0
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 24 deletions.
57 changes: 37 additions & 20 deletions src/ucl_parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ struct ucl_parser_saved_state {
*/
#define ucl_chunk_skipc(chunk, p) \
do { \
if (p == chunk->end) { \
break; \
} \
if (*(p) == '\n') { \
(chunk)->line ++; \
(chunk)->column = 0; \
Expand Down Expand Up @@ -395,6 +398,9 @@ ucl_check_variable (struct ucl_parser *parser, const char *ptr,
}
p ++;
}
if(p == end) {
(*out_len) ++;
}
}
else if (*ptr != '$') {
/* Not count escaped dollar sign */
Expand All @@ -418,13 +424,14 @@ ucl_check_variable (struct ucl_parser *parser, const char *ptr,
* Expand a single variable
* @param parser
* @param ptr
* @param remain
* @param in_len
* @param dest
* @param out_len
* @return
*/
static const char *
ucl_expand_single_variable (struct ucl_parser *parser, const char *ptr,
size_t remain, unsigned char **dest)
size_t in_len, unsigned char **dest, size_t out_len)
{
unsigned char *d = *dest, *dst;
const char *p = ptr + 1, *ret;
Expand All @@ -435,7 +442,8 @@ ucl_expand_single_variable (struct ucl_parser *parser, const char *ptr,
bool strict = false;

ret = ptr + 1;
remain --;
out_len --;
in_len --;

if (*p == '$') {
*d++ = *p++;
Expand All @@ -444,28 +452,31 @@ ucl_expand_single_variable (struct ucl_parser *parser, const char *ptr,
}
else if (*p == '{') {
p ++;
in_len --;
strict = true;
ret += 2;
remain -= 2;
out_len -= 2;
}

LL_FOREACH (parser->variables, var) {
if (remain >= var->var_len) {
if (out_len >= var->value_len && in_len >= (var->var_len + strict)) {
if (memcmp (p, var->var, var->var_len) == 0) {
memcpy (d, var->value, var->value_len);
ret += var->var_len;
d += var->value_len;
found = true;
break;
if (!strict || p[var->var_len] == '}') {
memcpy (d, var->value, var->value_len);
ret += var->var_len;
d += var->value_len;
found = true;
break;
}
}
}
}
if (!found) {
if (strict && parser->var_handler != NULL) {
if (parser->var_handler (p, remain, &dst, &dstlen, &need_free,
if (parser->var_handler (p, out_len, &dst, &dstlen, &need_free,
parser->var_data)) {
memcpy (d, dst, dstlen);
ret += remain;
ret += out_len;
d += dstlen;
found = true;
if (need_free) {
Expand All @@ -476,7 +487,7 @@ ucl_expand_single_variable (struct ucl_parser *parser, const char *ptr,

/* Leave variable as is */
if (!found) {
if (strict) {
if (strict && out_len >= 2) {
/* Copy '${' */
memcpy (d, ptr, 2);
d += 2;
Expand Down Expand Up @@ -506,7 +517,7 @@ ucl_expand_variable (struct ucl_parser *parser, unsigned char **dst,
const char *src, size_t in_len)
{
const char *p, *end = src + in_len;
unsigned char *d;
unsigned char *d, *d_end;
size_t out_len = 0;
bool vars_found = false;

Expand All @@ -517,7 +528,7 @@ ucl_expand_variable (struct ucl_parser *parser, unsigned char **dst,

p = src;
while (p != end) {
if (*p == '$') {
if (*p == '$' && p + 1 != end) {
p = ucl_check_variable (parser, p + 1, end - p - 1, &out_len, &vars_found);
}
else {
Expand All @@ -538,10 +549,11 @@ ucl_expand_variable (struct ucl_parser *parser, unsigned char **dst,
}

d = *dst;
d_end = d + out_len;
p = src;
while (p != end) {
if (*p == '$') {
p = ucl_expand_single_variable (parser, p, end - p, &d);
while (p != end && d != d_end) {
if (*p == '$' && p + 1 != end) {
p = ucl_expand_single_variable (parser, p, end - p, &d, d_end - d);
}
else {
*d++ = *p++;
Expand Down Expand Up @@ -1053,13 +1065,13 @@ ucl_lex_json_string (struct ucl_parser *parser,
}
else if (c == '\\') {
ucl_chunk_skipc (chunk, p);
c = *p;
if (p >= chunk->end) {
ucl_set_err (parser, UCL_ESYNTAX, "unfinished escape character",
&parser->err);
return false;
}
else if (ucl_test_character (c, UCL_CHARACTER_ESCAPE)) {
c = *p;
if (ucl_test_character (c, UCL_CHARACTER_ESCAPE)) {
if (c == 'u') {
ucl_chunk_skipc (chunk, p);
for (i = 0; i < 4 && p < chunk->end; i ++) {
Expand Down Expand Up @@ -1828,6 +1840,11 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
while (p < chunk->end && *p >= 'A' && *p <= 'Z') {
p ++;
}
if(p == chunk->end) {
ucl_set_err (parser, UCL_ESYNTAX,
"unterminated multiline value", &parser->err);
return false;
}
if (*p =='\n') {
/* Set chunk positions and start multiline parsing */
chunk->remain -= p - c + 1;
Expand Down
10 changes: 6 additions & 4 deletions src/ucl_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -1919,7 +1919,7 @@ ucl_inherit_handler (const unsigned char *data, size_t len,

/* Some sanity checks */
if (parent == NULL || ucl_object_type (parent) != UCL_OBJECT) {
ucl_create_err (&parser->err, "Unable to find inherited object %*.s",
ucl_create_err (&parser->err, "Unable to find inherited object %.*s",
(int)len, data);
return false;
}
Expand Down Expand Up @@ -2177,7 +2177,7 @@ ucl_strnstr (const char *s, const char *find, int len)
mlen = strlen (find);
do {
do {
if ((sc = *s++) == 0 || len-- == 0)
if ((sc = *s++) == 0 || len-- < mlen)
return (NULL);
} while (sc != c);
} while (strncmp (s, find, mlen) != 0);
Expand Down Expand Up @@ -3594,9 +3594,11 @@ ucl_object_copy_internal (const ucl_object_t *other, bool allow_array)

/* deep copy of values stored */
if (other->trash_stack[UCL_TRASH_KEY] != NULL) {
new->trash_stack[UCL_TRASH_KEY] =
strdup (other->trash_stack[UCL_TRASH_KEY]);
new->trash_stack[UCL_TRASH_KEY] = NULL;
if (other->key == (const char *)other->trash_stack[UCL_TRASH_KEY]) {
new->trash_stack[UCL_TRASH_KEY] = malloc(other->keylen + 1);
memcpy(new->trash_stack[UCL_TRASH_KEY], other->trash_stack[UCL_TRASH_KEY], other->keylen);
new->trash_stack[UCL_TRASH_KEY][other->keylen] = '\0';
new->key = new->trash_stack[UCL_TRASH_KEY];
}
}
Expand Down

0 comments on commit 64557c0

Please sign in to comment.