From 7011ecbaf12a07f912eaf1b3ed6d3a528cefc7ad Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Wed, 17 Mar 2021 09:01:30 +0200 Subject: Follow-up fixes to fd5cf245ea. These address https://puszcza.gnu.org.ua/bugs/?503 * src/gdbmdefs.h (gdbm_avail_block_valid_p): Remove. * src/gdbmopen.c (gdbm_avail_block_validate): Use inline conditional instead of gdbm_avail_block_valid_p. (gdbm_fd_open): Revert to reading master avail_block in two passes (as was before fd5cf245ea). (validate_header): Add back master avail block consistency check. * src/gdbmtool.c (_gdbm_avail_list_size): Use _gdbm_avail_block_read. * src/recover.c (_gdbm_finish_transfer): Reset dbf->file_size. --- src/gdbmdefs.h | 7 ------- src/gdbmopen.c | 34 +++++++++++++++++++++------------- src/gdbmtool.c | 20 +++++++++----------- src/recover.c | 2 ++ 4 files changed, 32 insertions(+), 31 deletions(-) diff --git a/src/gdbmdefs.h b/src/gdbmdefs.h index 4259815..0929e37 100644 --- a/src/gdbmdefs.h +++ b/src/gdbmdefs.h @@ -66,13 +66,6 @@ typedef struct 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 > 1 && av->count >= 0 && av->count <= av->size); -} - /* Return true if both AV and the size of AV->av_table are valid. See comment to this function in gdbmopen.c */ extern int gdbm_avail_table_valid_p (GDBM_FILE dbf, avail_elem *av, int count); diff --git a/src/gdbmopen.c b/src/gdbmopen.c index 3ae93a1..21f8e95 100644 --- a/src/gdbmopen.c +++ b/src/gdbmopen.c @@ -108,8 +108,9 @@ gdbm_avail_table_valid_p (GDBM_FILE dbf, avail_elem *av, int count) int gdbm_avail_block_validate (GDBM_FILE dbf, avail_block *avblk, size_t size) { - if (!(((size - sizeof (avail_block)) / sizeof (avail_elem) + 1) >= avblk->count - && gdbm_avail_block_valid_p (avblk) + if (!(size > sizeof (avail_block) + && (avblk->size > 1 && avblk->count >= 0 && avblk->count <= avblk->size) + && ((size - sizeof (avail_block)) / sizeof (avail_elem) + 1) >= avblk->count && gdbm_avail_table_valid_p (dbf, avblk->av_table, avblk->count))) { GDBM_SET_ERRNO (dbf, GDBM_BAD_AVAIL, TRUE); @@ -198,17 +199,15 @@ validate_header (gdbm_file_header const *hdr, struct stat const *st) if (hdr->bucket_elems != bucket_element_count (hdr->bucket_size)) return GDBM_BAD_HEADER; + if (((hdr->block_size - sizeof (gdbm_file_header)) / sizeof(avail_elem) + 1) + != hdr->avail.size) + return GDBM_BAD_HEADER; + return result; } -/* - * GDBM file header is read in two chunks: first, all fields up to avail, - * then the avail block. PARTIAL_HEADER_SIZE is the size of the first - * chunk, and HEADER_AVAIL_SIZE(dbf) gives the size of the second one. - */ -#define PARTIAL_HEADER_SIZE (offsetof (gdbm_file_header, avail)) #define HEADER_AVAIL_SIZE(dbf) \ - ((dbf)->header->block_size - PARTIAL_HEADER_SIZE) + ((dbf)->header->block_size - offsetof (gdbm_file_header, avail)) int _gdbm_validate_header (GDBM_FILE dbf) @@ -540,7 +539,7 @@ gdbm_fd_open (int fd, const char *file_name, int block_size, int rc; /* Read the partial file header. */ - if (_gdbm_full_read (dbf, &partial_header, PARTIAL_HEADER_SIZE)) + if (_gdbm_full_read (dbf, &partial_header, sizeof (partial_header))) { GDBM_DEBUG (GDBM_DEBUG_ERR|GDBM_DEBUG_OPEN, "%s: error reading partial header: %s", @@ -577,9 +576,9 @@ gdbm_fd_open (int fd, const char *file_name, int block_size, return NULL; } - memcpy (dbf->header, &partial_header, PARTIAL_HEADER_SIZE); - if (_gdbm_avail_block_read (dbf, &dbf->header->avail, - HEADER_AVAIL_SIZE (dbf))) + memcpy (dbf->header, &partial_header, sizeof (partial_header)); + if (_gdbm_full_read (dbf, &dbf->header->avail.av_table[1], + dbf->header->block_size - sizeof (gdbm_file_header))) { if (!(flags & GDBM_CLOERROR)) dbf->desc = -1; @@ -587,6 +586,15 @@ gdbm_fd_open (int fd, const char *file_name, int block_size, return NULL; } + if (gdbm_avail_block_validate (dbf, &dbf->header->avail, + HEADER_AVAIL_SIZE (dbf))) + { + if (!(flags & GDBM_CLOERROR)) + dbf->desc = -1; + SAVE_ERRNO (gdbm_close (dbf)); + return NULL; + } + /* Allocate space for the hash table directory. */ dbf->dir = malloc (dbf->header->dir_size); if (dbf->dir == NULL) diff --git a/src/gdbmtool.c b/src/gdbmtool.c index 1c473c9..e0030e1 100644 --- a/src/gdbmtool.c +++ b/src/gdbmtool.c @@ -240,19 +240,17 @@ _gdbm_avail_list_size (GDBM_FILE dbf, size_t min_size) terror ("lseek: %s", strerror (errno)); break; } - - if (_gdbm_full_read (dbf, av_stk, size)) + + if (_gdbm_avail_block_read (dbf, av_stk, size)) { terror ("read: %s", gdbm_db_strerror (dbf)); break; } - if (gdbm_avail_block_valid_p (av_stk)) - { - lines += av_stk->count; - if (lines > min_size) - break; - } + lines += av_stk->count; + if (lines > min_size) + break; + temp = av_stk->next_block; } free (av_stk); @@ -276,7 +274,7 @@ void _gdbm_print_avail_list (FILE *fp, GDBM_FILE dbf) { int temp; - int size; + size_t size; avail_block *av_stk; /* Print the the header avail block. */ @@ -286,8 +284,8 @@ _gdbm_print_avail_list (FILE *fp, GDBM_FILE dbf) /* Initialize the variables for a pass throught the avail stack. */ temp = dbf->header->avail.next_block; - size = ((dbf->header->avail.size - 1) * sizeof (avail_elem)) - + sizeof (avail_block); + size = (((size_t)dbf->header->avail.size - 1) * sizeof (avail_elem)) + + sizeof (avail_block); av_stk = emalloc (size); /* Print the stack. */ diff --git a/src/recover.c b/src/recover.c index 9623fae..45de923 100644 --- a/src/recover.c +++ b/src/recover.c @@ -168,6 +168,8 @@ _gdbm_finish_transfer (GDBM_FILE dbf, GDBM_FILE new_dbf, dbf->directory_changed = new_dbf->directory_changed; dbf->bucket_changed = new_dbf->bucket_changed; dbf->second_changed = new_dbf->second_changed; + + dbf->file_size = -1; free (new_dbf->name); free (new_dbf); -- cgit v1.2.1