Merge branch '339-issues-with-large-journal-entries' into 'master'

Fix handling of large journal entries.

Closes #339

See merge request isc-projects/bind9!432
This commit is contained in:
Evan Hunt 2018-06-27 21:24:29 -04:00
commit be38c1f041
4 changed files with 44 additions and 5 deletions

View file

@ -1,3 +1,6 @@
4984. [bug] Improve handling of very large incremental
zone transfers to prevent journal corruption. [GL #339]
4983. [func] Add the ability to not return a DNS COOKIE option
when one is present in the request (answer-cookie no;).
[GL #173]

View file

@ -316,7 +316,10 @@
<itemizedlist>
<listitem>
<para>
None.
<command>named</command> now rejects excessively large
incremental (IXFR) zone transfers in order to prevent
possible corruption of journal files which could cause
<command>named</command> to abort when loading zones. [GL #339]
</para>
</listitem>
</itemizedlist>

View file

@ -1011,7 +1011,7 @@ dns_journal_writediff(dns_journal_t *j, dns_diff_t *diff) {
dns_difftuple_t *t;
isc_buffer_t buffer;
void *mem = NULL;
unsigned int size;
isc_uint64_t size;
isc_result_t result;
isc_region_t used;
@ -1041,6 +1041,14 @@ dns_journal_writediff(dns_journal_t *j, dns_diff_t *diff) {
size += t->rdata.length;
}
if (size >= DNS_JOURNAL_SIZE_MAX) {
isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR,
"dns_journal_writediff: %s: journal entry "
"too big to be stored: %llu bytes", j->filename,
size);
return (ISC_R_NOSPACE);
}
mem = isc_mem_get(j->mctx, size);
if (mem == NULL)
return (ISC_R_NOMEMORY);
@ -1094,6 +1102,7 @@ isc_result_t
dns_journal_commit(dns_journal_t *j) {
isc_result_t result;
journal_rawheader_t rawheader;
isc_uint64_t total;
REQUIRE(DNS_JOURNAL_VALID(j));
REQUIRE(j->state == JOURNAL_STATE_TRANSACTION ||
@ -1143,6 +1152,18 @@ dns_journal_commit(dns_journal_t *j) {
}
}
/*
* We currently don't support huge journal entries.
*/
total = j->x.pos[1].offset - j->x.pos[0].offset;
if (total >= DNS_JOURNAL_SIZE_MAX) {
isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR,
"transaction too big to be stored in journal: "
"%llub (max is %llub)", total,
(isc_uint64_t)DNS_JOURNAL_SIZE_MAX);
return (ISC_R_UNEXPECTED);
}
/*
* Some old journal entries may become non-addressable
* when we increment the current serial number. Purge them
@ -1663,7 +1684,12 @@ read_one_rr(dns_journal_t *j) {
journal_xhdr_t xhdr;
journal_rrhdr_t rrhdr;
INSIST(j->offset <= j->it.epos.offset);
if (j->offset > j->it.epos.offset) {
isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR,
"%s: journal corrupt: possible integer overflow",
j->filename);
return (ISC_R_UNEXPECTED);
}
if (j->offset == j->it.epos.offset)
return (ISC_R_NOMORE);
if (j->it.xpos == j->it.xsize) {

View file

@ -15032,8 +15032,14 @@ zone_replacedb(dns_zone_t *zone, dns_db_t *db, isc_boolean_t dump) {
result = dns_db_diff(zone->mctx, db, ver, zone->db, NULL,
zone->journal);
if (result != ISC_R_SUCCESS)
goto fail;
if (result != ISC_R_SUCCESS) {
char strbuf[ISC_STRERRORSIZE];
isc__strerror(errno, strbuf, sizeof(strbuf));
dns_zone_log(zone, ISC_LOG_ERROR,
"ixfr-from-differences: failed: "
"%s", strbuf);
goto fallback;
}
if (dump)
zone_needdump(zone, DNS_DUMP_DELAY);
else
@ -15041,6 +15047,7 @@ zone_replacedb(dns_zone_t *zone, dns_db_t *db, isc_boolean_t dump) {
if (zone->type == dns_zone_master && inline_raw(zone))
zone_send_secureserial(zone, serial);
} else {
fallback:
if (dump && zone->masterfile != NULL) {
/*
* If DNS_ZONEFLG_FORCEXFER was set we don't want