Commit ae0506eb authored by Darrick J. Wong's avatar Darrick J. Wong

xfs: check used space of shortform xattr structures

Make sure that the records used inside a shortform xattr structure do
not overlap.
Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
parent 5b02a3e8
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "xfs_da_btree.h" #include "xfs_da_btree.h"
#include "xfs_attr.h" #include "xfs_attr.h"
#include "xfs_attr_leaf.h" #include "xfs_attr_leaf.h"
#include "xfs_attr_sf.h"
#include "scrub/scrub.h" #include "scrub/scrub.h"
#include "scrub/common.h" #include "scrub/common.h"
#include "scrub/dabtree.h" #include "scrub/dabtree.h"
...@@ -487,6 +488,73 @@ xchk_xattr_rec( ...@@ -487,6 +488,73 @@ xchk_xattr_rec(
return error; return error;
} }
/* Check space usage of shortform attrs. */
STATIC int
xchk_xattr_check_sf(
struct xfs_scrub *sc)
{
struct xchk_xattr_buf *ab = sc->buf;
struct xfs_attr_shortform *sf;
struct xfs_attr_sf_entry *sfe;
struct xfs_attr_sf_entry *next;
struct xfs_ifork *ifp;
unsigned char *end;
int i;
int error = 0;
ifp = xfs_ifork_ptr(sc->ip, XFS_ATTR_FORK);
bitmap_zero(ab->usedmap, ifp->if_bytes);
sf = (struct xfs_attr_shortform *)sc->ip->i_af.if_u1.if_data;
end = (unsigned char *)ifp->if_u1.if_data + ifp->if_bytes;
xchk_xattr_set_map(sc, ab->usedmap, 0, sizeof(sf->hdr));
sfe = &sf->list[0];
if ((unsigned char *)sfe > end) {
xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, 0);
return 0;
}
for (i = 0; i < sf->hdr.count; i++) {
unsigned char *name = sfe->nameval;
unsigned char *value = &sfe->nameval[sfe->namelen];
if (xchk_should_terminate(sc, &error))
return error;
next = xfs_attr_sf_nextentry(sfe);
if ((unsigned char *)next > end) {
xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, 0);
break;
}
if (!xchk_xattr_set_map(sc, ab->usedmap,
(char *)sfe - (char *)sf,
sizeof(struct xfs_attr_sf_entry))) {
xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, 0);
break;
}
if (!xchk_xattr_set_map(sc, ab->usedmap,
(char *)name - (char *)sf,
sfe->namelen)) {
xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, 0);
break;
}
if (!xchk_xattr_set_map(sc, ab->usedmap,
(char *)value - (char *)sf,
sfe->valuelen)) {
xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, 0);
break;
}
sfe = next;
}
return 0;
}
/* Scrub the extended attribute metadata. */ /* Scrub the extended attribute metadata. */
int int
xchk_xattr( xchk_xattr(
...@@ -506,10 +574,12 @@ xchk_xattr( ...@@ -506,10 +574,12 @@ xchk_xattr(
if (error) if (error)
return error; return error;
memset(&sx, 0, sizeof(sx)); /* Check the physical structure of the xattr. */
/* Check attribute tree structure */ if (sc->ip->i_af.if_format == XFS_DINODE_FMT_LOCAL)
error = xchk_da_btree(sc, XFS_ATTR_FORK, xchk_xattr_rec, error = xchk_xattr_check_sf(sc);
&last_checked); else
error = xchk_da_btree(sc, XFS_ATTR_FORK, xchk_xattr_rec,
&last_checked);
if (error) if (error)
goto out; goto out;
...@@ -517,6 +587,7 @@ xchk_xattr( ...@@ -517,6 +587,7 @@ xchk_xattr(
goto out; goto out;
/* Check that every attr key can also be looked up by hash. */ /* Check that every attr key can also be looked up by hash. */
memset(&sx, 0, sizeof(sx));
sx.context.dp = sc->ip; sx.context.dp = sc->ip;
sx.context.resynch = 1; sx.context.resynch = 1;
sx.context.put_listent = xchk_xattr_listent; sx.context.put_listent = xchk_xattr_listent;
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* Temporary storage for online scrub and repair of extended attributes. * Temporary storage for online scrub and repair of extended attributes.
*/ */
struct xchk_xattr_buf { struct xchk_xattr_buf {
/* Bitmap of used space in xattr leaf blocks. */ /* Bitmap of used space in xattr leaf blocks and shortform forks. */
unsigned long *usedmap; unsigned long *usedmap;
/* Bitmap of free space in xattr leaf blocks. */ /* Bitmap of free space in xattr leaf blocks. */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment