aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2018-05-16 22:02:53 +0300
committerSergey Poznyakoff <gray@gnu.org>2018-05-16 22:02:53 +0300
commit48733c9aca3d12fc07a791d24fb3e6890de9c01f (patch)
tree95d483c9738e83ea30cedd8b75ea93cdd7876bff /src
parentbbfd14e24d0c288bff351a9ed4cdac217e6cbe4d (diff)
downloadgdbm-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.c14
-rw-r--r--src/gdbm.h.in6
-rw-r--r--src/gdbmerrno.c4
-rw-r--r--src/gdbmopen.c76
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));

Return to:

Send suggestions and report system problems to the System administrator.