From 62edebad0614d7349d3b6ff17883e92ad665299d Mon Sep 17 00:00:00 2001 From: Thomas Schmitt Date: Wed, 19 Aug 2009 22:26:18 +0200 Subject: [PATCH] Introduced file content stability check with iso_write_opts_set_record_md5(). --- doc/checksums.txt | 5 ++- libisofs/ecma119.c | 8 ++-- libisofs/ecma119.h | 7 ++- libisofs/filesrc.c | 104 ++++++++++++++++++++++++++++++++++++++------ libisofs/libisofs.h | 23 +++++++++- libisofs/messages.c | 2 + 6 files changed, 125 insertions(+), 24 deletions(-) diff --git a/doc/checksums.txt b/doc/checksums.txt index 72705a5..56dc79a 100644 --- a/doc/checksums.txt +++ b/doc/checksums.txt @@ -19,10 +19,11 @@ is enabled by iso_read_opts_set_no_md5(). Loaded checksums can be inquired by iso_image_get_session_md5() and iso_file_get_md5(). Stream recognizable checksum tags occupy exactly one block each. They can -be detected by submitting a read-in block to iso_util_decode_md5_tag(). +be detected by submitting a block to iso_util_decode_md5_tag(). libisofs has own MD5 computation functions: -iso_md5_start(), iso_md5_compute(), iso_md5_clone(), iso_md5_end() +iso_md5_start(), iso_md5_compute(), iso_md5_clone(), iso_md5_end(), +iso_md5_match() Representation in the Image diff --git a/libisofs/ecma119.c b/libisofs/ecma119.c index cd99843..0aa9ce5 100644 --- a/libisofs/ecma119.c +++ b/libisofs/ecma119.c @@ -1135,7 +1135,7 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img) #ifdef Libisofs_with_checksumS - if (target->md5_file_checksums || target->md5_session_checksum) { + if ((target->md5_file_checksums & 1) || target->md5_session_checksum) { nwriters++; ret = checksum_prepare_image(src, 0); if (ret < 0) @@ -1213,7 +1213,7 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img) #ifdef Libisofs_with_checksumS - if (target->md5_file_checksums || target->md5_session_checksum) { + if ((target->md5_file_checksums & 1) || target->md5_session_checksum) { ret = checksum_writer_create(target); if (ret < 0) goto target_cleanup; @@ -1805,8 +1805,8 @@ int iso_write_opts_set_record_md5(IsoWriteOpts *opts, int session, int files) #ifdef Libisofs_with_checksumS - opts->md5_session_checksum = !!session; - opts->md5_file_checksums = !!files; + opts->md5_session_checksum = session & 1; + opts->md5_file_checksums = files & 3; #endif /* Libisofs_with_checksumS */ diff --git a/libisofs/ecma119.h b/libisofs/ecma119.h index d647cc8..cb4e37b 100644 --- a/libisofs/ecma119.h +++ b/libisofs/ecma119.h @@ -163,8 +163,11 @@ struct iso_write_opts { * blocks will be recorded in xattr "isofs.ca" of the root node. * The indice of the MD5 sums will be recorded with the IsoFile directory * entries as xattr "isofs.cx". See also API call iso_file_get_md5(). + * bit0= compute individual checksums + * bit1= pre-compute checksum and compare it with actual one. + * Raise MISHAP if mismatch. */ - unsigned int md5_file_checksums :1; + unsigned int md5_file_checksums :2; #endif /* Libisofs_with_checksumS */ @@ -336,7 +339,7 @@ struct ecma119_image #ifdef Libisofs_with_checksumS unsigned int md5_session_checksum :1; - unsigned int md5_file_checksums :1; + unsigned int md5_file_checksums :2; #endif /* Libisofs_with_checksumS */ diff --git a/libisofs/filesrc.c b/libisofs/filesrc.c index 206bec0..0cf2d3d 100644 --- a/libisofs/filesrc.c +++ b/libisofs/filesrc.c @@ -118,14 +118,15 @@ int iso_file_src_create(Ecma119Image *img, IsoFile *file, IsoFileSrc **src) #ifdef Libisofs_with_checksumS - if (img->md5_file_checksums && file->from_old_session && img->appendable) { + if ((img->md5_file_checksums & 1) && + file->from_old_session && img->appendable) { /* Omit MD5 indexing with old image nodes which have no MD5 */ ret = iso_node_get_xinfo((IsoNode *) file, checksum_xinfo_func, &xipt); if (ret <= 0) no_md5 = 1; } - if (img->md5_file_checksums && !no_md5) { + if ((img->md5_file_checksums & 1) && !no_md5) { img->checksum_idx_counter++; if (img->checksum_idx_counter < 0x80000000) { fsrc->checksum_index= img->checksum_idx_counter; @@ -313,10 +314,59 @@ int filesrc_read(IsoFileSrc *file, char *buf, size_t count) } } +#ifdef Libisofs_with_checksumS + +/* @return 1=ok, md5 is valid, + 0= not ok, go on, + <0 fatal error, abort +*/ +static +int filesrc_make_md5(Ecma119Image *t, IsoFileSrc *file, char md5[16], int flag) +{ + int res, is_open = 0; + char buffer[BLOCK_SIZE]; + void *ctx= NULL; + off_t file_size; + uint32_t b, nblocks; + + if (! iso_stream_is_repeatable(file->stream)) + return 0; + res = iso_md5_start(&ctx); + if (res < 0) + return res; + res = filesrc_open(file); + if (res < 0) + return 0; + is_open = 1; + file_size = iso_file_src_get_size(file); + nblocks = DIV_UP(file_size, BLOCK_SIZE); + for (b = 0; b < nblocks; ++b) { + res = filesrc_read(file, buffer, BLOCK_SIZE); + if (res < 0) { + res = 0; + goto ex; + } + if (file_size - b * BLOCK_SIZE > BLOCK_SIZE) + res = BLOCK_SIZE; + else + res = file_size - b * BLOCK_SIZE; + iso_md5_compute(ctx, buffer, res); + } + res = 1; +ex:; + if (is_open) + filesrc_close(file); + if (ctx != NULL) + iso_md5_end(&ctx, md5); + return res; +} + +#endif /* Libisofs_with_checksumS */ + static int filesrc_writer_write_data(IsoImageWriter *writer) { - int res, ret; + int res, ret, was_error; size_t i, b; Ecma119Image *t; IsoFileSrc *file; @@ -328,7 +378,8 @@ int filesrc_writer_write_data(IsoImageWriter *writer) #ifdef Libisofs_with_checksumS void *ctx= NULL; - char md5[16]; + char md5[16], pre_md5[16]; + int pre_md5_valid = 0; #endif @@ -343,10 +394,19 @@ int filesrc_writer_write_data(IsoImageWriter *writer) i = 0; while ((file = filelist[i++]) != NULL) { + was_error = 0; file_size = iso_file_src_get_size(file); nblocks = DIV_UP(file_size, BLOCK_SIZE); + +#ifdef Libisofs_with_checksumS - /* >>> Eventually obtain an MD5 of content by a first read pass */; + pre_md5_valid = 0; + if (file->checksum_index > 0 && (t->md5_file_checksums & 2)) { + /* Obtain an MD5 of content by a first read pass */ + pre_md5_valid = filesrc_make_md5(t, file, pre_md5, 0); + } + +#endif /* Libisofs_with_checksumS */ res = filesrc_open(file); iso_stream_get_file_name(file->stream, name); @@ -356,6 +416,7 @@ int filesrc_writer_write_data(IsoImageWriter *writer) * 0's to image */ iso_report_errfile(name, ISO_FILE_CANT_WRITE, 0, 0); + was_error = 1; res = iso_msg_submit(t->image->id, ISO_FILE_CANT_WRITE, res, "File \"%s\" can't be opened. Filling with 0s.", name); if (res < 0) { @@ -374,6 +435,7 @@ int filesrc_writer_write_data(IsoImageWriter *writer) continue; } else if (res > 1) { iso_report_errfile(name, ISO_FILE_CANT_WRITE, 0, 0); + was_error = 1; res = iso_msg_submit(t->image->id, ISO_FILE_CANT_WRITE, 0, "Size of file \"%s\" has changed. It will be %s", name, (res == 2 ? "truncated" : "padded with 0's")); @@ -400,7 +462,7 @@ int filesrc_writer_write_data(IsoImageWriter *writer) } #endif /* Libisofs_with_checksumS */ - + /* write file contents to image */ for (b = 0; b < nblocks; ++b) { int wres; @@ -421,9 +483,10 @@ int filesrc_writer_write_data(IsoImageWriter *writer) if (file->checksum_index > 0) { /* Add to file checksum */ - res = file_size - b * BLOCK_SIZE; - if (res > BLOCK_SIZE) + if (file_size - b * BLOCK_SIZE > BLOCK_SIZE) res = BLOCK_SIZE; + else + res = file_size - b * BLOCK_SIZE; res = iso_md5_compute(ctx, buffer, res); if (res <= 0) file->checksum_index = 0; @@ -438,6 +501,7 @@ int filesrc_writer_write_data(IsoImageWriter *writer) if (b < nblocks) { /* premature end of file, due to error or eof */ iso_report_errfile(name, ISO_FILE_CANT_WRITE, 0, 0); + was_error = 1; if (res < 0) { /* error */ res = iso_msg_submit(t->image->id, ISO_FILE_CANT_WRITE, res, @@ -469,9 +533,10 @@ int filesrc_writer_write_data(IsoImageWriter *writer) if (file->checksum_index > 0) { /* Add to file checksum */ - res = file_size - b * BLOCK_SIZE; - if (res > BLOCK_SIZE) + if (file_size - b * BLOCK_SIZE > BLOCK_SIZE) res = BLOCK_SIZE; + else + res = file_size - b * BLOCK_SIZE; res = iso_md5_compute(ctx, buffer, res); if (res <= 0) file->checksum_index = 0; @@ -489,10 +554,21 @@ int filesrc_writer_write_data(IsoImageWriter *writer) res = iso_md5_end(&ctx, md5); if (res <= 0) file->checksum_index = 0; - - /* >>> Eventually compare with MD5 of first read pass - and issue error if mismatch */; - + if ((t->md5_file_checksums & 2) && pre_md5_valid > 0 && + !was_error) { + if (! iso_md5_match(md5, pre_md5)) { + /* Issue MISHAP event */ + iso_report_errfile(name, ISO_MD5_STREAM_CHANGE, 0, 0); + was_error = 1; + res = iso_msg_submit(t->image->id, ISO_MD5_STREAM_CHANGE,0, + "Content of file '%s' changed while it was written into the image.", + name); + if (res < 0) { + ret = res; /* aborted due to error severity */ + goto ex; + } + } + } /* Write md5 into checksum buffer at file->checksum_index */ memcpy(t->checksum_buffer + 16 * file->checksum_index, md5, 16); } diff --git a/libisofs/libisofs.h b/libisofs/libisofs.h index 3663e75..9b67520 100644 --- a/libisofs/libisofs.h +++ b/libisofs/libisofs.h @@ -1424,9 +1424,21 @@ int iso_write_opts_set_sort_files(IsoWriteOpts *opts, int sort); * @param opts * The option set to be manipulated. * @param session - * If not 0: compute session checksum + * If bit0 set: compute session checksum * @param files - * If not 0: compute a checksum for each single IsoFile object. + * If bit0 set: compute a checksum for each single IsoFile object. + * If bit1 set: check content stability (only with bit0). I.e. before + * writing the file content into to image stream, read it + * once and compute a MD5. Do a second reading for writing + * into the image stream. Afterwards compare both MD5 and + * issue a MISHAP event ISO_MD5_STREAM_CHANGE if they do not + * match. + * Such a mismatch indicates content changes between the + * time point when the first MD5 reading started and the + * time point when the last block was read for writing. + * So there is high risk that the image stream was fed from + * changing and possibly inconsistent file content. + * * @since 0.6.22 */ int iso_write_opts_set_record_md5(IsoWriteOpts *opts, int session, int files); @@ -5478,6 +5490,13 @@ int iso_md5_match(char first_md5[16], char second_md5[16]); */ #define ISO_MD5_TAG_OTHER_RANGE 0xD030FE9B +/** + * Detected file content changes while it was written into the image. + * (MISHAP, HIGH, -358) + * @since 0.6.22 +*/ +#define ISO_MD5_STREAM_CHANGE 0xE430FE9A + /* ! PLACE NEW ERROR CODES HERE ! */ diff --git a/libisofs/messages.c b/libisofs/messages.c index bb80927..a44361b 100644 --- a/libisofs/messages.c +++ b/libisofs/messages.c @@ -272,6 +272,8 @@ const char *iso_error_to_msg(int errcode) return "Misplaced checksum tag type encountered"; case ISO_MD5_TAG_OTHER_RANGE: return "Checksum tag with unexpected address range encountered"; + case ISO_MD5_STREAM_CHANGE: + return "Detected file content changes while it was written into the image"; default: return "Unknown error"; }