summaryrefslogtreecommitdiffabout
path: root/src
authorSergey Poznyakoff <gray@gnu.org>2018-05-19 14:19:20 (GMT)
committer Sergey Poznyakoff <gray@gnu.org>2018-05-19 14:28:35 (GMT)
commit2ed5403c82833c8977171972b6779ec92bcc086f (patch) (side-by-side diff)
treed7c4b170b8ecc08e32e46653e07f45643c929669 /src
parentd228fddf791187b44839b8d8c40478f3577812a2 (diff)
downloadgdbm-2ed5403c82833c8977171972b6779ec92bcc086f.tar.gz
gdbm-2ed5403c82833c8977171972b6779ec92bcc086f.tar.bz2
Improve error checking
* src/bucket.c (_gdbm_get_bucket): Improve validation. * src/fullio.c (_gdbm_full_read,_gdbm_full_write): Don't overwrite an already set error. * src/gdbm.h.in (GDBM_WRONG_OFF_T): Merge with GDBM_BAD_FILE_OFFSET. (GDBM_BAD_HEADER): New error code. * src/gdbmdump.c (_gdbm_dump_ascii): Check for database error code. * src/gdbmerrno.c (gdbm_errlist): Add GDBM_BAD_HEADER * src/gdbmopen.c (validate_header: Imporve logic. (_gdbm_init_cache): Initialize bucket_cache * src/gdbmseq.c (gdbm_firstkey): Check return value from _gdbm_get_bucket. * src/mmap.c (_gdbm_mapped_remap): Bail out if current position is bigger than file size.
Diffstat (limited to 'src') (more/less context) (ignore whitespace changes)
-rw-r--r--src/bucket.c9
-rw-r--r--src/fullio.c6
-rw-r--r--src/gdbm.h.in6
-rw-r--r--src/gdbmdump.c3
-rw-r--r--src/gdbmerrno.c4
-rw-r--r--src/gdbmopen.c27
-rw-r--r--src/gdbmseq.c19
-rw-r--r--src/mmap.c14
8 files changed, 54 insertions, 34 deletions
diff --git a/src/bucket.c b/src/bucket.c
index 6def504..ce1915a 100644
--- a/src/bucket.c
+++ b/src/bucket.c
@@ -72,8 +72,6 @@ _gdbm_get_bucket (GDBM_FILE dbf, int dir_index)
/* Is that one is not already current, we must find it. */
if (dbf->cache_entry->ca_adr != bucket_adr)
{
- size_t max_bucket_elts;
-
/* Look in the cache. */
for (index = 0; index < dbf->cache_size; index++)
{
@@ -120,13 +118,10 @@ _gdbm_get_bucket (GDBM_FILE dbf, int dir_index)
return -1;
}
/* 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))
+ && dbf->bucket->count <= dbf->header->bucket_elems
+ && dbf->bucket->av_count <= dbf->header->bucket_elems))
{
GDBM_SET_ERRNO (dbf, GDBM_BAD_BUCKET, TRUE);
return -1;
diff --git a/src/fullio.c b/src/fullio.c
index edff89c..bdb51cb 100644
--- a/src/fullio.c
+++ b/src/fullio.c
@@ -32,7 +32,8 @@ _gdbm_full_read (GDBM_FILE dbf, void *buffer, size_t size)
{
if (errno == EINTR)
continue;
- GDBM_SET_ERRNO (dbf, GDBM_FILE_READ_ERROR, FALSE);
+ if (gdbm_last_errno (dbf) == GDBM_NO_ERROR)
+ GDBM_SET_ERRNO (dbf, GDBM_FILE_READ_ERROR, FALSE);
return -1;
}
if (rdbytes == 0)
@@ -59,7 +60,8 @@ _gdbm_full_write (GDBM_FILE dbf, void *buffer, size_t size)
{
if (errno == EINTR)
continue;
- GDBM_SET_ERRNO (dbf, GDBM_FILE_WRITE_ERROR, TRUE);
+ if (gdbm_last_errno (dbf) == GDBM_NO_ERROR)
+ GDBM_SET_ERRNO (dbf, GDBM_FILE_WRITE_ERROR, TRUE);
return -1;
}
if (wrbytes == 0)
diff --git a/src/gdbm.h.in b/src/gdbm.h.in
index 6e5fa96..3d19de7 100644
--- a/src/gdbm.h.in
+++ b/src/gdbm.h.in
@@ -220,10 +220,10 @@ extern int gdbm_copy_meta (GDBM_FILE dst, GDBM_FILE src);
# define GDBM_BACKUP_FAILED 30
# define GDBM_DIR_OVERFLOW 31
# define GDBM_BAD_BUCKET 32
-# define GDBM_WRONG_OFF_T 33
-
+# define GDBM_BAD_HEADER 33
+
# define _GDBM_MIN_ERRNO 0
-# define _GDBM_MAX_ERRNO GDBM_WRONG_OFF_T
+# define _GDBM_MAX_ERRNO GDBM_BAD_HEADER
/* This one was never used and will be removed in the future */
# define GDBM_UNKNOWN_UPDATE GDBM_UNKNOWN_ERROR
diff --git a/src/gdbmdump.c b/src/gdbmdump.c
index 42ed1d3..4b8b041 100644
--- a/src/gdbmdump.c
+++ b/src/gdbmdump.c
@@ -110,8 +110,9 @@ _gdbm_dump_ascii (GDBM_FILE dbf, FILE *fp)
count++;
}
- if (rc == 0)
+ if (rc == 0 && (rc = gdbm_last_errno (dbf)) == 0)
{
+
/* FIXME: Something like that won't hurt, although load does not
use it currently. */
fprintf (fp, "#:count=%lu\n", (unsigned long) count);
diff --git a/src/gdbmerrno.c b/src/gdbmerrno.c
index 0c8c8e5..7124b3a 100644
--- a/src/gdbmerrno.c
+++ b/src/gdbmerrno.c
@@ -122,7 +122,7 @@ const char * const gdbm_errlist[_GDBM_MAX_ERRNO+1] = {
[GDBM_OPT_ALREADY_SET] = N_("Option already set"),
[GDBM_OPT_ILLEGAL] = N_("Illegal option"),
[GDBM_BYTE_SWAPPED] = N_("Byte-swapped file"),
- [GDBM_BAD_FILE_OFFSET] = N_("Wrong file offset"),
+ [GDBM_BAD_FILE_OFFSET] = N_("File header assumes wrong off_t size"),
[GDBM_BAD_OPEN_FLAGS] = N_("Bad file flags"),
[GDBM_FILE_STAT_ERROR] = N_("Cannot stat file"),
[GDBM_FILE_EOF] = N_("Unexpected end of file"),
@@ -133,7 +133,7 @@ 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_BAD_BUCKET] = N_("Malformed bucket header"),
- [GDBM_WRONG_OFF_T] = N_("File header assumes wrong off_t size")
+ [GDBM_BAD_HEADER] = N_("Malformed database file header")
};
const char *
diff --git a/src/gdbmopen.c b/src/gdbmopen.c
index 669f8fb..9b214ad 100644
--- a/src/gdbmopen.c
+++ b/src/gdbmopen.c
@@ -49,6 +49,13 @@ compute_directory_size (GDBM_FILE dbf, blksize_t block_size,
*ret_dir_bits = dir_bits;
}
+static inline int
+bucket_element_count (gdbm_file_header const *hdr)
+{
+ return (hdr->block_size - sizeof (hash_bucket))
+ / sizeof (bucket_element) + 1;
+}
+
static int
validate_header (gdbm_file_header const *hdr, struct stat const *st)
{
@@ -68,14 +75,15 @@ validate_header (gdbm_file_header const *hdr, struct stat const *st)
case GDBM_MAGIC32:
case GDBM_MAGIC64:
- return GDBM_WRONG_OFF_T;
+ return GDBM_BAD_FILE_OFFSET;
default:
return GDBM_BAD_MAGIC_NUMBER;
}
}
- if (!(hdr->block_size > sizeof (gdbm_file_header)
+ if (!(hdr->block_size > 0
+ && hdr->block_size > sizeof (gdbm_file_header)
&& hdr->block_size - sizeof (gdbm_file_header) >=
sizeof(hdr->avail.av_table[0])))
{
@@ -87,11 +95,14 @@ validate_header (gdbm_file_header const *hdr, struct stat const *st)
&& hdr->dir < st->st_size
&& hdr->dir_size > 0
&& hdr->dir + hdr->dir_size < st->st_size))
- return GDBM_BAD_FILE_OFFSET;
+ return GDBM_BAD_HEADER;
- if (!(hdr->bucket_size > sizeof(hash_bucket)))
- return GDBM_BAD_MAGIC_NUMBER;
+ if (!(hdr->bucket_size > 0 && hdr->bucket_size > sizeof(hash_bucket)))
+ return GDBM_BAD_HEADER;
+ if (hdr->bucket_elems != bucket_element_count (hdr))
+ return GDBM_BAD_HEADER;
+
return 0;
}
@@ -291,9 +302,7 @@ gdbm_fd_open (int fd, const char *file_name, int block_size,
dbf->header->dir = dbf->header->block_size;
/* Create the first and only hash bucket. */
- dbf->header->bucket_elems =
- (dbf->header->block_size - sizeof (hash_bucket))
- / sizeof (bucket_element) + 1;
+ dbf->header->bucket_elems = bucket_element_count (dbf->header);
dbf->header->bucket_size = dbf->header->block_size;
dbf->bucket = calloc (1, dbf->header->bucket_size);
if (dbf->bucket == NULL)
@@ -557,7 +566,7 @@ _gdbm_init_cache (GDBM_FILE dbf, size_t size)
if (dbf->bucket_cache == NULL)
{
dbf->bucket_cache = GDBM_DEBUG_ALLOC ("_gdbm_init_cache:malloc-failure",
- malloc (sizeof(cache_elem) * size));
+ calloc (size, sizeof(cache_elem)));
if (dbf->bucket_cache == NULL)
{
GDBM_SET_ERRNO (dbf, GDBM_MALLOC_ERROR, TRUE);
diff --git a/src/gdbmseq.c b/src/gdbmseq.c
index 417bc75..e74d78d 100644
--- a/src/gdbmseq.c
+++ b/src/gdbmseq.c
@@ -111,15 +111,16 @@ gdbm_firstkey (GDBM_FILE dbf)
gdbm_set_errno (dbf, GDBM_NO_ERROR, FALSE);
/* Get the first bucket. */
- _gdbm_get_bucket (dbf, 0);
-
- /* Look for first entry. */
- get_next_key (dbf, -1, &return_val);
-
- if (return_val.dptr)
- GDBM_DEBUG_DATUM (GDBM_DEBUG_READ, return_val, "%s: found", dbf->name);
- else
- GDBM_DEBUG (GDBM_DEBUG_READ, "%s: key not found", dbf->name);
+ if (_gdbm_get_bucket (dbf, 0) == 0)
+ {
+ /* Look for first entry. */
+ get_next_key (dbf, -1, &return_val);
+
+ if (return_val.dptr)
+ GDBM_DEBUG_DATUM (GDBM_DEBUG_READ, return_val, "%s: found", dbf->name);
+ else
+ GDBM_DEBUG (GDBM_DEBUG_READ, "%s: key not found", dbf->name);
+ }
return return_val;
}
diff --git a/src/mmap.c b/src/mmap.c
index fd8a72b..9a7d400 100644
--- a/src/mmap.c
+++ b/src/mmap.c
@@ -233,7 +233,12 @@ _gdbm_mapped_remap (GDBM_FILE dbf, off_t size, int flag)
dbf->mapped_pos += dbf->mapped_off;
dbf->mapped_off = 0;
}
-
+ if (pos > file_size)
+ {
+ errno = EINVAL;
+ GDBM_SET_ERRNO (dbf, GDBM_FILE_SEEK_ERROR, TRUE);
+ return -1;
+ }
return _gdbm_internal_remap (dbf, size);
}
@@ -271,6 +276,10 @@ _gdbm_mapped_read (GDBM_FILE dbf, void *buffer, size_t len)
{
int rc;
+ if (dbf->need_recovery)
+ return -1;
+
+ /* Disable memory mapping and retry */
dbf->memory_mapping = FALSE;
if (lseek (dbf->desc, pos, SEEK_SET) != pos)
return total > 0 ? total : -1;
@@ -321,6 +330,9 @@ _gdbm_mapped_write (GDBM_FILE dbf, void *buffer, size_t len)
{
int rc;
+ if (dbf->need_recovery)
+ return -1;
+
dbf->memory_mapping = FALSE;
if (lseek (dbf->desc, pos, SEEK_SET) != pos)
return total > 0 ? total : -1;

Return to:

Send suggestions and report system problems to the System administrator.