Skip to content

Commit 64c3dd0

Browse files
committed
Merge tag 'xfs-6.1-fixes-4' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux
Pull xfs fixes from Darrick Wong: "Dave and I had thought that this would be a very quiet cycle, but we thought wrong. At first there were the usual trickle of minor bugfixes, but then Zorro pulled -rc1 and noticed complaints about the stronger memcpy checks w.r.t. flex arrays. Analyzing how to fix that revealed a bunch of validation gaps in validating ondisk log items during recovery, and then a customer hit an infinite loop in the refcounting code on a corrupt filesystem. So. This largeish batch of fixes addresses all those problems, I hope. Summary: - Fix a UAF bug during log recovery - Fix memory leaks when mount fails - Detect corrupt bestfree information in a directory block - Fix incorrect return value type for the dax page fault handlers - Fix fortify complaints about memcpy of xfs log item objects - Strengthen inadequate validation of recovered log items - Fix incorrectly declared flex array in EFI log item structs - Log corrupt log items for debugging purposes - Fix infinite loop problems in the refcount code if the refcount btree node block keys are corrupt - Fix infinite loop problems in the refcount code if the refcount btree records suffer MSB bitflips - Add more sanity checking to continued defer ops to prevent overflows from one AG to the next or off EOFS" * tag 'xfs-6.1-fixes-4' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux: (28 commits) xfs: rename XFS_REFC_COW_START to _COWFLAG xfs: fix uninitialized list head in struct xfs_refcount_recovery xfs: fix agblocks check in the cow leftover recovery function xfs: check record domain when accessing refcount records xfs: remove XFS_FIND_RCEXT_SHARED and _COW xfs: refactor domain and refcount checking xfs: report refcount domain in tracepoints xfs: track cow/shared record domains explicitly in xfs_refcount_irec xfs: refactor refcount record usage in xchk_refcountbt_rec xfs: dump corrupt recovered log intent items to dmesg consistently xfs: move _irec structs to xfs_types.h xfs: actually abort log recovery on corrupt intent-done log items xfs: check deferred refcount op continuation parameters xfs: refactor all the EFI/EFD log item sizeof logic xfs: create a predicate to verify per-AG extents xfs: fix memcpy fortify errors in EFI log format copying xfs: make sure aglen never goes negative in xfs_refcount_adjust_extents xfs: fix memcpy fortify errors in RUI log format copying xfs: fix memcpy fortify errors in CUI log format copying xfs: fix memcpy fortify errors in BUI log format copying ...
2 parents 5d8401b + 4eb559d commit 64c3dd0

29 files changed

+670
-386
lines changed

fs/xfs/libxfs/xfs_ag.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,21 @@ xfs_verify_agbno(struct xfs_perag *pag, xfs_agblock_t agbno)
133133
return true;
134134
}
135135

136+
static inline bool
137+
xfs_verify_agbext(
138+
struct xfs_perag *pag,
139+
xfs_agblock_t agbno,
140+
xfs_agblock_t len)
141+
{
142+
if (agbno + len <= agbno)
143+
return false;
144+
145+
if (!xfs_verify_agbno(pag, agbno))
146+
return false;
147+
148+
return xfs_verify_agbno(pag, agbno + len - 1);
149+
}
150+
136151
/*
137152
* Verify that an AG inode number pointer neither points outside the AG
138153
* nor points at static metadata.

fs/xfs/libxfs/xfs_alloc.c

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -263,11 +263,7 @@ xfs_alloc_get_rec(
263263
goto out_bad_rec;
264264

265265
/* check for valid extent range, including overflow */
266-
if (!xfs_verify_agbno(pag, *bno))
267-
goto out_bad_rec;
268-
if (*bno > *bno + *len)
269-
goto out_bad_rec;
270-
if (!xfs_verify_agbno(pag, *bno + *len - 1))
266+
if (!xfs_verify_agbext(pag, *bno, *len))
271267
goto out_bad_rec;
272268

273269
return 0;

fs/xfs/libxfs/xfs_dir2_leaf.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,8 @@ xfs_dir3_leaf_check_int(
146146
xfs_dir2_leaf_tail_t *ltp;
147147
int stale;
148148
int i;
149+
bool isleaf1 = (hdr->magic == XFS_DIR2_LEAF1_MAGIC ||
150+
hdr->magic == XFS_DIR3_LEAF1_MAGIC);
149151

150152
ltp = xfs_dir2_leaf_tail_p(geo, leaf);
151153

@@ -158,8 +160,7 @@ xfs_dir3_leaf_check_int(
158160
return __this_address;
159161

160162
/* Leaves and bests don't overlap in leaf format. */
161-
if ((hdr->magic == XFS_DIR2_LEAF1_MAGIC ||
162-
hdr->magic == XFS_DIR3_LEAF1_MAGIC) &&
163+
if (isleaf1 &&
163164
(char *)&hdr->ents[hdr->count] > (char *)xfs_dir2_leaf_bests_p(ltp))
164165
return __this_address;
165166

@@ -175,6 +176,10 @@ xfs_dir3_leaf_check_int(
175176
}
176177
if (hdr->ents[i].address == cpu_to_be32(XFS_DIR2_NULL_DATAPTR))
177178
stale++;
179+
if (isleaf1 && xfs_dir2_dataptr_to_db(geo,
180+
be32_to_cpu(hdr->ents[i].address)) >=
181+
be32_to_cpu(ltp->bestcount))
182+
return __this_address;
178183
}
179184
if (hdr->stale != stale)
180185
return __this_address;

fs/xfs/libxfs/xfs_format.h

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1564,20 +1564,6 @@ struct xfs_rmap_rec {
15641564
#define RMAPBT_UNUSED_OFFSET_BITLEN 7
15651565
#define RMAPBT_OFFSET_BITLEN 54
15661566

1567-
#define XFS_RMAP_ATTR_FORK (1 << 0)
1568-
#define XFS_RMAP_BMBT_BLOCK (1 << 1)
1569-
#define XFS_RMAP_UNWRITTEN (1 << 2)
1570-
#define XFS_RMAP_KEY_FLAGS (XFS_RMAP_ATTR_FORK | \
1571-
XFS_RMAP_BMBT_BLOCK)
1572-
#define XFS_RMAP_REC_FLAGS (XFS_RMAP_UNWRITTEN)
1573-
struct xfs_rmap_irec {
1574-
xfs_agblock_t rm_startblock; /* extent start block */
1575-
xfs_extlen_t rm_blockcount; /* extent length */
1576-
uint64_t rm_owner; /* extent owner */
1577-
uint64_t rm_offset; /* offset within the owner */
1578-
unsigned int rm_flags; /* state flags */
1579-
};
1580-
15811567
/*
15821568
* Key structure
15831569
*
@@ -1626,7 +1612,7 @@ unsigned int xfs_refc_block(struct xfs_mount *mp);
16261612
* on the startblock. This speeds up mount time deletion of stale
16271613
* staging extents because they're all at the right side of the tree.
16281614
*/
1629-
#define XFS_REFC_COW_START ((xfs_agblock_t)(1U << 31))
1615+
#define XFS_REFC_COWFLAG (1U << 31)
16301616
#define REFCNTBT_COWFLAG_BITLEN 1
16311617
#define REFCNTBT_AGBLOCK_BITLEN 31
16321618

@@ -1640,12 +1626,6 @@ struct xfs_refcount_key {
16401626
__be32 rc_startblock; /* starting block number */
16411627
};
16421628

1643-
struct xfs_refcount_irec {
1644-
xfs_agblock_t rc_startblock; /* starting block number */
1645-
xfs_extlen_t rc_blockcount; /* count of free blocks */
1646-
xfs_nlink_t rc_refcount; /* number of inodes linked here */
1647-
};
1648-
16491629
#define MAXREFCOUNT ((xfs_nlink_t)~0U)
16501630
#define MAXREFCEXTLEN ((xfs_extlen_t)~0U)
16511631

fs/xfs/libxfs/xfs_log_format.h

Lines changed: 54 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -613,25 +613,49 @@ typedef struct xfs_efi_log_format {
613613
uint16_t efi_size; /* size of this item */
614614
uint32_t efi_nextents; /* # extents to free */
615615
uint64_t efi_id; /* efi identifier */
616-
xfs_extent_t efi_extents[1]; /* array of extents to free */
616+
xfs_extent_t efi_extents[]; /* array of extents to free */
617617
} xfs_efi_log_format_t;
618618

619+
static inline size_t
620+
xfs_efi_log_format_sizeof(
621+
unsigned int nr)
622+
{
623+
return sizeof(struct xfs_efi_log_format) +
624+
nr * sizeof(struct xfs_extent);
625+
}
626+
619627
typedef struct xfs_efi_log_format_32 {
620628
uint16_t efi_type; /* efi log item type */
621629
uint16_t efi_size; /* size of this item */
622630
uint32_t efi_nextents; /* # extents to free */
623631
uint64_t efi_id; /* efi identifier */
624-
xfs_extent_32_t efi_extents[1]; /* array of extents to free */
632+
xfs_extent_32_t efi_extents[]; /* array of extents to free */
625633
} __attribute__((packed)) xfs_efi_log_format_32_t;
626634

635+
static inline size_t
636+
xfs_efi_log_format32_sizeof(
637+
unsigned int nr)
638+
{
639+
return sizeof(struct xfs_efi_log_format_32) +
640+
nr * sizeof(struct xfs_extent_32);
641+
}
642+
627643
typedef struct xfs_efi_log_format_64 {
628644
uint16_t efi_type; /* efi log item type */
629645
uint16_t efi_size; /* size of this item */
630646
uint32_t efi_nextents; /* # extents to free */
631647
uint64_t efi_id; /* efi identifier */
632-
xfs_extent_64_t efi_extents[1]; /* array of extents to free */
648+
xfs_extent_64_t efi_extents[]; /* array of extents to free */
633649
} xfs_efi_log_format_64_t;
634650

651+
static inline size_t
652+
xfs_efi_log_format64_sizeof(
653+
unsigned int nr)
654+
{
655+
return sizeof(struct xfs_efi_log_format_64) +
656+
nr * sizeof(struct xfs_extent_64);
657+
}
658+
635659
/*
636660
* This is the structure used to lay out an efd log item in the
637661
* log. The efd_extents array is a variable size array whose
@@ -642,25 +666,49 @@ typedef struct xfs_efd_log_format {
642666
uint16_t efd_size; /* size of this item */
643667
uint32_t efd_nextents; /* # of extents freed */
644668
uint64_t efd_efi_id; /* id of corresponding efi */
645-
xfs_extent_t efd_extents[1]; /* array of extents freed */
669+
xfs_extent_t efd_extents[]; /* array of extents freed */
646670
} xfs_efd_log_format_t;
647671

672+
static inline size_t
673+
xfs_efd_log_format_sizeof(
674+
unsigned int nr)
675+
{
676+
return sizeof(struct xfs_efd_log_format) +
677+
nr * sizeof(struct xfs_extent);
678+
}
679+
648680
typedef struct xfs_efd_log_format_32 {
649681
uint16_t efd_type; /* efd log item type */
650682
uint16_t efd_size; /* size of this item */
651683
uint32_t efd_nextents; /* # of extents freed */
652684
uint64_t efd_efi_id; /* id of corresponding efi */
653-
xfs_extent_32_t efd_extents[1]; /* array of extents freed */
685+
xfs_extent_32_t efd_extents[]; /* array of extents freed */
654686
} __attribute__((packed)) xfs_efd_log_format_32_t;
655687

688+
static inline size_t
689+
xfs_efd_log_format32_sizeof(
690+
unsigned int nr)
691+
{
692+
return sizeof(struct xfs_efd_log_format_32) +
693+
nr * sizeof(struct xfs_extent_32);
694+
}
695+
656696
typedef struct xfs_efd_log_format_64 {
657697
uint16_t efd_type; /* efd log item type */
658698
uint16_t efd_size; /* size of this item */
659699
uint32_t efd_nextents; /* # of extents freed */
660700
uint64_t efd_efi_id; /* id of corresponding efi */
661-
xfs_extent_64_t efd_extents[1]; /* array of extents freed */
701+
xfs_extent_64_t efd_extents[]; /* array of extents freed */
662702
} xfs_efd_log_format_64_t;
663703

704+
static inline size_t
705+
xfs_efd_log_format64_sizeof(
706+
unsigned int nr)
707+
{
708+
return sizeof(struct xfs_efd_log_format_64) +
709+
nr * sizeof(struct xfs_extent_64);
710+
}
711+
664712
/*
665713
* RUI/RUD (reverse mapping) log format definitions
666714
*/

0 commit comments

Comments
 (0)