From 8b800094af89c9a0ef0b2a51838e835375204a05 Mon Sep 17 00:00:00 2001 From: Thomas Schmitt Date: Tue, 18 Aug 2009 17:03:33 +0200 Subject: [PATCH] Verifying checksum tags of superblock and tree if available and enabled. New API call iso_md5_match(). --- libisofs/fs_image.c | 75 +++++++++++++++++++++++++++++++++++++-- libisofs/libisofs.h | 52 +++++++++++++++++++++++++-- libisofs/md5.c | 25 ++++++++----- libisofs/messages.c | 12 ++++++- libisofs/util.c | 86 +++++++++++++++++++++++++++++++++++++++------ libisofs/util.h | 24 +++++++++++++ 6 files changed, 249 insertions(+), 25 deletions(-) diff --git a/libisofs/fs_image.c b/libisofs/fs_image.c index 535975d..5382c69 100644 --- a/libisofs/fs_image.c +++ b/libisofs/fs_image.c @@ -2278,15 +2278,83 @@ int read_el_torito_boot_catalog(_ImageFsData *data, uint32_t block) return ISO_SUCCESS; } + +/* + @return 1= ok, checked, go on with loading + 2= no checksum tags found, go on with loading + <0= libisofs error + especially ISO_SB_TREE_CORRUPTED +*/ static int iso_src_check_sb_tree(IsoDataSource *src, uint32_t start_lba, int flag) { + int tag_type, ret; + char block[2048], md5[16]; + int desired = (1 << 2); + void *ctx = NULL; + uint32_t next_tag = 0, i; + + ret = iso_md5_start(&ctx); + if (ret < 0) + goto ex; + if (start_lba == 0) + desired |= (1 << 4); + for (i = 0; i < 32; i++) { + ret = src->read_block(src, start_lba + i, (uint8_t *) block); + if (ret < 0) + goto ex; + ret = 0; + if (i >= 16) + ret = iso_util_eval_md5_tag(block, desired, start_lba + i, + ctx, start_lba, &tag_type, &next_tag, 0); + iso_md5_compute(ctx, block, 2048); + if (ret == ISO_MD5_AREA_CORRUPTED || ret == ISO_MD5_TAG_MISMATCH) + ret = ISO_SB_TREE_CORRUPTED; + if (ret < 0) + goto ex; + if (ret == 1) + break; + } + if (i >= 32) { + ret = 2; + goto ex; + } + if (tag_type == 4) { + /* Relocated Superblock: restart checking at real session start */ + if (next_tag < 32) { + /* Non plausible session_start address */ + iso_msg_submit(-1, ret, 0, NULL); + ret = ISO_SB_TREE_CORRUPTED; + goto ex; + } + /* Check real session */ + ret = iso_src_check_sb_tree(src, next_tag, 0); + goto ex; + } - /* >>>> */; + /* Go on with tree */ + for (i++; start_lba + i <= next_tag; i++) { + ret = src->read_block(src, start_lba + i, (uint8_t *) block); + if (ret < 0) + goto ex; + if (start_lba + i < next_tag) + iso_md5_compute(ctx, block, 2048); + } + ret = iso_util_eval_md5_tag(block, (1 << 3), start_lba + i - 1, + ctx, start_lba, &tag_type, &next_tag, 0); + if (ret == ISO_MD5_AREA_CORRUPTED || ret == ISO_MD5_TAG_MISMATCH) + ret = ISO_SB_TREE_CORRUPTED; + if (ret < 0) + goto ex; - return 2; + ret = 1; +ex: + if (ctx != NULL) + iso_md5_end(&ctx, md5); + return ret; } + int iso_image_filesystem_new(IsoDataSource *src, struct iso_read_opts *opts, int msgid, IsoImageFilesystem **fs) { @@ -2355,12 +2423,13 @@ int iso_image_filesystem_new(IsoDataSource *src, struct iso_read_opts *opts, if (data->md5_load) { - /* >>> From opts->block on : check for superblock and tree tags */; + /* From opts->block on : check for superblock and tree tags */; ret = iso_src_check_sb_tree(src, opts->block, 0); if (ret <= 0) { /* >>> refuse to load, hint towards loading without MD5 check */; + goto fs_cleanup; } } diff --git a/libisofs/libisofs.h b/libisofs/libisofs.h index 38e6518..3663e75 100644 --- a/libisofs/libisofs.h +++ b/libisofs/libisofs.h @@ -5169,6 +5169,20 @@ int iso_md5_clone(void *old_md5_context, void **new_md5_context); */ int iso_md5_end(void **md5_context, char result[16]); +/** + * Inquire whether two MD5 checksums match. (This is trivial but such a call + * is convenient and completes the interface.) + * @param first_md5 + * A MD5 byte string as returned by iso_md5_end() + * @param second_md5 + * A MD5 byte string as returned by iso_md5_end() + * @return + * 1= match , 0= mismatch + * + * @since 0.6.22 + */ +int iso_md5_match(char first_md5[16], char second_md5[16]); + /************ Error codes and return values for libisofs ********************/ @@ -5426,11 +5440,43 @@ int iso_md5_end(void **md5_context, char result[16]); #define ISO_ZLIB_EARLY_EOF 0xE830FEA1 /** - * Checksum area appears damaged and not trustworthy for verifications. - * (WARNING,HIGH, -352) + * Checksum area or checksum tag appear corrupted (WARNING,HIGH, -352) * @since 0.6.22 */ -#define ISO_MD5_AREA_CORRUPTED 0xD030FEA0 +#define ISO_MD5_AREA_CORRUPTED 0xD030FEA0 + +/** + * Checksum mismatch between checksum tag and data blocks + * (FAILURE, HIGH, -353) + * @since 0.6.22 +*/ +#define ISO_MD5_TAG_MISMATCH 0xE830FE9F + +/** + * Checksum mismatch in System Area, Volume Descriptors, or directory tree. + * (FAILURE, HIGH, -354) + * @since 0.6.22 +*/ +#define ISO_SB_TREE_CORRUPTED 0xE830FE9E + +/** + * Unexpected checksum tag type encountered. (WARNING, HIGH, -355) + * @since 0.6.22 +*/ +#define ISO_MD5_TAG_UNEXPECTED 0xD030FE9D + +/** + * Misplaced checksum tag encountered. (WARNING, HIGH, -356) + * @since 0.6.22 +*/ +#define ISO_MD5_TAG_MISPLACED 0xD030FE9C + +/** + * Checksum tag with unexpected address range encountered. + * (WARNING, HIGH, -357) + * @since 0.6.22 +*/ +#define ISO_MD5_TAG_OTHER_RANGE 0xD030FE9B /* ! PLACE NEW ERROR CODES HERE ! */ diff --git a/libisofs/md5.c b/libisofs/md5.c index cf8a2c7..8be90b3 100644 --- a/libisofs/md5.c +++ b/libisofs/md5.c @@ -16,6 +16,7 @@ #include "messages.h" #include "ecma119.h" #include "image.h" +#include "util.h" #include "md5.h" @@ -386,6 +387,18 @@ int iso_md5_end(void **md5_context, char result[16]) } +/* API */ +int iso_md5_match(char first_md5[16], char second_md5[16]) +{ + int i; + + for (i= 0; i < 16; i++) + if (first_md5[i] != second_md5[i]) + return 0; + return 1; +} + + /* ----------------------------------------------------------------------- */ @@ -667,15 +680,10 @@ int iso_md5_write_tag(Ecma119Image *t, int flag) #ifdef Libisofs_with_checksumS - int res, mode, l, i, wres; + int res, mode, l, i, wres, tag_id_len; void *ctx = NULL; - char md5[16], tag_block[2048]; + char md5[16], tag_block[2048], *tag_id; uint32_t size = 0, pos = 0, start; - static char *tag_ids[] = {"", - "libisofs_checksum_tag_v1", - "libisofs_sb_checksum_tag_v1", - "libisofs_tree_checksum_tag_v1", - "libisofs_rlsb32_checksum_tag_v1"}; start = t->checksum_range_start; memset(tag_block, 0, 2048); @@ -702,9 +710,10 @@ int iso_md5_write_tag(Ecma119Image *t, int flag) return ISO_WRONG_ARG_VALUE; } if (res > 0) { + iso_util_tag_magic(mode, &tag_id, &tag_id_len, 0); sprintf(tag_block, "%s pos=%u range_start=%u range_size=%u", - tag_ids[mode], pos, start, size); + tag_id, pos, start, size); l = strlen(tag_block); if (mode == 2) { diff --git a/libisofs/messages.c b/libisofs/messages.c index 229a8dc..99941ba 100644 --- a/libisofs/messages.c +++ b/libisofs/messages.c @@ -261,7 +261,17 @@ const char *iso_error_to_msg(int errcode) case ISO_ZLIB_EARLY_EOF: return "Premature EOF of zlib input stream"; case ISO_MD5_AREA_CORRUPTED: - return "Checksum area appears damaged and not trustworthy for verifications"; + return "Checksum area or checksum tag appear corrupted"; + case ISO_MD5_TAG_MISMATCH: + return "Checksum mismatch between checksum tag and data blocks"; + case ISO_SB_TREE_CORRUPTED: + return "Checksum mismatch in System Area, Volume Descriptors, or directory tree"; + case ISO_MD5_TAG_UNEXPECTED: + return "Unexpected checksum tag type encountered"; + case ISO_MD5_TAG_MISPLACED: + return "Misplaced checksum tag type encountered"; + case ISO_MD5_TAG_OTHER_RANGE: + return "Checksum tag with unexpected address range encountered"; default: return "Unknown error"; } diff --git a/libisofs/util.c b/libisofs/util.c index b2bb1cd..dfd7cac 100644 --- a/libisofs/util.c +++ b/libisofs/util.c @@ -9,6 +9,7 @@ #include "util.h" #include "libisofs.h" +#include "messages.h" #include "../version.h" #include @@ -1563,18 +1564,33 @@ int iso_util_hex_to_bin(char *hex, char *bin, int bin_size, int *bin_count, } +int iso_util_tag_magic(int tag_type, char **tag_magic, int *len, int flag) +{ + static char *magic[] = {"", + "libisofs_checksum_tag_v1", + "libisofs_sb_checksum_tag_v1", + "libisofs_tree_checksum_tag_v1", + "libisofs_rlsb32_checksum_tag_v1"}; + static int magic_len[]= {0, 24, 27, 29, 31}; + static int magic_max = 4; + + *tag_magic = NULL; + *len = 0; + if (tag_type < 0 || tag_type > magic_max) + return ISO_WRONG_ARG_VALUE; + *tag_magic = magic[tag_type]; + *len = magic_len[tag_type]; + return magic_max; +} + + int iso_util_decode_md5_tag(char data[2048], int *tag_type, uint32_t *pos, uint32_t *range_start, uint32_t *range_size, uint32_t *next_tag, char md5[16], int flag) { - static char *tag_magic[] = {"", - "libisofs_checksum_tag_v1", - "libisofs_sb_checksum_tag_v1", - "libisofs_tree_checksum_tag_v1", - "libisofs_rlsb32_checksum_tag_v1"}; - static int magic_len[]= {0, 24, 27, 29, 31}; int ret, bin_count, i, mode, magic_first = 1, magic_last = 4; - char *cpt, self_md5[16], tag_md5[16]; + int magic_len = 0; + char *cpt, self_md5[16], tag_md5[16], *tag_magic; void *ctx = NULL; *next_tag = 0; @@ -1583,13 +1599,15 @@ int iso_util_decode_md5_tag(char data[2048], int *tag_type, uint32_t *pos, return ISO_WRONG_ARG_VALUE; if (mode > 0) magic_first = magic_last = mode; - for (i = magic_first; i <= magic_last; i++) - if (strncmp(data, tag_magic[i], magic_len[i]) == 0) + for (i = magic_first; i <= magic_last; i++) { + iso_util_tag_magic(i, &tag_magic, &magic_len, 0); + if (strncmp(data, tag_magic, magic_len) == 0) break; + } if (i > magic_last ) return 0; *tag_type = i; - cpt = data + magic_len[*tag_type] + 1; + cpt = data + magic_len + 1; if (strncmp(cpt, "pos=", 4) != 0) return 0; cpt+= 4; @@ -1650,3 +1668,51 @@ int iso_util_decode_md5_tag(char data[2048], int *tag_type, uint32_t *pos, return(1); } + +int iso_util_eval_md5_tag(char *block, int desired, uint32_t lba, + void *ctx, uint32_t ctx_start_lba, + int *tag_type, uint32_t *next_tag, int flag) +{ + int decode_ret, ret; + char md5[16], cloned_md5[16]; + uint32_t pos, range_start, range_size; + void *cloned_ctx = NULL; + + *tag_type = 0; + decode_ret = iso_util_decode_md5_tag(block, tag_type, &pos, + &range_start, &range_size, next_tag, md5, 0); + if (decode_ret != 1 && decode_ret != ISO_MD5_AREA_CORRUPTED) + return 0; + if (*tag_type > 30) + goto unexpected_type; + + if (decode_ret == ISO_MD5_AREA_CORRUPTED) { + ret = decode_ret; + goto ex; + } else if (!((1 << *tag_type) & desired)) { +unexpected_type:; + iso_msg_submit(-1, ISO_MD5_TAG_UNEXPECTED, 0, NULL); + ret = 0; + goto ex; + } else if(pos != lba) { + ret = ISO_MD5_TAG_MISPLACED; + goto ex; + } else if(range_start != ctx_start_lba) { + ret = ISO_MD5_TAG_MISPLACED; + } + ret = iso_md5_clone(ctx, &cloned_ctx); + if (ret < 0) + goto ex; + iso_md5_end(&cloned_ctx, cloned_md5); + if (! iso_md5_match(cloned_md5, md5)) { + ret = ISO_MD5_TAG_MISMATCH; + goto ex; + } + ret = 1; +ex:; + if (ret < 0) + iso_msg_submit(-1, ret, 0, NULL); + return ret; +} + + diff --git a/libisofs/util.h b/libisofs/util.h index c5af0d1..188d991 100644 --- a/libisofs/util.h +++ b/libisofs/util.h @@ -458,4 +458,28 @@ int iso_util_encode_len_bytes(uint32_t data, char *buffer, int data_len, int iso_util_decode_len_bytes(uint32_t *data, char *buffer, int *data_len, int buffer_len, int flag); + +/* Evaluate a data block whether it is a libisofs session checksum tag of + desired type and eventually use it to verify the MD5 checksum computed + so far. + @param block The data block to be evaluated + @param desired Bit map which tells what tag types are expected + (0 to 30) + @param lba The address from where block was read + @param ctx The checksum context computed so far + @param ctx_start_lba The block address where checksum computing started + @param tag_type Returns the tag type (0 means invalid tag type) + @param flag Bitfield for control purposes, unused yet, submit 0 + @return 1= tag is desired and matches + 0= not a recognizable tag or a undesired tag + <0 is error or mismatch +*/ +int iso_util_eval_md5_tag(char *block, int desired, uint32_t lba, + void *ctx, uint32_t ctx_start_lba, + int *tag_type, uint32_t *next_tag, int flag); + + +int iso_util_tag_magic(int tag_type, char **tag_magic, int *len, int flag); + + #endif /*LIBISO_UTIL_H_*/