]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
- Fix #637: Integer Overflow in sldns_str2period function.
authorW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Thu, 3 Mar 2022 13:19:59 +0000 (14:19 +0100)
committerW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Thu, 3 Mar 2022 13:19:59 +0000 (14:19 +0100)
doc/Changelog
services/authzone.c
sldns/parseutil.c
sldns/parseutil.h
sldns/str2wire.c

index ff410c21289d4d81b2c53c46190107289cf1997f..2236e55506128a93dcef2c206e16c118bb89536a 100644 (file)
@@ -1,3 +1,6 @@
+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
index 66d118b02df232e46d916af9729f67c411400549..b8ce8e73bdf7d1fe5dfc74a3dde96e1cbf83e2ac 100644 (file)
@@ -4456,7 +4456,7 @@ chunkline_get_line_collated(struct auth_chunk** chunk, size_t* chunk_pos,
        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)
 {
@@ -4467,13 +4467,16 @@ 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)
 {
@@ -4481,8 +4484,12 @@ 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;
@@ -4493,15 +4500,20 @@ static int
 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;
@@ -5007,6 +5019,7 @@ apply_http(struct auth_xfer* xfr, struct auth_zone* z,
        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)) {
@@ -5063,10 +5076,24 @@ apply_http(struct auth_xfer* xfr, struct auth_zone* z,
                        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)) {
index ba71df55d501d0d7483af45573eb7546d45f0d84..e69c568db08a471a2acc1cf91e10927d9d2c499c 100644 (file)
@@ -209,11 +209,13 @@ sldns_hexdigit_to_int(char ch)
 }
 
 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) {
@@ -236,26 +238,46 @@ sldns_str2period(const char *nptr, const char **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;
@@ -269,15 +291,27 @@ sldns_str2period(const char *nptr, const char **endptr)
                        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;
index 208fd2fbca8b4ff22fe175c8b04f5e2dd02dbe58..683f34e230704d2143aeabfcc0e9d0cae2c4938a 100644 (file)
@@ -74,9 +74,11 @@ struct tm * sldns_serial_arithmetics_gmtime_r(int32_t time, time_t now, struct t
  * 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
index 4e9da2b100485cc9468fbd266f245542e9a60bc7..09dedb0d7e84ef73e76d7fa1ba2fb1ccb90716ca 100644 (file)
@@ -249,11 +249,16 @@ rrinternal_get_ttl(sldns_buffer* strbuf, char* token, size_t token_len,
        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;
@@ -1055,12 +1060,15 @@ int sldns_fp2wire_rr_buf(FILE* in, uint8_t* rr, size_t* len, size_t* dname_len,
                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;
@@ -2157,9 +2165,13 @@ int sldns_str2wire_tsigtime_buf(const char* str, uint8_t* rd, size_t* len)
 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);