diff --git a/CHANGES b/CHANGES index ea32648a76..db1c491604 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,5 @@ +4792. [bug] Fix map file header correctness check. [RT #38418] + 4791. [doc] Fixed outdated documentation about export libraries. [RT #46341] diff --git a/bin/tests/system/masterformat/tests.sh b/bin/tests/system/masterformat/tests.sh index 8bbbee0ecc..8a95a7009b 100755 --- a/bin/tests/system/masterformat/tests.sh +++ b/bin/tests/system/masterformat/tests.sh @@ -238,6 +238,16 @@ done [ $ret -eq 0 ] || echo "I:failed" status=`expr $status + $ret` +# stomp on the file header +echo "I:checking corrupt map files fail to load (bad file header)" +ret=0 +./named-compilezone -D -f text -F map -o map.5 example.nil baseline.txt > /dev/null +cp map.5 badmap +stomp badmap 0 32 99 +./named-compilezone -D -f map -F text -o text.5 example.nil badmap > /dev/null +[ $? = 1 ] || ret=1 +[ $ret -eq 0 ] || echo "I:failed" +status=`expr $status + $ret` # stomp on the file data so it hashes differently. # these are small and subtle changes, so that the resulting file # would appear to be a legitimate map file and would not trigger an @@ -245,7 +255,6 @@ status=`expr $status + $ret` # load because of a SHA1 hash mismatch. echo "I:checking corrupt map files fail to load (bad node header)" ret=0 -./named-compilezone -D -f text -F map -o map.5 example.nil baseline.txt > /dev/null cp map.5 badmap stomp badmap 2754 2 99 ./named-compilezone -D -f map -F text -o text.5 example.nil badmap > /dev/null diff --git a/lib/dns/rbt.c b/lib/dns/rbt.c index 0704d379df..af1c865cb8 100644 --- a/lib/dns/rbt.c +++ b/lib/dns/rbt.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -138,6 +139,9 @@ static isc_result_t write_header(FILE *file, dns_rbt_t *rbt, isc_uint64_t first_node_offset, isc_uint64_t crc); +static isc_boolean_t +match_header_version(file_header_t *header); + static isc_result_t serialize_node(FILE *file, dns_rbtnode_t *node, uintptr_t left, uintptr_t right, uintptr_t down, uintptr_t parent, @@ -483,6 +487,18 @@ dns_rbt_zero_header(FILE *file) { return (ISC_R_SUCCESS); } +static isc_once_t once = ISC_ONCE_INIT; + +static void +init_file_version(void) { + int n; + + memset(FILE_VERSION, 0, sizeof(FILE_VERSION)); + n = snprintf(FILE_VERSION, sizeof(FILE_VERSION), + "RBT Image %s %s", dns_major, dns_mapapi); + INSIST(n > 0 && (unsigned int)n < sizeof(FILE_VERSION)); +} + /* * Write out the real header, including NodeDump version information * and the offset of the first node. @@ -498,11 +514,7 @@ write_header(FILE *file, dns_rbt_t *rbt, isc_uint64_t first_node_offset, isc_result_t result; off_t location; - if (FILE_VERSION[0] == '\0') { - memset(FILE_VERSION, 0, sizeof(FILE_VERSION)); - snprintf(FILE_VERSION, sizeof(FILE_VERSION), - "RBT Image %s %s", dns_major, dns_mapapi); - } + RUNTIME_CHECK(isc_once_do(&once, init_file_version) == ISC_R_SUCCESS); memset(&header, 0, sizeof(file_header_t)); memmove(header.version1, FILE_VERSION, sizeof(header.version1)); @@ -534,6 +546,21 @@ write_header(FILE *file, dns_rbt_t *rbt, isc_uint64_t first_node_offset, return (result); } +static isc_boolean_t +match_header_version(file_header_t *header) { + RUNTIME_CHECK(isc_once_do(&once, init_file_version) == ISC_R_SUCCESS); + + if (memcmp(header->version1, FILE_VERSION, + sizeof(header->version1)) != 0 || + memcmp(header->version2, FILE_VERSION, + sizeof(header->version1)) != 0) + { + return (ISC_FALSE); + } + + return (ISC_TRUE); +} + static isc_result_t serialize_node(FILE *file, dns_rbtnode_t *node, uintptr_t left, uintptr_t right, uintptr_t down, uintptr_t parent, @@ -608,7 +635,7 @@ serialize_node(FILE *file, dns_rbtnode_t *node, uintptr_t left, #endif isc_crc64_update(crc, (const isc_uint8_t *) &temp_node, - sizeof(dns_rbtnode_t)); + sizeof(dns_rbtnode_t)); isc_crc64_update(crc, (const isc_uint8_t *) node_data, datasize); cleanup: @@ -880,6 +907,10 @@ dns_rbt_deserialize_tree(void *base_address, size_t filesize, rbt->mmap_location = base_address; header = (file_header_t *)((char *)base_address + header_offset); + if (!match_header_version(header)) { + result = ISC_R_INVALIDFILE; + goto cleanup; + } #ifdef DNS_RDATASET_FIXED if (header->rdataset_fixed != 1) { diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c index 7d54e77b1a..850f4b3131 100644 --- a/lib/dns/rbtdb.c +++ b/lib/dns/rbtdb.c @@ -900,6 +900,8 @@ static void overmem(dns_db_t *db, isc_boolean_t over); static void setnsec3parameters(dns_db_t *db, rbtdb_version_t *version); static void setownercase(rdatasetheader_t *header, const dns_name_t *name); +static isc_boolean_t match_header_version(rbtdb_file_header_t *header); + /* Pad to 32 bytes */ static char FILE_VERSION[32] = "\0"; @@ -7479,10 +7481,14 @@ deserialize32(void *arg, FILE *f, off_t offset) { #endif base = isc_file_mmap(NULL, filesize, protect, flags, fd, 0); - if (base == NULL || base == MAP_FAILED) + if (base == NULL || base == MAP_FAILED) { return (ISC_R_FAILURE); + } header = (rbtdb_file_header_t *)(base + offset); + if (!match_header_version(header)) { + return (ISC_R_FAILURE); + } if (header->tree != 0) { result = dns_rbt_deserialize_tree(base, filesize, @@ -7786,6 +7792,21 @@ rbtdb_write_header(FILE *rbtfile, off_t tree_location, off_t nsec_location, return (result); } +static isc_boolean_t +match_header_version(rbtdb_file_header_t *header) { + RUNTIME_CHECK(isc_once_do(&once, init_file_version) == ISC_R_SUCCESS); + + if (memcmp(header->version1, FILE_VERSION, + sizeof(header->version1)) != 0 || + memcmp(header->version2, FILE_VERSION, + sizeof(header->version1)) != 0) + { + return (ISC_FALSE); + } + + return (ISC_TRUE); +} + static isc_result_t serialize(dns_db_t *db, dns_dbversion_t *ver, FILE *rbtfile) { rbtdb_version_t *version = (rbtdb_version_t *) ver;