xfs: enforce one namespace per attribute
[linux-2.6-block.git] / fs / xfs / libxfs / xfs_attr_leaf.c
index ac904cc1a97bae1eae0aa0acb8a3dc00ea92a55a..3b024ab892e68081f29f2b2b4bb2be23da263431 100644 (file)
@@ -388,6 +388,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)
@@ -448,16 +469,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;
 }
 
 /*========================================================================
@@ -904,6 +939,7 @@ xfs_attr_shortform_to_leaf(
        nargs.whichfork = XFS_ATTR_FORK;
        nargs.trans = args->trans;
        nargs.op_flags = XFS_DA_OP_OKNOENT;
+       nargs.owner = args->owner;
 
        sfe = xfs_attr_sf_firstentry(sf);
        for (i = 0; i < sf->count; i++) {
@@ -914,6 +950,11 @@ xfs_attr_shortform_to_leaf(
                nargs.hashval = xfs_da_hashname(sfe->nameval,
                                                sfe->namelen);
                nargs.attr_filter = sfe->flags & XFS_ATTR_NSP_ONDISK_MASK;
+               if (!xfs_attr_check_namespace(sfe->flags)) {
+                       xfs_da_mark_sick(args);
+                       error = -EFSCORRUPTED;
+                       goto out;
+               }
                error = xfs_attr3_leaf_lookup_int(bp, &nargs); /* set a->index */
                ASSERT(error == -ENOATTR);
                error = xfs_attr3_leaf_add(bp, &nargs);
@@ -1027,7 +1068,7 @@ xfs_attr_shortform_verify(
                 * one namespace flag per xattr, so we can just count the
                 * bits (i.e. hweight) here.
                 */
-               if (hweight8(sfep->flags & XFS_ATTR_NSP_ONDISK_MASK) > 1)
+               if (!xfs_attr_check_namespace(sfep->flags))
                        return __this_address;
 
                sfep = next_sfep;
@@ -1106,6 +1147,7 @@ xfs_attr3_leaf_to_shortform(
        nargs.whichfork = XFS_ATTR_FORK;
        nargs.trans = args->trans;
        nargs.op_flags = XFS_DA_OP_OKNOENT;
+       nargs.owner = args->owner;
 
        for (i = 0; i < ichdr.count; entry++, i++) {
                if (entry->flags & XFS_ATTR_INCOMPLETE)
@@ -1158,7 +1200,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;
 
@@ -1237,7 +1279,7 @@ xfs_attr3_leaf_create(
                ichdr.magic = XFS_ATTR3_LEAF_MAGIC;
 
                hdr3->blkno = cpu_to_be64(xfs_buf_daddr(bp));
-               hdr3->owner = cpu_to_be64(dp->i_ino);
+               hdr3->owner = cpu_to_be64(args->owner);
                uuid_copy(&hdr3->uuid, &mp->m_sb.sb_meta_uuid);
 
                ichdr.freemap[0].base = sizeof(struct xfs_attr3_leaf_hdr);
@@ -1993,7 +2035,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;
 
@@ -2715,7 +2757,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;
 
@@ -2779,7 +2822,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;
 
@@ -2838,7 +2882,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;
 
@@ -2846,8 +2891,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 {