Skip to content

Commit ea0b3e8

Browse files
author
Darrick J. Wong
committed
xfs: enforce one namespace per attribute
Create a standardized helper function to enforce one namespace bit per extended attribute, and refactor all the open-coded hweight logic. This function is not a static inline to avoid porting hassles in userspace. Signed-off-by: Darrick J. Wong <[email protected]> Reviewed-by: Christoph Hellwig <[email protected]>
1 parent ffdcc3b commit ea0b3e8

File tree

7 files changed

+41
-18
lines changed

7 files changed

+41
-18
lines changed

fs/xfs/libxfs/xfs_attr.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1532,12 +1532,23 @@ xfs_attr_node_get(
15321532
return error;
15331533
}
15341534

1535+
/* Enforce that there is at most one namespace bit per attr. */
1536+
inline bool xfs_attr_check_namespace(unsigned int attr_flags)
1537+
{
1538+
return hweight32(attr_flags & XFS_ATTR_NSP_ONDISK_MASK) < 2;
1539+
}
1540+
15351541
/* Returns true if the attribute entry name is valid. */
15361542
bool
15371543
xfs_attr_namecheck(
1544+
unsigned int attr_flags,
15381545
const void *name,
15391546
size_t length)
15401547
{
1548+
/* Only one namespace bit allowed. */
1549+
if (!xfs_attr_check_namespace(attr_flags))
1550+
return false;
1551+
15411552
/*
15421553
* MAXNAMELEN includes the trailing null, but (name/length) leave it
15431554
* out, so use >= for the length check.

fs/xfs/libxfs/xfs_attr.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -560,7 +560,9 @@ enum xfs_attr_update {
560560
int xfs_attr_set(struct xfs_da_args *args, enum xfs_attr_update op);
561561
int xfs_attr_set_iter(struct xfs_attr_intent *attr);
562562
int xfs_attr_remove_iter(struct xfs_attr_intent *attr);
563-
bool xfs_attr_namecheck(const void *name, size_t length);
563+
bool xfs_attr_check_namespace(unsigned int attr_flags);
564+
bool xfs_attr_namecheck(unsigned int attr_flags, const void *name,
565+
size_t length);
564566
int xfs_attr_calc_size(struct xfs_da_args *args, int *local);
565567
void xfs_init_attr_trans(struct xfs_da_args *args, struct xfs_trans_res *tres,
566568
unsigned int *total);

fs/xfs/libxfs/xfs_attr_leaf.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -950,6 +950,11 @@ xfs_attr_shortform_to_leaf(
950950
nargs.hashval = xfs_da_hashname(sfe->nameval,
951951
sfe->namelen);
952952
nargs.attr_filter = sfe->flags & XFS_ATTR_NSP_ONDISK_MASK;
953+
if (!xfs_attr_check_namespace(sfe->flags)) {
954+
xfs_da_mark_sick(args);
955+
error = -EFSCORRUPTED;
956+
goto out;
957+
}
953958
error = xfs_attr3_leaf_lookup_int(bp, &nargs); /* set a->index */
954959
ASSERT(error == -ENOATTR);
955960
error = xfs_attr3_leaf_add(bp, &nargs);
@@ -1063,7 +1068,7 @@ xfs_attr_shortform_verify(
10631068
* one namespace flag per xattr, so we can just count the
10641069
* bits (i.e. hweight) here.
10651070
*/
1066-
if (hweight8(sfep->flags & XFS_ATTR_NSP_ONDISK_MASK) > 1)
1071+
if (!xfs_attr_check_namespace(sfep->flags))
10671072
return __this_address;
10681073

10691074
sfep = next_sfep;

fs/xfs/scrub/attr.c

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -203,14 +203,8 @@ xchk_xattr_actor(
203203
return 0;
204204
}
205205

206-
/* Only one namespace bit allowed. */
207-
if (hweight32(attr_flags & XFS_ATTR_NSP_ONDISK_MASK) > 1) {
208-
xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, args.blkno);
209-
return -ECANCELED;
210-
}
211-
212206
/* Does this name make sense? */
213-
if (!xfs_attr_namecheck(name, namelen)) {
207+
if (!xfs_attr_namecheck(attr_flags, name, namelen)) {
214208
xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, args.blkno);
215209
return -ECANCELED;
216210
}
@@ -519,6 +513,10 @@ xchk_xattr_rec(
519513
xchk_da_set_corrupt(ds, level);
520514
return 0;
521515
}
516+
if (!xfs_attr_check_namespace(ent->flags)) {
517+
xchk_da_set_corrupt(ds, level);
518+
return 0;
519+
}
522520

523521
if (ent->flags & XFS_ATTR_LOCAL) {
524522
lentry = (struct xfs_attr_leaf_name_local *)

fs/xfs/scrub/attr_repair.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,12 +123,10 @@ xrep_xattr_want_salvage(
123123
return false;
124124
if (namelen > XATTR_NAME_MAX || namelen <= 0)
125125
return false;
126-
if (!xfs_attr_namecheck(name, namelen))
126+
if (!xfs_attr_namecheck(attr_flags, name, namelen))
127127
return false;
128128
if (valuelen > XATTR_SIZE_MAX || valuelen < 0)
129129
return false;
130-
if (hweight32(attr_flags & XFS_ATTR_NSP_ONDISK_MASK) > 1)
131-
return false;
132130
return true;
133131
}
134132

fs/xfs/xfs_attr_item.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,10 @@ xfs_attri_validate(
492492
if (attrp->alfi_attr_filter & ~XFS_ATTRI_FILTER_MASK)
493493
return false;
494494

495+
if (!xfs_attr_check_namespace(attrp->alfi_attr_filter &
496+
XFS_ATTR_NSP_ONDISK_MASK))
497+
return false;
498+
495499
switch (op) {
496500
case XFS_ATTRI_OP_FLAGS_SET:
497501
case XFS_ATTRI_OP_FLAGS_REPLACE:
@@ -633,7 +637,8 @@ xfs_attr_recover_work(
633637
*/
634638
attrp = &attrip->attri_format;
635639
if (!xfs_attri_validate(mp, attrp) ||
636-
!xfs_attr_namecheck(nv->name.i_addr, nv->name.i_len))
640+
!xfs_attr_namecheck(attrp->alfi_attr_filter, nv->name.i_addr,
641+
nv->name.i_len))
637642
return -EFSCORRUPTED;
638643

639644
attr = xfs_attri_recover_work(mp, dfp, attrp, &ip, nv);
@@ -747,7 +752,8 @@ xfs_attri_validate_name_iovec(
747752
return NULL;
748753
}
749754

750-
if (!xfs_attr_namecheck(iovec->i_addr, name_len)) {
755+
if (!xfs_attr_namecheck(attri_formatp->alfi_attr_filter, iovec->i_addr,
756+
name_len)) {
751757
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
752758
attri_formatp, sizeof(*attri_formatp));
753759
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,

fs/xfs/xfs_attr_list.c

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,8 @@ xfs_attr_shortform_list(
8282
(dp->i_af.if_bytes + sf->count * 16) < context->bufsize)) {
8383
for (i = 0, sfe = xfs_attr_sf_firstentry(sf); i < sf->count; i++) {
8484
if (XFS_IS_CORRUPT(context->dp->i_mount,
85-
!xfs_attr_namecheck(sfe->nameval,
85+
!xfs_attr_namecheck(sfe->flags,
86+
sfe->nameval,
8687
sfe->namelen))) {
8788
xfs_dirattr_mark_sick(context->dp, XFS_ATTR_FORK);
8889
return -EFSCORRUPTED;
@@ -122,7 +123,8 @@ xfs_attr_shortform_list(
122123
for (i = 0, sfe = xfs_attr_sf_firstentry(sf); i < sf->count; i++) {
123124
if (unlikely(
124125
((char *)sfe < (char *)sf) ||
125-
((char *)sfe >= ((char *)sf + dp->i_af.if_bytes)))) {
126+
((char *)sfe >= ((char *)sf + dp->i_af.if_bytes)) ||
127+
!xfs_attr_check_namespace(sfe->flags))) {
126128
XFS_CORRUPTION_ERROR("xfs_attr_shortform_list",
127129
XFS_ERRLEVEL_LOW,
128130
context->dp->i_mount, sfe,
@@ -177,7 +179,7 @@ xfs_attr_shortform_list(
177179
cursor->offset = 0;
178180
}
179181
if (XFS_IS_CORRUPT(context->dp->i_mount,
180-
!xfs_attr_namecheck(sbp->name,
182+
!xfs_attr_namecheck(sbp->flags, sbp->name,
181183
sbp->namelen))) {
182184
xfs_dirattr_mark_sick(context->dp, XFS_ATTR_FORK);
183185
error = -EFSCORRUPTED;
@@ -502,7 +504,8 @@ xfs_attr3_leaf_list_int(
502504
}
503505

504506
if (XFS_IS_CORRUPT(context->dp->i_mount,
505-
!xfs_attr_namecheck(name, namelen))) {
507+
!xfs_attr_namecheck(entry->flags, name,
508+
namelen))) {
506509
xfs_dirattr_mark_sick(context->dp, XFS_ATTR_FORK);
507510
return -EFSCORRUPTED;
508511
}

0 commit comments

Comments
 (0)