diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2018-05-24 08:09:48 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2018-05-24 08:09:48 +0300 |
commit | 0665bcf0c9cdf756f9d5edc6a638c56602c42065 (patch) | |
tree | 590d81a45721edca6b3530e7681d8f0db32af94b | |
parent | ce702a1ca5ed9240cd0a70583c4234c34ce81b73 (diff) | |
download | gdbm-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.c | 13 | ||||
-rw-r--r-- | src/gdbm.h.in | 3 | ||||
-rw-r--r-- | src/gdbmdefs.h | 7 | ||||
-rw-r--r-- | src/gdbmerrno.c | 3 | ||||
-rw-r--r-- | src/gdbmopen.c | 4 | ||||
-rw-r--r-- | src/gdbmtool.c | 37 |
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 | ||
159 | static int | 159 | static int |
160 | pop_avail_block (GDBM_FILE dbf) | 160 | pop_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 | ||
231 | typedef int gdbm_error; | 232 | typedef int gdbm_error; |
232 | extern int *gdbm_errno_location (void); | 233 | 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 | |||
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 */ | ||
55 | static int inline | ||
56 | gdbm_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 | ||
57 | typedef struct | 64 | typedef 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 | ||
139 | const char * | 140 | const char * |
140 | gdbm_strerror (gdbm_error error) | 141 | gdbm_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 | ||
115 | GDBM_FILE | 119 | GDBM_FILE |
116 | gdbm_fd_open (int fd, const char *file_name, int block_size, | 120 | gdbm_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 | ||
241 | static void | ||
242 | av_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 | |||
238 | void | 253 | void |
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)); |