diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2018-05-16 22:02:53 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2018-05-16 22:02:53 +0300 |
commit | 48733c9aca3d12fc07a791d24fb3e6890de9c01f (patch) | |
tree | 95d483c9738e83ea30cedd8b75ea93cdd7876bff /src | |
parent | bbfd14e24d0c288bff351a9ed4cdac217e6cbe4d (diff) | |
download | gdbm-48733c9aca3d12fc07a791d24fb3e6890de9c01f.tar.gz gdbm-48733c9aca3d12fc07a791d24fb3e6890de9c01f.tar.bz2 |
Improve database file safety checks.
* src/bucket.c (_gdbm_get_bucket): Verify bucket consistency.
* src/gdbm.h.in (GDBM_BAD_BUCKET, GDBM_WRONG_ARCH): New error
codes.
* src/gdbmerrno.c (gdbm_errlist): New error codes.
* src/gdbmopen.c (gdbm_fd_open): Improve header consistency checks.
Diffstat (limited to 'src')
-rw-r--r-- | src/bucket.c | 14 | ||||
-rw-r--r-- | src/gdbm.h.in | 6 | ||||
-rw-r--r-- | src/gdbmerrno.c | 4 | ||||
-rw-r--r-- | src/gdbmopen.c | 76 |
4 files changed, 75 insertions, 25 deletions
diff --git a/src/bucket.c b/src/bucket.c index 6d12589..6def504 100644 --- a/src/bucket.c +++ b/src/bucket.c @@ -74,2 +74,4 @@ _gdbm_get_bucket (GDBM_FILE dbf, int dir_index) { + size_t max_bucket_elts; + /* Look in the cache. */ @@ -119,2 +121,14 @@ _gdbm_get_bucket (GDBM_FILE dbf, int dir_index) } + /* Validate the bucket */ + max_bucket_elts = + (dbf->header->bucket_size - sizeof(hash_bucket)) + / sizeof(bucket_element) + 1; + if (!(dbf->bucket->count >= 0 + && dbf->bucket->av_count >= 0 + && dbf->bucket->count <= max_bucket_elts + && dbf->bucket->av_count <= max_bucket_elts)) + { + GDBM_SET_ERRNO (dbf, GDBM_BAD_BUCKET, TRUE); + return -1; + } } diff --git a/src/gdbm.h.in b/src/gdbm.h.in index 8dd61b0..d6a8306 100644 --- a/src/gdbm.h.in +++ b/src/gdbm.h.in @@ -221,5 +221,7 @@ extern int gdbm_copy_meta (GDBM_FILE dst, GDBM_FILE src); # define GDBM_DIR_OVERFLOW 31 - +# define GDBM_BAD_BUCKET 32 +# define GDBM_WRONG_ARCH 33 + # define _GDBM_MIN_ERRNO 0 -# define _GDBM_MAX_ERRNO GDBM_DIR_OVERFLOW +# define _GDBM_MAX_ERRNO GDBM_WRONG_ARCH diff --git a/src/gdbmerrno.c b/src/gdbmerrno.c index 1962d1a..0c8c8e5 100644 --- a/src/gdbmerrno.c +++ b/src/gdbmerrno.c @@ -133,3 +133,5 @@ const char * const gdbm_errlist[_GDBM_MAX_ERRNO+1] = { [GDBM_BACKUP_FAILED] = N_("Failed to create backup copy"), - [GDBM_DIR_OVERFLOW] = N_("Bucket directory overflow") + [GDBM_DIR_OVERFLOW] = N_("Bucket directory overflow"), + [GDBM_BAD_BUCKET] = N_("Malformed bucket header"), + [GDBM_WRONG_OFF_T] = N_("File header assumes wrong off_t size") }; diff --git a/src/gdbmopen.c b/src/gdbmopen.c index db56440..669f8fb 100644 --- a/src/gdbmopen.c +++ b/src/gdbmopen.c @@ -51,2 +51,48 @@ compute_directory_size (GDBM_FILE dbf, blksize_t block_size, +static int +validate_header (gdbm_file_header const *hdr, struct stat const *st) +{ + /* Is the magic number good? */ + if (hdr->header_magic != GDBM_MAGIC) + { + switch (hdr->header_magic) + { + case GDBM_OMAGIC: + /* OK */ + break; + + case GDBM_OMAGIC_SWAP: + case GDBM_MAGIC32_SWAP: + case GDBM_MAGIC64_SWAP: + return GDBM_BYTE_SWAPPED; + + case GDBM_MAGIC32: + case GDBM_MAGIC64: + return GDBM_WRONG_OFF_T; + + default: + return GDBM_BAD_MAGIC_NUMBER; + } + } + + if (!(hdr->block_size > sizeof (gdbm_file_header) + && hdr->block_size - sizeof (gdbm_file_header) >= + sizeof(hdr->avail.av_table[0]))) + { + return GDBM_BLOCK_SIZE_ERROR; + } + + /* Make sure dir and dir + dir_size fall within the file boundary */ + if (!(hdr->dir > 0 + && hdr->dir < st->st_size + && hdr->dir_size > 0 + && hdr->dir + hdr->dir_size < st->st_size)) + return GDBM_BAD_FILE_OFFSET; + + if (!(hdr->bucket_size > sizeof(hash_bucket))) + return GDBM_BAD_MAGIC_NUMBER; + + return 0; +} + GDBM_FILE @@ -325,3 +371,4 @@ gdbm_fd_open (int fd, const char *file_name, int block_size, gdbm_file_header partial_header; /* For the first part of it. */ - + int rc; + /* Read the partial file header. */ @@ -338,5 +385,5 @@ gdbm_fd_open (int fd, const char *file_name, int block_size, - /* Is the magic number good? */ - if (partial_header.header_magic != GDBM_MAGIC - && partial_header.header_magic != GDBM_OMAGIC) + /* Is the header valid? */ + rc = validate_header (&partial_header, &file_stat); + if (rc != GDBM_NO_ERROR) { @@ -345,22 +392,6 @@ gdbm_fd_open (int fd, const char *file_name, int block_size, gdbm_close (dbf); - switch (partial_header.header_magic) - { - case GDBM_OMAGIC_SWAP: - case GDBM_MAGIC32_SWAP: - case GDBM_MAGIC64_SWAP: - GDBM_SET_ERRNO2 (NULL, GDBM_BYTE_SWAPPED, FALSE, - GDBM_DEBUG_OPEN); - break; - case GDBM_MAGIC32: - case GDBM_MAGIC64: - GDBM_SET_ERRNO2 (NULL, GDBM_BAD_FILE_OFFSET, FALSE, - GDBM_DEBUG_OPEN); - break; - default: - GDBM_SET_ERRNO2 (NULL, GDBM_BAD_MAGIC_NUMBER, FALSE, - GDBM_DEBUG_OPEN); - } + GDBM_SET_ERRNO2 (NULL, rc, FALSE, GDBM_DEBUG_OPEN); return NULL; } - + /* It is a good database, read the entire header. */ @@ -375,2 +406,3 @@ gdbm_fd_open (int fd, const char *file_name, int block_size, } + memcpy (dbf->header, &partial_header, sizeof (gdbm_file_header)); |