--- /dev/null
+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" <darrick.wong@oracle.com>
+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
+
--- /dev/null
+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 <lczerner@redhat.com>
+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
+
--- /dev/null
+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 <adilger@dilger.ca>
+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
+
--- /dev/null
+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 <tytso@mit.edu>
+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
+
--- /dev/null
+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
+++ /dev/null
-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
+++ /dev/null
-test_description="e2fsck with quota and orphan inodes"
-OUT=$test_name.log
-EXP=$test_dir/expect
-
-bzip2 -dc < $test_dir/image.bz2 > $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