-
Notifications
You must be signed in to change notification settings - Fork 0
/
libext2fs-Verify-and-calculate-extent-tree-block-che
191 lines (178 loc) · 5.88 KB
/
libext2fs-Verify-and-calculate-extent-tree-block-che
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
libext2fs: verify and calculate extent tree block checksums
From: "Darrick J. Wong" <djwong@us.ibm.com>
Verify and calculate extent tree block checksums when processing
filesystems.
Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
---
lib/ext2fs/csum.c | 79 +++++++++++++++++++++++++++++++++++++++++++++
lib/ext2fs/ext2_err.et.in | 3 ++
lib/ext2fs/ext2fs.h | 6 +++
lib/ext2fs/extent.c | 21 ++++++++++++
4 files changed, 109 insertions(+), 0 deletions(-)
diff --git a/lib/ext2fs/csum.c b/lib/ext2fs/csum.c
index 5c5b7fb..8a0543c 100644
--- a/lib/ext2fs/csum.c
+++ b/lib/ext2fs/csum.c
@@ -30,6 +30,85 @@
#define STATIC static
#endif
+#define EXT3_EXTENT_TAIL_OFFSET(hdr) (sizeof(struct ext3_extent_header) + \
+ (sizeof(struct ext3_extent) * ext2fs_le16_to_cpu((hdr)->eh_max)))
+
+static struct ext3_extent_tail *get_extent_tail(struct ext3_extent_header *h)
+{
+ return (struct ext3_extent_tail *)(((void *)h) +
+ EXT3_EXTENT_TAIL_OFFSET(h));
+}
+
+static errcode_t ext2fs_extent_block_csum(ext2_filsys fs, ext2_ino_t inum,
+ struct ext3_extent_header *eh,
+ __u32 *crc)
+{
+ int size;
+ __u32 gen;
+ errcode_t retval;
+ struct ext2_inode inode;
+
+ size = EXT3_EXTENT_TAIL_OFFSET(eh) + offsetof(struct ext3_extent_tail,
+ et_checksum);
+
+ retval = ext2fs_read_inode(fs, inum, &inode);
+ if (retval)
+ return retval;
+ inum = ext2fs_cpu_to_le32(inum);
+ gen = ext2fs_cpu_to_le32(inode.i_generation);
+ *crc = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)&inum,
+ sizeof(inum));
+ *crc = ext2fs_crc32c_le(*crc, (unsigned char *)&gen, sizeof(gen));
+ *crc = ext2fs_crc32c_le(*crc, (unsigned char *)eh, size);
+
+ return 0;
+}
+
+int ext2fs_extent_block_csum_verify(ext2_filsys fs, ext2_ino_t inum,
+ struct ext3_extent_header *eh)
+{
+ errcode_t retval;
+ __u32 provided, calculated;
+ struct ext3_extent_tail *t = get_extent_tail(eh);
+
+ /*
+ * The extent tree structures are accessed in LE order, so we must
+ * swap the checksum bytes here.
+ */
+ if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+ return 1;
+
+ provided = ext2fs_le32_to_cpu(t->et_checksum);
+ retval = ext2fs_extent_block_csum(fs, inum, eh, &calculated);
+ if (retval)
+ return 0;
+
+ return provided == calculated;
+}
+
+errcode_t ext2fs_extent_block_csum_set(ext2_filsys fs, ext2_ino_t inum,
+ struct ext3_extent_header *eh)
+{
+ errcode_t retval;
+ __u32 crc;
+ struct ext3_extent_tail *t = get_extent_tail(eh);
+
+ if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+ return 0;
+
+ /*
+ * The extent tree structures are accessed in LE order, so we must
+ * swap the checksum bytes here.
+ */
+ retval = ext2fs_extent_block_csum(fs, inum, eh, &crc);
+ if (retval)
+ return retval;
+ t->et_checksum = ext2fs_cpu_to_le32(crc);
+ return retval;
+}
+
int ext2fs_inode_bitmap_csum_verify(ext2_filsys fs, dgrp_t group,
char *bitmap, int size)
{
diff --git a/lib/ext2fs/ext2_err.et.in b/lib/ext2fs/ext2_err.et.in
index 3f5d08f..9019026 100644
--- a/lib/ext2fs/ext2_err.et.in
+++ b/lib/ext2fs/ext2_err.et.in
@@ -449,4 +449,7 @@ ec EXT2_ET_INODE_CSUM_INVALID,
ec EXT2_ET_INODE_BITMAP_CSUM_INVALID,
"Inode bitmap checksum does not match bitmap"
+ec EXT2_ET_EXTENT_CSUM_INVALID,
+ "Extent block checksum does not match extent block"
+
end
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index 9d3e8c9..8dd038a 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -952,6 +952,12 @@ extern __u32 ext2fs_crc32c_be(__u32 crc, unsigned char const *p, size_t len);
extern __u32 ext2fs_crc32c_le(__u32 crc, unsigned char const *p, size_t len);
/* csum.c */
+extern errcode_t ext2fs_extent_block_csum_set(ext2_filsys fs,
+ ext2_ino_t inum,
+ struct ext3_extent_header *eh);
+extern int ext2fs_extent_block_csum_verify(ext2_filsys fs,
+ ext2_ino_t inum,
+ struct ext3_extent_header *eh);
extern errcode_t ext2fs_block_bitmap_csum_set(ext2_filsys fs, dgrp_t group,
char *bitmap, int size);
extern int ext2fs_block_bitmap_csum_verify(ext2_filsys fs, dgrp_t group,
diff --git a/lib/ext2fs/extent.c b/lib/ext2fs/extent.c
index eb096d6..7d456ef 100644
--- a/lib/ext2fs/extent.c
+++ b/lib/ext2fs/extent.c
@@ -455,6 +455,13 @@ retry:
return retval;
}
+ if (!(handle->fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) &&
+ !ext2fs_extent_block_csum_verify(handle->fs, handle->ino,
+ eh)) {
+ handle->level--;
+ return EXT2_ET_EXTENT_CSUM_INVALID;
+ }
+
newpath->left = newpath->entries =
ext2fs_le16_to_cpu(eh->eh_entries);
newpath->max_entries = ext2fs_le16_to_cpu(eh->eh_max);
@@ -541,6 +548,7 @@ static errcode_t update_path(ext2_extent_handle_t handle)
blk64_t blk;
errcode_t retval;
struct ext3_extent_idx *ix;
+ struct ext3_extent_header *eh;
if (handle->level == 0) {
retval = ext2fs_write_inode(handle->fs, handle->ino,
@@ -550,6 +558,14 @@ static errcode_t update_path(ext2_extent_handle_t handle)
blk = ext2fs_le32_to_cpu(ix->ei_leaf) +
((__u64) ext2fs_le16_to_cpu(ix->ei_leaf_hi) << 32);
+ /* then update the checksum */
+ eh = (struct ext3_extent_header *)
+ handle->path[handle->level].buf;
+ retval = ext2fs_extent_block_csum_set(handle->fs, handle->ino,
+ eh);
+ if (retval)
+ return retval;
+
retval = io_channel_write_blk64(handle->fs->io,
blk, 1, handle->path[handle->level].buf);
}
@@ -958,6 +974,11 @@ static errcode_t extent_node_split(ext2_extent_handle_t handle)
new_node_start = ext2fs_le32_to_cpu(EXT_FIRST_INDEX(neweh)->ei_block);
+ /* then update the checksum */
+ retval = ext2fs_extent_block_csum_set(handle->fs, handle->ino, neweh);
+ if (retval)
+ goto done;
+
/* ...and write the new node block out to disk. */
retval = io_channel_write_blk64(handle->fs->io, new_node_pblk, 1,
block_buf);
--
1.7.9.107.g97f9a