Blame SOURCES/e2fsprogs-1.44.6-debugfs-fix-set_inode_field-so-it-can-set-the-checks.patch

0ab26d
From 5862f45c314aaf97ce098add06c42b5d592dc984 Mon Sep 17 00:00:00 2001
0ab26d
From: Theodore Ts'o <tytso@mit.edu>
0ab26d
Date: Thu, 13 Dec 2018 00:53:16 -0500
0ab26d
Subject: [PATCH 2/4] debugfs: fix set_inode_field so it can set the checksum
0ab26d
 field
0ab26d
0ab26d
Previously, setting the inode field was a no-op, since the library
0ab26d
function ext2fs_write_inode_full() would override whatever value was
0ab26d
set by debugfs.  Use the new ext2fs_write_inode2() interface so we can
0ab26d
in fact set the checksum to a potentially wrong value.  Also, ignore
0ab26d
the inode checksum failures if we are setting the checksum, and if the
0ab26d
checksum value is "calc", set the inode checksum to the correct value.
0ab26d
0ab26d
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
0ab26d
---
0ab26d
 debugfs/debugfs.c    | 12 +++----
0ab26d
 debugfs/debugfs.h    |  8 ++---
0ab26d
 debugfs/set_fields.c | 84 +++++++++++++++++++++++++++++++++++++++-----
0ab26d
 debugfs/util.c       | 17 +++++----
0ab26d
 4 files changed, 94 insertions(+), 27 deletions(-)
0ab26d
0ab26d
diff --git a/debugfs/debugfs.c b/debugfs/debugfs.c
0ab26d
index faae12da..06a93270 100644
0ab26d
--- a/debugfs/debugfs.c
0ab26d
+++ b/debugfs/debugfs.c
0ab26d
@@ -985,8 +985,8 @@ void do_stat(int argc, char *argv[])
0ab26d
 		return;
0ab26d
 	}
0ab26d
 
0ab26d
-	if (debugfs_read_inode_full(inode, inode_buf, argv[0],
0ab26d
-					EXT2_INODE_SIZE(current_fs->super))) {
0ab26d
+	if (debugfs_read_inode2(inode, inode_buf, argv[0],
0ab26d
+				EXT2_INODE_SIZE(current_fs->super), 0)) {
0ab26d
 		free(inode_buf);
0ab26d
 		return;
0ab26d
 	}
0ab26d
@@ -1608,12 +1608,12 @@ void do_copy_inode(int argc, char *argv[])
0ab26d
 	if (!dest_ino)
0ab26d
 		return;
0ab26d
 
0ab26d
-	if (debugfs_read_inode_full(src_ino, (struct ext2_inode *) buf,
0ab26d
-				    argv[0], sizeof(buf)))
0ab26d
+	if (debugfs_read_inode2(src_ino, (struct ext2_inode *) buf,
0ab26d
+				argv[0], sizeof(buf), 0))
0ab26d
 		return;
0ab26d
 
0ab26d
-	if (debugfs_write_inode_full(dest_ino, (struct ext2_inode *) buf,
0ab26d
-				     argv[0], sizeof(buf)))
0ab26d
+	if (debugfs_write_inode2(dest_ino, (struct ext2_inode *) buf,
0ab26d
+				 argv[0], sizeof(buf), 0))
0ab26d
 		return;
0ab26d
 }
0ab26d
 
0ab26d
diff --git a/debugfs/debugfs.h b/debugfs/debugfs.h
0ab26d
index 93f036de..97fdde7e 100644
0ab26d
--- a/debugfs/debugfs.h
0ab26d
+++ b/debugfs/debugfs.h
0ab26d
@@ -54,12 +54,12 @@ extern int common_block_args_process(int argc, char *argv[],
0ab26d
 				     blk64_t *block, blk64_t *count);
0ab26d
 extern int debugfs_read_inode(ext2_ino_t ino, struct ext2_inode * inode,
0ab26d
 			      const char *cmd);
0ab26d
-extern int debugfs_read_inode_full(ext2_ino_t ino, struct ext2_inode * inode,
0ab26d
-				   const char *cmd, int bufsize);
0ab26d
+extern int debugfs_read_inode2(ext2_ino_t ino, struct ext2_inode * inode,
0ab26d
+			       const char *cmd, int bufsize, int flags);
0ab26d
 extern int debugfs_write_inode(ext2_ino_t ino, struct ext2_inode * inode,
0ab26d
 			       const char *cmd);
0ab26d
-extern int debugfs_write_inode_full(ext2_ino_t ino, struct ext2_inode * inode,
0ab26d
-				    const char *cmd, int bufsize);
0ab26d
+extern int debugfs_write_inode2(ext2_ino_t ino, struct ext2_inode * inode,
0ab26d
+				const char *cmd, int bufsize, int flags);
0ab26d
 extern int debugfs_write_new_inode(ext2_ino_t ino, struct ext2_inode * inode,
0ab26d
 				   const char *cmd);
0ab26d
 extern int ext2_file_type(unsigned int mode);
0ab26d
diff --git a/debugfs/set_fields.c b/debugfs/set_fields.c
0ab26d
index 3cdf617c..4f033249 100644
0ab26d
--- a/debugfs/set_fields.c
0ab26d
+++ b/debugfs/set_fields.c
0ab26d
@@ -53,6 +53,7 @@ static int array_idx;
0ab26d
 
0ab26d
 #define FLAG_ARRAY	0x0001
0ab26d
 #define FLAG_ALIAS	0x0002	/* Data intersects with other field */
0ab26d
+#define FLAG_CSUM	0x0004
0ab26d
 
0ab26d
 struct field_set_info {
0ab26d
 	const char	*name;
0ab26d
@@ -72,6 +73,8 @@ static errcode_t parse_hashalg(struct field_set_info *info, char *field, char *a
0ab26d
 static errcode_t parse_time(struct field_set_info *info, char *field, char *arg);
0ab26d
 static errcode_t parse_bmap(struct field_set_info *info, char *field, char *arg);
0ab26d
 static errcode_t parse_gd_csum(struct field_set_info *info, char *field, char *arg);
0ab26d
+static errcode_t parse_inode_csum(struct field_set_info *info, char *field,
0ab26d
+				  char *arg);
0ab26d
 static errcode_t parse_mmp_clear(struct field_set_info *info, char *field,
0ab26d
 				 char *arg);
0ab26d
 
0ab26d
@@ -218,7 +221,7 @@ static struct field_set_info inode_fields[] = {
0ab26d
 	{ "frag", &set_inode.osd2.hurd2.h_i_frag, NULL, 1, parse_uint, FLAG_ALIAS },
0ab26d
 	{ "fsize", &set_inode.osd2.hurd2.h_i_fsize, NULL, 1, parse_uint },
0ab26d
 	{ "checksum", &set_inode.osd2.linux2.l_i_checksum_lo, 
0ab26d
-		&set_inode.i_checksum_hi, 2, parse_uint },
0ab26d
+		&set_inode.i_checksum_hi, 2, parse_inode_csum, FLAG_CSUM },
0ab26d
 	{ "author", &set_inode.osd2.hurd2.h_i_author, NULL,
0ab26d
 		4, parse_uint, FLAG_ALIAS },
0ab26d
 	{ "extra_isize", &set_inode.i_extra_isize, NULL,
0ab26d
@@ -665,6 +668,68 @@ static errcode_t parse_gd_csum(struct field_set_info *info, char *field,
0ab26d
 	return parse_uint(info, field, arg);
0ab26d
 }
0ab26d
 
0ab26d
+static errcode_t parse_inode_csum(struct field_set_info *info, char *field,
0ab26d
+				  char *arg)
0ab26d
+{
0ab26d
+	errcode_t	retval = 0;
0ab26d
+	__u32		crc;
0ab26d
+	int		is_large_inode = 0;
0ab26d
+	struct ext2_inode_large *tmp_inode;
0ab26d
+
0ab26d
+	if (strcmp(arg, "calc") == 0) {
0ab26d
+		size_t sz = EXT2_INODE_SIZE(current_fs->super);
0ab26d
+		struct ext2_inode_large *tmp_inode = NULL;
0ab26d
+
0ab26d
+		retval = ext2fs_get_mem(sz, &tmp_inode);
0ab26d
+		if (retval)
0ab26d
+			goto out;
0ab26d
+
0ab26d
+		retval = ext2fs_read_inode_full(current_fs, set_ino,
0ab26d
+				     (struct ext2_inode *) tmp_inode,
0ab26d
+				     sz);
0ab26d
+		if (retval)
0ab26d
+			goto out;
0ab26d
+
0ab26d
+#ifdef WORDS_BIGENDIAN
0ab26d
+		ext2fs_swap_inode_full(current_fs, tmp_inode,
0ab26d
+				       tmp_inode, 1, sz);
0ab26d
+#endif
0ab26d
+
0ab26d
+		if (sz > EXT2_GOOD_OLD_INODE_SIZE)
0ab26d
+			is_large_inode = 1;
0ab26d
+
0ab26d
+		retval = ext2fs_inode_csum_set(current_fs, set_ino,
0ab26d
+					       tmp_inode);
0ab26d
+		if (retval)
0ab26d
+			goto out;
0ab26d
+#ifdef WORDS_BIGENDIAN
0ab26d
+		crc = set_inode.i_checksum_lo =
0ab26d
+			ext2fs_swab16(tmp_inode->i_checksum_lo);
0ab26d
+
0ab26d
+#else
0ab26d
+		crc = set_inode.i_checksum_lo = tmp_inode->i_checksum_lo;
0ab26d
+#endif
0ab26d
+		if (is_large_inode &&
0ab26d
+		    set_inode.i_extra_isize >=
0ab26d
+				(offsetof(struct ext2_inode_large,
0ab26d
+					  i_checksum_hi) -
0ab26d
+				 EXT2_GOOD_OLD_INODE_SIZE)) {
0ab26d
+#ifdef WORDS_BIGENDIAN
0ab26d
+			set_inode.i_checksum_lo =
0ab26d
+				ext2fs_swab16(tmp_inode->i_checksum_lo);
0ab26d
+#else
0ab26d
+			set_inode.i_checksum_hi = tmp_inode->i_checksum_hi;
0ab26d
+#endif
0ab26d
+			crc |= ((__u32)set_inode.i_checksum_hi) << 16;
0ab26d
+		}
0ab26d
+		printf("Checksum set to 0x%08x\n", crc);
0ab26d
+	out:
0ab26d
+		ext2fs_free_mem(&tmp_inode);
0ab26d
+		return retval;
0ab26d
+	}
0ab26d
+	return parse_uint(info, field, arg);
0ab26d
+}
0ab26d
+
0ab26d
 static void print_possible_fields(struct field_set_info *fields)
0ab26d
 {
0ab26d
 	struct field_set_info *ss;
0ab26d
@@ -775,16 +840,19 @@ void do_set_inode(int argc, char *argv[])
0ab26d
 	if (!set_ino)
0ab26d
 		return;
0ab26d
 
0ab26d
-	if (debugfs_read_inode_full(set_ino,
0ab26d
-			(struct ext2_inode *) &set_inode, argv[1],
0ab26d
-				    sizeof(set_inode)))
0ab26d
+	if (debugfs_read_inode2(set_ino,
0ab26d
+				(struct ext2_inode *) &set_inode, argv[1],
0ab26d
+				sizeof(set_inode),
0ab26d
+				(ss->flags & FLAG_CSUM) ?
0ab26d
+				READ_INODE_NOCSUM : 0))
0ab26d
 		return;
0ab26d
 
0ab26d
 	if (ss->func(ss, argv[2], argv[3]) == 0) {
0ab26d
-		if (debugfs_write_inode_full(set_ino, 
0ab26d
-			     (struct ext2_inode *) &set_inode,
0ab26d
-			     argv[1], sizeof(set_inode)))
0ab26d
-			return;
0ab26d
+		debugfs_write_inode2(set_ino,
0ab26d
+				     (struct ext2_inode *) &set_inode,
0ab26d
+				     argv[1], sizeof(set_inode),
0ab26d
+				     (ss->flags & FLAG_CSUM) ?
0ab26d
+				     WRITE_INODE_NOCSUM : 0);
0ab26d
 	}
0ab26d
 }
0ab26d
 
0ab26d
diff --git a/debugfs/util.c b/debugfs/util.c
0ab26d
index 452de749..759bb392 100644
0ab26d
--- a/debugfs/util.c
0ab26d
+++ b/debugfs/util.c
0ab26d
@@ -420,12 +420,12 @@ int common_block_args_process(int argc, char *argv[],
0ab26d
 	return 0;
0ab26d
 }
0ab26d
 
0ab26d
-int debugfs_read_inode_full(ext2_ino_t ino, struct ext2_inode * inode,
0ab26d
-			const char *cmd, int bufsize)
0ab26d
+int debugfs_read_inode2(ext2_ino_t ino, struct ext2_inode * inode,
0ab26d
+			const char *cmd, int bufsize, int flags)
0ab26d
 {
0ab26d
 	int retval;
0ab26d
 
0ab26d
-	retval = ext2fs_read_inode_full(current_fs, ino, inode, bufsize);
0ab26d
+	retval = ext2fs_read_inode2(current_fs, ino, inode, bufsize, flags);
0ab26d
 	if (retval) {
0ab26d
 		com_err(cmd, retval, "while reading inode %u", ino);
0ab26d
 		return 1;
0ab26d
@@ -446,15 +446,14 @@ int debugfs_read_inode(ext2_ino_t ino, struct ext2_inode * inode,
0ab26d
 	return 0;
0ab26d
 }
0ab26d
 
0ab26d
-int debugfs_write_inode_full(ext2_ino_t ino,
0ab26d
-			     struct ext2_inode *inode,
0ab26d
-			     const char *cmd,
0ab26d
-			     int bufsize)
0ab26d
+int debugfs_write_inode2(ext2_ino_t ino,
0ab26d
+			 struct ext2_inode *inode,
0ab26d
+			 const char *cmd,
0ab26d
+			 int bufsize, int flags)
0ab26d
 {
0ab26d
 	int retval;
0ab26d
 
0ab26d
-	retval = ext2fs_write_inode_full(current_fs, ino,
0ab26d
-					 inode, bufsize);
0ab26d
+	retval = ext2fs_write_inode2(current_fs, ino, inode, bufsize, flags);
0ab26d
 	if (retval) {
0ab26d
 		com_err(cmd, retval, "while writing inode %u", ino);
0ab26d
 		return 1;
0ab26d
-- 
0ab26d
2.20.1
0ab26d