+3 March 2022: Wouter
+ - Fix #637: Integer Overflow in sldns_str2period function.
+
2 March 2022: George
- Merge PR #632 from scottrw93: Match cnames in ipset.
- Various fixes for #632: variable initialisation, convert the qinfo
return 1;
}
-/** process $ORIGIN for http */
+/** process $ORIGIN for http, 0 nothing, 1 done, 2 error */
static int
http_parse_origin(sldns_buffer* buf, struct sldns_file_parse_state* pstate)
{
pstate->origin_len = sizeof(pstate->origin);
s = sldns_str2wire_dname_buf(sldns_strip_ws(line+8),
pstate->origin, &pstate->origin_len);
- if(s) pstate->origin_len = 0;
+ if(s) {
+ pstate->origin_len = 0;
+ return 2;
+ }
return 1;
}
return 0;
}
-/** process $TTL for http */
+/** process $TTL for http, 0 nothing, 1 done, 2 error */
static int
http_parse_ttl(sldns_buffer* buf, struct sldns_file_parse_state* pstate)
{
if(strncmp(line, "$TTL", 4) == 0 &&
isspace((unsigned char)line[4])) {
const char* end = NULL;
+ int overflow = 0;
pstate->default_ttl = sldns_str2period(
- sldns_strip_ws(line+5), &end);
+ sldns_strip_ws(line+5), &end, &overflow);
+ if(overflow) {
+ return 2;
+ }
return 1;
}
return 0;
chunkline_non_comment_RR(struct auth_chunk** chunk, size_t* chunk_pos,
sldns_buffer* buf, struct sldns_file_parse_state* pstate)
{
+ int ret;
while(chunkline_get_line_collated(chunk, chunk_pos, buf)) {
if(chunkline_is_comment_line_or_empty(buf)) {
/* a comment, go to next line */
continue;
}
- if(http_parse_origin(buf, pstate)) {
+ if((ret=http_parse_origin(buf, pstate))!=0) {
+ if(ret == 2)
+ return 0;
continue; /* $ORIGIN has been handled */
}
- if(http_parse_ttl(buf, pstate)) {
+ if((ret=http_parse_ttl(buf, pstate))!=0) {
+ if(ret == 2)
+ return 0;
continue; /* $TTL has been handled */
}
return 1;
struct sldns_file_parse_state pstate;
struct auth_chunk* chunk;
size_t chunk_pos;
+ int ret;
memset(&pstate, 0, sizeof(pstate));
pstate.default_ttl = 3600;
if(xfr->namelen < sizeof(pstate.origin)) {
continue;
}
/* parse line and add RR */
- if(http_parse_origin(scratch_buffer, &pstate)) {
+ if((ret=http_parse_origin(scratch_buffer, &pstate))!=0) {
+ if(ret == 2) {
+ verbose(VERB_ALGO, "error parsing ORIGIN on line [%s:%d] %s",
+ xfr->task_transfer->master->file,
+ pstate.lineno,
+ sldns_buffer_begin(scratch_buffer));
+ return 0;
+ }
continue; /* $ORIGIN has been handled */
}
- if(http_parse_ttl(scratch_buffer, &pstate)) {
+ if((ret=http_parse_ttl(scratch_buffer, &pstate))!=0) {
+ if(ret == 2) {
+ verbose(VERB_ALGO, "error parsing TTL on line [%s:%d] %s",
+ xfr->task_transfer->master->file,
+ pstate.lineno,
+ sldns_buffer_begin(scratch_buffer));
+ return 0;
+ }
continue; /* $TTL has been handled */
}
if(!http_parse_add_rr(xfr, z, scratch_buffer, &pstate)) {
}
uint32_t
-sldns_str2period(const char *nptr, const char **endptr)
+sldns_str2period(const char *nptr, const char **endptr, int* overflow)
{
int sign = 0;
uint32_t i = 0;
uint32_t seconds = 0;
+ const uint32_t maxint = 0xffffffff;
+ *overflow = 0;
for(*endptr = nptr; **endptr; (*endptr)++) {
switch (**endptr) {
break;
case 's':
case 'S':
+ if(seconds > maxint-i) {
+ *overflow = 1;
+ return 0;
+ }
seconds += i;
i = 0;
break;
case 'm':
case 'M':
+ if(i > maxint/60 || seconds > maxint-(i*60)) {
+ *overflow = 1;
+ return 0;
+ }
seconds += i * 60;
i = 0;
break;
case 'h':
case 'H':
+ if(i > maxint/(60*60) || seconds > maxint-(i*60*60)) {
+ *overflow = 1;
+ return 0;
+ }
seconds += i * 60 * 60;
i = 0;
break;
case 'd':
case 'D':
+ if(i > maxint/(60*60*24) || seconds > maxint-(i*60*60*24)) {
+ *overflow = 1;
+ return 0;
+ }
seconds += i * 60 * 60 * 24;
i = 0;
break;
case 'w':
case 'W':
+ if(i > maxint/(60*60*24*7) || seconds > maxint-(i*60*60*24*7)) {
+ *overflow = 1;
+ return 0;
+ }
seconds += i * 60 * 60 * 24 * 7;
i = 0;
break;
case '7':
case '8':
case '9':
+ if(i > maxint/10 || i > maxint - (**endptr - '0')) {
+ *overflow = 1;
+ return 0;
+ }
i *= 10;
i += (**endptr - '0');
break;
default:
+ if(seconds > maxint-i) {
+ *overflow = 1;
+ return 0;
+ }
seconds += i;
/* disregard signedness */
return seconds;
}
}
+ if(seconds > maxint-i) {
+ *overflow = 1;
+ return 0;
+ }
seconds += i;
/* disregard signedness */
return seconds;
* converts a ttl value (like 5d2h) to a long.
* \param[in] nptr the start of the string
* \param[out] endptr points to the last char in case of error
+ * \param[out] overflow returns if the string causes integer overflow error,
+ * the number is too big, string of digits too long.
* \return the convert duration value
*/
-uint32_t sldns_str2period(const char *nptr, const char **endptr);
+uint32_t sldns_str2period(const char *nptr, const char **endptr, int* overflow);
/**
* Returns the int value of the given (hex) digit
int* not_there, uint32_t* ttl, uint32_t default_ttl)
{
const char* endptr;
+ int overflow;
if(sldns_bget_token(strbuf, token, "\t\n ", token_len) == -1) {
return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_TTL,
sldns_buffer_position(strbuf));
}
- *ttl = (uint32_t) sldns_str2period(token, &endptr);
+ *ttl = (uint32_t) sldns_str2period(token, &endptr, &overflow);
+ if(overflow) {
+ return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_INTEGER_OVERFLOW,
+ sldns_buffer_position(strbuf));
+ }
if (strlen(token) > 0 && !isdigit((unsigned char)token[0])) {
*not_there = 1;
return s;
} else if(strncmp(line, "$TTL", 4) == 0 && isspace((unsigned char)line[4])) {
const char* end = NULL;
+ int overflow = 0;
strlcpy((char*)rr, line, *len);
*len = 0;
*dname_len = 0;
if(!parse_state) return LDNS_WIREPARSE_ERR_OK;
parse_state->default_ttl = sldns_str2period(
- sldns_strip_ws(line+5), &end);
+ sldns_strip_ws(line+5), &end, &overflow);
+ if(overflow)
+ return LDNS_WIREPARSE_ERR_SYNTAX_INTEGER_OVERFLOW;
} else if (strncmp(line, "$INCLUDE", 8) == 0) {
strlcpy((char*)rr, line, *len);
*len = 0;
int sldns_str2wire_period_buf(const char* str, uint8_t* rd, size_t* len)
{
const char* end;
- uint32_t p = sldns_str2period(str, &end);
+ int overflow;
+ uint32_t p = sldns_str2period(str, &end, &overflow);
if(*end != 0)
return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_PERIOD, end-str);
+ if(overflow)
+ return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_INTEGER_OVERFLOW,
+ end-str);
if(*len < 4)
return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
sldns_write_uint32(rd, p);