aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2018-05-24 08:09:48 +0300
committerSergey Poznyakoff <gray@gnu.org>2018-05-24 08:09:48 +0300
commit0665bcf0c9cdf756f9d5edc6a638c56602c42065 (patch)
tree590d81a45721edca6b3530e7681d8f0db32af94b
parentce702a1ca5ed9240cd0a70583c4234c34ce81b73 (diff)
downloadgdbm-0665bcf0c9cdf756f9d5edc6a638c56602c42065.tar.gz
gdbm-0665bcf0c9cdf756f9d5edc6a638c56602c42065.tar.bz2
error checking: check for avail_block consistency before using it
* src/gdbmdefs.h (gdbm_avail_block_valid_p): New function. * src/gdbm.h.in (GDBM_BAD_AVAIL): New error code. * src/gdbmerrno.c: Support new error code. * src/falloc.c (pop_avail_block): Validate the avail_block * src/gdbmopen.c (validate_header): Validate the avail_block. * src/gdbmtool.c (_gdbm_avail_list_size) (_gdbm_print_avail_list): Validate the avail_block.
-rw-r--r--src/falloc.c9
-rw-r--r--src/gdbm.h.in3
-rw-r--r--src/gdbmdefs.h7
-rw-r--r--src/gdbmerrno.c3
-rw-r--r--src/gdbmopen.c4
-rw-r--r--src/gdbmtool.c31
6 files changed, 43 insertions, 14 deletions
diff --git a/src/falloc.c b/src/falloc.c
index 3f437a6..33a238a 100644
--- a/src/falloc.c
+++ b/src/falloc.c
@@ -149,13 +149,13 @@ _gdbm_free (GDBM_FILE dbf, off_t file_adr, int num_bytes)
/* The following are all utility routines needed by the previous two. */
/* Gets the avail block at the top of the stack and loads it into the
- active avail block. It does a "free" for itself! This can (and is)
+ active avail block. It does a "free" for itself! This can be (and is)
now called even when the avail block is not empty, so we must be
smart about things. */
static int
pop_avail_block (GDBM_FILE dbf)
{
@@ -203,12 +203,19 @@ pop_avail_block (GDBM_FILE dbf)
if (rc)
{
_gdbm_fatal (dbf, gdbm_strerror (rc));
return -1;
}
+ if (!gdbm_avail_block_valid_p (new_blk))
+ {
+ gdbm_set_errno (dbf, GDBM_BAD_AVAIL, TRUE);
+ _gdbm_fatal (dbf, gdbm_db_strerror (dbf));
+ return -1;
+ }
+
/* Add the elements from the new block to the header. */
index = 0;
while (index < new_blk->count)
{
while (index < new_blk->count
&& dbf->header->avail.count < dbf->header->avail.size)
diff --git a/src/gdbm.h.in b/src/gdbm.h.in
index 3d19de7..61d5707 100644
--- a/src/gdbm.h.in
+++ b/src/gdbm.h.in
@@ -218,15 +218,16 @@ extern int gdbm_copy_meta (GDBM_FILE dst, GDBM_FILE src);
# define GDBM_ERR_FILE_MODE 28
# define GDBM_NEED_RECOVERY 29
# define GDBM_BACKUP_FAILED 30
# define GDBM_DIR_OVERFLOW 31
# define GDBM_BAD_BUCKET 32
# define GDBM_BAD_HEADER 33
+# define GDBM_BAD_AVAIL 34
# define _GDBM_MIN_ERRNO 0
-# define _GDBM_MAX_ERRNO GDBM_BAD_HEADER
+# define _GDBM_MAX_ERRNO GDBM_BAD_AVAIL
/* This one was never used and will be removed in the future */
# define GDBM_UNKNOWN_UPDATE GDBM_UNKNOWN_ERROR
typedef int gdbm_error;
extern int *gdbm_errno_location (void);
diff --git a/src/gdbmdefs.h b/src/gdbmdefs.h
index bd104e2..5305b0d 100644
--- a/src/gdbmdefs.h
+++ b/src/gdbmdefs.h
@@ -48,12 +48,19 @@ typedef struct
int size; /* The number of avail elements in the table.*/
int count; /* The number of entries in the table. */
off_t next_block; /* The file address of the next avail block. */
avail_elem av_table[1]; /* The table. Make it look like an array. */
} avail_block;
+/* Return true if avail_block is valid */
+static int inline
+gdbm_avail_block_valid_p (avail_block const *av)
+{
+ return (av->size >= 0 && av->count >= 0 && av->count <= av->size);
+}
+
/* The dbm file header keeps track of the current location of the hash
directory and the free space in the file. */
typedef struct
{
int header_magic; /* Version of file. */
diff --git a/src/gdbmerrno.c b/src/gdbmerrno.c
index 7124b3a..896bf70 100644
--- a/src/gdbmerrno.c
+++ b/src/gdbmerrno.c
@@ -130,13 +130,14 @@ const char * const gdbm_errlist[_GDBM_MAX_ERRNO+1] = {
[GDBM_ERR_FILE_OWNER] = N_("Failed to restore file owner"),
[GDBM_ERR_FILE_MODE] = N_("Failed to restore file mode"),
[GDBM_NEED_RECOVERY] = N_("Database needs recovery"),
[GDBM_BACKUP_FAILED] = N_("Failed to create backup copy"),
[GDBM_DIR_OVERFLOW] = N_("Bucket directory overflow"),
[GDBM_BAD_BUCKET] = N_("Malformed bucket header"),
- [GDBM_BAD_HEADER] = N_("Malformed database file header")
+ [GDBM_BAD_HEADER] = N_("Malformed database file header"),
+ [GDBM_BAD_AVAIL] = N_("Malforemd avail_block")
};
const char *
gdbm_strerror (gdbm_error error)
{
if (error < _GDBM_MIN_ERRNO || error > _GDBM_MAX_ERRNO)
diff --git a/src/gdbmopen.c b/src/gdbmopen.c
index 5d59f65..b84ad63 100644
--- a/src/gdbmopen.c
+++ b/src/gdbmopen.c
@@ -106,12 +106,16 @@ validate_header (gdbm_file_header const *hdr, struct stat const *st)
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;
+ /* Validate the avail block */
+ if (!gdbm_avail_block_valid_p (&hdr->avail))
+ return GDBM_BAD_HEADER;
+
return 0;
}
GDBM_FILE
gdbm_fd_open (int fd, const char *file_name, int block_size,
int flags, void (*fatal_func) (const char *))
diff --git a/src/gdbmtool.c b/src/gdbmtool.c
index c522ad0..18d0e10 100644
--- a/src/gdbmtool.c
+++ b/src/gdbmtool.c
@@ -222,39 +222,49 @@ _gdbm_avail_list_size (GDBM_FILE dbf, size_t min_size)
else
terror ("read: %s (%s)",
gdbm_strerror (rc), strerror (errno));
break;
}
+ if (gdbm_avail_block_valid_p (av_stk))
+ {
lines += av_stk->count;
if (lines > min_size)
break;
+ }
temp = av_stk->next_block;
}
free (av_stk);
return lines;
}
+static void
+av_table_display (avail_elem *av_table, int count, FILE *fp)
+{
+ int i;
+
+ for (i = 0; i < count; i++)
+ {
+ fprintf (fp, " %15d %10lu \n",
+ av_table[i].av_size, (unsigned long) av_table[i].av_adr);
+ }
+}
+
void
_gdbm_print_avail_list (FILE *fp, GDBM_FILE dbf)
{
int temp;
int size;
avail_block *av_stk;
int rc;
/* Print the the header avail block. */
fprintf (fp, _("\nheader block\nsize = %d\ncount = %d\n"),
dbf->header->avail.size, dbf->header->avail.count);
- for (temp = 0; temp < dbf->header->avail.count; temp++)
- {
- fprintf (fp, " %15d %10lu \n",
- dbf->header->avail.av_table[temp].av_size,
- (unsigned long) dbf->header->avail.av_table[temp].av_adr);
- }
+ av_table_display (dbf->header->avail.av_table, dbf->header->avail.count, fp);
/* Initialize the variables for a pass throught the avail stack. */
temp = dbf->header->avail.next_block;
size = (((dbf->header->avail.size * sizeof (avail_elem)) >> 1)
+ sizeof (avail_block));
av_stk = emalloc (size);
@@ -277,17 +287,16 @@ _gdbm_print_avail_list (FILE *fp, GDBM_FILE dbf)
break;
}
/* Print the block! */
fprintf (fp, _("\nblock = %d\nsize = %d\ncount = %d\n"), temp,
av_stk->size, av_stk->count);
- for (temp = 0; temp < av_stk->count; temp++)
- {
- fprintf (fp, " %15d %10lu \n", av_stk->av_table[temp].av_size,
- (unsigned long) av_stk->av_table[temp].av_adr);
- }
+ if (gdbm_avail_block_valid_p (av_stk))
+ av_table_display (av_stk->av_table, av_stk->count, fp);
+ else
+ terror (_("invalid avail_block"));
temp = av_stk->next_block;
}
free (av_stk);
}
void

Return to:

Send suggestions and report system problems to the System administrator.