Skip to content

Commit ae0506e

Browse files
author
Darrick J. Wong
committed
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>
1 parent 5b02a3e commit ae0506e

2 files changed

Lines changed: 76 additions & 5 deletions

File tree

fs/xfs/scrub/attr.c

Lines changed: 75 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "xfs_da_btree.h"
1616
#include "xfs_attr.h"
1717
#include "xfs_attr_leaf.h"
18+
#include "xfs_attr_sf.h"
1819
#include "scrub/scrub.h"
1920
#include "scrub/common.h"
2021
#include "scrub/dabtree.h"
@@ -487,6 +488,73 @@ xchk_xattr_rec(
487488
return error;
488489
}
489490

491+
/* Check space usage of shortform attrs. */
492+
STATIC int
493+
xchk_xattr_check_sf(
494+
struct xfs_scrub *sc)
495+
{
496+
struct xchk_xattr_buf *ab = sc->buf;
497+
struct xfs_attr_shortform *sf;
498+
struct xfs_attr_sf_entry *sfe;
499+
struct xfs_attr_sf_entry *next;
500+
struct xfs_ifork *ifp;
501+
unsigned char *end;
502+
int i;
503+
int error = 0;
504+
505+
ifp = xfs_ifork_ptr(sc->ip, XFS_ATTR_FORK);
506+
507+
bitmap_zero(ab->usedmap, ifp->if_bytes);
508+
sf = (struct xfs_attr_shortform *)sc->ip->i_af.if_u1.if_data;
509+
end = (unsigned char *)ifp->if_u1.if_data + ifp->if_bytes;
510+
xchk_xattr_set_map(sc, ab->usedmap, 0, sizeof(sf->hdr));
511+
512+
sfe = &sf->list[0];
513+
if ((unsigned char *)sfe > end) {
514+
xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, 0);
515+
return 0;
516+
}
517+
518+
for (i = 0; i < sf->hdr.count; i++) {
519+
unsigned char *name = sfe->nameval;
520+
unsigned char *value = &sfe->nameval[sfe->namelen];
521+
522+
if (xchk_should_terminate(sc, &error))
523+
return error;
524+
525+
next = xfs_attr_sf_nextentry(sfe);
526+
if ((unsigned char *)next > end) {
527+
xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, 0);
528+
break;
529+
}
530+
531+
if (!xchk_xattr_set_map(sc, ab->usedmap,
532+
(char *)sfe - (char *)sf,
533+
sizeof(struct xfs_attr_sf_entry))) {
534+
xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, 0);
535+
break;
536+
}
537+
538+
if (!xchk_xattr_set_map(sc, ab->usedmap,
539+
(char *)name - (char *)sf,
540+
sfe->namelen)) {
541+
xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, 0);
542+
break;
543+
}
544+
545+
if (!xchk_xattr_set_map(sc, ab->usedmap,
546+
(char *)value - (char *)sf,
547+
sfe->valuelen)) {
548+
xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, 0);
549+
break;
550+
}
551+
552+
sfe = next;
553+
}
554+
555+
return 0;
556+
}
557+
490558
/* Scrub the extended attribute metadata. */
491559
int
492560
xchk_xattr(
@@ -506,17 +574,20 @@ xchk_xattr(
506574
if (error)
507575
return error;
508576

509-
memset(&sx, 0, sizeof(sx));
510-
/* Check attribute tree structure */
511-
error = xchk_da_btree(sc, XFS_ATTR_FORK, xchk_xattr_rec,
512-
&last_checked);
577+
/* Check the physical structure of the xattr. */
578+
if (sc->ip->i_af.if_format == XFS_DINODE_FMT_LOCAL)
579+
error = xchk_xattr_check_sf(sc);
580+
else
581+
error = xchk_da_btree(sc, XFS_ATTR_FORK, xchk_xattr_rec,
582+
&last_checked);
513583
if (error)
514584
goto out;
515585

516586
if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
517587
goto out;
518588

519589
/* Check that every attr key can also be looked up by hash. */
590+
memset(&sx, 0, sizeof(sx));
520591
sx.context.dp = sc->ip;
521592
sx.context.resynch = 1;
522593
sx.context.put_listent = xchk_xattr_listent;

fs/xfs/scrub/attr.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
* Temporary storage for online scrub and repair of extended attributes.
1111
*/
1212
struct xchk_xattr_buf {
13-
/* Bitmap of used space in xattr leaf blocks. */
13+
/* Bitmap of used space in xattr leaf blocks and shortform forks. */
1414
unsigned long *usedmap;
1515

1616
/* Bitmap of free space in xattr leaf blocks. */

0 commit comments

Comments
 (0)