Mercurial > dovecot > original-hg > dovecot-1.2
changeset 914:fe0ba77d5506 HEAD
message_part_deserialize() now verifies that the data is valid so we don't
later crash to some assert.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Mon, 06 Jan 2003 20:54:36 +0200 |
parents | f8e189e8a98e |
children | f33a139029db |
files | src/lib-index/mail-index-update.c src/lib-mail/message-part-serialize.c src/lib-mail/message-part-serialize.h src/lib-storage/index/index-msgcache.c |
diffstat | 4 files changed, 117 insertions(+), 32 deletions(-) [+] |
line wrap: on
line diff
--- a/src/lib-index/mail-index-update.c Mon Jan 06 19:51:37 2003 +0200 +++ b/src/lib-index/mail-index-update.c Mon Jan 06 20:54:36 2003 +0200 @@ -413,7 +413,7 @@ struct message_size hdr_size, body_size; pool_t pool; buffer_t *buf; - const char *value; + const char *value, *error; size_t size; uoff_t start_offset; @@ -439,11 +439,13 @@ if (value == NULL) part = NULL; else { - part = message_part_deserialize(pool, value, size); + part = message_part_deserialize(pool, value, size, + &error); if (part == NULL) { /* corrupted, rebuild it */ index_set_corrupted(update->index, - "Corrupted cached MessagePart data"); + "Corrupted cached MessagePart data " + "(%s)", error); } }
--- a/src/lib-mail/message-part-serialize.c Mon Jan 06 19:51:37 2003 +0200 +++ b/src/lib-mail/message-part-serialize.c Mon Jan 06 20:54:36 2003 +0200 @@ -33,11 +33,21 @@ unsigned int flags; }; +struct deserialize_context { + pool_t pool; + + const struct serialized_message_part *spart; + unsigned int sparts_left; + + uoff_t pos; + const char *error; +}; + static unsigned int _message_part_serialize(struct message_part *part, buffer_t *dest) { struct serialized_message_part *spart; - unsigned int count = 1; + unsigned int count = 0; while (part != NULL) { /* create serialized part */ @@ -74,39 +84,87 @@ _message_part_serialize(part, dest); } -static struct message_part * -message_part_deserialize_part(pool_t pool, struct message_part *parent, - const struct serialized_message_part **spart_pos, - size_t *count, unsigned int child_count) +static int message_part_deserialize_part(struct deserialize_context *ctx, + struct message_part *parent, + unsigned int child_count, + struct message_part **part_r) { const struct serialized_message_part *spart; struct message_part *part, *first_part, **next_part; - unsigned int i; + uoff_t pos; first_part = NULL; next_part = NULL; - for (i = 0; i < child_count && *count > 0; i++) { - spart = *spart_pos; - (*spart_pos)++; - (*count)--; + while (child_count > 0) { + child_count--; + if (ctx->sparts_left == 0) { + ctx->error = "Not enough data for all parts"; + return FALSE; + } - part = p_new(pool, struct message_part, 1); + spart = ctx->spart; + ctx->spart++; + ctx->sparts_left--; + + part = p_new(ctx->pool, struct message_part, 1); part->physical_pos = spart->physical_pos; + if (part->physical_pos < ctx->pos) { + ctx->error = "physical_pos less than expected"; + return FALSE; + } + part->header_size.physical_size = spart->header_physical_size; part->header_size.virtual_size = spart->header_virtual_size; part->header_size.lines = spart->header_lines; + if (spart->header_virtual_size < spart->header_physical_size) { + ctx->error = "header_virtual_size too small"; + return FALSE; + } + part->body_size.physical_size = spart->body_physical_size; part->body_size.virtual_size = spart->body_virtual_size; part->body_size.lines = spart->body_lines; + if (spart->body_virtual_size < spart->body_physical_size) { + ctx->error = "body_virtual_size too small"; + return FALSE; + } + part->flags = spart->flags; - part->parent = parent; - part->children = message_part_deserialize_part(pool, part, - spart_pos, count, - spart->children_count); + + /* our children must be after our physical_pos and the last + child must be within our size. */ + ctx->pos = part->physical_pos; + pos = part->physical_pos + spart->header_physical_size + + spart->body_physical_size; + + if (!message_part_deserialize_part(ctx, part, + spart->children_count, + &part->children)) + return FALSE; + + if (ctx->pos > pos) { + ctx->error = "child part location exceeds our size"; + return FALSE; + } + ctx->pos = pos; /* save it for above check for parent */ + + if (part->flags & MESSAGE_PART_FLAG_MESSAGE_RFC822) { + /* Only one child is possible */ + if (part->children == NULL) { + ctx->error = + "message/rfc822 part has no children"; + return FALSE; + } + if (part->children->next != NULL) { + ctx->error = "message/rfc822 part " + "has multiple children"; + return FALSE; + } + } if (first_part == NULL) first_part = part; @@ -115,26 +173,49 @@ next_part = &part->next; } - return first_part; + *part_r = first_part; + return TRUE; } struct message_part *message_part_deserialize(pool_t pool, const void *data, - size_t size) + size_t size, const char **error) { - const struct serialized_message_part *spart; - size_t count; + struct deserialize_context ctx; + struct message_part *part; /* make sure it looks valid */ - if (size < sizeof(struct serialized_message_part)) + if (size < sizeof(struct serialized_message_part)) { + *error = "Not enough data for root"; return NULL; + } + + if ((size % sizeof(struct serialized_message_part)) != 0) { + *error = "Incorrect data size"; + return NULL; + } + + if (size / sizeof(struct serialized_message_part) > UINT_MAX) { + *error = "Insane amount of data"; + return NULL; + } - spart = data; - count = size / sizeof(struct serialized_message_part); - if (count > UINT_MAX) + memset(&ctx, 0, sizeof(ctx)); + ctx.pool = pool; + ctx.spart = data; + ctx.sparts_left = + (unsigned int) (size / sizeof(struct serialized_message_part)); + + if (!message_part_deserialize_part(&ctx, NULL, 1, &part)) { + *error = ctx.error; return NULL; + } - return message_part_deserialize_part(pool, NULL, &spart, &count, - (unsigned int)count); + if (ctx.sparts_left > 0) { + *error = "Too much data"; + return NULL; + } + + return part; } int message_part_serialize_update_header(void *data, size_t size,
--- a/src/lib-mail/message-part-serialize.h Mon Jan 06 19:51:37 2003 +0200 +++ b/src/lib-mail/message-part-serialize.h Mon Jan 06 20:54:36 2003 +0200 @@ -7,9 +7,10 @@ /* Serialize message part. */ void message_part_serialize(struct message_part *part, buffer_t *dest); -/* Generate struct message_part from serialized data. */ +/* Generate struct message_part from serialized data. Returns NULL and sets + error if any problems are detected. */ struct message_part *message_part_deserialize(pool_t pool, const void *data, - size_t size); + size_t size, const char **error); /* Update header size in serialized struct message_part. */ int message_part_serialize_update_header(void *data, size_t size,
--- a/src/lib-storage/index/index-msgcache.c Mon Jan 06 19:51:37 2003 +0200 +++ b/src/lib-storage/index/index-msgcache.c Mon Jan 06 20:54:36 2003 +0200 @@ -139,6 +139,7 @@ struct index_msgcache_context *ctx = context; struct message_part *part; const void *part_data; + const char *error; size_t part_size; part_data = ctx->index->lookup_field_raw(ctx->index, ctx->rec, @@ -150,10 +151,10 @@ return NULL; } - part = message_part_deserialize(pool, part_data, part_size); + part = message_part_deserialize(pool, part_data, part_size, &error); if (part == NULL) { index_set_corrupted(ctx->index, - "Corrupted cached message_part data"); + "Corrupted cached message_part data (%s)", error); return NULL; }