diff options
author | Stuart Henderson <sthen@cvs.openbsd.org> | 2014-03-14 16:01:57 +0000 |
---|---|---|
committer | Stuart Henderson <sthen@cvs.openbsd.org> | 2014-03-14 16:01:57 +0000 |
commit | 484d8522231c1b7bacc638b0b84d502e4231886a (patch) | |
tree | 9ef06b5e7ac887a9a14c095744236d7082b2ed61 | |
parent | 6ad247cd626ea34f6cb942bf33053b788613b984 (diff) |
Update to NSD 4.0.3, main change is to improve/fix nsd.db database
corruption checks and avoid some causes of corruption. More details at
http://article.gmane.org/gmane.network.dns.nsd.general/1687
-rw-r--r-- | usr.sbin/nsd/dbaccess.c | 1 | ||||
-rw-r--r-- | usr.sbin/nsd/nsd-control.8.in | 2 | ||||
-rw-r--r-- | usr.sbin/nsd/udb.c | 32 | ||||
-rw-r--r-- | usr.sbin/nsd/udb.h | 5 |
4 files changed, 34 insertions, 6 deletions
diff --git a/usr.sbin/nsd/dbaccess.c b/usr.sbin/nsd/dbaccess.c index 70366b058e9..4ecbf7a990b 100644 --- a/usr.sbin/nsd/dbaccess.c +++ b/usr.sbin/nsd/dbaccess.c @@ -42,6 +42,7 @@ namedb_close(struct namedb* db) if(db->udb) { udb_base_close(db->udb); udb_base_free(db->udb); + db->udb = NULL; } zonec_desetup_parser(); region_destroy(db->region); diff --git a/usr.sbin/nsd/nsd-control.8.in b/usr.sbin/nsd/nsd-control.8.in index 6e176e1665c..b8a8701bea5 100644 --- a/usr.sbin/nsd/nsd-control.8.in +++ b/usr.sbin/nsd/nsd-control.8.in @@ -1,4 +1,4 @@ -.TH "nsd\-control" "8" "Mar 12, 2014" "NLnet Labs" "nsd 4.0.2" +.TH "nsd\-control" "8" "Mar 14, 2014" "NLnet Labs" "nsd 4.0.3" .\" Copyright (c) 2011, NLnet Labs. All rights reserved. .\" See LICENSE for the license. .SH "NAME" diff --git a/usr.sbin/nsd/udb.c b/usr.sbin/nsd/udb.c index 02c81973942..c3b1de0347c 100644 --- a/usr.sbin/nsd/udb.c +++ b/usr.sbin/nsd/udb.c @@ -70,7 +70,7 @@ udb_base* udb_base_create_fd(const char* fname, int fd, udb_walk_relptr_func walkfunc, void* arg) { - uint64_t m; + uint64_t m, fsz; udb_glob_d g; ssize_t r; udb_base* udb = (udb_base*)xalloc_zero(sizeof(*udb)); @@ -136,7 +136,7 @@ udb_base_create_fd(const char* fname, int fd, udb_walk_relptr_func walkfunc, (int)g.hsize); goto fail; } - if(g.clean_close != 0) { + if(g.clean_close != 1) { log_msg(LOG_WARNING, "%s: not cleanly closed %d", fname, (int)g.clean_close); goto fail; @@ -146,13 +146,27 @@ udb_base_create_fd(const char* fname, int fd, udb_walk_relptr_func walkfunc, (int)g.dirty_alloc); goto fail; } - /* TODO check if too large (>4g on 32bit); mmap-usage would fail */ - + + /* check file size correctly written, for 4.0.2 nsd.db failure */ + fsz = (uint64_t)lseek(fd, (off_t)0, SEEK_END); + (void)lseek(fd, (off_t)0, SEEK_SET); + if(g.fsize != fsz) { + log_msg(LOG_WARNING, "%s: file size %llu but mmap header " + "has size %llu", fname, (unsigned long long)fsz, + (unsigned long long)g.fsize); + goto fail; + } + /* mmap it */ if(g.fsize < UDB_HEADER_SIZE || g.fsize < g.hsize) { log_msg(LOG_ERR, "%s: file too short", fname); goto fail; } + if(g.fsize > (uint64_t)400*1024*1024*1024*1024) /* 400 Tb */ { + log_msg(LOG_WARNING, "%s: file size too large %llu", + fname, (unsigned long long)g.fsize); + goto fail; + } udb->base_size = (size_t)g.fsize; /* note the size_t casts must be there for portability, on some * systems the layout of memory is otherwise broken. */ @@ -189,6 +203,7 @@ udb_base_create_fd(const char* fname, int fd, udb_walk_relptr_func walkfunc, udb_alloc_compact(udb, udb->alloc); udb_base_sync(udb, 1); } + udb->glob_data->clean_close = 0; return udb; } @@ -245,6 +260,7 @@ udb_base* udb_base_create_new(const char* fname, udb_walk_relptr_func walkfunc, m = UDB_MAGIC; udb_glob_init_new(&g); udb_alloc_init_new(&a); + g.clean_close = 1; /* write new data to file (closes fd on error) */ if(!write_fdata(fname, fd, &m, sizeof(m))) @@ -263,6 +279,13 @@ udb_base* udb_base_create_new(const char* fname, udb_walk_relptr_func walkfunc, close(fd); return NULL; } + /* truncate to the right size */ + if(ftruncate(fd, (off_t)g.fsize) < 0) { + log_msg(LOG_ERR, "%s: ftruncate(%d): %s", fname, + (int)g.fsize, strerror(errno)); + close(fd); + return NULL; + } return udb_base_create_fd(fname, fd, walkfunc, arg); } @@ -292,6 +315,7 @@ void udb_base_close(udb_base* udb) udb_base_shrink(udb, nsize); } if(udb->fd != -1) { + udb->glob_data->clean_close = 1; close(udb->fd); udb->fd = -1; } diff --git a/usr.sbin/nsd/udb.h b/usr.sbin/nsd/udb.h index de7985275c2..691b78c817f 100644 --- a/usr.sbin/nsd/udb.h +++ b/usr.sbin/nsd/udb.h @@ -40,10 +40,13 @@ typedef struct udb_base udb_base; typedef struct udb_alloc udb_alloc; +/** these checks are very slow, disabled by default */ +#if 0 /** perform extra checks (when --enable-checking is used) */ #ifndef NDEBUG #define UDB_CHECK 1 #endif +#endif /** pointers are stored like this */ typedef uint64_t udb_void; @@ -141,7 +144,7 @@ struct udb_glob_d { uint64_t hsize; /** version number of this file */ uint8_t version; - /** was the file not cleanly closed, 0 is ok */ + /** was the file cleanly closed, 0 is not clean, 1 is clean */ uint8_t clean_close; /** an allocation operation was in progress, file needs to be salvaged * type enum udb_dirty_alloc */ |