aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs
diff options
context:
space:
mode:
authorDarrick J. Wong <darrick.wong@oracle.com>2017-02-02 18:14:00 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-04-08 03:30:31 -0400
commit3d2bd2fd5cbaf3d4e0f0642030cd7d21facb07e7 (patch)
tree128662444ca85ee06107bb5dcb2aa6507d72c48e /fs/xfs
parent4056a74aafba368f763d5dd7ab92a5d74e098c1e (diff)
xfs: verify free block header fields
commit de14c5f541e78c59006bee56f6c5c2ef1ca07272 upstream. Perform basic sanity checking of the directory free block header fields so that we avoid hanging the system on invalid data. (Granted that just means that now we shutdown on directory write, but that seems better than hanging...) Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs/xfs')
-rw-r--r--fs/xfs/libxfs/xfs_dir2_node.c51
1 files changed, 49 insertions, 2 deletions
diff --git a/fs/xfs/libxfs/xfs_dir2_node.c b/fs/xfs/libxfs/xfs_dir2_node.c
index 75a557432d0f..bbd1238852b3 100644
--- a/fs/xfs/libxfs/xfs_dir2_node.c
+++ b/fs/xfs/libxfs/xfs_dir2_node.c
@@ -155,6 +155,42 @@ const struct xfs_buf_ops xfs_dir3_free_buf_ops = {
155 .verify_write = xfs_dir3_free_write_verify, 155 .verify_write = xfs_dir3_free_write_verify,
156}; 156};
157 157
158/* Everything ok in the free block header? */
159static bool
160xfs_dir3_free_header_check(
161 struct xfs_inode *dp,
162 xfs_dablk_t fbno,
163 struct xfs_buf *bp)
164{
165 struct xfs_mount *mp = dp->i_mount;
166 unsigned int firstdb;
167 int maxbests;
168
169 maxbests = dp->d_ops->free_max_bests(mp->m_dir_geo);
170 firstdb = (xfs_dir2_da_to_db(mp->m_dir_geo, fbno) -
171 xfs_dir2_byte_to_db(mp->m_dir_geo, XFS_DIR2_FREE_OFFSET)) *
172 maxbests;
173 if (xfs_sb_version_hascrc(&mp->m_sb)) {
174 struct xfs_dir3_free_hdr *hdr3 = bp->b_addr;
175
176 if (be32_to_cpu(hdr3->firstdb) != firstdb)
177 return false;
178 if (be32_to_cpu(hdr3->nvalid) > maxbests)
179 return false;
180 if (be32_to_cpu(hdr3->nvalid) < be32_to_cpu(hdr3->nused))
181 return false;
182 } else {
183 struct xfs_dir2_free_hdr *hdr = bp->b_addr;
184
185 if (be32_to_cpu(hdr->firstdb) != firstdb)
186 return false;
187 if (be32_to_cpu(hdr->nvalid) > maxbests)
188 return false;
189 if (be32_to_cpu(hdr->nvalid) < be32_to_cpu(hdr->nused))
190 return false;
191 }
192 return true;
193}
158 194
159static int 195static int
160__xfs_dir3_free_read( 196__xfs_dir3_free_read(
@@ -168,11 +204,22 @@ __xfs_dir3_free_read(
168 204
169 err = xfs_da_read_buf(tp, dp, fbno, mappedbno, bpp, 205 err = xfs_da_read_buf(tp, dp, fbno, mappedbno, bpp,
170 XFS_DATA_FORK, &xfs_dir3_free_buf_ops); 206 XFS_DATA_FORK, &xfs_dir3_free_buf_ops);
207 if (err || !*bpp)
208 return err;
209
210 /* Check things that we can't do in the verifier. */
211 if (!xfs_dir3_free_header_check(dp, fbno, *bpp)) {
212 xfs_buf_ioerror(*bpp, -EFSCORRUPTED);
213 xfs_verifier_error(*bpp);
214 xfs_trans_brelse(tp, *bpp);
215 return -EFSCORRUPTED;
216 }
171 217
172 /* try read returns without an error or *bpp if it lands in a hole */ 218 /* try read returns without an error or *bpp if it lands in a hole */
173 if (!err && tp && *bpp) 219 if (tp)
174 xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_DIR_FREE_BUF); 220 xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_DIR_FREE_BUF);
175 return err; 221
222 return 0;
176} 223}
177 224
178int 225int