summaryrefslogtreecommitdiffstats
path: root/fs/xfs
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@kernel.org>2023-04-12 04:00:33 +0200
committerDarrick J. Wong <djwong@kernel.org>2023-04-12 04:00:33 +0200
commitae0506eba78fd1d6236b46ca5aa089c8fc6050cf (patch)
treeeabd37a0474755f795786625a272548f0baf797b /fs/xfs
parentxfs: move xattr scrub buffer allocation to top level function (diff)
downloadlinux-ae0506eba78fd1d6236b46ca5aa089c8fc6050cf.tar.xz
linux-ae0506eba78fd1d6236b46ca5aa089c8fc6050cf.zip
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: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Dave Chinner <dchinner@redhat.com>
Diffstat (limited to 'fs/xfs')
-rw-r--r--fs/xfs/scrub/attr.c79
-rw-r--r--fs/xfs/scrub/attr.h2
2 files changed, 76 insertions, 5 deletions
diff --git a/fs/xfs/scrub/attr.c b/fs/xfs/scrub/attr.c
index b37de9459dc0..a49048f2a3db 100644
--- a/fs/xfs/scrub/attr.c
+++ b/fs/xfs/scrub/attr.c
@@ -15,6 +15,7 @@
#include "xfs_da_btree.h"
#include "xfs_attr.h"
#include "xfs_attr_leaf.h"
+#include "xfs_attr_sf.h"
#include "scrub/scrub.h"
#include "scrub/common.h"
#include "scrub/dabtree.h"
@@ -487,6 +488,73 @@ out:
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. */
int
xchk_xattr(
@@ -506,10 +574,12 @@ xchk_xattr(
if (error)
return error;
- memset(&sx, 0, sizeof(sx));
- /* Check attribute tree structure */
- error = xchk_da_btree(sc, XFS_ATTR_FORK, xchk_xattr_rec,
- &last_checked);
+ /* Check the physical structure of the xattr. */
+ if (sc->ip->i_af.if_format == XFS_DINODE_FMT_LOCAL)
+ error = xchk_xattr_check_sf(sc);
+ else
+ error = xchk_da_btree(sc, XFS_ATTR_FORK, xchk_xattr_rec,
+ &last_checked);
if (error)
goto out;
@@ -517,6 +587,7 @@ xchk_xattr(
goto out;
/* Check that every attr key can also be looked up by hash. */
+ memset(&sx, 0, sizeof(sx));
sx.context.dp = sc->ip;
sx.context.resynch = 1;
sx.context.put_listent = xchk_xattr_listent;
diff --git a/fs/xfs/scrub/attr.h b/fs/xfs/scrub/attr.h
index 3c764722da61..48fd9402c432 100644
--- a/fs/xfs/scrub/attr.h
+++ b/fs/xfs/scrub/attr.h
@@ -10,7 +10,7 @@
* Temporary storage for online scrub and repair of extended attributes.
*/
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;
/* Bitmap of free space in xattr leaf blocks. */