linux-ext4.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/2] mke2fs: fix project quota creation
@ 2016-05-22  2:19 Theodore Ts'o
  2016-05-22  2:19 ` [PATCH 2/2] e2fsck: fix project quota support Theodore Ts'o
  2016-05-22  5:34 ` [PATCH 1/2] mke2fs: fix project quota creation Wang Shilong
  0 siblings, 2 replies; 5+ messages in thread
From: Theodore Ts'o @ 2016-05-22  2:19 UTC (permalink / raw)
  To: Ext4 Developers List; +Cc: Theodore Ts'o

Creating a file system with project quotas can fail if mke2fs is built
using hardening options.  This is because quota_compute_usage() used
ext2fs_get_next_inode() instead of ext2fs_get_inode_full(), and a
small inode was passed into quota_data_add, when a large inode needs
to be used.  As a result get_dq() would end up dereferencing undefined
space in the stack.  Without the hardening options, this would be
zero, so "mke2fs -t ext4 -O project.quota -I 256 test.img" would work
essentially by accident.

Fix this by using ext2fs_get_inode_full() so that a large inode is
available to quota_data_inodes().

Signed-off-by: Theodore Ts'o <tytso@mit.edu>
---
 lib/support/mkquota.c | 21 +++++++++++++--------
 1 file changed, 13 insertions(+), 8 deletions(-)

diff --git a/lib/support/mkquota.c b/lib/support/mkquota.c
index c5dd140..a432d4e 100644
--- a/lib/support/mkquota.c
+++ b/lib/support/mkquota.c
@@ -448,7 +448,8 @@ errcode_t quota_compute_usage(quota_ctx_t qctx)
 	ext2_filsys fs;
 	ext2_ino_t ino;
 	errcode_t ret;
-	struct ext2_inode inode;
+	struct ext2_inode *inode;
+	int inode_size;
 	qsize_t space;
 	ext2_inode_scan scan;
 
@@ -461,27 +462,31 @@ errcode_t quota_compute_usage(quota_ctx_t qctx)
 		log_err("while opening inode scan. ret=%ld", ret);
 		return ret;
 	}
-
+	inode_size = fs->super->s_inode_size;
+	inode = malloc(inode_size);
+	if (!inode)
+		return ENOMEM;
 	while (1) {
-		ret = ext2fs_get_next_inode(scan, &ino, &inode);
+		ret = ext2fs_get_next_inode_full(scan, &ino, inode, inode_size);
 		if (ret) {
 			log_err("while getting next inode. ret=%ld", ret);
 			ext2fs_close_inode_scan(scan);
+			free(inode);
 			return ret;
 		}
 		if (ino == 0)
 			break;
-		if (inode.i_links_count &&
+		if (inode->i_links_count &&
 		    (ino == EXT2_ROOT_INO ||
 		     ino >= EXT2_FIRST_INODE(fs->super))) {
-			space = ext2fs_inode_i_blocks(fs, &inode) << 9;
-			quota_data_add(qctx, &inode, ino, space);
-			quota_data_inodes(qctx, &inode, ino, +1);
+			space = ext2fs_inode_i_blocks(fs, inode) << 9;
+			quota_data_add(qctx, inode, ino, space);
+			quota_data_inodes(qctx, inode, ino, +1);
 		}
 	}
 
 	ext2fs_close_inode_scan(scan);

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 2/2] e2fsck: fix project quota support
  2016-05-22  2:19 [PATCH 1/2] mke2fs: fix project quota creation Theodore Ts'o
@ 2016-05-22  2:19 ` Theodore Ts'o
  2016-05-22  5:38   ` Wang Shilong
  2016-05-22  5:34 ` [PATCH 1/2] mke2fs: fix project quota creation Wang Shilong
  1 sibling, 1 reply; 5+ messages in thread
From: Theodore Ts'o @ 2016-05-22  2:19 UTC (permalink / raw)
  To: Ext4 Developers List; +Cc: Theodore Ts'o

Use a large_inode so that when e2fsck is fixing a file system with
project quota enabled, the correct project id's quota is adjusted when
a corrupted inode is deleted.

Signed-off-by: Theodore Ts'o <tytso@mit.edu>
---
 e2fsck/pass1.c        |  7 +++--
 e2fsck/pass1b.c       | 83 +++++++++++++++++++++++++++++----------------------
 e2fsck/pass3.c        | 21 +++++++------
 e2fsck/pass4.c        | 33 ++++++++++----------
 lib/ext2fs/ext2_fs.h  |  6 ++++
 lib/support/mkquota.c | 22 +++++++-------
 lib/support/quotaio.h | 12 ++++----
 7 files changed, 103 insertions(+), 81 deletions(-)

diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c
index e097c39..799158e 100644
--- a/e2fsck/pass1.c
+++ b/e2fsck/pass1.c
@@ -3165,9 +3165,10 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
 
 	if (ino != quota_type2inum(PRJQUOTA, fs->super) &&
 	    (ino == EXT2_ROOT_INO || ino >= EXT2_FIRST_INODE(ctx->fs->super))) {
-		quota_data_add(ctx->qctx, inode, ino,
-			       pb.num_blocks * fs->blocksize);
-		quota_data_inodes(ctx->qctx, inode, ino, +1);
+		quota_data_add(ctx->qctx, (struct ext2_inode_large *) inode,
+			       ino, pb.num_blocks * fs->blocksize);
+		quota_data_inodes(ctx->qctx, (struct ext2_inode_large *) inode,
+				  ino, +1);
 	}
 
 	if (!ext2fs_has_feature_huge_file(fs->super) ||
diff --git a/e2fsck/pass1b.c b/e2fsck/pass1b.c
index 2cbf82a..b40f026 100644
--- a/e2fsck/pass1b.c
+++ b/e2fsck/pass1b.c
@@ -79,7 +79,7 @@ struct dup_cluster {
 struct dup_inode {
 	ext2_ino_t		dir;
 	int			num_dupblocks;
-	struct ext2_inode	inode;
+	struct ext2_inode_large	inode;
 	struct cluster_el	*cluster_list;
 };
 
@@ -118,7 +118,7 @@ static int dict_int_cmp(const void *a, const void *b)
  * Add a duplicate block record
  */
 static void add_dupe(e2fsck_t ctx, ext2_ino_t ino, blk64_t cluster,
-		     struct ext2_inode *inode)
+		     struct ext2_inode_large *inode)
 {
 	dnode_t	*n;
 	struct dup_cluster	*db;
@@ -263,7 +263,7 @@ struct process_block_struct {
 	int		dup_blocks;
 	blk64_t		cur_cluster, phys_cluster;
 	blk64_t		last_blk;
-	struct ext2_inode *inode;
+	struct ext2_inode_large *inode;
 	struct problem_context *pctx;
 };
 
@@ -271,7 +271,7 @@ static void pass1b(e2fsck_t ctx, char *block_buf)
 {
 	ext2_filsys fs = ctx->fs;
 	ext2_ino_t ino = 0;
-	struct ext2_inode inode;
+	struct ext2_inode_large inode;
 	ext2_inode_scan	scan;
 	struct process_block_struct pb;
 	struct problem_context pctx;
@@ -288,7 +288,7 @@ static void pass1b(e2fsck_t ctx, char *block_buf)
 		ctx->flags |= E2F_FLAG_ABORT;
 		return;
 	}
-	ctx->stashed_inode = &inode;
+	ctx->stashed_inode = EXT2_INODE(&inode);
 	pb.ctx = ctx;
 	pb.pctx = &pctx;
 	pctx.str = "pass1b";
@@ -297,7 +297,8 @@ static void pass1b(e2fsck_t ctx, char *block_buf)
 			if (e2fsck_mmp_update(fs))
 				fatal_error(ctx, 0);
 		}
-		pctx.errcode = ext2fs_get_next_inode(scan, &ino, &inode);
+		pctx.errcode = ext2fs_get_next_inode_full(scan, &ino,
+				EXT2_INODE(&inode), sizeof(inode));
 		if (pctx.errcode == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE)
 			continue;
 		if (pctx.errcode) {
@@ -321,18 +322,18 @@ static void pass1b(e2fsck_t ctx, char *block_buf)
 		pb.last_blk = 0;
 		pb.pctx->blk = pb.pctx->blk2 = 0;
 
-		if (ext2fs_inode_has_valid_blocks2(fs, &inode) ||
+		if (ext2fs_inode_has_valid_blocks2(fs, EXT2_INODE(&inode)) ||
 		    (ino == EXT2_BAD_INO))
 			pctx.errcode = ext2fs_block_iterate3(fs, ino,
 					     BLOCK_FLAG_READ_ONLY, block_buf,
 					     process_pass1b_block, &pb);
 		/* If the feature is not set, attrs will be cleared later anyway */
 		if (ext2fs_has_feature_xattr(fs->super) &&
-		    ext2fs_file_acl_block(fs, &inode)) {
-			blk64_t blk = ext2fs_file_acl_block(fs, &inode);
+		    ext2fs_file_acl_block(fs, EXT2_INODE(&inode))) {
+			blk64_t blk = ext2fs_file_acl_block(fs, EXT2_INODE(&inode));
 			process_pass1b_block(fs, &blk,
 					     BLOCK_COUNT_EXTATTR, 0, 0, &pb);
-			ext2fs_file_acl_block_set(fs, &inode, blk);
+			ext2fs_file_acl_block_set(fs, EXT2_INODE(&inode), blk);
 		}
 		if (pb.dup_blocks) {
 			if (ino != EXT2_BAD_INO) {
@@ -548,7 +549,7 @@ static void pass1d(e2fsck_t ctx, char *block_buf)
 		/*
 		 * Report the inode that we are working on
 		 */
-		pctx.inode = &p->inode;
+		pctx.inode = EXT2_INODE(&p->inode);
 		pctx.ino = ino;
 		pctx.dir = p->dir;
 		pctx.blkcount = p->num_dupblocks;
@@ -568,7 +569,7 @@ static void pass1d(e2fsck_t ctx, char *block_buf)
 			/*
 			 * Report the inode that we are sharing with
 			 */
-			pctx.inode = &t->inode;
+			pctx.inode = EXT2_INODE(&t->inode);
 			pctx.ino = shared[i];
 			pctx.dir = t->dir;
 			fix_problem(ctx, PR_1D_DUP_FILE_LIST, &pctx);
@@ -668,7 +669,7 @@ static void delete_file(e2fsck_t ctx, ext2_ino_t ino,
 	pctx.str = "delete_file";
 	pb.cur_cluster = ~0;
 
-	if (ext2fs_inode_has_valid_blocks2(fs, &dp->inode))
+	if (ext2fs_inode_has_valid_blocks2(fs, EXT2_INODE(&dp->inode)))
 		pctx.errcode = ext2fs_block_iterate3(fs, ino,
 						     BLOCK_FLAG_READ_ONLY,
 						     block_buf,
@@ -683,20 +684,23 @@ static void delete_file(e2fsck_t ctx, ext2_ino_t ino,
 	quota_data_inodes(ctx->qctx, &dp->inode, ino, -1);
 
 	/* Inode may have changed by block_iterate, so reread it */
-	e2fsck_read_inode(ctx, ino, &dp->inode, "delete_file");
-	e2fsck_clear_inode(ctx, ino, &dp->inode, 0, "delete_file");
-	if (ext2fs_file_acl_block(fs, &dp->inode) &&
+	e2fsck_read_inode_full(ctx, ino, EXT2_INODE(&dp->inode),
+			       sizeof(dp->inode), "delete_file");
+	e2fsck_clear_inode(ctx, ino, EXT2_INODE(&dp->inode), 0, "delete_file");
+	if (ext2fs_file_acl_block(fs, EXT2_INODE(&dp->inode)) &&
 	    ext2fs_has_feature_xattr(fs->super)) {
+		blk64_t file_acl_block = ext2fs_file_acl_block(fs,
+						EXT2_INODE(&dp->inode));
+
 		count = 1;
-		pctx.errcode = ext2fs_adjust_ea_refcount3(fs,
-					ext2fs_file_acl_block(fs, &dp->inode),
+		pctx.errcode = ext2fs_adjust_ea_refcount3(fs, file_acl_block,
 					block_buf, -1, &count, ino);
 		if (pctx.errcode == EXT2_ET_BAD_EA_BLOCK_NUM) {
 			pctx.errcode = 0;
 			count = 1;
 		}
 		if (pctx.errcode) {
-			pctx.blk = ext2fs_file_acl_block(fs, &dp->inode);
+			pctx.blk = file_acl_block;
 			fix_problem(ctx, PR_1B_ADJ_EA_REFCOUNT, &pctx);
 		}
 		/*
@@ -707,12 +711,13 @@ static void delete_file(e2fsck_t ctx, ext2_ino_t ino,
 		 */
 		if ((count == 0) ||
 		    ext2fs_test_block_bitmap2(ctx->block_dup_map,
-					ext2fs_file_acl_block(fs, &dp->inode))) {
-			blk64_t blk = ext2fs_file_acl_block(fs, &dp->inode);
-			delete_file_block(fs, &blk,
+					      file_acl_block)) {
+			delete_file_block(fs, &file_acl_block,
 					  BLOCK_COUNT_EXTATTR, 0, 0, &pb);
-			ext2fs_file_acl_block_set(fs, &dp->inode, blk);
-			quota_data_sub(ctx->qctx, &dp->inode, ino, fs->blocksize);
+			ext2fs_file_acl_block_set(fs, EXT2_INODE(&dp->inode),
+						  file_acl_block);
+			quota_data_sub(ctx->qctx, &dp->inode, ino,
+				       fs->blocksize);
 		}
 	}
 }
@@ -724,7 +729,7 @@ struct clone_struct {
 	ext2_ino_t	dir, ino;
 	char	*buf;
 	e2fsck_t ctx;
-	struct ext2_inode	*inode;
+	struct ext2_inode_large	*inode;
 
 	struct dup_cluster *save_dup_cluster;
 	blk64_t save_blocknr;
@@ -800,7 +805,8 @@ static int clone_file_block(ext2_filsys fs,
 		 * mapped to multiple physical clusters.
 		 */
 		new_block = 0;
-		retval = ext2fs_map_cluster_block(fs, cs->ino, cs->inode,
+		retval = ext2fs_map_cluster_block(fs, cs->ino,
+						  EXT2_INODE(cs->inode),
 						  blockcnt, &new_block);
 		if (retval == 0 && new_block != 0 &&
 		    EXT2FS_B2C(ctx->fs, new_block) !=
@@ -882,7 +888,7 @@ static errcode_t clone_file(e2fsck_t ctx, ext2_ino_t ino,
 
 	pctx.ino = ino;
 	pctx.str = "clone_file";
-	if (ext2fs_inode_has_valid_blocks2(fs, &dp->inode))
+	if (ext2fs_inode_has_valid_blocks2(fs, EXT2_INODE(&dp->inode)))
 		pctx.errcode = ext2fs_block_iterate3(fs, ino, 0, block_buf,
 						     clone_file_block, &cs);
 	deferred_dec_badcount(&cs);
@@ -899,14 +905,16 @@ static errcode_t clone_file(e2fsck_t ctx, ext2_ino_t ino,
 		goto errout;
 	}
 	/* The inode may have changed on disk, so we have to re-read it */
-	e2fsck_read_inode(ctx, ino, &dp->inode, "clone file EA");
-	blk = ext2fs_file_acl_block(fs, &dp->inode);
+	e2fsck_read_inode_full(ctx, ino, EXT2_INODE(&dp->inode),
+			       sizeof(dp->inode), "clone file EA");
+	blk = ext2fs_file_acl_block(fs, EXT2_INODE(&dp->inode));
 	new_blk = blk;
 	if (blk && (clone_file_block(fs, &new_blk,
 				     BLOCK_COUNT_EXTATTR, 0, 0, &cs) ==
 		    BLOCK_CHANGED)) {
-		ext2fs_file_acl_block_set(fs, &dp->inode, new_blk);
-		e2fsck_write_inode(ctx, ino, &dp->inode, "clone file EA");
+		ext2fs_file_acl_block_set(fs, EXT2_INODE(&dp->inode), new_blk);
+		e2fsck_write_inode_full(ctx, ino, EXT2_INODE(&dp->inode),
+					sizeof(dp->inode), "clone file EA");
 		/*
 		 * If we cloned the EA block, find all other inodes
 		 * which refered to that EA block, and modify
@@ -935,11 +943,14 @@ static errcode_t clone_file(e2fsck_t ctx, ext2_ino_t ino,
 				goto errout;
 			}
 			di = (struct dup_inode *) dnode_get(n);
-			if (ext2fs_file_acl_block(fs, &di->inode) == blk) {
-				ext2fs_file_acl_block_set(fs, &di->inode,
-					ext2fs_file_acl_block(fs, &dp->inode));
-				e2fsck_write_inode(ctx, ino_el->inode,
-					   &di->inode, "clone file EA");
+			if (ext2fs_file_acl_block(fs,
+					EXT2_INODE(&di->inode)) == blk) {
+				ext2fs_file_acl_block_set(fs,
+					EXT2_INODE(&di->inode),
+					ext2fs_file_acl_block(fs, EXT2_INODE(&dp->inode)));
+				e2fsck_write_inode_full(ctx, ino_el->inode,
+					EXT2_INODE(&di->inode),
+					sizeof(di->inode), "clone file EA");
 				decrement_badcount(ctx, blk, dc);
 			}
 		}
diff --git a/e2fsck/pass3.c b/e2fsck/pass3.c
index 3b076c4..44203ca 100644
--- a/e2fsck/pass3.c
+++ b/e2fsck/pass3.c
@@ -381,7 +381,7 @@ ext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix)
 	ext2_ino_t			ino;
 	blk64_t			blk;
 	errcode_t		retval;
-	struct ext2_inode	inode;
+	struct ext2_inode_large	inode;
 	char *			block;
 	static const char	name[] = "lost+found";
 	struct 	problem_context	pctx;
@@ -406,7 +406,8 @@ ext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix)
 		return 0;
 	if (!retval) {
 		/* Lost+found shouldn't have inline data */
-		retval = ext2fs_read_inode(fs, ino, &inode);
+		retval = ext2fs_read_inode_full(fs, ino, EXT2_INODE(&inode),
+						sizeof(inode));
 		if (fix && retval)
 			return 0;
 
@@ -518,13 +519,13 @@ skip_new_block:
 	inode.i_size = fs->blocksize;
 	inode.i_atime = inode.i_ctime = inode.i_mtime = ctx->now;
 	inode.i_links_count = 2;
-	ext2fs_iblk_set(fs, &inode, 1);
+	ext2fs_iblk_set(fs, EXT2_INODE(&inode), 1);
 	inode.i_block[0] = blk;
 
 	/*
 	 * Next, write out the inode.
 	 */
-	pctx.errcode = ext2fs_write_new_inode(fs, ino, &inode);
+	pctx.errcode = ext2fs_write_new_inode(fs, ino, EXT2_INODE(&inode));
 	if (pctx.errcode) {
 		pctx.str = "ext2fs_write_inode";
 		fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx);
@@ -855,7 +856,7 @@ errcode_t e2fsck_expand_directory(e2fsck_t ctx, ext2_ino_t dir,
 	ext2_filsys fs = ctx->fs;
 	errcode_t	retval;
 	struct expand_dir_struct es;
-	struct ext2_inode	inode;
+	struct ext2_inode_large	inode;
 	blk64_t		sz;
 
 	if (!(fs->flags & EXT2_FLAG_RW))
@@ -888,18 +889,20 @@ errcode_t e2fsck_expand_directory(e2fsck_t ctx, ext2_ino_t dir,
 	/*
 	 * Update the size and block count fields in the inode.
 	 */
-	retval = ext2fs_read_inode(fs, dir, &inode);
+	retval = ext2fs_read_inode_full(fs, dir,
+					EXT2_INODE(&inode), sizeof(inode));
 	if (retval)
 		return retval;
 
 	sz = (es.last_block + 1) * fs->blocksize;
-	retval = ext2fs_inode_size_set(fs, &inode, sz);
+	retval = ext2fs_inode_size_set(fs, EXT2_INODE(&inode), sz);
 	if (retval)
 		return retval;
-	ext2fs_iblk_add_blocks(fs, &inode, es.newblocks);
+	ext2fs_iblk_add_blocks(fs, EXT2_INODE(&inode), es.newblocks);
 	quota_data_add(ctx->qctx, &inode, dir, es.newblocks * fs->blocksize);
 
-	e2fsck_write_inode(ctx, dir, &inode, "expand_directory");
+	e2fsck_write_inode_full(ctx, dir, EXT2_INODE(&inode),
+				sizeof(inode), "expand_directory");
 
 	return 0;
 }
diff --git a/e2fsck/pass4.c b/e2fsck/pass4.c
index c490438..8c101fd 100644
--- a/e2fsck/pass4.c
+++ b/e2fsck/pass4.c
@@ -26,23 +26,21 @@
  * rest of the pass 4 tests.
  */
 static int disconnect_inode(e2fsck_t ctx, ext2_ino_t i,
-			    struct ext2_inode *inode)
+			    struct ext2_inode_large *inode)
 {
 	ext2_filsys fs = ctx->fs;
 	struct problem_context	pctx;
 	__u32 eamagic = 0;
 	int extra_size = 0;
 
-	if (EXT2_INODE_SIZE(fs->super) > EXT2_GOOD_OLD_INODE_SIZE) {
-		e2fsck_read_inode_full(ctx, i, inode,EXT2_INODE_SIZE(fs->super),
-				       "pass4: disconnect_inode");
-		extra_size = ((struct ext2_inode_large *)inode)->i_extra_isize;
-	} else {
-		e2fsck_read_inode(ctx, i, inode, "pass4: disconnect_inode");
-	}
+	e2fsck_read_inode_full(ctx, i, EXT2_INODE(inode),
+			       EXT2_INODE_SIZE(fs->super),
+			       "pass4: disconnect_inode");
+	if (EXT2_INODE_SIZE(fs->super) > EXT2_GOOD_OLD_INODE_SIZE)
+		extra_size = inode->i_extra_isize;
 	clear_problem_context(&pctx);
 	pctx.ino = i;
-	pctx.inode = inode;
+	pctx.inode = EXT2_INODE(inode);
 
 	if (EXT2_INODE_SIZE(fs->super) -EXT2_GOOD_OLD_INODE_SIZE -extra_size >0)
 		eamagic = *(__u32 *)(((char *)inode) +EXT2_GOOD_OLD_INODE_SIZE +
@@ -56,7 +54,7 @@ static int disconnect_inode(e2fsck_t ctx, ext2_ino_t i,
 	if (!inode->i_blocks && eamagic != EXT2_EXT_ATTR_MAGIC &&
 	    (LINUX_S_ISREG(inode->i_mode) || LINUX_S_ISDIR(inode->i_mode))) {
 		if (fix_problem(ctx, PR_4_ZERO_LEN_INODE, &pctx)) {
-			e2fsck_clear_inode(ctx, i, inode, 0,
+			e2fsck_clear_inode(ctx, i, EXT2_INODE(inode), 0,
 					   "disconnect_inode");
 			/*
 			 * Fix up the bitmaps...
@@ -92,7 +90,8 @@ void e2fsck_pass4(e2fsck_t ctx)
 {
 	ext2_filsys fs = ctx->fs;
 	ext2_ino_t	i;
-	struct ext2_inode	*inode;
+	struct ext2_inode_large	*inode;
+	int inode_size = EXT2_INODE_SIZE(fs->super);
 #ifdef RESOURCE_TRACK
 	struct resource_track	rtrack;
 #endif
@@ -127,8 +126,7 @@ void e2fsck_pass4(e2fsck_t ctx)
 		if ((ctx->progress)(ctx, 4, 0, maxgroup))
 			return;
 
-	inode = e2fsck_allocate_memory(ctx, EXT2_INODE_SIZE(fs->super),
-				       "scratch inode");
+	inode = e2fsck_allocate_memory(ctx, inode_size, "scratch inode");
 
 	/* Protect loop from wrap-around if s_inodes_count maxed */
 	for (i=1; i <= fs->super->s_inodes_count && i > 0; i++) {
@@ -171,9 +169,10 @@ void e2fsck_pass4(e2fsck_t ctx)
 		if (isdir && (link_counted > EXT2_LINK_MAX))
 			link_counted = 1;
 		if (link_counted != link_count) {
-			e2fsck_read_inode(ctx, i, inode, "pass4");
+			e2fsck_read_inode_full(ctx, i, EXT2_INODE(inode),
+					       inode_size, "pass4");
 			pctx.ino = i;
-			pctx.inode = inode;
+			pctx.inode = EXT2_INODE(inode);
 			if ((link_count != inode->i_links_count) && !isdir &&
 			    (inode->i_links_count <= EXT2_LINK_MAX)) {
 				pctx.num = link_count;
@@ -188,7 +187,9 @@ void e2fsck_pass4(e2fsck_t ctx)
 			     link_count == 1 && !(ctx->options & E2F_OPT_NO)) ||
 			    fix_problem(ctx, PR_4_BAD_REF_COUNT, &pctx)) {
 				inode->i_links_count = link_counted;
-				e2fsck_write_inode(ctx, i, inode, "pass4");
+				e2fsck_write_inode_full(ctx, i,
+							EXT2_INODE(inode),
+							inode_size, "pass4");
 			}
 		}
 	}
diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h
index 9918356..ee9a5f2 100644
--- a/lib/ext2fs/ext2_fs.h
+++ b/lib/ext2fs/ext2_fs.h
@@ -519,6 +519,12 @@ struct ext2_inode_large {
 #define ext2fs_set_i_uid_high(inode,x) ((inode).osd2.linux2.l_i_uid_high = (x))
 #define ext2fs_set_i_gid_high(inode,x) ((inode).osd2.linux2.l_i_gid_high = (x))
 
+static inline
+struct ext2_inode *EXT2_INODE(struct ext2_inode_large *large_inode)
+{
+	return (struct ext2_inode *) large_inode;
+}
+
 /*
  * File system states
  */
diff --git a/lib/support/mkquota.c b/lib/support/mkquota.c
index a432d4e..add60ca 100644
--- a/lib/support/mkquota.c
+++ b/lib/support/mkquota.c
@@ -243,9 +243,8 @@ static int dict_uint_cmp(const void *a, const void *b)
 		return -1;
 }
 
-static inline qid_t get_qid(struct ext2_inode *inode, enum quota_type qtype)
+static inline qid_t get_qid(struct ext2_inode_large *inode, enum quota_type qtype)
 {
-	struct ext2_inode_large *large_inode;
 	int inode_size;
 
 	switch (qtype) {
@@ -254,11 +253,10 @@ static inline qid_t get_qid(struct ext2_inode *inode, enum quota_type qtype)
 	case GRPQUOTA:
 		return inode_gid(*inode);
 	case PRJQUOTA:
-		large_inode = (struct ext2_inode_large *)inode;
 		inode_size = EXT2_GOOD_OLD_INODE_SIZE +
-			     large_inode->i_extra_isize;
+			inode->i_extra_isize;
 		if (inode_includes(inode_size, i_projid))
-			return inode_projid(*large_inode);
+			return inode_projid(*inode);
 	default:
 		return 0;
 	}
@@ -368,7 +366,7 @@ static struct dquot *get_dq(dict_t *dict, __u32 key)
 /*
  * Called to update the blocks used by a particular inode
  */
-void quota_data_add(quota_ctx_t qctx, struct ext2_inode *inode,
+void quota_data_add(quota_ctx_t qctx, struct ext2_inode_large *inode,
 		    ext2_ino_t ino EXT2FS_ATTR((unused)),
 		    qsize_t space)
 {
@@ -395,7 +393,7 @@ void quota_data_add(quota_ctx_t qctx, struct ext2_inode *inode,
 /*
  * Called to remove some blocks used by a particular inode
  */
-void quota_data_sub(quota_ctx_t qctx, struct ext2_inode *inode,
+void quota_data_sub(quota_ctx_t qctx, struct ext2_inode_large *inode,
 		    ext2_ino_t ino EXT2FS_ATTR((unused)),
 		    qsize_t space)
 {
@@ -421,7 +419,7 @@ void quota_data_sub(quota_ctx_t qctx, struct ext2_inode *inode,
 /*
  * Called to count the files used by an inode's user/group
  */
-void quota_data_inodes(quota_ctx_t qctx, struct ext2_inode *inode,
+void quota_data_inodes(quota_ctx_t qctx, struct ext2_inode_large *inode,
 		       ext2_ino_t ino EXT2FS_ATTR((unused)), int adjust)
 {
 	struct dquot	*dq;
@@ -448,7 +446,7 @@ errcode_t quota_compute_usage(quota_ctx_t qctx)
 	ext2_filsys fs;
 	ext2_ino_t ino;
 	errcode_t ret;
-	struct ext2_inode *inode;
+	struct ext2_inode_large *inode;
 	int inode_size;
 	qsize_t space;
 	ext2_inode_scan scan;
@@ -467,7 +465,8 @@ errcode_t quota_compute_usage(quota_ctx_t qctx)
 	if (!inode)
 		return ENOMEM;
 	while (1) {
-		ret = ext2fs_get_next_inode_full(scan, &ino, inode, inode_size);
+		ret = ext2fs_get_next_inode_full(scan, &ino,
+						 EXT2_INODE(inode), inode_size);
 		if (ret) {
 			log_err("while getting next inode. ret=%ld", ret);
 			ext2fs_close_inode_scan(scan);
@@ -479,7 +478,8 @@ errcode_t quota_compute_usage(quota_ctx_t qctx)
 		if (inode->i_links_count &&
 		    (ino == EXT2_ROOT_INO ||
 		     ino >= EXT2_FIRST_INODE(fs->super))) {
-			space = ext2fs_inode_i_blocks(fs, inode) << 9;
+			space = ext2fs_inode_i_blocks(fs,
+						      EXT2_INODE(inode)) << 9;
 			quota_data_add(qctx, inode, ino, space);
 			quota_data_inodes(qctx, inode, ino, +1);
 		}
diff --git a/lib/support/quotaio.h b/lib/support/quotaio.h
index 5f1073f..8f7ddcb 100644
--- a/lib/support/quotaio.h
+++ b/lib/support/quotaio.h
@@ -217,12 +217,12 @@ const char *quota_get_qf_name(enum quota_type, int fmt, char *buf);
 /* In mkquota.c */
 errcode_t quota_init_context(quota_ctx_t *qctx, ext2_filsys fs,
 			     unsigned int qtype_bits);
-void quota_data_inodes(quota_ctx_t qctx, struct ext2_inode *inode, ext2_ino_t ino,
-		int adjust);
-void quota_data_add(quota_ctx_t qctx, struct ext2_inode *inode, ext2_ino_t ino,
-		qsize_t space);
-void quota_data_sub(quota_ctx_t qctx, struct ext2_inode *inode, ext2_ino_t ino,
-		qsize_t space);
+void quota_data_inodes(quota_ctx_t qctx, struct ext2_inode_large *inode,
+		       ext2_ino_t ino, int adjust);
+void quota_data_add(quota_ctx_t qctx, struct ext2_inode_large *inode,
+		    ext2_ino_t ino, qsize_t space);
+void quota_data_sub(quota_ctx_t qctx, struct ext2_inode_large *inode,
+		    ext2_ino_t ino, qsize_t space);
 errcode_t quota_write_inode(quota_ctx_t qctx, enum quota_type qtype);
 errcode_t quota_update_limits(quota_ctx_t qctx, ext2_ino_t qf_ino,
 			      enum quota_type type);
-- 
2.5.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH 1/2] mke2fs: fix project quota creation
  2016-05-22  2:19 [PATCH 1/2] mke2fs: fix project quota creation Theodore Ts'o
  2016-05-22  2:19 ` [PATCH 2/2] e2fsck: fix project quota support Theodore Ts'o
@ 2016-05-22  5:34 ` Wang Shilong
  2016-05-23  0:49   ` Theodore Ts'o
  1 sibling, 1 reply; 5+ messages in thread
From: Wang Shilong @ 2016-05-22  5:34 UTC (permalink / raw)
  To: Theodore Ts'o; +Cc: Ext4 Developers List

On Sun, May 22, 2016 at 10:19 AM, Theodore Ts'o <tytso@mit.edu> wrote:
> Creating a file system with project quotas can fail if mke2fs is built
> using hardening options.  This is because quota_compute_usage() used
> ext2fs_get_next_inode() instead of ext2fs_get_inode_full(), and a
> small inode was passed into quota_data_add, when a large inode needs
> to be used.  As a result get_dq() would end up dereferencing undefined
> space in the stack.  Without the hardening options, this would be
> zero, so "mke2fs -t ext4 -O project.quota -I 256 test.img" would work
> essentially by accident.
>
> Fix this by using ext2fs_get_inode_full() so that a large inode is
> available to quota_data_inodes().
>
> Signed-off-by: Theodore Ts'o <tytso@mit.edu>

I thought Li Xi sent updated e2fsprogs including this fixing parts.
maybe because you merged early version patches.

Reviewed-by: Wang Shilong <wshilong@ddn.com>

> ---
>  lib/support/mkquota.c | 21 +++++++++++++--------
>  1 file changed, 13 insertions(+), 8 deletions(-)
>
> diff --git a/lib/support/mkquota.c b/lib/support/mkquota.c
> index c5dd140..a432d4e 100644
> --- a/lib/support/mkquota.c
> +++ b/lib/support/mkquota.c
> @@ -448,7 +448,8 @@ errcode_t quota_compute_usage(quota_ctx_t qctx)
>         ext2_filsys fs;
>         ext2_ino_t ino;
>         errcode_t ret;
> -       struct ext2_inode inode;
> +       struct ext2_inode *inode;
> +       int inode_size;
>         qsize_t space;
>         ext2_inode_scan scan;
>
> @@ -461,27 +462,31 @@ errcode_t quota_compute_usage(quota_ctx_t qctx)
>                 log_err("while opening inode scan. ret=%ld", ret);
>                 return ret;
>         }
> -
> +       inode_size = fs->super->s_inode_size;
> +       inode = malloc(inode_size);
> +       if (!inode)
> +               return ENOMEM;
>         while (1) {
> -               ret = ext2fs_get_next_inode(scan, &ino, &inode);
> +               ret = ext2fs_get_next_inode_full(scan, &ino, inode, inode_size);
>                 if (ret) {
>                         log_err("while getting next inode. ret=%ld", ret);
>                         ext2fs_close_inode_scan(scan);
> +                       free(inode);
>                         return ret;
>                 }
>                 if (ino == 0)
>                         break;
> -               if (inode.i_links_count &&
> +               if (inode->i_links_count &&
>                     (ino == EXT2_ROOT_INO ||
>                      ino >= EXT2_FIRST_INODE(fs->super))) {
> -                       space = ext2fs_inode_i_blocks(fs, &inode) << 9;
> -                       quota_data_add(qctx, &inode, ino, space);
> -                       quota_data_inodes(qctx, &inode, ino, +1);
> +                       space = ext2fs_inode_i_blocks(fs, inode) << 9;
> +                       quota_data_add(qctx, inode, ino, space);
> +                       quota_data_inodes(qctx, inode, ino, +1);
>                 }
>         }
>
>         ext2fs_close_inode_scan(scan);
> -
> +       free(inode);
>         return 0;
>  }
>
> --
> 2.5.0
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 2/2] e2fsck: fix project quota support
  2016-05-22  2:19 ` [PATCH 2/2] e2fsck: fix project quota support Theodore Ts'o
@ 2016-05-22  5:38   ` Wang Shilong
  0 siblings, 0 replies; 5+ messages in thread
From: Wang Shilong @ 2016-05-22  5:38 UTC (permalink / raw)
  To: Theodore Ts'o; +Cc: Ext4 Developers List

On Sun, May 22, 2016 at 10:19 AM, Theodore Ts'o <tytso@mit.edu> wrote:
> Use a large_inode so that when e2fsck is fixing a file system with
> project quota enabled, the correct project id's quota is adjusted when
> a corrupted inode is deleted.
>
> Signed-off-by: Theodore Ts'o <tytso@mit.edu>

Reviewed-by: Wang Shilong <wshilong@ddn.com>

> ---
>  e2fsck/pass1.c        |  7 +++--
>  e2fsck/pass1b.c       | 83 +++++++++++++++++++++++++++++----------------------
>  e2fsck/pass3.c        | 21 +++++++------
>  e2fsck/pass4.c        | 33 ++++++++++----------
>  lib/ext2fs/ext2_fs.h  |  6 ++++
>  lib/support/mkquota.c | 22 +++++++-------
>  lib/support/quotaio.h | 12 ++++----
>  7 files changed, 103 insertions(+), 81 deletions(-)
>
> diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c
> index e097c39..799158e 100644
> --- a/e2fsck/pass1.c
> +++ b/e2fsck/pass1.c
> @@ -3165,9 +3165,10 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
>
>         if (ino != quota_type2inum(PRJQUOTA, fs->super) &&
>             (ino == EXT2_ROOT_INO || ino >= EXT2_FIRST_INODE(ctx->fs->super))) {
> -               quota_data_add(ctx->qctx, inode, ino,
> -                              pb.num_blocks * fs->blocksize);
> -               quota_data_inodes(ctx->qctx, inode, ino, +1);
> +               quota_data_add(ctx->qctx, (struct ext2_inode_large *) inode,
> +                              ino, pb.num_blocks * fs->blocksize);
> +               quota_data_inodes(ctx->qctx, (struct ext2_inode_large *) inode,
> +                                 ino, +1);
>         }
>
>         if (!ext2fs_has_feature_huge_file(fs->super) ||
> diff --git a/e2fsck/pass1b.c b/e2fsck/pass1b.c
> index 2cbf82a..b40f026 100644
> --- a/e2fsck/pass1b.c
> +++ b/e2fsck/pass1b.c
> @@ -79,7 +79,7 @@ struct dup_cluster {
>  struct dup_inode {
>         ext2_ino_t              dir;
>         int                     num_dupblocks;
> -       struct ext2_inode       inode;
> +       struct ext2_inode_large inode;
>         struct cluster_el       *cluster_list;
>  };
>
> @@ -118,7 +118,7 @@ static int dict_int_cmp(const void *a, const void *b)
>   * Add a duplicate block record
>   */
>  static void add_dupe(e2fsck_t ctx, ext2_ino_t ino, blk64_t cluster,
> -                    struct ext2_inode *inode)
> +                    struct ext2_inode_large *inode)
>  {
>         dnode_t *n;
>         struct dup_cluster      *db;
> @@ -263,7 +263,7 @@ struct process_block_struct {
>         int             dup_blocks;
>         blk64_t         cur_cluster, phys_cluster;
>         blk64_t         last_blk;
> -       struct ext2_inode *inode;
> +       struct ext2_inode_large *inode;
>         struct problem_context *pctx;
>  };
>
> @@ -271,7 +271,7 @@ static void pass1b(e2fsck_t ctx, char *block_buf)
>  {
>         ext2_filsys fs = ctx->fs;
>         ext2_ino_t ino = 0;
> -       struct ext2_inode inode;
> +       struct ext2_inode_large inode;
>         ext2_inode_scan scan;
>         struct process_block_struct pb;
>         struct problem_context pctx;
> @@ -288,7 +288,7 @@ static void pass1b(e2fsck_t ctx, char *block_buf)
>                 ctx->flags |= E2F_FLAG_ABORT;
>                 return;
>         }
> -       ctx->stashed_inode = &inode;
> +       ctx->stashed_inode = EXT2_INODE(&inode);
>         pb.ctx = ctx;
>         pb.pctx = &pctx;
>         pctx.str = "pass1b";
> @@ -297,7 +297,8 @@ static void pass1b(e2fsck_t ctx, char *block_buf)
>                         if (e2fsck_mmp_update(fs))
>                                 fatal_error(ctx, 0);
>                 }
> -               pctx.errcode = ext2fs_get_next_inode(scan, &ino, &inode);
> +               pctx.errcode = ext2fs_get_next_inode_full(scan, &ino,
> +                               EXT2_INODE(&inode), sizeof(inode));
>                 if (pctx.errcode == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE)
>                         continue;
>                 if (pctx.errcode) {
> @@ -321,18 +322,18 @@ static void pass1b(e2fsck_t ctx, char *block_buf)
>                 pb.last_blk = 0;
>                 pb.pctx->blk = pb.pctx->blk2 = 0;
>
> -               if (ext2fs_inode_has_valid_blocks2(fs, &inode) ||
> +               if (ext2fs_inode_has_valid_blocks2(fs, EXT2_INODE(&inode)) ||
>                     (ino == EXT2_BAD_INO))
>                         pctx.errcode = ext2fs_block_iterate3(fs, ino,
>                                              BLOCK_FLAG_READ_ONLY, block_buf,
>                                              process_pass1b_block, &pb);
>                 /* If the feature is not set, attrs will be cleared later anyway */
>                 if (ext2fs_has_feature_xattr(fs->super) &&
> -                   ext2fs_file_acl_block(fs, &inode)) {
> -                       blk64_t blk = ext2fs_file_acl_block(fs, &inode);
> +                   ext2fs_file_acl_block(fs, EXT2_INODE(&inode))) {
> +                       blk64_t blk = ext2fs_file_acl_block(fs, EXT2_INODE(&inode));
>                         process_pass1b_block(fs, &blk,
>                                              BLOCK_COUNT_EXTATTR, 0, 0, &pb);
> -                       ext2fs_file_acl_block_set(fs, &inode, blk);
> +                       ext2fs_file_acl_block_set(fs, EXT2_INODE(&inode), blk);
>                 }
>                 if (pb.dup_blocks) {
>                         if (ino != EXT2_BAD_INO) {
> @@ -548,7 +549,7 @@ static void pass1d(e2fsck_t ctx, char *block_buf)
>                 /*
>                  * Report the inode that we are working on
>                  */
> -               pctx.inode = &p->inode;
> +               pctx.inode = EXT2_INODE(&p->inode);
>                 pctx.ino = ino;
>                 pctx.dir = p->dir;
>                 pctx.blkcount = p->num_dupblocks;
> @@ -568,7 +569,7 @@ static void pass1d(e2fsck_t ctx, char *block_buf)
>                         /*
>                          * Report the inode that we are sharing with
>                          */
> -                       pctx.inode = &t->inode;
> +                       pctx.inode = EXT2_INODE(&t->inode);
>                         pctx.ino = shared[i];
>                         pctx.dir = t->dir;
>                         fix_problem(ctx, PR_1D_DUP_FILE_LIST, &pctx);
> @@ -668,7 +669,7 @@ static void delete_file(e2fsck_t ctx, ext2_ino_t ino,
>         pctx.str = "delete_file";
>         pb.cur_cluster = ~0;
>
> -       if (ext2fs_inode_has_valid_blocks2(fs, &dp->inode))
> +       if (ext2fs_inode_has_valid_blocks2(fs, EXT2_INODE(&dp->inode)))
>                 pctx.errcode = ext2fs_block_iterate3(fs, ino,
>                                                      BLOCK_FLAG_READ_ONLY,
>                                                      block_buf,
> @@ -683,20 +684,23 @@ static void delete_file(e2fsck_t ctx, ext2_ino_t ino,
>         quota_data_inodes(ctx->qctx, &dp->inode, ino, -1);
>
>         /* Inode may have changed by block_iterate, so reread it */
> -       e2fsck_read_inode(ctx, ino, &dp->inode, "delete_file");
> -       e2fsck_clear_inode(ctx, ino, &dp->inode, 0, "delete_file");
> -       if (ext2fs_file_acl_block(fs, &dp->inode) &&
> +       e2fsck_read_inode_full(ctx, ino, EXT2_INODE(&dp->inode),
> +                              sizeof(dp->inode), "delete_file");
> +       e2fsck_clear_inode(ctx, ino, EXT2_INODE(&dp->inode), 0, "delete_file");
> +       if (ext2fs_file_acl_block(fs, EXT2_INODE(&dp->inode)) &&
>             ext2fs_has_feature_xattr(fs->super)) {
> +               blk64_t file_acl_block = ext2fs_file_acl_block(fs,
> +                                               EXT2_INODE(&dp->inode));
> +
>                 count = 1;
> -               pctx.errcode = ext2fs_adjust_ea_refcount3(fs,
> -                                       ext2fs_file_acl_block(fs, &dp->inode),
> +               pctx.errcode = ext2fs_adjust_ea_refcount3(fs, file_acl_block,
>                                         block_buf, -1, &count, ino);
>                 if (pctx.errcode == EXT2_ET_BAD_EA_BLOCK_NUM) {
>                         pctx.errcode = 0;
>                         count = 1;
>                 }
>                 if (pctx.errcode) {
> -                       pctx.blk = ext2fs_file_acl_block(fs, &dp->inode);
> +                       pctx.blk = file_acl_block;
>                         fix_problem(ctx, PR_1B_ADJ_EA_REFCOUNT, &pctx);
>                 }
>                 /*
> @@ -707,12 +711,13 @@ static void delete_file(e2fsck_t ctx, ext2_ino_t ino,
>                  */
>                 if ((count == 0) ||
>                     ext2fs_test_block_bitmap2(ctx->block_dup_map,
> -                                       ext2fs_file_acl_block(fs, &dp->inode))) {
> -                       blk64_t blk = ext2fs_file_acl_block(fs, &dp->inode);
> -                       delete_file_block(fs, &blk,
> +                                             file_acl_block)) {
> +                       delete_file_block(fs, &file_acl_block,
>                                           BLOCK_COUNT_EXTATTR, 0, 0, &pb);
> -                       ext2fs_file_acl_block_set(fs, &dp->inode, blk);
> -                       quota_data_sub(ctx->qctx, &dp->inode, ino, fs->blocksize);
> +                       ext2fs_file_acl_block_set(fs, EXT2_INODE(&dp->inode),
> +                                                 file_acl_block);
> +                       quota_data_sub(ctx->qctx, &dp->inode, ino,
> +                                      fs->blocksize);
>                 }
>         }
>  }
> @@ -724,7 +729,7 @@ struct clone_struct {
>         ext2_ino_t      dir, ino;
>         char    *buf;
>         e2fsck_t ctx;
> -       struct ext2_inode       *inode;
> +       struct ext2_inode_large *inode;
>
>         struct dup_cluster *save_dup_cluster;
>         blk64_t save_blocknr;
> @@ -800,7 +805,8 @@ static int clone_file_block(ext2_filsys fs,
>                  * mapped to multiple physical clusters.
>                  */
>                 new_block = 0;
> -               retval = ext2fs_map_cluster_block(fs, cs->ino, cs->inode,
> +               retval = ext2fs_map_cluster_block(fs, cs->ino,
> +                                                 EXT2_INODE(cs->inode),
>                                                   blockcnt, &new_block);
>                 if (retval == 0 && new_block != 0 &&
>                     EXT2FS_B2C(ctx->fs, new_block) !=
> @@ -882,7 +888,7 @@ static errcode_t clone_file(e2fsck_t ctx, ext2_ino_t ino,
>
>         pctx.ino = ino;
>         pctx.str = "clone_file";
> -       if (ext2fs_inode_has_valid_blocks2(fs, &dp->inode))
> +       if (ext2fs_inode_has_valid_blocks2(fs, EXT2_INODE(&dp->inode)))
>                 pctx.errcode = ext2fs_block_iterate3(fs, ino, 0, block_buf,
>                                                      clone_file_block, &cs);
>         deferred_dec_badcount(&cs);
> @@ -899,14 +905,16 @@ static errcode_t clone_file(e2fsck_t ctx, ext2_ino_t ino,
>                 goto errout;
>         }
>         /* The inode may have changed on disk, so we have to re-read it */
> -       e2fsck_read_inode(ctx, ino, &dp->inode, "clone file EA");
> -       blk = ext2fs_file_acl_block(fs, &dp->inode);
> +       e2fsck_read_inode_full(ctx, ino, EXT2_INODE(&dp->inode),
> +                              sizeof(dp->inode), "clone file EA");
> +       blk = ext2fs_file_acl_block(fs, EXT2_INODE(&dp->inode));
>         new_blk = blk;
>         if (blk && (clone_file_block(fs, &new_blk,
>                                      BLOCK_COUNT_EXTATTR, 0, 0, &cs) ==
>                     BLOCK_CHANGED)) {
> -               ext2fs_file_acl_block_set(fs, &dp->inode, new_blk);
> -               e2fsck_write_inode(ctx, ino, &dp->inode, "clone file EA");
> +               ext2fs_file_acl_block_set(fs, EXT2_INODE(&dp->inode), new_blk);
> +               e2fsck_write_inode_full(ctx, ino, EXT2_INODE(&dp->inode),
> +                                       sizeof(dp->inode), "clone file EA");
>                 /*
>                  * If we cloned the EA block, find all other inodes
>                  * which refered to that EA block, and modify
> @@ -935,11 +943,14 @@ static errcode_t clone_file(e2fsck_t ctx, ext2_ino_t ino,
>                                 goto errout;
>                         }
>                         di = (struct dup_inode *) dnode_get(n);
> -                       if (ext2fs_file_acl_block(fs, &di->inode) == blk) {
> -                               ext2fs_file_acl_block_set(fs, &di->inode,
> -                                       ext2fs_file_acl_block(fs, &dp->inode));
> -                               e2fsck_write_inode(ctx, ino_el->inode,
> -                                          &di->inode, "clone file EA");
> +                       if (ext2fs_file_acl_block(fs,
> +                                       EXT2_INODE(&di->inode)) == blk) {
> +                               ext2fs_file_acl_block_set(fs,
> +                                       EXT2_INODE(&di->inode),
> +                                       ext2fs_file_acl_block(fs, EXT2_INODE(&dp->inode)));
> +                               e2fsck_write_inode_full(ctx, ino_el->inode,
> +                                       EXT2_INODE(&di->inode),
> +                                       sizeof(di->inode), "clone file EA");
>                                 decrement_badcount(ctx, blk, dc);
>                         }
>                 }
> diff --git a/e2fsck/pass3.c b/e2fsck/pass3.c
> index 3b076c4..44203ca 100644
> --- a/e2fsck/pass3.c
> +++ b/e2fsck/pass3.c
> @@ -381,7 +381,7 @@ ext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix)
>         ext2_ino_t                      ino;
>         blk64_t                 blk;
>         errcode_t               retval;
> -       struct ext2_inode       inode;
> +       struct ext2_inode_large inode;
>         char *                  block;
>         static const char       name[] = "lost+found";
>         struct  problem_context pctx;
> @@ -406,7 +406,8 @@ ext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix)
>                 return 0;
>         if (!retval) {
>                 /* Lost+found shouldn't have inline data */
> -               retval = ext2fs_read_inode(fs, ino, &inode);
> +               retval = ext2fs_read_inode_full(fs, ino, EXT2_INODE(&inode),
> +                                               sizeof(inode));
>                 if (fix && retval)
>                         return 0;
>
> @@ -518,13 +519,13 @@ skip_new_block:
>         inode.i_size = fs->blocksize;
>         inode.i_atime = inode.i_ctime = inode.i_mtime = ctx->now;
>         inode.i_links_count = 2;
> -       ext2fs_iblk_set(fs, &inode, 1);
> +       ext2fs_iblk_set(fs, EXT2_INODE(&inode), 1);
>         inode.i_block[0] = blk;
>
>         /*
>          * Next, write out the inode.
>          */
> -       pctx.errcode = ext2fs_write_new_inode(fs, ino, &inode);
> +       pctx.errcode = ext2fs_write_new_inode(fs, ino, EXT2_INODE(&inode));
>         if (pctx.errcode) {
>                 pctx.str = "ext2fs_write_inode";
>                 fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx);
> @@ -855,7 +856,7 @@ errcode_t e2fsck_expand_directory(e2fsck_t ctx, ext2_ino_t dir,
>         ext2_filsys fs = ctx->fs;
>         errcode_t       retval;
>         struct expand_dir_struct es;
> -       struct ext2_inode       inode;
> +       struct ext2_inode_large inode;
>         blk64_t         sz;
>
>         if (!(fs->flags & EXT2_FLAG_RW))
> @@ -888,18 +889,20 @@ errcode_t e2fsck_expand_directory(e2fsck_t ctx, ext2_ino_t dir,
>         /*
>          * Update the size and block count fields in the inode.
>          */
> -       retval = ext2fs_read_inode(fs, dir, &inode);
> +       retval = ext2fs_read_inode_full(fs, dir,
> +                                       EXT2_INODE(&inode), sizeof(inode));
>         if (retval)
>                 return retval;
>
>         sz = (es.last_block + 1) * fs->blocksize;
> -       retval = ext2fs_inode_size_set(fs, &inode, sz);
> +       retval = ext2fs_inode_size_set(fs, EXT2_INODE(&inode), sz);
>         if (retval)
>                 return retval;
> -       ext2fs_iblk_add_blocks(fs, &inode, es.newblocks);
> +       ext2fs_iblk_add_blocks(fs, EXT2_INODE(&inode), es.newblocks);
>         quota_data_add(ctx->qctx, &inode, dir, es.newblocks * fs->blocksize);
>
> -       e2fsck_write_inode(ctx, dir, &inode, "expand_directory");
> +       e2fsck_write_inode_full(ctx, dir, EXT2_INODE(&inode),
> +                               sizeof(inode), "expand_directory");
>
>         return 0;
>  }
> diff --git a/e2fsck/pass4.c b/e2fsck/pass4.c
> index c490438..8c101fd 100644
> --- a/e2fsck/pass4.c
> +++ b/e2fsck/pass4.c
> @@ -26,23 +26,21 @@
>   * rest of the pass 4 tests.
>   */
>  static int disconnect_inode(e2fsck_t ctx, ext2_ino_t i,
> -                           struct ext2_inode *inode)
> +                           struct ext2_inode_large *inode)
>  {
>         ext2_filsys fs = ctx->fs;
>         struct problem_context  pctx;
>         __u32 eamagic = 0;
>         int extra_size = 0;
>
> -       if (EXT2_INODE_SIZE(fs->super) > EXT2_GOOD_OLD_INODE_SIZE) {
> -               e2fsck_read_inode_full(ctx, i, inode,EXT2_INODE_SIZE(fs->super),
> -                                      "pass4: disconnect_inode");
> -               extra_size = ((struct ext2_inode_large *)inode)->i_extra_isize;
> -       } else {
> -               e2fsck_read_inode(ctx, i, inode, "pass4: disconnect_inode");
> -       }
> +       e2fsck_read_inode_full(ctx, i, EXT2_INODE(inode),
> +                              EXT2_INODE_SIZE(fs->super),
> +                              "pass4: disconnect_inode");
> +       if (EXT2_INODE_SIZE(fs->super) > EXT2_GOOD_OLD_INODE_SIZE)
> +               extra_size = inode->i_extra_isize;
>         clear_problem_context(&pctx);
>         pctx.ino = i;
> -       pctx.inode = inode;
> +       pctx.inode = EXT2_INODE(inode);
>
>         if (EXT2_INODE_SIZE(fs->super) -EXT2_GOOD_OLD_INODE_SIZE -extra_size >0)
>                 eamagic = *(__u32 *)(((char *)inode) +EXT2_GOOD_OLD_INODE_SIZE +
> @@ -56,7 +54,7 @@ static int disconnect_inode(e2fsck_t ctx, ext2_ino_t i,
>         if (!inode->i_blocks && eamagic != EXT2_EXT_ATTR_MAGIC &&
>             (LINUX_S_ISREG(inode->i_mode) || LINUX_S_ISDIR(inode->i_mode))) {
>                 if (fix_problem(ctx, PR_4_ZERO_LEN_INODE, &pctx)) {
> -                       e2fsck_clear_inode(ctx, i, inode, 0,
> +                       e2fsck_clear_inode(ctx, i, EXT2_INODE(inode), 0,
>                                            "disconnect_inode");
>                         /*
>                          * Fix up the bitmaps...
> @@ -92,7 +90,8 @@ void e2fsck_pass4(e2fsck_t ctx)
>  {
>         ext2_filsys fs = ctx->fs;
>         ext2_ino_t      i;
> -       struct ext2_inode       *inode;
> +       struct ext2_inode_large *inode;
> +       int inode_size = EXT2_INODE_SIZE(fs->super);
>  #ifdef RESOURCE_TRACK
>         struct resource_track   rtrack;
>  #endif
> @@ -127,8 +126,7 @@ void e2fsck_pass4(e2fsck_t ctx)
>                 if ((ctx->progress)(ctx, 4, 0, maxgroup))
>                         return;
>
> -       inode = e2fsck_allocate_memory(ctx, EXT2_INODE_SIZE(fs->super),
> -                                      "scratch inode");
> +       inode = e2fsck_allocate_memory(ctx, inode_size, "scratch inode");
>
>         /* Protect loop from wrap-around if s_inodes_count maxed */
>         for (i=1; i <= fs->super->s_inodes_count && i > 0; i++) {
> @@ -171,9 +169,10 @@ void e2fsck_pass4(e2fsck_t ctx)
>                 if (isdir && (link_counted > EXT2_LINK_MAX))
>                         link_counted = 1;
>                 if (link_counted != link_count) {
> -                       e2fsck_read_inode(ctx, i, inode, "pass4");
> +                       e2fsck_read_inode_full(ctx, i, EXT2_INODE(inode),
> +                                              inode_size, "pass4");
>                         pctx.ino = i;
> -                       pctx.inode = inode;
> +                       pctx.inode = EXT2_INODE(inode);
>                         if ((link_count != inode->i_links_count) && !isdir &&
>                             (inode->i_links_count <= EXT2_LINK_MAX)) {
>                                 pctx.num = link_count;
> @@ -188,7 +187,9 @@ void e2fsck_pass4(e2fsck_t ctx)
>                              link_count == 1 && !(ctx->options & E2F_OPT_NO)) ||
>                             fix_problem(ctx, PR_4_BAD_REF_COUNT, &pctx)) {
>                                 inode->i_links_count = link_counted;
> -                               e2fsck_write_inode(ctx, i, inode, "pass4");
> +                               e2fsck_write_inode_full(ctx, i,
> +                                                       EXT2_INODE(inode),
> +                                                       inode_size, "pass4");
>                         }
>                 }
>         }
> diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h
> index 9918356..ee9a5f2 100644
> --- a/lib/ext2fs/ext2_fs.h
> +++ b/lib/ext2fs/ext2_fs.h
> @@ -519,6 +519,12 @@ struct ext2_inode_large {
>  #define ext2fs_set_i_uid_high(inode,x) ((inode).osd2.linux2.l_i_uid_high = (x))
>  #define ext2fs_set_i_gid_high(inode,x) ((inode).osd2.linux2.l_i_gid_high = (x))
>
> +static inline
> +struct ext2_inode *EXT2_INODE(struct ext2_inode_large *large_inode)
> +{
> +       return (struct ext2_inode *) large_inode;
> +}
> +
>  /*
>   * File system states
>   */
> diff --git a/lib/support/mkquota.c b/lib/support/mkquota.c
> index a432d4e..add60ca 100644
> --- a/lib/support/mkquota.c
> +++ b/lib/support/mkquota.c
> @@ -243,9 +243,8 @@ static int dict_uint_cmp(const void *a, const void *b)
>                 return -1;
>  }
>
> -static inline qid_t get_qid(struct ext2_inode *inode, enum quota_type qtype)
> +static inline qid_t get_qid(struct ext2_inode_large *inode, enum quota_type qtype)
>  {
> -       struct ext2_inode_large *large_inode;
>         int inode_size;
>
>         switch (qtype) {
> @@ -254,11 +253,10 @@ static inline qid_t get_qid(struct ext2_inode *inode, enum quota_type qtype)
>         case GRPQUOTA:
>                 return inode_gid(*inode);
>         case PRJQUOTA:
> -               large_inode = (struct ext2_inode_large *)inode;
>                 inode_size = EXT2_GOOD_OLD_INODE_SIZE +
> -                            large_inode->i_extra_isize;
> +                       inode->i_extra_isize;
>                 if (inode_includes(inode_size, i_projid))
> -                       return inode_projid(*large_inode);
> +                       return inode_projid(*inode);
>         default:
>                 return 0;
>         }
> @@ -368,7 +366,7 @@ static struct dquot *get_dq(dict_t *dict, __u32 key)
>  /*
>   * Called to update the blocks used by a particular inode
>   */
> -void quota_data_add(quota_ctx_t qctx, struct ext2_inode *inode,
> +void quota_data_add(quota_ctx_t qctx, struct ext2_inode_large *inode,
>                     ext2_ino_t ino EXT2FS_ATTR((unused)),
>                     qsize_t space)
>  {
> @@ -395,7 +393,7 @@ void quota_data_add(quota_ctx_t qctx, struct ext2_inode *inode,
>  /*
>   * Called to remove some blocks used by a particular inode
>   */
> -void quota_data_sub(quota_ctx_t qctx, struct ext2_inode *inode,
> +void quota_data_sub(quota_ctx_t qctx, struct ext2_inode_large *inode,
>                     ext2_ino_t ino EXT2FS_ATTR((unused)),
>                     qsize_t space)
>  {
> @@ -421,7 +419,7 @@ void quota_data_sub(quota_ctx_t qctx, struct ext2_inode *inode,
>  /*
>   * Called to count the files used by an inode's user/group
>   */
> -void quota_data_inodes(quota_ctx_t qctx, struct ext2_inode *inode,
> +void quota_data_inodes(quota_ctx_t qctx, struct ext2_inode_large *inode,
>                        ext2_ino_t ino EXT2FS_ATTR((unused)), int adjust)
>  {
>         struct dquot    *dq;
> @@ -448,7 +446,7 @@ errcode_t quota_compute_usage(quota_ctx_t qctx)
>         ext2_filsys fs;
>         ext2_ino_t ino;
>         errcode_t ret;
> -       struct ext2_inode *inode;
> +       struct ext2_inode_large *inode;
>         int inode_size;
>         qsize_t space;
>         ext2_inode_scan scan;
> @@ -467,7 +465,8 @@ errcode_t quota_compute_usage(quota_ctx_t qctx)
>         if (!inode)
>                 return ENOMEM;
>         while (1) {
> -               ret = ext2fs_get_next_inode_full(scan, &ino, inode, inode_size);
> +               ret = ext2fs_get_next_inode_full(scan, &ino,
> +                                                EXT2_INODE(inode), inode_size);
>                 if (ret) {
>                         log_err("while getting next inode. ret=%ld", ret);
>                         ext2fs_close_inode_scan(scan);
> @@ -479,7 +478,8 @@ errcode_t quota_compute_usage(quota_ctx_t qctx)
>                 if (inode->i_links_count &&
>                     (ino == EXT2_ROOT_INO ||
>                      ino >= EXT2_FIRST_INODE(fs->super))) {
> -                       space = ext2fs_inode_i_blocks(fs, inode) << 9;
> +                       space = ext2fs_inode_i_blocks(fs,
> +                                                     EXT2_INODE(inode)) << 9;
>                         quota_data_add(qctx, inode, ino, space);
>                         quota_data_inodes(qctx, inode, ino, +1);
>                 }
> diff --git a/lib/support/quotaio.h b/lib/support/quotaio.h
> index 5f1073f..8f7ddcb 100644
> --- a/lib/support/quotaio.h
> +++ b/lib/support/quotaio.h
> @@ -217,12 +217,12 @@ const char *quota_get_qf_name(enum quota_type, int fmt, char *buf);
>  /* In mkquota.c */
>  errcode_t quota_init_context(quota_ctx_t *qctx, ext2_filsys fs,
>                              unsigned int qtype_bits);
> -void quota_data_inodes(quota_ctx_t qctx, struct ext2_inode *inode, ext2_ino_t ino,
> -               int adjust);
> -void quota_data_add(quota_ctx_t qctx, struct ext2_inode *inode, ext2_ino_t ino,
> -               qsize_t space);
> -void quota_data_sub(quota_ctx_t qctx, struct ext2_inode *inode, ext2_ino_t ino,
> -               qsize_t space);
> +void quota_data_inodes(quota_ctx_t qctx, struct ext2_inode_large *inode,
> +                      ext2_ino_t ino, int adjust);
> +void quota_data_add(quota_ctx_t qctx, struct ext2_inode_large *inode,
> +                   ext2_ino_t ino, qsize_t space);
> +void quota_data_sub(quota_ctx_t qctx, struct ext2_inode_large *inode,
> +                   ext2_ino_t ino, qsize_t space);
>  errcode_t quota_write_inode(quota_ctx_t qctx, enum quota_type qtype);
>  errcode_t quota_update_limits(quota_ctx_t qctx, ext2_ino_t qf_ino,
>                               enum quota_type type);
> --
> 2.5.0
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 1/2] mke2fs: fix project quota creation
  2016-05-22  5:34 ` [PATCH 1/2] mke2fs: fix project quota creation Wang Shilong
@ 2016-05-23  0:49   ` Theodore Ts'o
  0 siblings, 0 replies; 5+ messages in thread
From: Theodore Ts'o @ 2016-05-23  0:49 UTC (permalink / raw)
  To: Wang Shilong; +Cc: Ext4 Developers List

On Sun, May 22, 2016 at 01:34:59PM +0800, Wang Shilong wrote:
> On Sun, May 22, 2016 at 10:19 AM, Theodore Ts'o <tytso@mit.edu> wrote:
> > Creating a file system with project quotas can fail if mke2fs is built
> > using hardening options.  This is because quota_compute_usage() used
> > ext2fs_get_next_inode() instead of ext2fs_get_inode_full(), and a
> > small inode was passed into quota_data_add, when a large inode needs
> > to be used.  As a result get_dq() would end up dereferencing undefined
> > space in the stack.  Without the hardening options, this would be
> > zero, so "mke2fs -t ext4 -O project.quota -I 256 test.img" would work
> > essentially by accident.
> >
> > Fix this by using ext2fs_get_inode_full() so that a large inode is
> > available to quota_data_inodes().
> >
> > Signed-off-by: Theodore Ts'o <tytso@mit.edu>
> 
> I thought Li Xi sent updated e2fsprogs including this fixing parts.
> maybe because you merged early version patches.

There was a separate patch that broke ABI backwards compatibility of
e2fsprogs' shared libraries, which I rejected on those grounds,
perhaps that's what you thinking of?  It wasn't clear that the patch
was in fact fixing a problem, as opposed to just being a clean up.  So
I didn't realize there was a problem that needed fixing.

  	 	       	     	     	  - Ted

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2016-05-23  0:50 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-05-22  2:19 [PATCH 1/2] mke2fs: fix project quota creation Theodore Ts'o
2016-05-22  2:19 ` [PATCH 2/2] e2fsck: fix project quota support Theodore Ts'o
2016-05-22  5:38   ` Wang Shilong
2016-05-22  5:34 ` [PATCH 1/2] mke2fs: fix project quota creation Wang Shilong
2016-05-23  0:49   ` Theodore Ts'o

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).