From a7ea2ec02c096fc6deb36ee04f6c4c33b904b21f Mon Sep 17 00:00:00 2001 From: Marcus Huewe Date: Thu, 12 May 2016 15:35:04 -0400 Subject: [PATCH] libext2fs: fix offset code in undo_write_tdb The old code has some issues, for example, when backing up fs block 0 (can be reproduced via "mke2fs -z undo -b 1024 -E offset=1024 out 1024"): * backing_blk_num is set to ULLONG_MAX instead of 0 * data is read from the beginning of the file instead of offset 1024 * data_ptr is set to read_ptr - 1024 ("invalid" address) Hence, the wrong fs block is associated with the wrong data. For details, see also commit 76da764639cbfcc998f13c263a11a4601bcb9961. Signed-off-by: Marcus Huewe Signed-off-by: Theodore Ts'o --- lib/ext2fs/undo_io.c | 32 ++++++++++++-------------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/lib/ext2fs/undo_io.c b/lib/ext2fs/undo_io.c index 57c085e..4cc1e9d 100644 --- a/lib/ext2fs/undo_io.c +++ b/lib/ext2fs/undo_io.c @@ -312,7 +312,6 @@ static errcode_t undo_write_tdb(io_channel channel, unsigned char *read_ptr; unsigned long long end_block; unsigned long long data_size; - void *data_ptr; struct undo_key *key; __u32 blk_crc; @@ -368,22 +367,21 @@ static errcode_t undo_write_tdb(io_channel channel, * Also we need to recalcuate the block number with respect * to the backing I/O manager. */ - offset = block_num * data->tdb_data_size; + offset = block_num * data->tdb_data_size + + (data->offset % data->tdb_data_size); backing_blk_num = (offset - data->offset) / channel->block_size; - count = data->tdb_data_size + - ((offset - data->offset) % channel->block_size); - retval = ext2fs_get_mem(count, &read_ptr); + retval = ext2fs_get_mem(data->tdb_data_size, &read_ptr); if (retval) { return retval; } - memset(read_ptr, 0, count); + memset(read_ptr, 0, data->tdb_data_size); actual_size = 0; - if ((count % channel->block_size) == 0) - sz = count / channel->block_size; + if ((data->tdb_data_size % channel->block_size) == 0) + sz = data->tdb_data_size / channel->block_size; else - sz = -count; + sz = -data->tdb_data_size; retval = io_channel_read_blk64(data->real, backing_blk_num, sz, read_ptr); if (retval) { @@ -405,13 +403,11 @@ static errcode_t undo_write_tdb(io_channel channel, continue; } dbg_printf("Read %llu bytes from FS block %llu (blk=%llu cnt=%u)\n", - data_size, backing_blk_num, block, count); + data_size, backing_blk_num, block, data->tdb_data_size); if ((data_size % data->undo_file->block_size) == 0) sz = data_size / data->undo_file->block_size; else - sz = -actual_size; - data_ptr = read_ptr + ((offset - data->offset) % - data->undo_file->block_size); + sz = -data_size;; /* extend this key? */ if (data->keys_in_block) { key = data->keyb->keys + data->keys_in_block - 1; @@ -427,9 +423,7 @@ static errcode_t undo_write_tdb(io_channel channel, E2UNDO_MAX_EXTENT_BLOCKS * data->tdb_data_size > keysz + sz) { blk_crc = ext2fs_le32_to_cpu(key->blk_crc); - blk_crc = ext2fs_crc32c_le(blk_crc, - (unsigned char *)data_ptr, - data_size); + blk_crc = ext2fs_crc32c_le(blk_crc, read_ptr, data_size); key->blk_crc = ext2fs_cpu_to_le32(blk_crc); key->size = ext2fs_cpu_to_le32(keysz + data_size); } else { @@ -437,9 +431,7 @@ static errcode_t undo_write_tdb(io_channel channel, key = data->keyb->keys + data->keys_in_block; data->keys_in_block++; key->fsblk = ext2fs_cpu_to_le64(backing_blk_num); - blk_crc = ext2fs_crc32c_le(~0, - (unsigned char *)data_ptr, - data_size); + blk_crc = ext2fs_crc32c_le(~0, read_ptr, data_size); key->blk_crc = ext2fs_cpu_to_le32(blk_crc); key->size = ext2fs_cpu_to_le32(data_size); } @@ -448,7 +440,7 @@ static errcode_t undo_write_tdb(io_channel channel, data->undo_blk_num, sz, data->num_keys - 1); retval = io_channel_write_blk64(data->undo_file, - data->undo_blk_num, sz, data_ptr); + data->undo_blk_num, sz, read_ptr); if (retval) { free(read_ptr); return retval; -- 1.8.3.1