aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Chinner <dchinner@redhat.com>2017-10-09 14:37:22 -0400
committerDarrick J. Wong <darrick.wong@oracle.com>2017-10-11 13:21:06 -0400
commit20413e37d71befd02b5846acdaf5e2564dd1c38e (patch)
treee82e3b0d39a6f9322af59f3ed8146f9cd00a6d9e
parente12199f85d0ad1b04ce6c425ad93cd847fe930bb (diff)
xfs: Don't log uninitialised fields in inode structures
Prevent kmemcheck from throwing warnings about reading uninitialised memory when formatting inodes into the incore log buffer. There are several issues here - we don't always log all the fields in the inode log format item, and we never log the inode the di_next_unlinked field. In the case of the inode log format item, this is exacerbated by the old xfs_inode_log_format structure padding issue. Hence make the padded, 64 bit aligned version of the structure the one we always use for formatting the log and get rid of the 64 bit variant. This means we'll always log the 64-bit version and so recovery only needs to convert from the unpadded 32 bit version from older 32 bit kernels. Signed-Off-By: Dave Chinner <dchinner@redhat.com> Tested-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> Reviewed-by: Brian Foster <bfoster@redhat.com> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
-rw-r--r--fs/xfs/libxfs/xfs_log_format.h27
-rw-r--r--fs/xfs/xfs_inode_item.c79
-rw-r--r--fs/xfs/xfs_ondisk.h2
3 files changed, 50 insertions, 58 deletions
diff --git a/fs/xfs/libxfs/xfs_log_format.h b/fs/xfs/libxfs/xfs_log_format.h
index 8372e9bcd7b6..71de185735e0 100644
--- a/fs/xfs/libxfs/xfs_log_format.h
+++ b/fs/xfs/libxfs/xfs_log_format.h
@@ -270,6 +270,7 @@ typedef struct xfs_inode_log_format {
270 uint32_t ilf_fields; /* flags for fields logged */ 270 uint32_t ilf_fields; /* flags for fields logged */
271 uint16_t ilf_asize; /* size of attr d/ext/root */ 271 uint16_t ilf_asize; /* size of attr d/ext/root */
272 uint16_t ilf_dsize; /* size of data/ext/root */ 272 uint16_t ilf_dsize; /* size of data/ext/root */
273 uint32_t ilf_pad; /* pad for 64 bit boundary */
273 uint64_t ilf_ino; /* inode number */ 274 uint64_t ilf_ino; /* inode number */
274 union { 275 union {
275 uint32_t ilfu_rdev; /* rdev value for dev inode*/ 276 uint32_t ilfu_rdev; /* rdev value for dev inode*/
@@ -280,29 +281,17 @@ typedef struct xfs_inode_log_format {
280 int32_t ilf_boffset; /* off of inode in buffer */ 281 int32_t ilf_boffset; /* off of inode in buffer */
281} xfs_inode_log_format_t; 282} xfs_inode_log_format_t;
282 283
283typedef struct xfs_inode_log_format_32 { 284/*
284 uint16_t ilf_type; /* inode log item type */ 285 * Old 32 bit systems will log in this format without the 64 bit
285 uint16_t ilf_size; /* size of this item */ 286 * alignment padding. Recovery will detect this and convert it to the
286 uint32_t ilf_fields; /* flags for fields logged */ 287 * correct format.
287 uint16_t ilf_asize; /* size of attr d/ext/root */ 288 */
288 uint16_t ilf_dsize; /* size of data/ext/root */ 289struct xfs_inode_log_format_32 {
289 uint64_t ilf_ino; /* inode number */
290 union {
291 uint32_t ilfu_rdev; /* rdev value for dev inode*/
292 uuid_t ilfu_uuid; /* mount point value */
293 } ilf_u;
294 int64_t ilf_blkno; /* blkno of inode buffer */
295 int32_t ilf_len; /* len of inode buffer */
296 int32_t ilf_boffset; /* off of inode in buffer */
297} __attribute__((packed)) xfs_inode_log_format_32_t;
298
299typedef struct xfs_inode_log_format_64 {
300 uint16_t ilf_type; /* inode log item type */ 290 uint16_t ilf_type; /* inode log item type */
301 uint16_t ilf_size; /* size of this item */ 291 uint16_t ilf_size; /* size of this item */
302 uint32_t ilf_fields; /* flags for fields logged */ 292 uint32_t ilf_fields; /* flags for fields logged */
303 uint16_t ilf_asize; /* size of attr d/ext/root */ 293 uint16_t ilf_asize; /* size of attr d/ext/root */
304 uint16_t ilf_dsize; /* size of data/ext/root */ 294 uint16_t ilf_dsize; /* size of data/ext/root */
305 uint32_t ilf_pad; /* pad for 64 bit boundary */
306 uint64_t ilf_ino; /* inode number */ 295 uint64_t ilf_ino; /* inode number */
307 union { 296 union {
308 uint32_t ilfu_rdev; /* rdev value for dev inode*/ 297 uint32_t ilfu_rdev; /* rdev value for dev inode*/
@@ -311,7 +300,7 @@ typedef struct xfs_inode_log_format_64 {
311 int64_t ilf_blkno; /* blkno of inode buffer */ 300 int64_t ilf_blkno; /* blkno of inode buffer */
312 int32_t ilf_len; /* len of inode buffer */ 301 int32_t ilf_len; /* len of inode buffer */
313 int32_t ilf_boffset; /* off of inode in buffer */ 302 int32_t ilf_boffset; /* off of inode in buffer */
314} xfs_inode_log_format_64_t; 303} __attribute__((packed));
315 304
316 305
317/* 306/*
diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c
index a705f34b58fa..9bbc2d7cc8cb 100644
--- a/fs/xfs/xfs_inode_item.c
+++ b/fs/xfs/xfs_inode_item.c
@@ -364,6 +364,9 @@ xfs_inode_to_log_dinode(
364 to->di_dmstate = from->di_dmstate; 364 to->di_dmstate = from->di_dmstate;
365 to->di_flags = from->di_flags; 365 to->di_flags = from->di_flags;
366 366
367 /* log a dummy value to ensure log structure is fully initialised */
368 to->di_next_unlinked = NULLAGINO;
369
367 if (from->di_version == 3) { 370 if (from->di_version == 3) {
368 to->di_changecount = inode->i_version; 371 to->di_changecount = inode->i_version;
369 to->di_crtime.t_sec = from->di_crtime.t_sec; 372 to->di_crtime.t_sec = from->di_crtime.t_sec;
@@ -404,6 +407,11 @@ xfs_inode_item_format_core(
404 * the second with the on-disk inode structure, and a possible third and/or 407 * the second with the on-disk inode structure, and a possible third and/or
405 * fourth with the inode data/extents/b-tree root and inode attributes 408 * fourth with the inode data/extents/b-tree root and inode attributes
406 * data/extents/b-tree root. 409 * data/extents/b-tree root.
410 *
411 * Note: Always use the 64 bit inode log format structure so we don't
412 * leave an uninitialised hole in the format item on 64 bit systems. Log
413 * recovery on 32 bit systems handles this just fine, so there's no reason
414 * for not using an initialising the properly padded structure all the time.
407 */ 415 */
408STATIC void 416STATIC void
409xfs_inode_item_format( 417xfs_inode_item_format(
@@ -412,8 +420,8 @@ xfs_inode_item_format(
412{ 420{
413 struct xfs_inode_log_item *iip = INODE_ITEM(lip); 421 struct xfs_inode_log_item *iip = INODE_ITEM(lip);
414 struct xfs_inode *ip = iip->ili_inode; 422 struct xfs_inode *ip = iip->ili_inode;
415 struct xfs_inode_log_format *ilf;
416 struct xfs_log_iovec *vecp = NULL; 423 struct xfs_log_iovec *vecp = NULL;
424 struct xfs_inode_log_format *ilf;
417 425
418 ASSERT(ip->i_d.di_version > 1); 426 ASSERT(ip->i_d.di_version > 1);
419 427
@@ -425,7 +433,17 @@ xfs_inode_item_format(
425 ilf->ilf_boffset = ip->i_imap.im_boffset; 433 ilf->ilf_boffset = ip->i_imap.im_boffset;
426 ilf->ilf_fields = XFS_ILOG_CORE; 434 ilf->ilf_fields = XFS_ILOG_CORE;
427 ilf->ilf_size = 2; /* format + core */ 435 ilf->ilf_size = 2; /* format + core */
428 xlog_finish_iovec(lv, vecp, sizeof(struct xfs_inode_log_format)); 436
437 /*
438 * make sure we don't leak uninitialised data into the log in the case
439 * when we don't log every field in the inode.
440 */
441 ilf->ilf_dsize = 0;
442 ilf->ilf_asize = 0;
443 ilf->ilf_pad = 0;
444 uuid_copy(&ilf->ilf_u.ilfu_uuid, &uuid_null);
445
446 xlog_finish_iovec(lv, vecp, sizeof(*ilf));
429 447
430 xfs_inode_item_format_core(ip, lv, &vecp); 448 xfs_inode_item_format_core(ip, lv, &vecp);
431 xfs_inode_item_format_data_fork(iip, ilf, lv, &vecp); 449 xfs_inode_item_format_data_fork(iip, ilf, lv, &vecp);
@@ -855,44 +873,29 @@ xfs_istale_done(
855} 873}
856 874
857/* 875/*
858 * convert an xfs_inode_log_format struct from either 32 or 64 bit versions 876 * convert an xfs_inode_log_format struct from the old 32 bit version
859 * (which can have different field alignments) to the native version 877 * (which can have different field alignments) to the native 64 bit version
860 */ 878 */
861int 879int
862xfs_inode_item_format_convert( 880xfs_inode_item_format_convert(
863 xfs_log_iovec_t *buf, 881 struct xfs_log_iovec *buf,
864 xfs_inode_log_format_t *in_f) 882 struct xfs_inode_log_format *in_f)
865{ 883{
866 if (buf->i_len == sizeof(xfs_inode_log_format_32_t)) { 884 struct xfs_inode_log_format_32 *in_f32 = buf->i_addr;
867 xfs_inode_log_format_32_t *in_f32 = buf->i_addr; 885
868 886 if (buf->i_len != sizeof(*in_f32))
869 in_f->ilf_type = in_f32->ilf_type; 887 return -EFSCORRUPTED;
870 in_f->ilf_size = in_f32->ilf_size; 888
871 in_f->ilf_fields = in_f32->ilf_fields; 889 in_f->ilf_type = in_f32->ilf_type;
872 in_f->ilf_asize = in_f32->ilf_asize; 890 in_f->ilf_size = in_f32->ilf_size;
873 in_f->ilf_dsize = in_f32->ilf_dsize; 891 in_f->ilf_fields = in_f32->ilf_fields;
874 in_f->ilf_ino = in_f32->ilf_ino; 892 in_f->ilf_asize = in_f32->ilf_asize;
875 /* copy biggest field of ilf_u */ 893 in_f->ilf_dsize = in_f32->ilf_dsize;
876 uuid_copy(&in_f->ilf_u.ilfu_uuid, &in_f32->ilf_u.ilfu_uuid); 894 in_f->ilf_ino = in_f32->ilf_ino;
877 in_f->ilf_blkno = in_f32->ilf_blkno; 895 /* copy biggest field of ilf_u */
878 in_f->ilf_len = in_f32->ilf_len; 896 uuid_copy(&in_f->ilf_u.ilfu_uuid, &in_f32->ilf_u.ilfu_uuid);
879 in_f->ilf_boffset = in_f32->ilf_boffset; 897 in_f->ilf_blkno = in_f32->ilf_blkno;
880 return 0; 898 in_f->ilf_len = in_f32->ilf_len;
881 } else if (buf->i_len == sizeof(xfs_inode_log_format_64_t)){ 899 in_f->ilf_boffset = in_f32->ilf_boffset;
882 xfs_inode_log_format_64_t *in_f64 = buf->i_addr; 900 return 0;
883
884 in_f->ilf_type = in_f64->ilf_type;
885 in_f->ilf_size = in_f64->ilf_size;
886 in_f->ilf_fields = in_f64->ilf_fields;
887 in_f->ilf_asize = in_f64->ilf_asize;
888 in_f->ilf_dsize = in_f64->ilf_dsize;
889 in_f->ilf_ino = in_f64->ilf_ino;
890 /* copy biggest field of ilf_u */
891 uuid_copy(&in_f->ilf_u.ilfu_uuid, &in_f64->ilf_u.ilfu_uuid);
892 in_f->ilf_blkno = in_f64->ilf_blkno;
893 in_f->ilf_len = in_f64->ilf_len;
894 in_f->ilf_boffset = in_f64->ilf_boffset;
895 return 0;
896 }
897 return -EFSCORRUPTED;
898} 901}
diff --git a/fs/xfs/xfs_ondisk.h b/fs/xfs/xfs_ondisk.h
index 0c381d71b242..0492436a053f 100644
--- a/fs/xfs/xfs_ondisk.h
+++ b/fs/xfs/xfs_ondisk.h
@@ -134,7 +134,7 @@ xfs_check_ondisk_structs(void)
134 XFS_CHECK_STRUCT_SIZE(struct xfs_icreate_log, 28); 134 XFS_CHECK_STRUCT_SIZE(struct xfs_icreate_log, 28);
135 XFS_CHECK_STRUCT_SIZE(struct xfs_ictimestamp, 8); 135 XFS_CHECK_STRUCT_SIZE(struct xfs_ictimestamp, 8);
136 XFS_CHECK_STRUCT_SIZE(struct xfs_inode_log_format_32, 52); 136 XFS_CHECK_STRUCT_SIZE(struct xfs_inode_log_format_32, 52);
137 XFS_CHECK_STRUCT_SIZE(struct xfs_inode_log_format_64, 56); 137 XFS_CHECK_STRUCT_SIZE(struct xfs_inode_log_format, 56);
138 XFS_CHECK_STRUCT_SIZE(struct xfs_qoff_logformat, 20); 138 XFS_CHECK_STRUCT_SIZE(struct xfs_qoff_logformat, 20);
139 XFS_CHECK_STRUCT_SIZE(struct xfs_trans_header, 16); 139 XFS_CHECK_STRUCT_SIZE(struct xfs_trans_header, 16);
140} 140}