]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
[master] check file and tree headers when loading map files
authorEvan Hunt <each@isc.org>
Thu, 26 Oct 2017 04:37:00 +0000 (21:37 -0700)
committerEvan Hunt <each@isc.org>
Thu, 26 Oct 2017 04:37:00 +0000 (21:37 -0700)
4792. [bug] Fix map file header correctness check. [RT #38418]

CHANGES
bin/tests/system/masterformat/tests.sh
lib/dns/rbt.c
lib/dns/rbtdb.c

diff --git a/CHANGES b/CHANGES
index ea32648a76a436e24dc048b60f056f16376622f1..db1c491604b23d38899e05629737f3d2ab40eeca 100644 (file)
--- 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]
 
index 8bbbee0ecc8c438c41908b8cca478f247fac1a3b..8a95a7009b25d176248d8fbc87d1208daf66fed7 100755 (executable)
@@ -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
index 0704d379df418757e3a003ca022082b2f2b603de..af1c865cb8e205f6b66d696f1007e56e84264d93 100644 (file)
@@ -21,6 +21,7 @@
 #include <isc/file.h>
 #include <isc/hex.h>
 #include <isc/mem.h>
+#include <isc/once.h>
 #include <isc/platform.h>
 #include <isc/print.h>
 #include <isc/refcount.h>
@@ -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) {
index 7d54e77b1a0541b02df3ce54fa9a8810685814dc..850f4b3131e2481e181ed91d7104a463519ebd20 100644 (file)
@@ -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;