]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
xfs: validate attr leaf buffer owners
authorDarrick J. Wong <djwong@kernel.org>
Mon, 29 Jul 2024 23:22:37 +0000 (16:22 -0700)
committerDarrick J. Wong <djwong@kernel.org>
Tue, 30 Jul 2024 00:01:00 +0000 (17:01 -0700)
Source kernel commit: f4887fbc41dcb1560ec5da982ac7c6ad04b71de5

Create a leaf block header checking function to validate the owner field
of xattr leaf blocks.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
libxfs/xfs_attr.c
libxfs/xfs_attr_leaf.c
libxfs/xfs_attr_leaf.h
libxfs/xfs_da_btree.c
libxfs/xfs_da_btree.h
libxfs/xfs_exchmaps.c

index 21b5d922b71dc1fe5fb018fb6c215ba1c4d98363..cc291cf7619a140d53eb0c860808d0b2c1da131a 100644 (file)
@@ -647,8 +647,8 @@ xfs_attr_leaf_remove_attr(
        int                             forkoff;
        int                             error;
 
-       error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno,
-                                  &bp);
+       error = xfs_attr3_leaf_read(args->trans, args->dp, args->owner,
+                       args->blkno, &bp);
        if (error)
                return error;
 
@@ -679,7 +679,7 @@ xfs_attr_leaf_shrink(
        if (!xfs_attr_is_leaf(dp))
                return 0;
 
-       error = xfs_attr3_leaf_read(args->trans, args->dp, 0, &bp);
+       error = xfs_attr3_leaf_read(args->trans, args->dp, args->owner, 0, &bp);
        if (error)
                return error;
 
@@ -1156,7 +1156,7 @@ xfs_attr_leaf_try_add(
        struct xfs_buf          *bp;
        int                     error;
 
-       error = xfs_attr3_leaf_read(args->trans, args->dp, 0, &bp);
+       error = xfs_attr3_leaf_read(args->trans, args->dp, args->owner, 0, &bp);
        if (error)
                return error;
 
@@ -1204,7 +1204,7 @@ xfs_attr_leaf_hasname(
 {
        int                     error = 0;
 
-       error = xfs_attr3_leaf_read(args->trans, args->dp, 0, bp);
+       error = xfs_attr3_leaf_read(args->trans, args->dp, args->owner, 0, bp);
        if (error)
                return error;
 
index ed3b63f8c646575c9e0dab65924873114d57ef25..47f2836fb711c687c0c1d9df2761051adbfcfeee 100644 (file)
@@ -385,6 +385,27 @@ xfs_attr3_leaf_verify(
        return NULL;
 }
 
+xfs_failaddr_t
+xfs_attr3_leaf_header_check(
+       struct xfs_buf          *bp,
+       xfs_ino_t               owner)
+{
+       struct xfs_mount        *mp = bp->b_mount;
+
+       if (xfs_has_crc(mp)) {
+               struct xfs_attr3_leafblock *hdr3 = bp->b_addr;
+
+               if (hdr3->hdr.info.hdr.magic !=
+                               cpu_to_be16(XFS_ATTR3_LEAF_MAGIC))
+                       return __this_address;
+
+               if (be64_to_cpu(hdr3->hdr.info.owner) != owner)
+                       return __this_address;
+       }
+
+       return NULL;
+}
+
 static void
 xfs_attr3_leaf_write_verify(
        struct xfs_buf  *bp)
@@ -445,16 +466,30 @@ int
 xfs_attr3_leaf_read(
        struct xfs_trans        *tp,
        struct xfs_inode        *dp,
+       xfs_ino_t               owner,
        xfs_dablk_t             bno,
        struct xfs_buf          **bpp)
 {
+       xfs_failaddr_t          fa;
        int                     err;
 
        err = xfs_da_read_buf(tp, dp, bno, 0, bpp, XFS_ATTR_FORK,
                        &xfs_attr3_leaf_buf_ops);
-       if (!err && tp && *bpp)
+       if (err || !(*bpp))
+               return err;
+
+       fa = xfs_attr3_leaf_header_check(*bpp, owner);
+       if (fa) {
+               __xfs_buf_mark_corrupt(*bpp, fa);
+               xfs_trans_brelse(tp, *bpp);
+               *bpp = NULL;
+               xfs_dirattr_mark_sick(dp, XFS_ATTR_FORK);
+               return -EFSCORRUPTED;
+       }
+
+       if (tp)
                xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_ATTR_LEAF_BUF);
-       return err;
+       return 0;
 }
 
 /*========================================================================
@@ -1157,7 +1192,7 @@ xfs_attr3_leaf_to_node(
        error = xfs_da_grow_inode(args, &blkno);
        if (error)
                goto out;
-       error = xfs_attr3_leaf_read(args->trans, dp, 0, &bp1);
+       error = xfs_attr3_leaf_read(args->trans, dp, args->owner, 0, &bp1);
        if (error)
                goto out;
 
@@ -1992,7 +2027,7 @@ xfs_attr3_leaf_toosmall(
                if (blkno == 0)
                        continue;
                error = xfs_attr3_leaf_read(state->args->trans, state->args->dp,
-                                       blkno, &bp);
+                                       state->args->owner, blkno, &bp);
                if (error)
                        return error;
 
@@ -2714,7 +2749,8 @@ xfs_attr3_leaf_clearflag(
        /*
         * Set up the operation.
         */
-       error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, &bp);
+       error = xfs_attr3_leaf_read(args->trans, args->dp, args->owner,
+                       args->blkno, &bp);
        if (error)
                return error;
 
@@ -2778,7 +2814,8 @@ xfs_attr3_leaf_setflag(
        /*
         * Set up the operation.
         */
-       error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, &bp);
+       error = xfs_attr3_leaf_read(args->trans, args->dp, args->owner,
+                       args->blkno, &bp);
        if (error)
                return error;
 
@@ -2837,7 +2874,8 @@ xfs_attr3_leaf_flipflags(
        /*
         * Read the block containing the "old" attr
         */
-       error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, &bp1);
+       error = xfs_attr3_leaf_read(args->trans, args->dp, args->owner,
+                       args->blkno, &bp1);
        if (error)
                return error;
 
@@ -2845,8 +2883,8 @@ xfs_attr3_leaf_flipflags(
         * Read the block containing the "new" attr, if it is different
         */
        if (args->blkno2 != args->blkno) {
-               error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno2,
-                                          &bp2);
+               error = xfs_attr3_leaf_read(args->trans, args->dp, args->owner,
+                               args->blkno2, &bp2);
                if (error)
                        return error;
        } else {
index 9b9948639c0fb34f20c503eb9e0d6ed3e17817e4..bac219589896ad6c2bc623da6e34540f6cd8f6a5 100644 (file)
@@ -98,12 +98,14 @@ int xfs_attr_leaf_order(struct xfs_buf *leaf1_bp,
                                   struct xfs_buf *leaf2_bp);
 int    xfs_attr_leaf_newentsize(struct xfs_da_args *args, int *local);
 int    xfs_attr3_leaf_read(struct xfs_trans *tp, struct xfs_inode *dp,
-                       xfs_dablk_t bno, struct xfs_buf **bpp);
+                       xfs_ino_t owner, xfs_dablk_t bno, struct xfs_buf **bpp);
 void   xfs_attr3_leaf_hdr_from_disk(struct xfs_da_geometry *geo,
                                     struct xfs_attr3_icleaf_hdr *to,
                                     struct xfs_attr_leafblock *from);
 void   xfs_attr3_leaf_hdr_to_disk(struct xfs_da_geometry *geo,
                                   struct xfs_attr_leafblock *to,
                                   struct xfs_attr3_icleaf_hdr *from);
+xfs_failaddr_t xfs_attr3_leaf_header_check(struct xfs_buf *bp,
+               xfs_ino_t owner);
 
 #endif /* __XFS_ATTR_LEAF_H__ */
index 3ad58ab04bf103fc3f6ac9ffe9098c40fe09c527..28fd87c2db2247671528e1e1ea39a216ad4b6275 100644 (file)
@@ -248,6 +248,25 @@ xfs_da3_node_verify(
        return NULL;
 }
 
+xfs_failaddr_t
+xfs_da3_header_check(
+       struct xfs_buf          *bp,
+       xfs_ino_t               owner)
+{
+       struct xfs_mount        *mp = bp->b_mount;
+       struct xfs_da_blkinfo   *hdr = bp->b_addr;
+
+       if (!xfs_has_crc(mp))
+               return NULL;
+
+       switch (hdr->magic) {
+       case cpu_to_be16(XFS_ATTR3_LEAF_MAGIC):
+               return xfs_attr3_leaf_header_check(bp, owner);
+       }
+
+       return NULL;
+}
+
 static void
 xfs_da3_node_write_verify(
        struct xfs_buf  *bp)
@@ -1587,6 +1606,7 @@ xfs_da3_node_lookup_int(
        struct xfs_da_node_entry *btree;
        struct xfs_da3_icnode_hdr nodehdr;
        struct xfs_da_args      *args;
+       xfs_failaddr_t          fa;
        xfs_dablk_t             blkno;
        xfs_dahash_t            hashval;
        xfs_dahash_t            btreehashval;
@@ -1625,6 +1645,12 @@ xfs_da3_node_lookup_int(
 
                if (magic == XFS_ATTR_LEAF_MAGIC ||
                    magic == XFS_ATTR3_LEAF_MAGIC) {
+                       fa = xfs_attr3_leaf_header_check(blk->bp, args->owner);
+                       if (fa) {
+                               __xfs_buf_mark_corrupt(blk->bp, fa);
+                               xfs_da_mark_sick(args);
+                               return -EFSCORRUPTED;
+                       }
                        blk->magic = XFS_ATTR_LEAF_MAGIC;
                        blk->hashval = xfs_attr_leaf_lasthash(blk->bp, NULL);
                        break;
@@ -1992,6 +2018,7 @@ xfs_da3_path_shift(
        struct xfs_da_node_entry *btree;
        struct xfs_da3_icnode_hdr nodehdr;
        struct xfs_buf          *bp;
+       xfs_failaddr_t          fa;
        xfs_dablk_t             blkno = 0;
        int                     level;
        int                     error;
@@ -2083,6 +2110,12 @@ xfs_da3_path_shift(
                        break;
                case XFS_ATTR_LEAF_MAGIC:
                case XFS_ATTR3_LEAF_MAGIC:
+                       fa = xfs_attr3_leaf_header_check(blk->bp, args->owner);
+                       if (fa) {
+                               __xfs_buf_mark_corrupt(blk->bp, fa);
+                               xfs_da_mark_sick(args);
+                               return -EFSCORRUPTED;
+                       }
                        blk->magic = XFS_ATTR_LEAF_MAGIC;
                        ASSERT(level == path->active-1);
                        blk->index = 0;
@@ -2286,6 +2319,7 @@ xfs_da3_swap_lastblock(
        struct xfs_buf          *last_buf;
        struct xfs_buf          *sib_buf;
        struct xfs_buf          *par_buf;
+       xfs_failaddr_t          fa;
        xfs_dahash_t            dead_hash;
        xfs_fileoff_t           lastoff;
        xfs_dablk_t             dead_blkno;
@@ -2322,6 +2356,14 @@ xfs_da3_swap_lastblock(
        error = xfs_da3_node_read(tp, dp, last_blkno, &last_buf, w);
        if (error)
                return error;
+       fa = xfs_da3_header_check(last_buf, args->owner);
+       if (fa) {
+               __xfs_buf_mark_corrupt(last_buf, fa);
+               xfs_trans_brelse(tp, last_buf);
+               xfs_da_mark_sick(args);
+               return -EFSCORRUPTED;
+       }
+
        /*
         * Copy the last block into the dead buffer and log it.
         */
index 7fb13f26edaa7bed7a57c9edfc3c4c0b68d40f5a..99618e0c8a72b7f4ae8ccda4447030d9f07e1ceb 100644 (file)
@@ -236,6 +236,7 @@ void        xfs_da3_node_hdr_from_disk(struct xfs_mount *mp,
                struct xfs_da3_icnode_hdr *to, struct xfs_da_intnode *from);
 void   xfs_da3_node_hdr_to_disk(struct xfs_mount *mp,
                struct xfs_da_intnode *to, struct xfs_da3_icnode_hdr *from);
+xfs_failaddr_t xfs_da3_header_check(struct xfs_buf *bp, xfs_ino_t owner);
 
 extern struct kmem_cache       *xfs_da_state_cache;
 
index 6160beef1886228ab40a80f5248b144a6709fdfc..21c501aab3e8b25bb9c6a4d60a197bf175a8ae08 100644 (file)
@@ -435,7 +435,8 @@ xfs_exchmaps_attr_to_sf(
        if (!xfs_attr_is_leaf(xmi->xmi_ip2))
                return 0;
 
-       error = xfs_attr3_leaf_read(tp, xmi->xmi_ip2, 0, &bp);
+       error = xfs_attr3_leaf_read(tp, xmi->xmi_ip2, xmi->xmi_ip2->i_ino, 0,
+                       &bp);
        if (error)
                return error;