From 4bec1debc677632e6a0dc27a015195c962e5cd4c Mon Sep 17 00:00:00 2001 From: Mark Andrews Date: Thu, 21 Jan 2016 15:33:08 +1100 Subject: [PATCH] 4299. [bug] Check that exactly totallen bytes are read when reading a RRset from raw files in both single read and incremental modes. [RT #41402] (cherry picked from commit 1d383fd4b23fc7031e562bf5db02e3018c5d0b9e) --- CHANGES | 4 ++++ lib/dns/master.c | 24 ++++++++++++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/CHANGES b/CHANGES index 8299d290f4..6525fbec31 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,7 @@ +4299. [bug] Check that exactly totallen bytes are read when + reading a RRset from raw files in both single read + and incremental modes. [RT #41402] + 4297. [bug] RPZ zones with errors could cause a crash when a pointer was cleaned up twice. [RT #41518] diff --git a/lib/dns/master.c b/lib/dns/master.c index 66e353641a..6bbfa500a4 100644 --- a/lib/dns/master.c +++ b/lib/dns/master.c @@ -2091,12 +2091,18 @@ pushfile(const char *master_file, dns_name_t *origin, dns_loadctx_t *lctx) { return (result); } +/* + * Fill/check exists buffer with 'len' bytes. Track remaining bytes to be + * read when incrementally filling the buffer. + */ static inline isc_result_t read_and_check(isc_boolean_t do_read, isc_buffer_t *buffer, - size_t len, FILE *f) + size_t len, FILE *f, isc_uint32_t *totallen) { isc_result_t result; + REQUIRE(totallen != NULL); + if (do_read) { INSIST(isc_buffer_availablelength(buffer) >= len); result = isc_stdio_read(isc_buffer_used(buffer), 1, len, @@ -2104,6 +2110,9 @@ read_and_check(isc_boolean_t do_read, isc_buffer_t *buffer, if (result != ISC_R_SUCCESS) return (result); isc_buffer_add(buffer, (unsigned int)len); + if (*totallen < len) + return (ISC_R_RANGE); + *totallen -= len; } else if (isc_buffer_remaininglength(buffer) < len) return (ISC_R_RANGE); @@ -2245,6 +2254,7 @@ load_raw(dns_loadctx_t *lctx) { goto cleanup; isc_buffer_add(&target, sizeof(totallen)); totallen = isc_buffer_getuint32(&target); + /* * Validation: the input data must at least contain the common * header. @@ -2286,6 +2296,7 @@ load_raw(dns_loadctx_t *lctx) { if (result != ISC_R_SUCCESS) goto cleanup; isc_buffer_add(&target, (unsigned int)readlen); + totallen -= readlen; /* Construct RRset headers */ dns_rdatalist_init(&rdatalist); @@ -2306,7 +2317,7 @@ load_raw(dns_loadctx_t *lctx) { /* Owner name: length followed by name */ result = read_and_check(sequential_read, &target, - sizeof(namelen), lctx->f); + sizeof(namelen), lctx->f, &totallen); if (result != ISC_R_SUCCESS) goto cleanup; namelen = isc_buffer_getuint16(&target); @@ -2316,7 +2327,7 @@ load_raw(dns_loadctx_t *lctx) { } result = read_and_check(sequential_read, &target, namelen, - lctx->f); + lctx->f, &totallen); if (result != ISC_R_SUCCESS) goto cleanup; @@ -2374,14 +2385,15 @@ load_raw(dns_loadctx_t *lctx) { /* rdata length */ result = read_and_check(sequential_read, &target, - sizeof(rdlen), lctx->f); + sizeof(rdlen), lctx->f, + &totallen); if (result != ISC_R_SUCCESS) goto cleanup; rdlen = isc_buffer_getuint16(&target); /* rdata */ result = read_and_check(sequential_read, &target, - rdlen, lctx->f); + rdlen, lctx->f, &totallen); if (result != ISC_R_SUCCESS) goto cleanup; isc_buffer_setactive(&target, (unsigned int)rdlen); @@ -2407,7 +2419,7 @@ load_raw(dns_loadctx_t *lctx) { * necessarily critical, but it very likely indicates broken * or malformed data. */ - if (isc_buffer_remaininglength(&target) != 0) { + if (isc_buffer_remaininglength(&target) != 0 || totallen != 0) { result = ISC_R_RANGE; goto cleanup; }