-
Notifications
You must be signed in to change notification settings - Fork 138
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix memory safety issues #260
Changes from all commits
ac8d760
08de358
3a94514
54a5b59
852f752
f9e5446
a9c0965
9e0e06f
9b898ea
110428d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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; \ | ||
|
@@ -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 */ | ||
|
@@ -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; | ||
|
@@ -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++; | ||
|
@@ -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) { | ||
|
@@ -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; | ||
|
@@ -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; | ||
|
||
|
@@ -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) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch! |
||
p = ucl_check_variable (parser, p + 1, end - p - 1, &out_len, &vars_found); | ||
} | ||
else { | ||
|
@@ -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++; | ||
|
@@ -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 ++) { | ||
|
@@ -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; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, I always forget about the order of |
||
(int)len, data); | ||
return false; | ||
} | ||
|
@@ -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); | ||
|
@@ -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); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This change is really good, however, I think it will still be a good idea to terminate There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This makes a lot of sense. I added the null-byte terminator in 110428d. |
||
new->trash_stack[UCL_TRASH_KEY][other->keylen] = '\0'; | ||
new->key = new->trash_stack[UCL_TRASH_KEY]; | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, this name is more fortunate, I agree.