dovecot: If extension header is broken, drop it when fscking.
dovecot at dovecot.org
dovecot at dovecot.org
Sat Sep 15 13:07:49 EEST 2007
details: http://hg.dovecot.org/dovecot/rev/9dde743dfbc1
changeset: 6385:9dde743dfbc1
user: Timo Sirainen <tss at iki.fi>
date: Sat Sep 15 11:44:11 2007 +0300
description:
If extension header is broken, drop it when fscking.
diffstat:
3 files changed, 165 insertions(+), 62 deletions(-)
src/lib-index/mail-index-fsck.c | 62 ++++++++++++++
src/lib-index/mail-index-map.c | 157 +++++++++++++++++++++---------------
src/lib-index/mail-index-private.h | 8 +
diffs (truncated from 307 to 300 lines):
diff -r 2c8b1d487728 -r 9dde743dfbc1 src/lib-index/mail-index-fsck.c
--- a/src/lib-index/mail-index-fsck.c Sat Sep 15 10:51:03 2007 +0300
+++ b/src/lib-index/mail-index-fsck.c Sat Sep 15 11:44:11 2007 +0300
@@ -2,6 +2,7 @@
#include "lib.h"
#include "ioloop.h"
+#include "array.h"
#include "mail-index-private.h"
#include "mail-transaction-log.h"
@@ -54,6 +55,66 @@ mail_index_fsck_header(struct mail_index
CHECK(log_file_head_offset, !=);
CHECK(log_file_tail_offset, !=);
}
+}
+
+static bool
+array_has_name(const ARRAY_TYPE(const_string) *names, const char *name)
+{
+ const char *const *str;
+ unsigned int i, count;
+
+ str = array_get(names, &count);
+ for (i = 0; i < count; i++) {
+ if (strcmp(str[i], name) == 0)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static void
+mail_index_fsck_extensions(struct mail_index *index, struct mail_index_map *map,
+ struct mail_index_header *hdr)
+{
+ const struct mail_index_ext_header *ext_hdr;
+ ARRAY_TYPE(const_string) names;
+ const char *name, *error;
+ unsigned int offset, ext_offset, i;
+
+ t_push();
+ t_array_init(&names, 64);
+ offset = MAIL_INDEX_HEADER_SIZE_ALIGN(hdr->base_header_size);
+ for (i = 0; offset < hdr->header_size; i++) {
+ ext_offset = offset;
+ if (mail_index_map_ext_get_next(map, &offset,
+ &ext_hdr, &name) < 0) {
+ /* the extension continued outside header, drop it */
+ mail_index_fsck_error(index,
+ "Dropped extension #%d (%s) "
+ "with invalid header size",
+ i, name);
+ hdr->header_size = ext_offset;
+ break;
+ }
+ if (mail_index_map_ext_hdr_check(hdr, ext_hdr, name,
+ &error) < 0) {
+ mail_index_fsck_error(index,
+ "Dropped broken extension #%d (%s)", i, name);
+ } else if (array_has_name(&names, name)) {
+ mail_index_fsck_error(index,
+ "Dropped duplicate extension %s", name);
+ } else {
+ array_append(&names, &name, 1);
+ continue;
+ }
+
+ /* drop the field */
+ hdr->header_size -= offset - ext_offset;
+ buffer_copy(map->hdr_copy_buf, ext_offset,
+ map->hdr_copy_buf, offset, (size_t)-1);
+ buffer_set_used_size(map->hdr_copy_buf, hdr->header_size);
+ offset = ext_offset;
+ }
+ t_pop();
}
static void
@@ -162,6 +223,7 @@ mail_index_fsck_map(struct mail_index *i
hdr = map->hdr;
mail_index_fsck_header(index, map, &hdr);
+ mail_index_fsck_extensions(index, map, &hdr);
mail_index_fsck_records(index, map, &hdr);
map->hdr = hdr;
diff -r 2c8b1d487728 -r 9dde743dfbc1 src/lib-index/mail-index-map.c
--- a/src/lib-index/mail-index-map.c Sat Sep 15 10:51:03 2007 +0300
+++ b/src/lib-index/mail-index-map.c Sat Sep 15 11:44:11 2007 +0300
@@ -106,14 +106,92 @@ mail_index_map_register_ext(struct mail_
return idx;
}
-static int mail_index_parse_extensions(struct mail_index_map *map)
+int mail_index_map_ext_get_next(struct mail_index_map *map,
+ unsigned int *offset_p,
+ const struct mail_index_ext_header **ext_hdr_r,
+ const char **name_r)
+{
+ const struct mail_index_ext_header *ext_hdr;
+ unsigned int offset, name_offset;
+
+ offset = *offset_p;
+ *name_r = "";
+
+ /* Extension header contains:
+ - struct mail_index_ext_header
+ - name (not 0-terminated)
+ - 64bit alignment padding
+ - extension header contents
+ - 64bit alignment padding
+ */
+ name_offset = offset + sizeof(*ext_hdr);
+ ext_hdr = CONST_PTR_OFFSET(map->hdr_base, offset);
+ if (offset + sizeof(*ext_hdr) >= map->hdr.header_size)
+ return -1;
+
+ offset += get_ext_size(ext_hdr->name_size);
+ if (offset > map->hdr.header_size)
+ return -1;
+
+ *name_r = t_strndup(CONST_PTR_OFFSET(map->hdr_base, name_offset),
+ ext_hdr->name_size);
+ if (strcmp(*name_r, str_sanitize(*name_r, -1)) != 0) {
+ /* we allow only plain ASCII names, so this extension
+ is most likely broken */
+ *name_r = "";
+ }
+
+ /* finally make sure that the hdr_size is small enough.
+ do this last so that we could return a usable name. */
+ offset += MAIL_INDEX_HEADER_SIZE_ALIGN(ext_hdr->hdr_size);
+ if (offset > map->hdr.header_size)
+ return -1;
+
+ *offset_p = offset;
+ *ext_hdr_r = ext_hdr;
+ return 0;
+}
+
+int mail_index_map_ext_hdr_check(const struct mail_index_header *hdr,
+ const struct mail_index_ext_header *ext_hdr,
+ const char *name, const char **error_r)
+{
+ if ((ext_hdr->record_size == 0 && ext_hdr->hdr_size == 0) ||
+ (ext_hdr->record_align == 0 && ext_hdr->record_size != 0)) {
+ *error_r = "Invalid field values";
+ return -1;
+ }
+ if (*name == '\0') {
+ *error_r = "Broken name";
+ return -1;
+ }
+
+ if (ext_hdr->record_offset + ext_hdr->record_size > hdr->record_size) {
+ *error_r = t_strdup_printf("Record field points "
+ "outside record size (%u+%u > %u)",
+ ext_hdr->record_offset,
+ ext_hdr->record_size,
+ hdr->record_size);
+ return -1;
+ }
+
+ if (ext_hdr->record_size > 0 &&
+ ((ext_hdr->record_offset % ext_hdr->record_align) != 0 ||
+ (hdr->record_size % ext_hdr->record_align) != 0)) {
+ *error_r = t_strdup_printf("Record field alignmentation %u "
+ "not used", ext_hdr->record_align);
+ return -1;
+ }
+ return 0;
+}
+
+static int mail_index_map_parse_extensions(struct mail_index_map *map)
{
struct mail_index *index = map->index;
const struct mail_index_ext_header *ext_hdr;
- unsigned int i, old_count;
- const char *name;
- uint32_t ext_id, ext_offset, offset, name_offset;
- size_t size_left;
+ unsigned int i, old_count, offset;
+ const char *name, *error;
+ uint32_t ext_id, ext_offset;
/* extension headers always start from 64bit offsets, so if base header
doesn't happen to be 64bit aligned we'll skip some bytes */
@@ -132,44 +210,22 @@ static int mail_index_parse_extensions(s
for (i = 0; offset < map->hdr.header_size; i++) {
ext_offset = offset;
- ext_hdr = CONST_PTR_OFFSET(map->hdr_base, offset);
-
- /* Extension header contains:
- - struct mail_index_ext_header
- - name (not 0-terminated)
- - 64bit alignment padding
- - extension header contents
- - 64bit alignment padding
- */
- size_left = map->hdr.header_size - offset;
- if (size_left < sizeof(*ext_hdr) ||
- size_left < get_ext_size(ext_hdr->name_size) +
- ext_hdr->hdr_size) {
+
+ t_push();
+ if (mail_index_map_ext_get_next(map, &offset,
+ &ext_hdr, &name) < 0) {
mail_index_set_error(index, "Corrupted index file %s: "
- "Header extension goes outside header",
- index->filepath);
+ "Header extension #%d (%s) goes outside header",
+ index->filepath, i, name);
+ t_pop();
return -1;
}
- name_offset = offset + sizeof(*ext_hdr);
- offset += get_ext_size(ext_hdr->name_size);
-
- t_push();
- name = t_strndup(CONST_PTR_OFFSET(map->hdr_base, name_offset),
- ext_hdr->name_size);
- if (strcmp(name, str_sanitize(name, -1)) != 0) {
- /* we allow only plain ASCII names, so this extension
- is most likely broken */
- name = "";
- }
-
- if ((ext_hdr->record_size == 0 && ext_hdr->hdr_size == 0) ||
- (ext_hdr->record_align == 0 && ext_hdr->record_size != 0) ||
- *name == '\0') {
+ if (mail_index_map_ext_hdr_check(&map->hdr, ext_hdr,
+ name, &error) < 0) {
mail_index_set_error(index, "Corrupted index file %s: "
- "Broken header extension %s",
- index->filepath, *name == '\0' ?
- t_strdup_printf("#%d", i) : name);
+ "Broken extension #%d (%s): %s",
+ index->filepath, i, name, error);
t_pop();
return -1;
}
@@ -177,27 +233,6 @@ static int mail_index_parse_extensions(s
mail_index_set_error(index, "Corrupted index file %s: "
"Duplicate header extension %s",
index->filepath, name);
- t_pop();
- return -1;
- }
-
- if (map->hdr.record_size <
- ext_hdr->record_offset + ext_hdr->record_size) {
- mail_index_set_error(index, "Corrupted index file %s: "
- "Record field %s points outside record size "
- "(%u < %u+%u)", index->filepath, name,
- map->hdr.record_size,
- ext_hdr->record_offset, ext_hdr->record_size);
- t_pop();
- return -1;
- }
-
- if (ext_hdr->record_size > 0 &&
- ((ext_hdr->record_offset % ext_hdr->record_align) != 0 ||
- (map->hdr.record_size % ext_hdr->record_align) != 0)) {
- mail_index_set_error(index, "Corrupted index file %s: "
- "Record field %s alignmentation %u not used",
- index->filepath, name, ext_hdr->record_align);
t_pop();
return -1;
}
@@ -209,8 +244,6 @@ static int mail_index_parse_extensions(s
ext_hdr->record_align,
ext_hdr->reset_id);
t_pop();
-
- offset += MAIL_INDEX_HEADER_SIZE_ALIGN(ext_hdr->hdr_size);
}
return 0;
}
@@ -800,7 +833,7 @@ static int mail_index_map_latest_file(st
/* make sure the header is ok before using this mapping */
ret = mail_index_map_check_header(new_map);
if (ret > 0) {
- if (mail_index_parse_extensions(new_map) < 0)
+ if (mail_index_map_parse_extensions(new_map) < 0)
ret = 0;
else if (mail_index_map_parse_keywords(new_map) < 0)
ret = 0;
diff -r 2c8b1d487728 -r 9dde743dfbc1 src/lib-index/mail-index-private.h
--- a/src/lib-index/mail-index-private.h Sat Sep 15 10:51:03 2007 +0300
+++ b/src/lib-index/mail-index-private.h Sat Sep 15 11:44:11 2007 +0300
@@ -289,6 +289,14 @@ int mail_index_map_check_header(struct m
int mail_index_map_check_header(struct mail_index_map *map);
int mail_index_map_parse_keywords(struct mail_index_map *map);
+int mail_index_map_ext_get_next(struct mail_index_map *map,
+ unsigned int *offset,
+ const struct mail_index_ext_header **ext_hdr_r,
+ const char **name_r);
More information about the dovecot-cvs
mailing list