From 39299ed61065d76b4b09f0b9a1be84a823c43451 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Mon, 9 Apr 2018 16:31:27 -0400 Subject: [PATCH] Add debian patches for commits cherry picked since v1.44.1-1 (Also remove tests/f_orphquot since it has a binary file which makes debian's patch infrastructure unhappy.) Signed-off-by: Theodore Ts'o --- ...st-quota-counters-when-clearing-orphaned-inodes | 302 +++++++++++++++++++++ ...x-metadata-image-handling-on-big-endian-systems | 221 +++++++++++++++ .../filefrag-avoid-temporary-buffer-overflow | 27 ++ .../libext2fs-add-sanity-checks-for-ea_in_inode | 68 +++++ debian/patches/series | 4 + tests/f_orphquot/expect | 10 - tests/f_orphquot/image.bz2 | Bin 1327 -> 0 bytes tests/f_orphquot/script | 26 -- 8 files changed, 622 insertions(+), 36 deletions(-) create mode 100644 debian/patches/e2fsck-adjust-quota-counters-when-clearing-orphaned-inodes create mode 100644 debian/patches/e2image-fix-metadata-image-handling-on-big-endian-systems create mode 100644 debian/patches/filefrag-avoid-temporary-buffer-overflow create mode 100644 debian/patches/libext2fs-add-sanity-checks-for-ea_in_inode create mode 100644 debian/patches/series delete mode 100644 tests/f_orphquot/expect delete mode 100644 tests/f_orphquot/image.bz2 delete mode 100644 tests/f_orphquot/script diff --git a/debian/patches/e2fsck-adjust-quota-counters-when-clearing-orphaned-inodes b/debian/patches/e2fsck-adjust-quota-counters-when-clearing-orphaned-inodes new file mode 100644 index 0000000..a999329 --- /dev/null +++ b/debian/patches/e2fsck-adjust-quota-counters-when-clearing-orphaned-inodes @@ -0,0 +1,302 @@ +Description: e2fsck: adjust quota counters when clearing orphaned inodes + If e2fsck encounters a filesystem that supports internal quotas, it is + responsible for adjusting the quota counters if it decides to clear any + orphaned inodes. Therefore, we must read the quota files, adjust the + counters, and write the quota files back out when we are done. +From: "Darrick J. Wong" +Origin: upstream, commit:7d79b40bb30e +--- + e2fsck/super.c | 121 +++++++++++++++++++++++++++++++++++++-------- + lib/support/mkquota.c | 12 +++-- + 2 files changed, 133 insertions(+), 24 deletions(-) + +diff --git a/e2fsck/super.c b/e2fsck/super.c +index 5e29b64ef..9c0e0e7b3 100644 +--- a/e2fsck/super.c ++++ b/e2fsck/super.c +@@ -72,6 +72,7 @@ struct process_block_struct { + int abort; + errcode_t errcode; + blk64_t last_cluster; ++ struct ext2_inode_large *inode; + }; + + static int release_inode_block(ext2_filsys fs, +@@ -168,6 +169,8 @@ static int release_inode_block(ext2_filsys fs, + retval |= BLOCK_CHANGED; + } + ++ if (ctx->qctx) ++ quota_data_sub(ctx->qctx, pb->inode, 0, ctx->fs->blocksize); + ext2fs_block_alloc_stats2(fs, blk, -1); + ctx->free_blocks++; + return retval; +@@ -179,15 +182,16 @@ static int release_inode_block(ext2_filsys fs, + * not deleted. + */ + static int release_inode_blocks(e2fsck_t ctx, ext2_ino_t ino, +- struct ext2_inode *inode, char *block_buf, ++ struct ext2_inode_large *inode, char *block_buf, + struct problem_context *pctx) + { + struct process_block_struct pb; + ext2_filsys fs = ctx->fs; ++ blk64_t blk; + errcode_t retval; + __u32 count; + +- if (!ext2fs_inode_has_valid_blocks2(fs, inode)) ++ if (!ext2fs_inode_has_valid_blocks2(fs, EXT2_INODE(inode))) + return 0; + + pb.buf = block_buf + 3 * ctx->fs->blocksize; +@@ -196,6 +200,7 @@ static int release_inode_blocks(e2fsck_t ctx, ext2_ino_t ino, + pb.errcode = 0; + pb.pctx = pctx; + pb.last_cluster = 0; ++ pb.inode = inode; + if (inode->i_links_count) { + pb.truncating = 1; + pb.truncate_block = (e2_blkcnt_t) +@@ -220,15 +225,17 @@ static int release_inode_blocks(e2fsck_t ctx, ext2_ino_t ino, + return 1; + + /* Refresh the inode since ext2fs_block_iterate may have changed it */ +- e2fsck_read_inode(ctx, ino, inode, "release_inode_blocks"); ++ e2fsck_read_inode_full(ctx, ino, EXT2_INODE(inode), sizeof(*inode), ++ "release_inode_blocks"); + + if (pb.truncated_blocks) +- ext2fs_iblk_sub_blocks(fs, inode, pb.truncated_blocks); ++ ext2fs_iblk_sub_blocks(fs, EXT2_INODE(inode), ++ pb.truncated_blocks); + +- if (ext2fs_file_acl_block(fs, inode)) { +- retval = ext2fs_adjust_ea_refcount3(fs, +- ext2fs_file_acl_block(fs, inode), +- block_buf, -1, &count, ino); ++ blk = ext2fs_file_acl_block(fs, EXT2_INODE(inode)); ++ if (blk) { ++ retval = ext2fs_adjust_ea_refcount3(fs, blk, block_buf, -1, ++ &count, ino); + if (retval == EXT2_ET_BAD_EA_BLOCK_NUM) { + retval = 0; + count = 1; +@@ -240,15 +247,68 @@ static int release_inode_blocks(e2fsck_t ctx, ext2_ino_t ino, + return 1; + } + if (count == 0) { +- ext2fs_block_alloc_stats2(fs, +- ext2fs_file_acl_block(fs, inode), -1); ++ if (ctx->qctx) ++ quota_data_sub(ctx->qctx, inode, 0, ++ ctx->fs->blocksize); ++ ext2fs_block_alloc_stats2(fs, blk, -1); + ctx->free_blocks++; + } +- ext2fs_file_acl_block_set(fs, inode, 0); ++ ext2fs_file_acl_block_set(fs, EXT2_INODE(inode), 0); + } + return 0; + } + ++/* Load all quota data in preparation for orphan clearing. */ ++static errcode_t e2fsck_read_all_quotas(e2fsck_t ctx) ++{ ++ ext2_ino_t qf_ino; ++ enum quota_type qtype; ++ errcode_t retval = 0; ++ ++ if (!ext2fs_has_feature_quota(ctx->fs->super)) ++ return retval; ++ ++ retval = quota_init_context(&ctx->qctx, ctx->fs, 0); ++ if (retval) ++ return retval; ++ ++ for (qtype = 0 ; qtype < MAXQUOTAS; qtype++) { ++ qf_ino = *quota_sb_inump(ctx->fs->super, qtype); ++ if (qf_ino == 0) ++ continue; ++ ++ retval = quota_update_limits(ctx->qctx, qf_ino, qtype); ++ if (retval) ++ break; ++ } ++ if (retval) ++ quota_release_context(&ctx->qctx); ++ return retval; ++} ++ ++/* Write all the quota info to disk. */ ++static errcode_t e2fsck_write_all_quotas(e2fsck_t ctx) ++{ ++ struct problem_context pctx; ++ enum quota_type qtype; ++ ++ if (!ext2fs_has_feature_quota(ctx->fs->super)) ++ return 0; ++ ++ clear_problem_context(&pctx); ++ for (qtype = 0 ; qtype < MAXQUOTAS; qtype++) { ++ pctx.num = qtype; ++ pctx.errcode = quota_write_inode(ctx->qctx, 1 << qtype); ++ if (pctx.errcode) { ++ fix_problem(ctx, PR_6_WRITE_QUOTAS, &pctx); ++ break; ++ } ++ } ++ ++ quota_release_context(&ctx->qctx); ++ return pctx.errcode; ++} ++ + /* + * This function releases all of the orphan inodes. It returns 1 if + * it hit some error, and 0 on success. +@@ -257,13 +317,20 @@ static int release_orphan_inodes(e2fsck_t ctx) + { + ext2_filsys fs = ctx->fs; + ext2_ino_t ino, next_ino; +- struct ext2_inode inode; ++ struct ext2_inode_large inode; + struct problem_context pctx; + char *block_buf; + + if ((ino = fs->super->s_last_orphan) == 0) + return 0; + ++ clear_problem_context(&pctx); ++ pctx.errcode = e2fsck_read_all_quotas(ctx); ++ if (pctx.errcode) { ++ fix_problem(ctx, PR_0_QUOTA_INIT_CTX, &pctx); ++ return 1; ++ } ++ + /* + * Win or lose, we won't be using the head of the orphan inode + * list again. +@@ -276,15 +343,18 @@ static int release_orphan_inodes(e2fsck_t ctx) + * list, since the orphan list can't be trusted; and we're + * going to be running a full e2fsck run anyway... + */ +- if (fs->super->s_state & EXT2_ERROR_FS) ++ if (fs->super->s_state & EXT2_ERROR_FS) { ++ if (ctx->qctx) ++ quota_release_context(&ctx->qctx); + return 0; ++ } + + if ((ino < EXT2_FIRST_INODE(fs->super)) || + (ino > fs->super->s_inodes_count)) { + clear_problem_context(&pctx); + pctx.ino = ino; + fix_problem(ctx, PR_0_ORPHAN_ILLEGAL_HEAD_INODE, &pctx); +- return 1; ++ goto err_qctx; + } + + block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 4, +@@ -292,10 +362,11 @@ static int release_orphan_inodes(e2fsck_t ctx) + e2fsck_read_bitmaps(ctx); + + while (ino) { +- e2fsck_read_inode(ctx, ino, &inode, "release_orphan_inodes"); ++ e2fsck_read_inode_full(ctx, ino, EXT2_INODE(&inode), ++ sizeof(inode), "release_orphan_inodes"); + clear_problem_context(&pctx); + pctx.ino = ino; +- pctx.inode = &inode; ++ pctx.inode = EXT2_INODE(&inode); + pctx.str = inode.i_links_count ? _("Truncating") : + _("Clearing"); + +@@ -307,13 +378,15 @@ static int release_orphan_inodes(e2fsck_t ctx) + (next_ino > fs->super->s_inodes_count))) { + pctx.ino = next_ino; + fix_problem(ctx, PR_0_ORPHAN_ILLEGAL_INODE, &pctx); +- goto return_abort; ++ goto err_buf; + } + + if (release_inode_blocks(ctx, ino, &inode, block_buf, &pctx)) +- goto return_abort; ++ goto err_buf; + + if (!inode.i_links_count) { ++ if (ctx->qctx) ++ quota_data_inodes(ctx->qctx, &inode, ino, -1); + ext2fs_inode_alloc_stats2(fs, ino, -1, + LINUX_S_ISDIR(inode.i_mode)); + ctx->free_inodes++; +@@ -321,13 +394,21 @@ static int release_orphan_inodes(e2fsck_t ctx) + } else { + inode.i_dtime = 0; + } +- e2fsck_write_inode(ctx, ino, &inode, "delete_file"); ++ e2fsck_write_inode_full(ctx, ino, EXT2_INODE(&inode), ++ sizeof(inode), "delete_file"); + ino = next_ino; + } + ext2fs_free_mem(&block_buf); ++ pctx.errcode = e2fsck_write_all_quotas(ctx); ++ if (pctx.errcode) ++ goto err; + return 0; +-return_abort: ++err_buf: + ext2fs_free_mem(&block_buf); ++err_qctx: ++ if (ctx->qctx) ++ quota_release_context(&ctx->qctx); ++err: + return 1; + } + +diff --git a/lib/support/mkquota.c b/lib/support/mkquota.c +index e65c95b76..efc37cb49 100644 +--- a/lib/support/mkquota.c ++++ b/lib/support/mkquota.c +@@ -516,6 +516,7 @@ struct scan_dquots_data { + dict_t *quota_dict; + int update_limits; /* update limits from disk */ + int update_usage; ++ int check_consistency; + int usage_is_inconsistent; + }; + +@@ -533,8 +534,9 @@ static int scan_dquots_callback(struct dquot *dquot, void *cb_data) + print_dquot("dsk", dquot); + + /* Check if there is inconsistency */ +- if (dq->dq_dqb.dqb_curspace != dquot->dq_dqb.dqb_curspace || +- dq->dq_dqb.dqb_curinodes != dquot->dq_dqb.dqb_curinodes) { ++ if (scan_data->check_consistency && ++ (dq->dq_dqb.dqb_curspace != dquot->dq_dqb.dqb_curspace || ++ dq->dq_dqb.dqb_curinodes != dquot->dq_dqb.dqb_curinodes)) { + scan_data->usage_is_inconsistent = 1; + fprintf(stderr, "[QUOTA WARNING] Usage inconsistent for ID %u:" + "actual (%lld, %lld) != expected (%lld, %lld)\n", +@@ -568,8 +570,9 @@ static errcode_t quota_read_all_dquots(struct quota_handle *qh, + struct scan_dquots_data scan_data; + + scan_data.quota_dict = qctx->quota_dict[qh->qh_type]; +- scan_data.update_limits = update_limits; +- scan_data.update_usage = 0; ++ scan_data.check_consistency = 0; ++ scan_data.update_limits = 0; ++ scan_data.update_usage = 1; + + return qh->qh_ops->scan_dquots(qh, scan_dquots_callback, &scan_data); + } +@@ -659,6 +662,7 @@ errcode_t quota_compare_and_update(quota_ctx_t qctx, enum quota_type qtype, + scan_data.quota_dict = qctx->quota_dict[qtype]; + scan_data.update_limits = 1; + scan_data.update_usage = 0; ++ scan_data.check_consistency = 1; + scan_data.usage_is_inconsistent = 0; + err = qh.qh_ops->scan_dquots(&qh, scan_dquots_callback, &scan_data); + if (err) { +-- +2.16.1.72.g5be1f00a9a + diff --git a/debian/patches/e2image-fix-metadata-image-handling-on-big-endian-systems b/debian/patches/e2image-fix-metadata-image-handling-on-big-endian-systems new file mode 100644 index 0000000..41b3407 --- /dev/null +++ b/debian/patches/e2image-fix-metadata-image-handling-on-big-endian-systems @@ -0,0 +1,221 @@ +Description: e2image: fix metadata image handling on big endian systems + Currently e2image metadata image handling and creating is completely + broken on big endian systems. It just does not care about endianness at + all. This was uncovered With addition of i_bitmaps test, which is the + first test that actually tests e2image metadata image. + . + Fix it by making sure that all on-disk metadata that we write and read + to/from the metadata image is properly converted. +From: Lukas Czerner +Origin: upstream, commit:bfc1856029ff +--- + lib/ext2fs/imager.c | 41 +++++++++++++++++++++++++++++++++++++++++ + lib/ext2fs/inode.c | 2 +- + lib/ext2fs/openfs.c | 4 ++-- + lib/ext2fs/rw_bitmaps.c | 4 ++-- + misc/e2image.c | 22 +++++++++++----------- + 5 files changed, 57 insertions(+), 16 deletions(-) + +diff --git a/lib/ext2fs/imager.c b/lib/ext2fs/imager.c +index efb85b947..7fd06f743 100644 +--- a/lib/ext2fs/imager.c ++++ b/lib/ext2fs/imager.c +@@ -195,6 +195,11 @@ errcode_t ext2fs_image_super_write(ext2_filsys fs, int fd, + char *buf, *cp; + ssize_t actual; + errcode_t retval; ++#ifdef WORDS_BIGENDIAN ++ unsigned int groups_per_block; ++ struct ext2_group_desc *gdp; ++ int j; ++#endif + + buf = malloc(fs->blocksize); + if (!buf) +@@ -204,7 +209,17 @@ errcode_t ext2fs_image_super_write(ext2_filsys fs, int fd, + * Write out the superblock + */ + memset(buf, 0, fs->blocksize); ++#ifdef WORDS_BIGENDIAN ++ /* ++ * We're writing out superblock so let's convert ++ * it to little endian and then back if needed ++ */ ++ ext2fs_swap_super(fs->super); + memcpy(buf, fs->super, SUPERBLOCK_SIZE); ++ ext2fs_swap_super(fs->super); ++#else ++ memcpy(buf, fs->super, SUPERBLOCK_SIZE); ++#endif + actual = write(fd, buf, fs->blocksize); + if (actual == -1) { + retval = errno; +@@ -218,8 +233,34 @@ errcode_t ext2fs_image_super_write(ext2_filsys fs, int fd, + /* + * Now write out the block group descriptors + */ ++ + cp = (char *) fs->group_desc; ++ ++#ifdef WORDS_BIGENDIAN ++ /* ++ * Convert group descriptors to little endian and back ++ * if needed ++ */ ++ groups_per_block = EXT2_DESC_PER_BLOCK(fs->super); ++ gdp = (struct ext2_group_desc *) cp; ++ for (j=0; j < groups_per_block*fs->desc_blocks; j++) { ++ gdp = ext2fs_group_desc(fs, fs->group_desc, j); ++ ext2fs_swap_group_desc2(fs, gdp); ++ } ++#endif ++ + actual = write(fd, cp, fs->blocksize * fs->desc_blocks); ++ ++ ++#ifdef WORDS_BIGENDIAN ++ groups_per_block = EXT2_DESC_PER_BLOCK(fs->super); ++ gdp = (struct ext2_group_desc *) cp; ++ for (j=0; j < groups_per_block*fs->desc_blocks; j++) { ++ gdp = ext2fs_group_desc(fs, fs->group_desc, j); ++ ext2fs_swap_group_desc2(fs, gdp); ++ } ++#endif ++ + if (actual == -1) { + retval = errno; + goto errout; +diff --git a/lib/ext2fs/inode.c b/lib/ext2fs/inode.c +index ad01a9fc5..015cfe4b5 100644 +--- a/lib/ext2fs/inode.c ++++ b/lib/ext2fs/inode.c +@@ -770,7 +770,7 @@ errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino, + } + if (fs->flags & EXT2_FLAG_IMAGE_FILE) { + inodes_per_block = fs->blocksize / EXT2_INODE_SIZE(fs->super); +- block_nr = fs->image_header->offset_inode / fs->blocksize; ++ block_nr = ext2fs_le32_to_cpu(fs->image_header->offset_inode) / fs->blocksize; + block_nr += (ino - 1) / inodes_per_block; + offset = ((ino - 1) % inodes_per_block) * + EXT2_INODE_SIZE(fs->super); +diff --git a/lib/ext2fs/openfs.c b/lib/ext2fs/openfs.c +index 385d6e88c..532e70f7f 100644 +--- a/lib/ext2fs/openfs.c ++++ b/lib/ext2fs/openfs.c +@@ -185,10 +185,10 @@ errcode_t ext2fs_open2(const char *name, const char *io_options, + fs->image_header); + if (retval) + goto cleanup; +- if (fs->image_header->magic_number != EXT2_ET_MAGIC_E2IMAGE) ++ if (ext2fs_le32_to_cpu(fs->image_header->magic_number) != EXT2_ET_MAGIC_E2IMAGE) + return EXT2_ET_MAGIC_E2IMAGE; + superblock = 1; +- block_size = fs->image_header->fs_blocksize; ++ block_size = ext2fs_le32_to_cpu(fs->image_header->fs_blocksize); + } + + /* +diff --git a/lib/ext2fs/rw_bitmaps.c b/lib/ext2fs/rw_bitmaps.c +index 0b532dbf9..e86bacd53 100644 +--- a/lib/ext2fs/rw_bitmaps.c ++++ b/lib/ext2fs/rw_bitmaps.c +@@ -253,7 +253,7 @@ static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block) + ext2fs_free_mem(&buf); + + if (fs->flags & EXT2_FLAG_IMAGE_FILE) { +- blk = (fs->image_header->offset_inodemap / fs->blocksize); ++ blk = (ext2fs_le32_to_cpu(fs->image_header->offset_inodemap) / fs->blocksize); + ino_cnt = fs->super->s_inodes_count; + while (inode_bitmap && ino_cnt > 0) { + retval = io_channel_read_blk64(fs->image_io, blk++, +@@ -270,7 +270,7 @@ static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block) + ino_itr += cnt; + ino_cnt -= cnt; + } +- blk = (fs->image_header->offset_blockmap / ++ blk = (ext2fs_le32_to_cpu(fs->image_header->offset_blockmap) / + fs->blocksize); + blk_cnt = EXT2_GROUPS_TO_CLUSTERS(fs->super, + fs->group_desc_count); +diff --git a/misc/e2image.c b/misc/e2image.c +index 5a18bb41d..83ae6335b 100644 +--- a/misc/e2image.c ++++ b/misc/e2image.c +@@ -240,7 +240,7 @@ static void write_image_file(ext2_filsys fs, int fd) + write_header(fd, NULL, sizeof(struct ext2_image_hdr), fs->blocksize); + memset(&hdr, 0, sizeof(struct ext2_image_hdr)); + +- hdr.offset_super = seek_relative(fd, 0); ++ hdr.offset_super = ext2fs_cpu_to_le32(seek_relative(fd, 0)); + retval = ext2fs_image_super_write(fs, fd, 0); + if (retval) { + com_err(program_name, retval, "%s", +@@ -248,7 +248,7 @@ static void write_image_file(ext2_filsys fs, int fd) + exit(1); + } + +- hdr.offset_inode = seek_relative(fd, 0); ++ hdr.offset_inode = ext2fs_cpu_to_le32(seek_relative(fd, 0)); + retval = ext2fs_image_inode_write(fs, fd, + (fd != 1) ? IMAGER_FLAG_SPARSEWRITE : 0); + if (retval) { +@@ -257,7 +257,7 @@ static void write_image_file(ext2_filsys fs, int fd) + exit(1); + } + +- hdr.offset_blockmap = seek_relative(fd, 0); ++ hdr.offset_blockmap = ext2fs_cpu_to_le32(seek_relative(fd, 0)); + retval = ext2fs_image_bitmap_write(fs, fd, 0); + if (retval) { + com_err(program_name, retval, "%s", +@@ -265,7 +265,7 @@ static void write_image_file(ext2_filsys fs, int fd) + exit(1); + } + +- hdr.offset_inodemap = seek_relative(fd, 0); ++ hdr.offset_inodemap = ext2fs_cpu_to_le32(seek_relative(fd, 0)); + retval = ext2fs_image_bitmap_write(fs, fd, IMAGER_FLAG_INODEMAP); + if (retval) { + com_err(program_name, retval, "%s", +@@ -273,23 +273,23 @@ static void write_image_file(ext2_filsys fs, int fd) + exit(1); + } + +- hdr.magic_number = EXT2_ET_MAGIC_E2IMAGE; ++ hdr.magic_number = ext2fs_cpu_to_le32(EXT2_ET_MAGIC_E2IMAGE); + strcpy(hdr.magic_descriptor, "Ext2 Image 1.0"); + gethostname(hdr.fs_hostname, sizeof(hdr.fs_hostname)); + strncpy(hdr.fs_device_name, device_name, sizeof(hdr.fs_device_name)-1); + hdr.fs_device_name[sizeof(hdr.fs_device_name) - 1] = 0; +- hdr.fs_blocksize = fs->blocksize; ++ hdr.fs_blocksize = ext2fs_cpu_to_le32(fs->blocksize); + + if (stat(device_name, &st) == 0) +- hdr.fs_device = st.st_rdev; ++ hdr.fs_device = ext2fs_cpu_to_le32(st.st_rdev); + + if (fstat(fd, &st) == 0) { +- hdr.image_device = st.st_dev; +- hdr.image_inode = st.st_ino; ++ hdr.image_device = ext2fs_cpu_to_le32(st.st_dev); ++ hdr.image_inode = ext2fs_cpu_to_le32(st.st_ino); + } + memcpy(hdr.fs_uuid, fs->super->s_uuid, sizeof(hdr.fs_uuid)); + +- hdr.image_time = time(0); ++ hdr.image_time = ext2fs_cpu_to_le32(time(0)); + write_header(fd, &hdr, sizeof(struct ext2_image_hdr), fs->blocksize); + } + +@@ -1423,7 +1423,7 @@ static void install_image(char *device, char *image_fn, int type) + + ext2fs_rewrite_to_io(fs, io); + +- seek_set(fd, fs->image_header->offset_inode); ++ seek_set(fd, ext2fs_le32_to_cpu(fs->image_header->offset_inode)); + + retval = ext2fs_image_inode_read(fs, fd, 0); + if (retval) { +-- +2.16.1.72.g5be1f00a9a + diff --git a/debian/patches/filefrag-avoid-temporary-buffer-overflow b/debian/patches/filefrag-avoid-temporary-buffer-overflow new file mode 100644 index 0000000..0feecea --- /dev/null +++ b/debian/patches/filefrag-avoid-temporary-buffer-overflow @@ -0,0 +1,27 @@ +Description: filefrag: avoid temporary buffer overflow + If an unknown flag is present in a FIEMAP extent, it is printed as a + hex value into a temporary buffer before adding it to the flags. If + that unknown flag is over 0xfff then it will overflow the temporary + buffer. +From: Andreas Dilger +Origin: upstream, commit:17a1f2c19296 +--- + misc/filefrag.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/misc/filefrag.c b/misc/filefrag.c +index 9c57ab930..dc003931b 100644 +--- a/misc/filefrag.c ++++ b/misc/filefrag.c +@@ -179,7 +179,7 @@ static void print_extent_info(struct fiemap_extent *fm_extent, int cur_ex, + print_flag(&fe_flags, FIEMAP_EXTENT_SHARED, flags, "shared,"); + /* print any unknown flags as hex values */ + for (mask = 1; fe_flags != 0 && mask != 0; mask <<= 1) { +- char hex[6]; ++ char hex[sizeof(mask) * 2 + 4]; /* 2 chars/byte + 0x, + NUL */ + + if ((fe_flags & mask) == 0) + continue; +-- +2.16.1.72.g5be1f00a9a + diff --git a/debian/patches/libext2fs-add-sanity-checks-for-ea_in_inode b/debian/patches/libext2fs-add-sanity-checks-for-ea_in_inode new file mode 100644 index 0000000..4e629c9 --- /dev/null +++ b/debian/patches/libext2fs-add-sanity-checks-for-ea_in_inode @@ -0,0 +1,68 @@ +Description: libext2fs: add sanity checks for ea_in_inode + An inode containing the value for an extended attribute (aka an + ea_in_inode) must not have the INLINE_DATA flag and must have the + EA_INODE flag set. Enforcing this prevents e2fsck and debugfs crashes + caused by a maliciously crafted file system containing an inode which + has both the EA_INODE and INLINE_DATA flags set, and where that inode + has an extended attribute whose e_value_inum points to itself. +From: Theodore Ts'o +Origin: upstream, commit:9db53e3fec34 +--- + e2fsck/pass1.c | 1 + + lib/ext2fs/ext2_err.et.in | 3 +++ + lib/ext2fs/ext_attr.c | 8 +++++++- + 3 files changed, 11 insertions(+), 1 deletion(-) + +diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c +index fccd8816a..69b3f09e7 100644 +--- a/e2fsck/pass1.c ++++ b/e2fsck/pass1.c +@@ -1542,6 +1542,7 @@ void e2fsck_pass1(e2fsck_t ctx) + case EXT2_ET_NO_INLINE_DATA: + case EXT2_ET_EXT_ATTR_CSUM_INVALID: + case EXT2_ET_EA_BAD_VALUE_OFFSET: ++ case EXT2_ET_EA_INODE_CORRUPTED: + /* broken EA or no system.data EA; truncate */ + if (fix_problem(ctx, PR_1_INLINE_DATA_NO_ATTR, + &pctx)) { +diff --git a/lib/ext2fs/ext2_err.et.in b/lib/ext2fs/ext2_err.et.in +index ac96964d9..16abd23d8 100644 +--- a/lib/ext2fs/ext2_err.et.in ++++ b/lib/ext2fs/ext2_err.et.in +@@ -542,4 +542,7 @@ ec EXT2_ET_CORRUPT_JOURNAL_SB, + ec EXT2_ET_INODE_CORRUPTED, + "Inode is corrupted" + ++ec EXT2_ET_EA_INODE_CORRUPTED, ++ "Inode containing extended attribute value is corrupted" ++ + end +diff --git a/lib/ext2fs/ext_attr.c b/lib/ext2fs/ext_attr.c +index 89c5f2cb6..81b067ad5 100644 +--- a/lib/ext2fs/ext_attr.c ++++ b/lib/ext2fs/ext_attr.c +@@ -903,6 +903,7 @@ static errcode_t read_xattrs_from_buffer(struct ext2_xattr_handle *handle, + memcpy(x->value, value_start + entry->e_value_offs, + entry->e_value_size); + } else { ++ struct ext2_inode *ea_inode; + ext2_file_t ea_file; + + if (entry->e_value_offs != 0) +@@ -920,7 +921,12 @@ static errcode_t read_xattrs_from_buffer(struct ext2_xattr_handle *handle, + if (err) + return err; + +- if (ext2fs_file_get_size(ea_file) != ++ ea_inode = ext2fs_file_get_inode(ea_file); ++ if ((ea_inode->i_flags & EXT4_INLINE_DATA_FL) || ++ !(ea_inode->i_flags & EXT4_EA_INODE_FL) || ++ ea_inode->i_links_count == 0) ++ err = EXT2_ET_EA_INODE_CORRUPTED; ++ else if (ext2fs_file_get_size(ea_file) != + entry->e_value_size) + err = EXT2_ET_EA_BAD_VALUE_SIZE; + else +-- +2.16.1.72.g5be1f00a9a + diff --git a/debian/patches/series b/debian/patches/series new file mode 100644 index 0000000..e0639d5 --- /dev/null +++ b/debian/patches/series @@ -0,0 +1,4 @@ +filefrag-avoid-temporary-buffer-overflow +e2fsck-adjust-quota-counters-when-clearing-orphaned-inodes +libext2fs-add-sanity-checks-for-ea_in_inode +e2image-fix-metadata-image-handling-on-big-endian-systems diff --git a/tests/f_orphquot/expect b/tests/f_orphquot/expect deleted file mode 100644 index 90a7813..0000000 --- a/tests/f_orphquot/expect +++ /dev/null @@ -1,10 +0,0 @@ -Clearing orphaned inode 12 (uid=0, gid=0, mode=0100644, size=3842048) -Pass 1: Checking inodes, blocks, and sizes -Pass 2: Checking directory structure -Pass 3: Checking directory connectivity -Pass 4: Checking reference counts -Pass 5: Checking group summary information - -test_filesystem: ***** FILE SYSTEM WAS MODIFIED ***** -test_filesystem: 11/512 files (9.1% non-contiguous), 1070/2048 blocks -Exit status is 0 diff --git a/tests/f_orphquot/image.bz2 b/tests/f_orphquot/image.bz2 deleted file mode 100644 index 44c831852b0740019705c1ffbafa3d37cc561da8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1327 zcmV+~1 zXg~na8Z^}8U|8G00004z$O3y z044%334j3500004!fB%+r=TVP002c2OoE=KN2!uz$l4&tVjiPRnKBvyqaX}`(?Osb zX{LiiMuvbI00ThDrkI9-gsStIa}90{i-o$^7K0&Fnl9v$_;F03eab6_f5x#K3=KaF zQ*~*u%QiQ&Qe^9>Ziq-jW<+WByf<$9k6!f8P~E+8+J^C$TbAECr+Q!unGTl)FSayf zd4mzQ(W!iAD$TM%gJAb=^|Tg6pp0z^MJZp}M z1JcvVyY18apMiIyk;CoH8RNGpg0 zAfO#HnNBxN;}K4G%$Qds2I7IBU_&6n&|q=LNaHxIL!4n-3NnK7D+rdz1poj7+YMn` zDQF;2p#n0%jbu~}V+@Ki*fP<9LstkF7*(Lc2T20mVH<1=u&WFRLkfkVg>&pR)gZ9K zx5!yx1%^2i6+i$0lBbAqGtI4FMl%5{A*d?8(UYiniqs~V`5gmccz_%3*oI0FhE^Y^ zf=$*6?1_B)*(yI?9!zK-mYBF+YEZ+4pineT4oo3ze#iM90hJqVVupqAU5iJSgu`LN zV~q%9&HVncsrB4Kii9xstOGE?02!?5xFDl;FN`hog)Oup9HHOqYC;XQXfubk_YG6Q#l1RKVbf!O&f?0|I>j>Z_eUk!0*UG z0q`KG-U56NoMHGFn$Rtk<~qL`^DECnE8gi$Q8>RDhNJ3$I7t;W?+fA|1#AW`;+cz1PgL $TMPFILE - -rm -rf $OUT -$FSCK -f -y -N test_filesystem $TMPFILE > $OUT.new 2>&1 -status=$? -echo Exit status is $status >> $OUT.new -sed -f $cmd_dir/filter.sed $OUT.new >> $OUT -rm -f $OUT.new - -cmp -s $OUT $EXP -status=$? - -if [ "$status" = 0 ] ; then - echo "$test_name: $test_description: ok" - touch $test_name.ok -else - echo "$test_name: $test_description: failed" - diff $DIFF_OPTS $EXP $OUT > $test_name.failed - rm -f tmp_expect -fi - -unset IMAGE FSCK_OPT OUT EXP -- 1.8.3.1