Mercurial > dovecot > original-hg > dovecot-1.2
changeset 50:d493b9cc265e HEAD
Introduced uoff_t which is the unsigned-equilevant of off_t. This was needed
to be able to handle off_t overflows properly. Also changed a few unsigned
int fields into uoff_t so we should now support >2G mails if uoff_t is
64bit. Also fixed several potential integer overflows.
line wrap: on
line diff
--- a/acconfig.h Tue Aug 27 20:35:00 2002 +0300 +++ b/acconfig.h Tue Aug 27 22:16:54 2002 +0300 @@ -21,3 +21,17 @@ /* Required memory alignment */ #undef MEM_ALIGN_SIZE + +/* If set to 64, enables 64bit off_t for some systems (eg. Linux, Solaris) */ +#undef _FILE_OFFSET_BITS + +/* Maximum value for uoff_t */ +#undef OFF_T_MAX + +/* printf()-format for uoff_t, eg. "u" or "lu" or "llu" */ +#undef UOFF_T_FORMAT + +/* What type should be used for uoff_t */ +#undef UOFF_T_INT +#undef UOFF_T_LONG +#undef UOFF_T_LONG_LONG
--- a/configure.in Tue Aug 27 20:35:00 2002 +0300 +++ b/configure.in Tue Aug 27 22:16:54 2002 +0300 @@ -94,7 +94,7 @@ dnl * gcc specific options if test "x$ac_cv_prog_gcc" = "xyes"; then - # -W -Wchar-subscripts -Wpointer-arith -Wcast-align -Wconversion -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations + # -Wchar-subscripts -Wpointer-arith -Wcast-align -Wconversion -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations CFLAGS="$CFLAGS -Wall -W" fi @@ -107,6 +107,52 @@ ;; esac +dnl * off_t checks, try to make it 64bit +preferred_off_t_bits=32 +AC_DEFINE_UNQUOTED(_FILE_OFFSET_BITS, $preferred_off_t_bits) + +AC_MSG_CHECKING([size of off_t]) +sizeof_off_t=0 +for size in 4 8; do + AC_TRY_RUN([ + #define _FILE_OFFSET_BITS $preferred_off_t_bits + #include <sys/types.h> + #include <unistd.h> + int main() { off_t size; return sizeof(size) == $size ? 0 : 1; } + ], [ + sizeof_off_t=$size + break + ]) +done + +if test x$sizeof_off_t = x0; then + AC_ERROR([Unsupported off_t size]) +fi +AC_MSG_RESULT($sizeof_off_t) + +AC_CHECK_SIZEOF(int) +AC_CHECK_SIZEOF(long) +AC_CHECK_SIZEOF(long long) + +if test x$sizeof_off_t = x$ac_cv_sizeof_long; then + # try to use unsigned long always first + AC_DEFINE_UNQUOTED(OFF_T_MAX, LONG_MAX) + AC_DEFINE_UNQUOTED(UOFF_T_FORMAT, "lu") + AC_DEFINE(UOFF_T_LONG) +elif test x$sizeof_off_t = x$ac_cv_sizeof_int; then + # next try int + AC_DEFINE_UNQUOTED(OFF_T_MAX, INT_MAX) + AC_DEFINE_UNQUOTED(UOFF_T_FORMAT, "u") + AC_DEFINE(UOFF_T_INT) +elif test x$sizeof_off_t = x$ac_cv_sizeof_long_long; then + # and finally long long + AC_DEFINE_UNQUOTED(OFF_T_MAX, LONG_LONG_MAX) + AC_DEFINE_UNQUOTED(UOFF_T_FORMAT, "llu") + AC_DEFINE(UOFF_T_LONG_LONG) +else + AC_ERROR([Couldn't find integer type for off_t]) +fi + dnl * memory alignment, could be 1 for x86 systems but 4 should be dnl * compatible with everyone. note that only 1, 2 and 4 work corrently. dnl * is 8 needed anywhere?
--- a/src/imap/cmd-fetch.c Tue Aug 27 20:35:00 2002 +0300 +++ b/src/imap/cmd-fetch.c Tue Aug 27 22:16:54 2002 +0300 @@ -5,14 +5,14 @@ /* Parse next digits in string into integer. Returns FALSE if the integer becomes too big and wraps. */ -static int read_int(char **p, unsigned int *value) +static int read_uoff_t(char **p, uoff_t *value) { - unsigned int prev; + uoff_t prev; + *value = 0; - while (**p >= '0' && **p <= '9') { prev = *value; - *value = *value * 10 + **p - '0'; + *value = *value * 10 + (**p - '0'); if (*value < prev) return FALSE; @@ -28,7 +28,7 @@ MailFetchData *data, int peek) { MailFetchBodyData *body; - unsigned int num; + uoff_t num; const char *section; char *p; @@ -50,7 +50,7 @@ /* <start.end> */ body->skip = 0; - body->max_size = -1; + body->max_size = (uoff_t)-1; if (*p != '<' && *p != '\0') { client_send_tagline(client, t_strconcat( "BAD Unexpected character after ']' with ", @@ -60,7 +60,7 @@ p++; body->skip_set = TRUE; - if (!read_int(&p, &num) || num > INT_MAX) { + if (!read_uoff_t(&p, &num) || num > OFF_T_MAX) { /* wrapped */ client_send_tagline(client, t_strconcat( "BAD Too big partial start with ", item, NULL)); @@ -71,7 +71,7 @@ if (*p == '.') { /* read end */ p++; - if (!read_int(&p, &num) || num > INT_MAX) { + if (!read_uoff_t(&p, &num) || num > OFF_T_MAX) { /* wrapped */ client_send_tagline(client, t_strconcat( "BAD Too big partial end with ",
--- a/src/lib-imap/imap-bodystructure.c Tue Aug 27 20:35:00 2002 +0300 +++ b/src/lib-imap/imap-bodystructure.c Tue Aug 27 22:16:54 2002 +0300 @@ -106,8 +106,8 @@ static void parse_header(MessagePart *part, const char *name, unsigned int name_len, - const char *value, - unsigned int value_len, void *context) + const char *value, unsigned int value_len, + void *context) { Pool pool = context; MessagePartBodyData *part_data; @@ -265,11 +265,11 @@ t_string_append_c(str, ')'); } - t_string_printfa(str, " %s %s %s %lu", + t_string_printfa(str, " %s %s %s %"UOFF_T_FORMAT, NVL(data->content_id, "NIL"), NVL(data->content_description, "NIL"), NVL(data->content_transfer_encoding, "\"8bit\""), - (unsigned long) part->body_size.virtual_size); + part->body_size.virtual_size); if (part->text) { /* text/.. contains line count */
--- a/src/lib-imap/imap-envelope.c Tue Aug 27 20:35:00 2002 +0300 +++ b/src/lib-imap/imap-envelope.c Tue Aug 27 22:16:54 2002 +0300 @@ -15,8 +15,8 @@ char *in_reply_to, *message_id; }; -static const char *t_buffer_get_quote(const char *value, - unsigned int *value_len) +static const char * +t_buffer_get_quote(const char *value, unsigned int *value_len) { char *buf, *p; unsigned int i, len; @@ -46,7 +46,7 @@ value_len = strlen(value); buf = t_buffer_get_quote(value, &value_len); - t_buffer_alloc((unsigned int) value_len); + t_buffer_alloc(value_len); return buf; }
--- a/src/lib-imap/imap-message-cache.c Tue Aug 27 20:35:00 2002 +0300 +++ b/src/lib-imap/imap-message-cache.c Tue Aug 27 22:16:54 2002 +0300 @@ -45,7 +45,7 @@ CachedMessage *open_msg; IOBuffer *open_inbuf; - off_t open_virtual_size; + uoff_t open_virtual_size; IOBuffer *(*inbuf_rewind)(IOBuffer *inbuf, void *context); void *context; @@ -163,7 +163,7 @@ return NULL; } -static void imap_msgcache_get_inbuf(ImapMessageCache *cache, off_t offset) +static void imap_msgcache_get_inbuf(ImapMessageCache *cache, uoff_t offset) { if (offset < cache->open_inbuf->offset) { /* need to rewind */ @@ -292,9 +292,11 @@ message_get_header_size(cache->open_inbuf, msg->hdr_size); - i_assert((off_t)msg->hdr_size->physical_size < + /* FIXME: this may actually happen if file size is + shrinked.. */ + i_assert(msg->hdr_size->physical_size < cache->open_inbuf->size); - i_assert((off_t)msg->hdr_size->virtual_size < + i_assert(msg->hdr_size->virtual_size < cache->open_virtual_size); msg->body_size->lines = 0; @@ -326,8 +328,8 @@ } void imap_msgcache_message(ImapMessageCache *cache, unsigned int uid, - ImapCacheField fields, off_t virtual_size, - off_t pv_headers_size, off_t pv_body_size, + ImapCacheField fields, uoff_t virtual_size, + uoff_t pv_headers_size, uoff_t pv_body_size, IOBuffer *inbuf, IOBuffer *(*inbuf_rewind)(IOBuffer *inbuf, void *context), @@ -447,7 +449,7 @@ IOBuffer **inbuf) { CachedMessage *msg; - off_t offset; + uoff_t offset; if (inbuf != NULL) { if (cache->open_msg == NULL || cache->open_msg->uid != uid) @@ -485,7 +487,7 @@ } static void get_partial_size(IOBuffer *inbuf, - off_t virtual_skip, off_t max_virtual_size, + uoff_t virtual_skip, uoff_t max_virtual_size, MessageSize *partial, MessageSize *dest) { unsigned char *msg; @@ -493,7 +495,7 @@ int cr_skipped; /* see if we can use the existing partial */ - if ((off_t)partial->virtual_size > virtual_skip) + if (partial->virtual_size > virtual_skip) memset(partial, 0, sizeof(MessageSize)); else { io_buffer_skip(inbuf, partial->physical_size); @@ -517,12 +519,13 @@ } int imap_msgcache_get_rfc822_partial(ImapMessageCache *cache, unsigned int uid, - off_t virtual_skip, off_t max_virtual_size, + uoff_t virtual_skip, + uoff_t max_virtual_size, int get_header, MessageSize *size, IOBuffer **inbuf) { CachedMessage *msg; - off_t physical_skip; + uoff_t physical_skip; int size_got; msg = cache->open_msg; @@ -540,7 +543,8 @@ /* see if we can do this easily */ size_got = FALSE; if (virtual_skip == 0) { - if (max_virtual_size < 0 && msg->body_size == NULL) { + if (msg->body_size == NULL) { + /* FIXME: may underflow */ msg->body_size = p_new(msg->pool, MessageSize, 1); msg->body_size->physical_size = cache->open_inbuf->size - @@ -550,9 +554,7 @@ msg->hdr_size->virtual_size; } - if (msg->body_size != NULL && - (max_virtual_size < 0 || - max_virtual_size >= (off_t)msg->body_size->virtual_size)) { + if (max_virtual_size >= msg->body_size->virtual_size) { *size = *msg->body_size; size_got = TRUE; }
--- a/src/lib-imap/imap-message-cache.h Tue Aug 27 20:35:00 2002 +0300 +++ b/src/lib-imap/imap-message-cache.h Tue Aug 27 22:16:54 2002 +0300 @@ -37,8 +37,8 @@ non-zero, they're set to saved to message's both physical and virtual sizes (ie. doesn't need to be calculated). */ void imap_msgcache_message(ImapMessageCache *cache, unsigned int uid, - ImapCacheField fields, off_t virtual_size, - off_t pv_headers_size, off_t pv_body_size, + ImapCacheField fields, uoff_t virtual_size, + uoff_t pv_headers_size, uoff_t pv_body_size, IOBuffer *inbuf, IOBuffer *(*inbuf_rewind)(IOBuffer *inbuf, void *context), @@ -68,7 +68,8 @@ /* Returns FALSE if message isn't in cache. *inbuf is set to point to the first non-skipped character. size is set to specify the full size of message. */ int imap_msgcache_get_rfc822_partial(ImapMessageCache *cache, unsigned int uid, - off_t virtual_skip, off_t max_virtual_size, + uoff_t virtual_skip, + uoff_t max_virtual_size, int get_header, MessageSize *size, IOBuffer **inbuf);
--- a/src/lib-imap/imap-parser.c Tue Aug 27 20:35:00 2002 +0300 +++ b/src/lib-imap/imap-parser.c Tue Aug 27 22:16:54 2002 +0300 @@ -31,7 +31,7 @@ ImapParserFlags flags; int str_first_escape; /* ARG_PARSE_STRING: index to first '\' */ - unsigned int literal_size; /* ARG_PARSE_LITERAL: string size */ + uoff_t literal_size; /* ARG_PARSE_LITERAL: string size */ unsigned int literal_skip_crlf:1; unsigned int inside_bracket:1; @@ -304,7 +304,7 @@ return FALSE; prev_size = parser->literal_size; - parser->literal_size = parser->literal_size*10 + data[i]-'0'; + parser->literal_size = parser->literal_size*10 + (data[i]-'0'); if (parser->literal_size < prev_size) { /* wrapped around, abort. */ @@ -344,7 +344,7 @@ if (data_size >= parser->literal_size) { imap_parser_save_arg(parser, data, parser->literal_size); - parser->cur_pos = parser->literal_size; + parser->cur_pos = (unsigned int) parser->literal_size; } } else { /* we want to save only literal size, not the literal itself. */
--- a/src/lib-imap/imap-parser.h Tue Aug 27 20:35:00 2002 +0300 +++ b/src/lib-imap/imap-parser.h Tue Aug 27 22:16:54 2002 +0300 @@ -27,7 +27,7 @@ union { char *str; - unsigned int literal_size; + uoff_t literal_size; ImapArgList *list; } data; };
--- a/src/lib-index/mail-hash.c Tue Aug 27 20:35:00 2002 +0300 +++ b/src/lib-index/mail-hash.c Tue Aug 27 22:16:54 2002 +0300 @@ -195,6 +195,8 @@ int ret, old_errno; off_t pos; + i_assert(size >= 0); + /* try truncating it to the size we want. if this succeeds, the written area is full of zeros - exactly what we want. however, this may not work at all, in which case we fallback to write()ing the zeros. */ @@ -246,7 +248,7 @@ /* fill the file with zeros */ new_size = sizeof(MailHashHeader) + hash_size * sizeof(MailHashRecord); - if (!file_set_size(fd, (off_t) new_size)) { + if (!file_set_size(fd, (off_t)new_size)) { index_set_error(index, "Failed to fill temp hash to size %lu: %m", (unsigned long) new_size); @@ -372,7 +374,7 @@ return TRUE; } -off_t mail_hash_lookup_uid(MailHash *hash, unsigned int uid) +uoff_t mail_hash_lookup_uid(MailHash *hash, unsigned int uid) { MailHashRecord *rec; unsigned int hashidx, idx; @@ -439,7 +441,7 @@ return NULL; } -void mail_hash_update(MailHash *hash, unsigned int uid, off_t pos) +void mail_hash_update(MailHash *hash, unsigned int uid, uoff_t pos) { MailHashRecord *rec; unsigned int max_used;
--- a/src/lib-index/mail-hash.h Tue Aug 27 20:35:00 2002 +0300 +++ b/src/lib-index/mail-hash.h Tue Aug 27 22:16:54 2002 +0300 @@ -12,7 +12,7 @@ struct _MailHashRecord { unsigned int uid; - off_t position; + uoff_t position; }; /* Open or create a hash file for index. If the hash needs to be created, @@ -30,10 +30,10 @@ int mail_hash_rebuild(MailHash *hash); /* Returns position in index file to given UID, or 0 if not found. */ -off_t mail_hash_lookup_uid(MailHash *hash, unsigned int uid); +uoff_t mail_hash_lookup_uid(MailHash *hash, unsigned int uid); /* Update hash file. If pos is 0, the record is deleted. This call may rebuild the hash if it's too full. */ -void mail_hash_update(MailHash *hash, unsigned int uid, off_t pos); +void mail_hash_update(MailHash *hash, unsigned int uid, uoff_t pos); #endif
--- a/src/lib-index/mail-index-compress.c Tue Aug 27 20:35:00 2002 +0300 +++ b/src/lib-index/mail-index-compress.c Tue Aug 27 22:16:54 2002 +0300 @@ -23,7 +23,7 @@ return TRUE; } - if (index->header->first_hole_position >= (off_t)index->mmap_length) { + if (index->header->first_hole_position >= index->mmap_length) { index_set_error(index, "Error in index file %s: " "first_hole_position points outside file", index->filepath); @@ -78,7 +78,7 @@ MailIndexRecord *rec; unsigned char *mmap_data; size_t mmap_data_size; - off_t offset; + uoff_t offset; mmap_data = mail_index_data_get_mmaped(index->data, &mmap_data_size); if (mmap_data == NULL)
--- a/src/lib-index/mail-index-data.c Tue Aug 27 20:35:00 2002 +0300 +++ b/src/lib-index/mail-index-data.c Tue Aug 27 22:16:54 2002 +0300 @@ -11,7 +11,7 @@ #include <fcntl.h> #define DATA_FILE_POSITION(data, rec) \ - ((off_t) ((char *) (rec) - (char *) ((data)->mmap_base))) + ((uoff_t) ((char *) (rec) - (char *) ((data)->mmap_base))) /* Never compress the file if it's smaller than this (50kB) */ #define COMPRESS_MIN_SIZE (1024*50) @@ -31,9 +31,10 @@ unsigned int dirty_mmap:1; }; -static int mmap_update(MailIndexData *data, off_t pos, unsigned int size) +static int mmap_update(MailIndexData *data, uoff_t pos, unsigned int size) { - if (!data->dirty_mmap || (size != 0 && pos+size <= data->mmap_length)) + if (!data->dirty_mmap || (size != 0 && pos <= data->mmap_length && + pos+size <= data->mmap_length)) return TRUE; if (data->mmap_base != NULL) @@ -203,8 +204,8 @@ data->dirty_mmap = TRUE; } -off_t mail_index_data_append(MailIndexData *data, const void *buffer, - size_t size) +uoff_t mail_index_data_append(MailIndexData *data, const void *buffer, + size_t size) { off_t pos; @@ -214,24 +215,30 @@ if (pos == -1) { index_set_error(data->index, "lseek() failed with file %s: %m", data->filepath); - return -1; + return 0; + } + + if (pos < (int)sizeof(MailIndexDataHeader)) { + index_set_error(data->index, "Header missing from data file %s", + data->filepath); + return 0; } if (write_full(data->fd, buffer, size) < 0) { index_set_error(data->index, "Error appending to file %s: %m", data->filepath); - return -1; + return 0; } mail_index_data_new_data_notify(data); - return pos; + return (uoff_t)pos; } int mail_index_data_add_deleted_space(MailIndexData *data, unsigned int data_size) { MailIndexDataHeader *hdr; - off_t max_del_space; + uoff_t max_del_space; i_assert(data->index->lock_type == MAIL_LOCK_EXCLUSIVE); @@ -275,9 +282,10 @@ MailField field) { MailIndexDataRecord *rec; - off_t pos, max_pos; + uoff_t pos, max_pos; if (index_rec->data_position == 0) { + /* data not yet written to record */ index_reset_error(data->index); return NULL; } @@ -285,38 +293,36 @@ if (!mmap_update(data, index_rec->data_position, index_rec->data_size)) return NULL; - max_pos = index_rec->data_position + (off_t)index_rec->data_size; - if (max_pos > (off_t)data->mmap_length) { + if (index_rec->data_position > data->mmap_length || + (data->mmap_length - + index_rec->data_position > index_rec->data_size)) { INDEX_MARK_CORRUPTED(data->index); index_set_error(data->index, "Error in data file %s: " "Given data size larger than file size " - "(%lu > %lu)", data->filepath, - (unsigned long) max_pos, + "(%lu + %u > %lu)", data->filepath, + (unsigned long) index_rec->data_position, + index_rec->data_size, (unsigned long) data->mmap_length); return NULL; } pos = index_rec->data_position; + max_pos = pos + index_rec->data_size; + do { - if (pos + (off_t)sizeof(MailIndexDataRecord) > max_pos) { - INDEX_MARK_CORRUPTED(data->index); - index_set_error(data->index, "Error in data file %s: " - "Index points outside file " - "(%lu > %lu)", data->filepath, - (unsigned long) pos, - (unsigned long) data->mmap_length); - break; - } + rec = (MailIndexDataRecord *) ((char *) data->mmap_base + pos); - rec = (MailIndexDataRecord *) ((char *) data->mmap_base + pos); - if (pos + (off_t)DATA_RECORD_SIZE(rec) > max_pos) { + /* pos + DATA_RECORD_SIZE() may actually overflow, but it + points to beginning of file then. Don't bother checking + this as it won't crash and is quite likely noticed later. */ + if (pos + sizeof(MailIndexDataRecord) > max_pos || + pos + DATA_RECORD_SIZE(rec) > max_pos) { INDEX_MARK_CORRUPTED(data->index); index_set_error(data->index, "Error in data file %s: " "Field size points outside file " - "(%lu + %u > %lu)", data->filepath, + "(%lu / %lu)", data->filepath, (unsigned long) pos, - rec->full_field_size, - (unsigned long) data->mmap_length); + (unsigned long) max_pos); break; } @@ -340,7 +346,7 @@ mail_index_data_next(MailIndexData *data, MailIndexRecord *index_rec, MailIndexDataRecord *rec) { - off_t pos, max_pos; + uoff_t pos, end_pos, max_pos; if (rec == NULL) return NULL; @@ -354,14 +360,15 @@ return NULL; rec = (MailIndexDataRecord *) ((char *) data->mmap_base + pos); - if (pos + (off_t)DATA_RECORD_SIZE(rec) > max_pos) { + end_pos = pos + DATA_RECORD_SIZE(rec); + if (end_pos < pos || end_pos > max_pos) { INDEX_MARK_CORRUPTED(data->index); index_set_error(data->index, "Error in data file %s: " "Field size points outside file " "(%lu + %u > %lu)", data->filepath, (unsigned long) pos, rec->full_field_size, - (unsigned long) data->mmap_length); + (unsigned long) max_pos); return NULL; } @@ -372,8 +379,15 @@ { int i; + if (rec->full_field_size > INT_MAX) { + INDEX_MARK_CORRUPTED(data->index); + index_set_error(data->index, "Error in data file %s: " + "full_field_size > INT_MAX", data->filepath); + return FALSE; + } + /* make sure the data actually contains \0 */ - for (i = rec->full_field_size-1; i >= 0; i--) { + for (i = (int)rec->full_field_size-1; i >= 0; i--) { if (rec->data[i] == '\0') { /* yes, everything ok */ return TRUE;
--- a/src/lib-index/mail-index-data.h Tue Aug 27 20:35:00 2002 +0300 +++ b/src/lib-index/mail-index-data.h Tue Aug 27 22:16:54 2002 +0300 @@ -15,9 +15,9 @@ void mail_index_data_new_data_notify(MailIndexData *data); /* Append new data at the end of the file. Returns the position in file - where the data begins, or (off_t)-1 if error occured. */ -off_t mail_index_data_append(MailIndexData *data, const void *buffer, - size_t size); + where the data begins, or 0 if error occured. */ +uoff_t mail_index_data_append(MailIndexData *data, const void *buffer, + size_t size); /* Increase header->deleted_space field */ int mail_index_data_add_deleted_space(MailIndexData *data,
--- a/src/lib-index/mail-index-fsck.c Tue Aug 27 20:35:00 2002 +0300 +++ b/src/lib-index/mail-index-fsck.c Tue Aug 27 22:16:54 2002 +0300 @@ -10,7 +10,7 @@ MailIndexHeader *hdr; MailIndexRecord *rec, *end_rec; unsigned int max_uid; - off_t pos; + uoff_t pos; i_assert(index->lock_type != MAIL_LOCK_SHARED); @@ -42,9 +42,9 @@ if (hdr->first_hole_position == 0) { hdr->first_hole_position = pos; hdr->first_hole_records = 1; - } else if ((off_t) (hdr->first_hole_position + - (hdr->first_hole_records * - sizeof(MailIndexRecord))) == pos) { + } else if (hdr->first_hole_position + + (hdr->first_hole_records * + sizeof(MailIndexRecord)) == pos) { /* hole continues */ hdr->first_hole_records++; }
--- a/src/lib-index/mail-index-update.c Tue Aug 27 20:35:00 2002 +0300 +++ b/src/lib-index/mail-index-update.c Tue Aug 27 22:16:54 2002 +0300 @@ -73,11 +73,21 @@ static int have_too_large_fields(MailIndexUpdate *update) { MailIndexDataRecord *rec; + unsigned int size_left; int index; + size_left = update->rec->data_size; + /* start from the first data field - it's required to exist */ rec = mail_index_data_lookup(update->index->data, update->rec, 1); while (rec != NULL) { + if (rec->full_field_size > size_left) { + /* corrupted */ + update->index->header->flags |= MAIL_INDEX_FLAG_REBUILD; + return TRUE; + } + size_left -= rec->full_field_size; + if (rec->field & update->updated_fields) { /* field was changed */ index = mail_field_get_index(rec->field); @@ -99,22 +109,36 @@ { MailIndexDataRecord *rec, *destrec; MailField field; - off_t fpos; + uoff_t fpos; void *mem; - unsigned int max_size, pos; + const void *src; + unsigned int max_size, pos, src_size; int i; /* allocate the old size + also the new size of all changed or added fields. this is more than required, but it's much easier than - calculating the exact size. */ + calculating the exact size. + + If this calculation overflows (no matter what value), it doesn't + really matter as it's later checked anyway. */ max_size = update->rec->data_size; for (i = 0; i < FIELD_TYPE_MAX_BITS; i++) { - max_size += sizeof(MailIndexDataRecord)-sizeof(rec->data) + + max_size += SIZEOF_MAIL_INDEX_DATA + update->field_sizes[i] + update->field_extra_sizes[i] + MEM_ALIGN_SIZE-1; } - mem = p_malloc(update->pool, max_size); + if (max_size > INT_MAX) { + /* rec->data_size most likely corrupted */ + update->index->header->flags |= MAIL_INDEX_FLAG_REBUILD; + return FALSE; + } + + /* allocate two extra records to avoid overflows in case of bad + rec->full_field_size which itself fits into max_size, but + either the record part would make it point ouside allocate memory, + or the next field's record would do that */ + mem = p_malloc(update->pool, max_size + sizeof(MailIndexDataRecord)*2); pos = 0; rec = mail_index_data_lookup(update->index->data, update->rec, 1); @@ -125,17 +149,26 @@ /* value was modified - use it */ destrec->full_field_size = update->field_sizes[i] + update->field_extra_sizes[i]; - memcpy(destrec->data, update->fields[i], - update->field_sizes[i]); + src = update->fields[i]; + src_size = update->field_sizes[i]; } else if (rec != NULL) { /* use the old value */ destrec->full_field_size = rec->full_field_size; - memcpy(destrec->data, rec->data, rec->full_field_size); + src = rec->data; + src_size = rec->full_field_size; } else { /* the field doesn't exist, jump to next */ continue; } + if (src_size > max_size || max_size - src_size > pos) { + /* corrupted data file - old value had a field + larger than expected */ + update->index->header->flags |= MAIL_INDEX_FLAG_REBUILD; + return FALSE; + } + memcpy(destrec->data, src, src_size); + /* memory alignment fix */ destrec->full_field_size = MEM_ALIGN(destrec->full_field_size); @@ -152,7 +185,7 @@ /* append the data at the end of the data file */ fpos = mail_index_data_append(update->index->data, mem, pos); - if (fpos == -1) + if (fpos == 0) return FALSE; /* update index file position - it's mmap()ed so it'll be writte @@ -177,10 +210,11 @@ index = mail_field_get_index(rec->field); i_assert(index >= 0); - i_assert(update->field_sizes[index] < + i_assert(update->field_sizes[index] <= rec->full_field_size); - strcpy(rec->data, update->fields[index]); + memcpy(rec->data, update->fields[index], + update->field_sizes[index]); } rec = mail_index_data_next(update->index->data, update->rec, rec); @@ -391,7 +425,7 @@ /* we need to calculate virtual size of the body as well. message_parse_header() left the inbuf point to beginning of the body. */ - message_get_body_size(inbuf, &body_size, -1); + message_get_body_size(inbuf, &body_size, (uoff_t)-1); update->rec->full_virtual_size = hdr_size.virtual_size + body_size.virtual_size;
--- a/src/lib-index/mail-index.c Tue Aug 27 20:35:00 2002 +0300 +++ b/src/lib-index/mail-index.c Tue Aug 27 22:16:54 2002 +0300 @@ -53,7 +53,7 @@ /* partial write or corrupted - truncate the file to valid length */ index->mmap_length -= extra; - (void)ftruncate(index->fd, (off_t) index->mmap_length); + (void)ftruncate(index->fd, (off_t)index->mmap_length); } index->header = (MailIndexHeader *) index->mmap_base; @@ -371,7 +371,7 @@ if (hdr->compat_data[0] != MAIL_INDEX_COMPAT_FLAGS || hdr->compat_data[1] != sizeof(unsigned int) || hdr->compat_data[2] != sizeof(time_t) || - hdr->compat_data[3] != sizeof(off_t)) + hdr->compat_data[3] != sizeof(uoff_t)) return FALSE; /* check the version */ @@ -575,7 +575,7 @@ hdr->compat_data[0] = MAIL_INDEX_COMPAT_FLAGS; hdr->compat_data[1] = sizeof(unsigned int); hdr->compat_data[2] = sizeof(time_t); - hdr->compat_data[3] = sizeof(off_t); + hdr->compat_data[3] = sizeof(uoff_t); hdr->version = MAIL_INDEX_VERSION; hdr->indexid = ioloop_time; @@ -759,7 +759,7 @@ MailIndexHeader *hdr; MailIndexRecord *rec, *end_rec; unsigned int seq; - off_t seekpos; + uoff_t seekpos; if (lookup_seq == index->last_lookup_seq && index->last_lookup != NULL && index->last_lookup->uid != 0) { @@ -772,8 +772,8 @@ sizeof(MailIndexHeader)); seekpos = sizeof(MailIndexHeader) + - (off_t)(lookup_seq-1) * sizeof(MailIndexRecord); - if (seekpos > (off_t) (index->mmap_length - sizeof(MailIndexRecord))) { + (uoff_t)(lookup_seq-1) * sizeof(MailIndexRecord); + if (seekpos > index->mmap_length - sizeof(MailIndexRecord)) { /* out of range */ return NULL; } @@ -865,7 +865,7 @@ { MailIndexRecord *rec, *end_rec; unsigned int uid, last_try_uid; - off_t pos; + uoff_t pos; i_assert(index->lock_type != MAIL_LOCK_UNLOCK); i_assert(first_uid > 0 && last_uid > 0); @@ -1045,7 +1045,7 @@ static int mail_index_truncate(MailIndex *index) { /* truncate index file */ - if (ftruncate(index->fd, index->header->first_hole_position) < 0) + if (ftruncate(index->fd, (off_t)index->header->first_hole_position) < 0) return FALSE; /* update header */ @@ -1069,7 +1069,7 @@ unsigned int seq, int external_change) { MailIndexHeader *hdr; - off_t pos; + uoff_t pos; i_assert(index->lock_type == MAIL_LOCK_EXCLUSIVE); i_assert(rec->uid != 0); @@ -1103,14 +1103,12 @@ /* first deleted message in index */ hdr->first_hole_position = pos; hdr->first_hole_records = 1; - } else if ((off_t) (hdr->first_hole_position - - sizeof(MailIndexRecord)) == pos) { + } else if (hdr->first_hole_position - sizeof(MailIndexRecord) == pos) { /* deleted the previous record before hole */ hdr->first_hole_position -= sizeof(MailIndexRecord); hdr->first_hole_records++; - } else if ((off_t) (hdr->first_hole_position + - (hdr->first_hole_records * - sizeof(MailIndexRecord))) == pos) { + } else if (hdr->first_hole_position + + (hdr->first_hole_records * sizeof(MailIndexRecord)) == pos) { /* deleted the next record after hole */ hdr->first_hole_records++; update_first_hole_records(index); @@ -1169,7 +1167,7 @@ (*rec)->uid = index->header->next_uid++; pos = lseek(index->fd, 0, SEEK_END); - if (pos == -1) { + if (pos < 0) { index_set_error(index, "lseek() failed with file %s: %m", index->filepath); return FALSE; @@ -1185,7 +1183,7 @@ index_mark_flag_changes(index, *rec, 0, (*rec)->msg_flags); if (index->hash != NULL) - mail_hash_update(index->hash, (*rec)->uid, pos); + mail_hash_update(index->hash, (*rec)->uid, (uoff_t)pos); index->dirty_mmap = TRUE; if (!mmap_update(index))
--- a/src/lib-index/mail-index.h Tue Aug 27 20:35:00 2002 +0300 +++ b/src/lib-index/mail-index.h Tue Aug 27 22:16:54 2002 +0300 @@ -76,7 +76,7 @@ /* 0 = flags, 1 = sizeof(unsigned int), 2 = sizeof(time_t), - 3 = sizeof(off_t) */ + 3 = sizeof(uoff_t) */ unsigned int version; unsigned int indexid; @@ -84,7 +84,7 @@ unsigned int flags; unsigned int cache_fields; - off_t first_hole_position; + uoff_t first_hole_position; unsigned int first_hole_records; unsigned int uid_validity; @@ -104,7 +104,7 @@ struct _MailIndexDataHeader { unsigned int indexid; - off_t deleted_space; + uoff_t deleted_space; }; struct _MailIndexRecord { @@ -113,13 +113,13 @@ time_t internal_date; time_t sent_date; - off_t data_position; + uoff_t data_position; unsigned int data_size; unsigned int cached_fields; - off_t header_size; - off_t body_size; - off_t full_virtual_size; + uoff_t header_size; + uoff_t body_size; + uoff_t full_virtual_size; }; #define MSG_HAS_VALID_CRLF_DATA(rec) \ @@ -131,8 +131,11 @@ char data[MEM_ALIGN_SIZE]; /* variable size */ }; +#define SIZEOF_MAIL_INDEX_DATA \ + (sizeof(MailIndexDataRecord) - MEM_ALIGN_SIZE) + #define DATA_RECORD_SIZE(rec) \ - (sizeof(MailIndexDataRecord) - MEM_ALIGN_SIZE + (rec)->full_field_size) + (SIZEOF_MAIL_INDEX_DATA + (rec)->full_field_size) struct _MailIndex { int (*open)(MailIndex *index, int update_recent); @@ -272,7 +275,7 @@ unsigned int indexid; char *mbox_path; /* mbox-specific path to the actual mbox file */ - off_t mbox_size; /* last synced size of mbox file */ + uoff_t mbox_size; /* last synced size of mbox file */ int mbox_locks; int fd; /* opened index file */ @@ -354,11 +357,11 @@ /* Max. mmap()ed size for a message */ #define MAIL_MMAP_BLOCK_SIZE (1024*256) -/* off_t to index file for given record */ +/* uoff_t to index file for given record */ #define INDEX_FILE_POSITION(index, ptr) \ - ((off_t) ((char *) (ptr) - (char *) ((index)->mmap_base))) + ((uoff_t) ((char *) (ptr) - (char *) ((index)->mmap_base))) -/* index number for off_t position */ +/* index number for uoff_t position */ #define INDEX_POSITION_INDEX(pos) \ (((pos) - sizeof(MailIndexHeader)) / sizeof(MailIndexRecord))
--- a/src/lib-index/mail-messageset.c Tue Aug 27 20:35:00 2002 +0300 +++ b/src/lib-index/mail-messageset.c Tue Aug 27 22:16:54 2002 +0300 @@ -16,7 +16,7 @@ if (**str < '0' || **str > '9') break; - num = num*10 + **str - '0'; + num = num*10 + (**str - '0'); (*str)++; } @@ -172,7 +172,7 @@ const char **error) { MailIndexRecord *rec; - off_t pos; + uoff_t pos; const unsigned int *expunges; unsigned int seq; int expunges_found;
--- a/src/lib-index/mail-modifylog.c Tue Aug 27 20:35:00 2002 +0300 +++ b/src/lib-index/mail-modifylog.c Tue Aug 27 22:16:54 2002 +0300 @@ -134,7 +134,7 @@ /* partial write or corrupted - truncate the file to valid length */ log->mmap_length -= extra; - (void)ftruncate(log->fd, (off_t) log->mmap_length); + (void)ftruncate(log->fd, (off_t)log->mmap_length); } log->dirty_mmap = FALSE;
--- a/src/lib-index/maildir/maildir-sync.c Tue Aug 27 20:35:00 2002 +0300 +++ b/src/lib-index/maildir/maildir-sync.c Tue Aug 27 22:16:54 2002 +0300 @@ -151,8 +151,8 @@ return FALSE; } - file_changed = st.st_size != (off_t) (rec->body_size + - rec->header_size); + file_changed = (uoff_t)st.st_size != + rec->body_size + rec->header_size; } /* changed - update */
--- a/src/lib-index/mbox/mbox-append.c Tue Aug 27 20:35:00 2002 +0300 +++ b/src/lib-index/mbox/mbox-append.c Tue Aug 27 22:16:54 2002 +0300 @@ -81,7 +81,7 @@ MailIndexUpdate *update; MboxHeaderContext ctx; time_t internal_date; - off_t start_offset, stop_offset, old_size; + uoff_t start_offset, stop_offset, old_size; unsigned char *data, md5_digest[16]; unsigned int size, pos, virtual_size; const char *location;
--- a/src/lib-index/mbox/mbox-from.c Tue Aug 27 20:35:00 2002 +0300 +++ b/src/lib-index/mbox/mbox-from.c Tue Aug 27 22:16:54 2002 +0300 @@ -1,6 +1,7 @@ /* Copyright (C) 2002 Timo Sirainen */ #include "lib.h" +#include "mbox-index.h" #include <time.h> #include <ctype.h> @@ -94,7 +95,7 @@ { struct tm *tm; char *ret, *p; - int len, year; + unsigned int len, year; len = strlen(sender); ret = t_malloc(len + 24 + 1);
--- a/src/lib-index/mbox/mbox-fsck.c Tue Aug 27 20:35:00 2002 +0300 +++ b/src/lib-index/mbox/mbox-fsck.c Tue Aug 27 22:16:54 2002 +0300 @@ -37,7 +37,7 @@ { MessageSize hdr_size; MboxHeaderContext ctx; - off_t body_offset; + uoff_t body_offset; unsigned char *data, current_digest[16], old_digest[16]; unsigned int size; const char *md5sum; @@ -101,7 +101,7 @@ static int mbox_index_fsck_buf(MailIndex *index, IOBuffer *inbuf) { MailIndexRecord *rec; - off_t from_offset; + uoff_t from_offset; unsigned char *data; unsigned int seq, size; @@ -178,7 +178,7 @@ } inbuf = io_buffer_create_mmap(fd, default_pool, - MAIL_MMAP_BLOCK_SIZE, -1); + MAIL_MMAP_BLOCK_SIZE, 0); /* lock the mailbox so we can be sure no-one interrupts us. we are trying to repair our index after all. */
--- a/src/lib-index/mbox/mbox-open.c Tue Aug 27 20:35:00 2002 +0300 +++ b/src/lib-index/mbox/mbox-open.c Tue Aug 27 22:16:54 2002 +0300 @@ -13,7 +13,8 @@ IOBuffer *mbox_open_mail(MailIndex *index, MailIndexRecord *rec) { const char *location; - off_t pos, offset, stop_offset; + uoff_t offset, stop_offset; + off_t pos; char buf[7], *p; int fd, ret, failed; @@ -30,7 +31,8 @@ /* location = offset in hex */ if (strlen(location) != sizeof(offset)*2 || - hex_to_binary(location, (unsigned char *) &offset) <= 0) { + hex_to_binary(location, (unsigned char *) &offset) <= 0 || + offset > OFF_T_MAX) { INDEX_MARK_CORRUPTED(index); index_set_error(index, "Corrupted index file %s: " "Invalid location field for record %u", @@ -47,7 +49,7 @@ return NULL; } - pos = lseek(fd, offset, SEEK_SET); + pos = lseek(fd, (off_t)offset, SEEK_SET); if (pos == -1) { index_set_error(index, "lseek() failed with mbox file %s: %m", index->mbox_path); @@ -56,9 +58,10 @@ } failed = TRUE; - if (pos == offset) { + if ((uoff_t)pos == offset) { /* make sure message size is valid */ - if (lseek(fd, stop_offset, SEEK_SET) == stop_offset) { + if (lseek(fd, (off_t)stop_offset, SEEK_SET) == + (off_t)stop_offset) { /* and check that we end with either EOF or to beginning of next message */ ret = read(fd, buf, 7); @@ -79,7 +82,7 @@ } if (!failed) { - if (lseek(fd, offset, SEEK_SET) == offset) { + if (lseek(fd, (off_t)offset, SEEK_SET) == (off_t)offset) { /* everything ok */ return io_buffer_create_mmap(fd, default_pool, MAIL_MMAP_BLOCK_SIZE,
--- a/src/lib-index/mbox/mbox-rebuild.c Tue Aug 27 20:35:00 2002 +0300 +++ b/src/lib-index/mbox/mbox-rebuild.c Tue Aug 27 22:16:54 2002 +0300 @@ -67,7 +67,7 @@ } inbuf = io_buffer_create_mmap(fd, default_pool, - MAIL_MMAP_BLOCK_SIZE, -1); + MAIL_MMAP_BLOCK_SIZE, 0); if (!mbox_index_append(index, inbuf)) { (void)mbox_unlock(index, index->mbox_path, fd); (void)close(fd);
--- a/src/lib-index/mbox/mbox-sync.c Tue Aug 27 20:35:00 2002 +0300 +++ b/src/lib-index/mbox/mbox-sync.c Tue Aug 27 22:16:54 2002 +0300 @@ -11,11 +11,11 @@ #include <fcntl.h> #include <sys/stat.h> -static off_t get_indexed_mbox_size(MailIndex *index) +static uoff_t get_indexed_mbox_size(MailIndex *index) { MailIndexRecord *rec, *prev; const char *location; - off_t size; + uoff_t size; if (index->lock_type == MAIL_LOCK_UNLOCK) { if (!mail_index_set_lock(index, MAIL_LOCK_SHARED)) @@ -59,6 +59,12 @@ if (index->lock_type == MAIL_LOCK_SHARED) (void)mail_index_set_lock(index, MAIL_LOCK_UNLOCK); + + if (size > OFF_T_MAX) { + /* too large to fit in off_t */ + return 0; + } + return size; } @@ -75,7 +81,7 @@ return FALSE; } - pos = lseek(fd, index->mbox_size, SEEK_SET); + pos = lseek(fd, (off_t)index->mbox_size, SEEK_SET); if (pos == -1) { index_set_error(index, "lseek() failed with mbox file %s: %m", index->mbox_path); @@ -83,7 +89,7 @@ return FALSE; } - if (pos != index->mbox_size) { + if ((uoff_t)pos != index->mbox_size) { /* someone just shrinked the file? */ (void)close(fd); return mbox_index_fsck(index); @@ -91,7 +97,7 @@ /* add the new data */ inbuf = io_buffer_create_mmap(fd, default_pool, - MAIL_MMAP_BLOCK_SIZE, -1); + MAIL_MMAP_BLOCK_SIZE, 0); ret = mbox_index_append(index, inbuf); (void)close(fd); io_buffer_destroy(inbuf); @@ -126,7 +132,7 @@ index->mbox_size = get_indexed_mbox_size(index); /* file has been modified. */ - if (index->mbox_size > st.st_size) { + if (index->mbox_size > (uoff_t)st.st_size) { /* file was grown, hopefully just new mail */ return mbox_check_new_mail(index); } else {
--- a/src/lib-mail/message-parser.c Tue Aug 27 20:35:00 2002 +0300 +++ b/src/lib-mail/message-parser.c Tue Aug 27 22:16:54 2002 +0300 @@ -188,7 +188,7 @@ MessageParseContext *parse_ctx) { MessagePart *next_part, *part; - size_t hdr_size; + uoff_t hdr_size; message_parse_header(parse_ctx->part, inbuf, &parse_ctx->part->header_size, @@ -550,7 +550,7 @@ MessageBoundary *boundary; if (boundaries == NULL) { - message_get_body_size(inbuf, body_size, -1); + message_get_body_size(inbuf, body_size, (uoff_t)-1); return NULL; } else { boundary = message_find_boundary(inbuf, boundaries,
--- a/src/lib-mail/message-parser.h Tue Aug 27 20:35:00 2002 +0300 +++ b/src/lib-mail/message-parser.h Tue Aug 27 22:16:54 2002 +0300 @@ -6,13 +6,13 @@ typedef struct _MessageSize MessageSize; struct _MessagePosition { - off_t physical_pos; - off_t virtual_pos; + uoff_t physical_pos; + uoff_t virtual_pos; }; struct _MessageSize { - size_t physical_size; - size_t virtual_size; + uoff_t physical_size; + uoff_t virtual_size; unsigned int lines; };
--- a/src/lib-mail/message-send.c Tue Aug 27 20:35:00 2002 +0300 +++ b/src/lib-mail/message-send.c Tue Aug 27 22:16:54 2002 +0300 @@ -8,18 +8,17 @@ #define OUTPUT_BUFFER_SIZE 1024 int message_send(IOBuffer *outbuf, IOBuffer *inbuf, MessageSize *msg_size, - off_t virtual_skip, off_t max_virtual_size) + uoff_t virtual_skip, uoff_t max_virtual_size) { unsigned char *msg, buf[OUTPUT_BUFFER_SIZE]; unsigned int i, size, pos; int cr_skipped, add_cr; if (msg_size->physical_size == 0 || - virtual_skip >= (off_t)msg_size->virtual_size) + virtual_skip >= msg_size->virtual_size) return TRUE; - if (max_virtual_size == -1 || - max_virtual_size > (off_t)msg_size->virtual_size - virtual_skip) + if (max_virtual_size > msg_size->virtual_size - virtual_skip) max_virtual_size = msg_size->virtual_size - virtual_skip; if (msg_size->physical_size == msg_size->virtual_size) {
--- a/src/lib-mail/message-send.h Tue Aug 27 20:35:00 2002 +0300 +++ b/src/lib-mail/message-send.h Tue Aug 27 22:16:54 2002 +0300 @@ -3,10 +3,10 @@ #include "message-parser.h" -/* Send message to client inserting CRs if needed. If max_virtual_size is - not negative, only that much of the message is sent (relative to - virtual_skip). Returns TRUE if successful. */ +/* Send message to client inserting CRs if needed. Only max_virtual_size + bytes if sent (relative to virtual_skip), if you want it unlimited, + use (uoff_t)-1. Returns TRUE if successful. */ int message_send(IOBuffer *outbuf, IOBuffer *inbuf, MessageSize *msg_size, - off_t virtual_skip, off_t max_virtual_size); + uoff_t virtual_skip, uoff_t max_virtual_size); #endif
--- a/src/lib-mail/message-size.c Tue Aug 27 20:35:00 2002 +0300 +++ b/src/lib-mail/message-size.c Tue Aug 27 22:16:54 2002 +0300 @@ -58,7 +58,7 @@ } void message_get_body_size(IOBuffer *inbuf, MessageSize *body, - off_t max_virtual_size) + uoff_t max_virtual_size) { unsigned char *msg; unsigned int i, size, startpos, missing_cr_count; @@ -107,7 +107,7 @@ i_assert(body->virtual_size >= body->physical_size); } -void message_skip_virtual(IOBuffer *inbuf, off_t virtual_skip, +void message_skip_virtual(IOBuffer *inbuf, uoff_t virtual_skip, MessageSize *msg_size, int *cr_skipped) { unsigned char *msg;
--- a/src/lib-mail/message-size.h Tue Aug 27 20:35:00 2002 +0300 +++ b/src/lib-mail/message-size.h Tue Aug 27 22:16:54 2002 +0300 @@ -6,15 +6,15 @@ /* Calculate size of message header. Leave the inbuf point to first character in body. */ void message_get_header_size(IOBuffer *inbuf, MessageSize *hdr); -/* Calculate size of message body. Read only max_virtual_size virtual bytes - if it's >= 0. */ +/* Calculate size of message body. Read only max_virtual_size virtual bytes, + if you want it unlimited, use (uoff_t)-1. */ void message_get_body_size(IOBuffer *inbuf, MessageSize *body, - off_t max_virtual_size); + uoff_t max_virtual_size); /* Skip number of virtual bytes from buffer. If first character is \n, and cr_skipped is FALSE, \r must be sent before it. msg_size is updated if it's not NULL. */ -void message_skip_virtual(IOBuffer *inbuf, off_t virtual_skip, +void message_skip_virtual(IOBuffer *inbuf, uoff_t virtual_skip, MessageSize *msg_size, int *cr_skipped); /* Sum contents of src into dest. */
--- a/src/lib-storage/flags-file/flags-file.c Tue Aug 27 20:35:00 2002 +0300 +++ b/src/lib-storage/flags-file/flags-file.c Tue Aug 27 22:16:54 2002 +0300 @@ -80,7 +80,8 @@ static void flags_file_sync(FlagsFile *ff) { char *data, *data_end, *line; - int i, num; + unsigned int num; + int i; memcpy(ff->sync_counter, ff->mmap_base, COUNTER_SIZE); @@ -110,12 +111,12 @@ continue; num = 0; - while (data != data_end && i_isdigit(*data)) { - num = num*10 + *data-'0'; + while (data != data_end && *data >= '0' && *data <= '9') { + num = num*10 + (*data-'0'); data++; } - if (num >= 0 && num < MAIL_CUSTOM_FLAGS_COUNT) { + if (num < MAIL_CUSTOM_FLAGS_COUNT) { /* get the name */ if (data == data_end || *data != ' ') continue; @@ -334,10 +335,11 @@ return TRUE; } -static int flags_file_remove(FlagsFile *ff, int idx) +static int flags_file_remove(FlagsFile *ff, unsigned int idx) { char *data, *data_end, *line; - int num, pos, linelen; + unsigned int num; + int pos, linelen; data = ff->mmap_base; data_end = data + ff->mmap_length; @@ -354,8 +356,8 @@ line = ++data; num = 0; - while (data != data_end && i_isdigit(*data)) { - num = num*10 + *data-'0'; + while (data != data_end && *data >= '0' && *data <= '9') { + num = num*10 + (*data-'0'); data++; } @@ -397,7 +399,7 @@ static void remove_unused_custom_flags(FlagsFile *ff, MailFlags used_flags) { - int i; + unsigned int i; for (i = 0; i < MAIL_CUSTOM_FLAGS_COUNT; i++) { if ((used_flags & (1 << (i + MAIL_CUSTOM_FLAG_1_BIT))) == 0) {
--- a/src/lib-storage/index/index-fetch-section.c Tue Aug 27 20:35:00 2002 +0300 +++ b/src/lib-storage/index/index-fetch-section.c Tue Aug 27 22:16:54 2002 +0300 @@ -234,13 +234,13 @@ i_assert(len <= size->virtual_size); - if ((off_t)len <= sect->skip) + if (len <= sect->skip) len = 0; else { dest += sect->skip; len -= sect->skip; - if (sect->max_size >= 0 && (off_t)len > sect->max_size) + if (len > sect->max_size) len = sect->max_size; } @@ -272,7 +272,7 @@ { MessagePart *part; const char *path; - int num; + unsigned int num; part = imap_msgcache_get_parts(ctx->cache, rec->uid); @@ -283,7 +283,7 @@ while (*path != '\0' && *path != '.') { if (*path < '0' || *path > '9') return NULL; - num = num*10 + *path - '0'; + num = num*10 + (*path - '0'); path++; } @@ -312,14 +312,13 @@ { IOBuffer *inbuf; const char *str; - off_t skip_pos; + uoff_t skip_pos; if (!imap_msgcache_get_data(ctx->cache, uid, &inbuf)) return FALSE; /* jump to beginning of wanted data */ - skip_pos = (off_t) (part->pos.physical_pos + - part->header_size.physical_size); + skip_pos = part->pos.physical_pos + part->header_size.physical_size; io_buffer_skip(inbuf, skip_pos); str = t_strdup_printf("{%lu}\r\n",
--- a/src/lib-storage/index/index-fetch.c Tue Aug 27 20:35:00 2002 +0300 +++ b/src/lib-storage/index/index-fetch.c Tue Aug 27 22:16:54 2002 +0300 @@ -106,7 +106,7 @@ body_size.physical_size += hdr_size.physical_size; body_size.virtual_size += hdr_size.virtual_size; - (void)message_send(ctx->outbuf, inbuf, &body_size, 0, -1); + (void)message_send(ctx->outbuf, inbuf, &body_size, 0, (uoff_t)-1); } static void index_fetch_rfc822_header(MailIndexRecord *rec, FetchContext *ctx) @@ -125,7 +125,7 @@ str = t_strdup_printf(" RFC822.HEADER {%lu}\r\n", (unsigned long) hdr_size.virtual_size); (void)io_buffer_send(ctx->outbuf, str, strlen(str)); - (void)message_send(ctx->outbuf, inbuf, &hdr_size, 0, -1); + (void)message_send(ctx->outbuf, inbuf, &hdr_size, 0, (uoff_t)-1); } static void index_fetch_rfc822_text(MailIndexRecord *rec, FetchContext *ctx) @@ -144,7 +144,7 @@ str = t_strdup_printf(" RFC822.TEXT {%lu}\r\n", (unsigned long) body_size.virtual_size); (void)io_buffer_send(ctx->outbuf, str, strlen(str)); - (void)message_send(ctx->outbuf, inbuf, &body_size, 0, -1); + (void)message_send(ctx->outbuf, inbuf, &body_size, 0, (uoff_t)-1); } static ImapCacheField index_get_cache(MailFetchData *fetch_data)
--- a/src/lib-storage/index/index-save.c Tue Aug 27 20:35:00 2002 +0300 +++ b/src/lib-storage/index/index-save.c Tue Aug 27 22:16:54 2002 +0300 @@ -11,15 +11,17 @@ static int write_with_crlf(int fd, const unsigned char *data, unsigned int size, unsigned int *last_cr) { - unsigned int i, cr; + int i, cr; + + i_assert(size < INT_MAX); cr = *last_cr ? -1 : -2; - for (i = 0; i < size; i++) { + for (i = 0; i < (int)size; i++) { if (data[i] == '\r') cr = i; else if (data[i] == '\n' && cr != i-1) { /* missing CR */ - if (write_full(fd, data, i) < 0) + if (write_full(fd, data, (unsigned int) i) < 0) return FALSE; if (write_full(fd, "\r", 1) < 0) return FALSE;
--- a/src/lib-storage/index/index-search.c Tue Aug 27 20:35:00 2002 +0300 +++ b/src/lib-storage/index/index-search.c Tue Aug 27 22:16:54 2002 +0300 @@ -98,18 +98,16 @@ return FALSE; } -static off_t str_to_off_t(const char *str) +static uoff_t str_to_uoff_t(const char *str) { - off_t num; + uoff_t num; num = 0; while (*str != '\0') { if (*str < '0' || *str > '9') - return -1; + return 0; - /* FIXME: this may overflow, and ANSI-C says overflowing - signed values have undefined behaviour.. */ - num = num*10 + *str - '0'; + num = num*10 + (*str - '0'); } return num; @@ -180,9 +178,9 @@ /* sizes */ case SEARCH_SMALLER: - return rec->full_virtual_size < str_to_off_t(value); + return rec->full_virtual_size < str_to_uoff_t(value); case SEARCH_LARGER: - return rec->full_virtual_size > str_to_off_t(value); + return rec->full_virtual_size > str_to_uoff_t(value); default: return -1; @@ -505,7 +503,7 @@ } if (have_text || have_body) { - if (inbuf->offset != (off_t)rec->header_size) { + if (inbuf->offset != rec->header_size) { /* skip over headers */ i_assert(inbuf->offset == 0); io_buffer_skip(inbuf, rec->header_size);
--- a/src/lib-storage/mail-storage.h Tue Aug 27 20:35:00 2002 +0300 +++ b/src/lib-storage/mail-storage.h Tue Aug 27 22:16:54 2002 +0300 @@ -208,7 +208,8 @@ MailFetchBodyData *next; const char *section; /* NOTE: always uppercased */ - off_t skip, max_size; /* max_size is ignored if it's < 0 */ + uoff_t skip, max_size; /* if you don't want max_size, + set it to (uoff_t)-1 */ unsigned int skip_set:1; unsigned int peek:1; };
--- a/src/lib/iobuffer.c Tue Aug 27 20:35:00 2002 +0300 +++ b/src/lib/iobuffer.c Tue Aug 27 22:16:54 2002 +0300 @@ -65,9 +65,10 @@ } IOBuffer *io_buffer_create_mmap(int fd, Pool pool, unsigned int block_size, - off_t size) + uoff_t size) { IOBuffer *buf; + off_t start_offset, stop_offset; /* block size must be page aligned, and at least two pages long */ if (mmap_pagesize == 0) { @@ -87,15 +88,19 @@ buf->receive = TRUE; /* set offsets */ - buf->start_offset = lseek(fd, 0, SEEK_CUR); - buf->size = size > 0 ? size : - lseek(fd, 0, SEEK_END) - buf->start_offset; + start_offset = lseek(fd, 0, SEEK_CUR); + stop_offset = lseek(fd, 0, SEEK_END); - if (buf->start_offset < 0 || buf->size < 0) { + if (start_offset < 0 || stop_offset < 0) { i_error("io_buffer_create_mmap(): lseek() failed: %m"); buf->start_offset = buf->size = 0; } + buf->start_offset = start_offset; + buf->size = size > 0 ? size : + start_offset > stop_offset ? 0 : + stop_offset - start_offset; + buf->skip = buf->pos = buf->start_offset; return buf; } @@ -555,7 +560,7 @@ return -1; outbuf->offset += ret; - io_buffer_skip(inbuf, ret); + io_buffer_skip(inbuf, (unsigned int)ret); if ((unsigned int) ret == size) { /* all sent */ return 1; @@ -595,12 +600,13 @@ buf->flush_context = context; } -int io_buffer_read_mmaped(IOBuffer *buf, unsigned int size) +static int io_buffer_read_mmaped(IOBuffer *buf, unsigned int size) { - off_t stop_offset, aligned_skip; + uoff_t stop_offset; + unsigned int aligned_skip; - stop_offset = buf->size + buf->start_offset; - if (stop_offset - buf->mmap_offset <= (off_t)buf->buffer_size) { + stop_offset = buf->start_offset + buf->size; + if (stop_offset - buf->mmap_offset <= buf->buffer_size) { /* end of file is already mapped */ return -1; } @@ -694,7 +700,7 @@ return io_buffer_read_max(buf, UINT_MAX); } -void io_buffer_skip(IOBuffer *buf, unsigned int size) +void io_buffer_skip(IOBuffer *buf, uoff_t size) { int ret; @@ -723,15 +729,13 @@ size -= ret; } - (void)io_buffer_read_max(buf, size); + (void)io_buffer_read_max(buf, (unsigned int)size); } } -int io_buffer_seek(IOBuffer *buf, off_t offset) +int io_buffer_seek(IOBuffer *buf, uoff_t offset) { - off_t real_offset; - - i_assert(offset >= 0); + uoff_t real_offset; if (buf->mmaped) { /* first reset everything */ @@ -743,7 +747,13 @@ buf->pos = buf->skip = offset; } else { real_offset = buf->start_offset + offset; - if (lseek(buf->fd, real_offset, SEEK_SET) != real_offset) + if (real_offset > OFF_T_MAX) { + errno = EINVAL; + return FALSE; + } + + if (lseek(buf->fd, (off_t)real_offset, SEEK_SET) != + (off_t)real_offset) return FALSE; }
--- a/src/lib/iobuffer.h Tue Aug 27 20:35:00 2002 +0300 +++ b/src/lib/iobuffer.h Tue Aug 27 22:16:54 2002 +0300 @@ -10,8 +10,8 @@ struct _IOBuffer { int fd; - off_t start_offset; - off_t offset, size; /* virtual offset, 0 = start_offset */ + uoff_t start_offset; + uoff_t offset, size; /* virtual offset, 0 = start_offset */ /* private: */ Pool pool; @@ -53,7 +53,7 @@ /* Read the file by mmap()ing it in blocks. stop_offset specifies where to stop reading, or 0 to end of file. */ IOBuffer *io_buffer_create_mmap(int fd, Pool pool, unsigned int block_size, - off_t size); + uoff_t size); /* Destroy a buffer. */ void io_buffer_destroy(IOBuffer *buf); /* Mark the buffer closed. Any sends/reads after this will return -1. @@ -102,10 +102,10 @@ /* Like io_buffer_read(), but don't read more than specified size. */ int io_buffer_read_max(IOBuffer *buf, unsigned int size); /* Skip forward a number of bytes */ -void io_buffer_skip(IOBuffer *buf, unsigned int size); +void io_buffer_skip(IOBuffer *buf, uoff_t size); /* Seek to specified position from beginning of file. This works only for files. Returns TRUE if successful. */ -int io_buffer_seek(IOBuffer *buf, off_t offset); +int io_buffer_seek(IOBuffer *buf, uoff_t offset); /* Returns the next line from input buffer, or NULL if more data is needed to make a full line. NOTE: call to io_buffer_read() invalidates the returned data. */
--- a/src/lib/lib.h Tue Aug 27 20:35:00 2002 +0300 +++ b/src/lib/lib.h Tue Aug 27 22:16:54 2002 +0300 @@ -19,6 +19,17 @@ #ifdef HAVE_CONFIG_H # include "../../config.h" #endif + +#if defined (UOFF_T_INT) +typedef unsigned int uoff_t; +#elif defined (UOFF_T_LONG) +typedef unsigned long uoff_t; +#elif defined (UOFF_T_LONG_LONG) +typedef unsigned long long uoff_t; +#else +# error uoff_t size not set +#endif + #include "compat.h" #include "macros.h" #include "failures.h"
--- a/src/lib/strfuncs.c Tue Aug 27 20:35:00 2002 +0300 +++ b/src/lib/strfuncs.c Tue Aug 27 22:16:54 2002 +0300 @@ -164,7 +164,7 @@ while (c >= '0' && c <= '9') { format++; - v_uint = v_uint * 10 + c - '0'; + v_uint = v_uint * 10 + (c - '0'); c = *format; } if (spec.seen_precision)
--- a/src/lib/temp-string.c Tue Aug 27 20:35:00 2002 +0300 +++ b/src/lib/temp-string.c Tue Aug 27 22:16:54 2002 +0300 @@ -54,8 +54,14 @@ RealTempString *rstr = (RealTempString *) tstr; char *str; - if (rstr->len + size + 1 > rstr->alloc_size) { - rstr->alloc_size = nearest_power(rstr->len + size + 1); + size += rstr->len + 1; + if (size <= rstr->len || size > INT_MAX) { + /* overflow */ + i_panic("t_string_inc(): Out of memory for %u bytes", size); + } + + if (size > rstr->alloc_size) { + rstr->alloc_size = nearest_power(size); if (!t_try_grow(rstr->str, rstr->alloc_size)) { str = t_malloc(rstr->alloc_size);