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.c13
-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.c37
6 files changed, 48 insertions, 19 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)
149 149
150 150
151/* The following are all utility routines needed by the previous two. */ 151/* The following are all utility routines needed by the previous two. */
152 152
153 153
154/* Gets the avail block at the top of the stack and loads it into the 154/* Gets the avail block at the top of the stack and loads it into the
155 active avail block. It does a "free" for itself! This can (and is) 155 active avail block. It does a "free" for itself! This can be (and is)
156 now called even when the avail block is not empty, so we must be 156 now called even when the avail block is not empty, so we must be
157 smart about things. */ 157 smart about things. */
158 158
159static int 159static int
160pop_avail_block (GDBM_FILE dbf) 160pop_avail_block (GDBM_FILE dbf)
161{ 161{
@@ -203,18 +203,25 @@ pop_avail_block (GDBM_FILE dbf)
203 if (rc) 203 if (rc)
204 { 204 {
205 _gdbm_fatal (dbf, gdbm_strerror (rc)); 205 _gdbm_fatal (dbf, gdbm_strerror (rc));
206 return -1; 206 return -1;
207 } 207 }
208 208
209 if (!gdbm_avail_block_valid_p (new_blk))
210 {
211 gdbm_set_errno (dbf, GDBM_BAD_AVAIL, TRUE);
212 _gdbm_fatal (dbf, gdbm_db_strerror (dbf));
213 return -1;
214 }
215
209 /* Add the elements from the new block to the header. */ 216 /* Add the elements from the new block to the header. */
210 index = 0; 217 index = 0;
211 while (index < new_blk->count) 218 while (index < new_blk->count)
212 { 219 {
213 while(index < new_blk->count 220 while (index < new_blk->count
214 && dbf->header->avail.count < dbf->header->avail.size) 221 && dbf->header->avail.count < dbf->header->avail.size)
215 { 222 {
216 /* With luck, this will merge a lot of blocks! */ 223 /* With luck, this will merge a lot of blocks! */
217 _gdbm_put_av_elem (new_blk->av_table[index], 224 _gdbm_put_av_elem (new_blk->av_table[index],
218 dbf->header->avail.av_table, 225 dbf->header->avail.av_table,
219 &dbf->header->avail.count, TRUE); 226 &dbf->header->avail.count, TRUE);
220 index++; 227 index++;
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);
218# define GDBM_ERR_FILE_MODE 28 218# define GDBM_ERR_FILE_MODE 28
219# define GDBM_NEED_RECOVERY 29 219# define GDBM_NEED_RECOVERY 29
220# define GDBM_BACKUP_FAILED 30 220# define GDBM_BACKUP_FAILED 30
221# define GDBM_DIR_OVERFLOW 31 221# define GDBM_DIR_OVERFLOW 31
222# define GDBM_BAD_BUCKET 32 222# define GDBM_BAD_BUCKET 32
223# define GDBM_BAD_HEADER 33 223# define GDBM_BAD_HEADER 33
224# define GDBM_BAD_AVAIL 34
224 225
225# define _GDBM_MIN_ERRNO 0 226# define _GDBM_MIN_ERRNO 0
226# define _GDBM_MAX_ERRNO GDBM_BAD_HEADER 227# define _GDBM_MAX_ERRNO GDBM_BAD_AVAIL
227 228
228/* This one was never used and will be removed in the future */ 229/* This one was never used and will be removed in the future */
229# define GDBM_UNKNOWN_UPDATE GDBM_UNKNOWN_ERROR 230# define GDBM_UNKNOWN_UPDATE GDBM_UNKNOWN_ERROR
230 231
231typedef int gdbm_error; 232typedef int gdbm_error;
232extern int *gdbm_errno_location (void); 233extern 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
48 int size; /* The number of avail elements in the table.*/ 48 int size; /* The number of avail elements in the table.*/
49 int count; /* The number of entries in the table. */ 49 int count; /* The number of entries in the table. */
50 off_t next_block; /* The file address of the next avail block. */ 50 off_t next_block; /* The file address of the next avail block. */
51 avail_elem av_table[1]; /* The table. Make it look like an array. */ 51 avail_elem av_table[1]; /* The table. Make it look like an array. */
52} avail_block; 52} avail_block;
53 53
54/* Return true if avail_block is valid */
55static int inline
56gdbm_avail_block_valid_p (avail_block const *av)
57{
58 return (av->size >= 0 && av->count >= 0 && av->count <= av->size);
59}
60
54/* The dbm file header keeps track of the current location of the hash 61/* The dbm file header keeps track of the current location of the hash
55 directory and the free space in the file. */ 62 directory and the free space in the file. */
56 63
57typedef struct 64typedef struct
58{ 65{
59 int header_magic; /* Version of file. */ 66 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] = {
130 [GDBM_ERR_FILE_OWNER] = N_("Failed to restore file owner"), 130 [GDBM_ERR_FILE_OWNER] = N_("Failed to restore file owner"),
131 [GDBM_ERR_FILE_MODE] = N_("Failed to restore file mode"), 131 [GDBM_ERR_FILE_MODE] = N_("Failed to restore file mode"),
132 [GDBM_NEED_RECOVERY] = N_("Database needs recovery"), 132 [GDBM_NEED_RECOVERY] = N_("Database needs recovery"),
133 [GDBM_BACKUP_FAILED] = N_("Failed to create backup copy"), 133 [GDBM_BACKUP_FAILED] = N_("Failed to create backup copy"),
134 [GDBM_DIR_OVERFLOW] = N_("Bucket directory overflow"), 134 [GDBM_DIR_OVERFLOW] = N_("Bucket directory overflow"),
135 [GDBM_BAD_BUCKET] = N_("Malformed bucket header"), 135 [GDBM_BAD_BUCKET] = N_("Malformed bucket header"),
136 [GDBM_BAD_HEADER] = N_("Malformed database file header") 136 [GDBM_BAD_HEADER] = N_("Malformed database file header"),
137 [GDBM_BAD_AVAIL] = N_("Malforemd avail_block")
137}; 138};
138 139
139const char * 140const char *
140gdbm_strerror (gdbm_error error) 141gdbm_strerror (gdbm_error error)
141{ 142{
142 if (error < _GDBM_MIN_ERRNO || error > _GDBM_MAX_ERRNO) 143 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
@@ -105,12 +105,16 @@ validate_header (gdbm_file_header const *hdr, struct stat const *st)
105 105
106 if (!(hdr->bucket_size > 0 && hdr->bucket_size > sizeof(hash_bucket))) 106 if (!(hdr->bucket_size > 0 && hdr->bucket_size > sizeof(hash_bucket)))
107 return GDBM_BAD_HEADER; 107 return GDBM_BAD_HEADER;
108 108
109 if (hdr->bucket_elems != bucket_element_count (hdr)) 109 if (hdr->bucket_elems != bucket_element_count (hdr))
110 return GDBM_BAD_HEADER; 110 return GDBM_BAD_HEADER;
111
112 /* Validate the avail block */
113 if (!gdbm_avail_block_valid_p (&hdr->avail))
114 return GDBM_BAD_HEADER;
111 115
112 return 0; 116 return 0;
113} 117}
114 118
115GDBM_FILE 119GDBM_FILE
116gdbm_fd_open (int fd, const char *file_name, int block_size, 120gdbm_fd_open (int fd, const char *file_name, int block_size,
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)
222 else 222 else
223 terror ("read: %s (%s)", 223 terror ("read: %s (%s)",
224 gdbm_strerror (rc), strerror (errno)); 224 gdbm_strerror (rc), strerror (errno));
225 break; 225 break;
226 } 226 }
227 227
228 lines += av_stk->count; 228 if (gdbm_avail_block_valid_p (av_stk))
229 if (lines > min_size) 229 {
230 break; 230 lines += av_stk->count;
231 if (lines > min_size)
232 break;
233 }
231 temp = av_stk->next_block; 234 temp = av_stk->next_block;
232 } 235 }
233 free (av_stk); 236 free (av_stk);
234 237
235 return lines; 238 return lines;
236} 239}
237 240
241static void
242av_table_display (avail_elem *av_table, int count, FILE *fp)
243{
244 int i;
245
246 for (i = 0; i < count; i++)
247 {
248 fprintf (fp, " %15d %10lu \n",
249 av_table[i].av_size, (unsigned long) av_table[i].av_adr);
250 }
251}
252
238void 253void
239_gdbm_print_avail_list (FILE *fp, GDBM_FILE dbf) 254_gdbm_print_avail_list (FILE *fp, GDBM_FILE dbf)
240{ 255{
241 int temp; 256 int temp;
242 int size; 257 int size;
243 avail_block *av_stk; 258 avail_block *av_stk;
244 int rc; 259 int rc;
245 260
246 /* Print the the header avail block. */ 261 /* Print the the header avail block. */
247 fprintf (fp, _("\nheader block\nsize = %d\ncount = %d\n"), 262 fprintf (fp, _("\nheader block\nsize = %d\ncount = %d\n"),
248 dbf->header->avail.size, dbf->header->avail.count); 263 dbf->header->avail.size, dbf->header->avail.count);
249 for (temp = 0; temp < dbf->header->avail.count; temp++) 264 av_table_display (dbf->header->avail.av_table, dbf->header->avail.count, fp);
250 {
251 fprintf (fp, " %15d %10lu \n",
252 dbf->header->avail.av_table[temp].av_size,
253 (unsigned long) dbf->header->avail.av_table[temp].av_adr);
254 }
255 265
256 /* Initialize the variables for a pass throught the avail stack. */ 266 /* Initialize the variables for a pass throught the avail stack. */
257 temp = dbf->header->avail.next_block; 267 temp = dbf->header->avail.next_block;
258 size = (((dbf->header->avail.size * sizeof (avail_elem)) >> 1) 268 size = (((dbf->header->avail.size * sizeof (avail_elem)) >> 1)
259 + sizeof (avail_block));