Message ID | 20220611094200.129502-9-allison.henderson@oracle.com (mailing list archive) |
---|---|
State | Superseded, archived |
Headers | show |
Series | Return of the Parent Pointers | expand |
On Sat, Jun 11, 2022 at 02:41:51AM -0700, Allison Henderson wrote: > Attribute names of parent pointers are not strings. So we need to modify > attr_namecheck to verify parent pointer records when the XFS_ATTR_PARENT flag is > set. > > Signed-off-by: Allison Henderson <allison.henderson@oracle.com> Looks good, Reviewed-by: Darrick J. Wong <djwong@kernel.org> --D > --- > fs/xfs/libxfs/xfs_attr.c | 43 +++++++++++++++++++++++++++++++++++++--- > fs/xfs/libxfs/xfs_attr.h | 3 ++- > fs/xfs/scrub/attr.c | 2 +- > fs/xfs/xfs_attr_item.c | 6 ++++-- > fs/xfs/xfs_attr_list.c | 17 +++++++++++----- > 5 files changed, 59 insertions(+), 12 deletions(-) > > diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c > index ee5dfebcf163..30c8d9e9c2f1 100644 > --- a/fs/xfs/libxfs/xfs_attr.c > +++ b/fs/xfs/libxfs/xfs_attr.c > @@ -1606,9 +1606,29 @@ xfs_attr_node_get( > return error; > } > > -/* Returns true if the attribute entry name is valid. */ > -bool > -xfs_attr_namecheck( > +/* > + * Verify parent pointer attribute is valid. > + * Return true on success or false on failure > + */ > +STATIC bool > +xfs_verify_pptr(struct xfs_mount *mp, struct xfs_parent_name_rec *rec) > +{ > + xfs_ino_t p_ino = (xfs_ino_t)be64_to_cpu(rec->p_ino); > + xfs_dir2_dataptr_t p_diroffset = > + (xfs_dir2_dataptr_t)be32_to_cpu(rec->p_diroffset); > + > + if (!xfs_verify_ino(mp, p_ino)) > + return false; > + > + if (p_diroffset > XFS_DIR2_MAX_DATAPTR) > + return false; > + > + return true; > +} > + > +/* Returns true if the string attribute entry name is valid. */ > +static bool > +xfs_str_attr_namecheck( > const void *name, > size_t length) > { > @@ -1623,6 +1643,23 @@ xfs_attr_namecheck( > return !memchr(name, 0, length); > } > > +/* Returns true if the attribute entry name is valid. */ > +bool > +xfs_attr_namecheck( > + struct xfs_mount *mp, > + const void *name, > + size_t length, > + int flags) > +{ > + if (flags & XFS_ATTR_PARENT) { > + if (length != sizeof(struct xfs_parent_name_rec)) > + return false; > + return xfs_verify_pptr(mp, (struct xfs_parent_name_rec *)name); > + } > + > + return xfs_str_attr_namecheck(name, length); > +} > + > int __init > xfs_attr_intent_init_cache(void) > { > diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h > index 7600eac74db7..a87bc503976b 100644 > --- a/fs/xfs/libxfs/xfs_attr.h > +++ b/fs/xfs/libxfs/xfs_attr.h > @@ -562,7 +562,8 @@ int xfs_attr_get(struct xfs_da_args *args); > int xfs_attr_set(struct xfs_da_args *args); > int xfs_attr_set_iter(struct xfs_attr_intent *attr); > int xfs_attr_remove_iter(struct xfs_attr_intent *attr); > -bool xfs_attr_namecheck(const void *name, size_t length); > +bool xfs_attr_namecheck(struct xfs_mount *mp, const void *name, size_t length, > + int flags); > int xfs_attr_calc_size(struct xfs_da_args *args, int *local); > void xfs_init_attr_trans(struct xfs_da_args *args, struct xfs_trans_res *tres, > unsigned int *total); > diff --git a/fs/xfs/scrub/attr.c b/fs/xfs/scrub/attr.c > index b6f0c9f3f124..d3e75c077fab 100644 > --- a/fs/xfs/scrub/attr.c > +++ b/fs/xfs/scrub/attr.c > @@ -128,7 +128,7 @@ xchk_xattr_listent( > } > > /* Does this name make sense? */ > - if (!xfs_attr_namecheck(name, namelen)) { > + if (!xfs_attr_namecheck(sx->sc->mp, name, namelen, flags)) { > xchk_fblock_set_corrupt(sx->sc, XFS_ATTR_FORK, args.blkno); > return; > } > diff --git a/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c > index f524dbbb42d3..60fee5814655 100644 > --- a/fs/xfs/xfs_attr_item.c > +++ b/fs/xfs/xfs_attr_item.c > @@ -587,7 +587,8 @@ xfs_attri_item_recover( > */ > attrp = &attrip->attri_format; > if (!xfs_attri_validate(mp, attrp) || > - !xfs_attr_namecheck(nv->name.i_addr, nv->name.i_len)) > + !xfs_attr_namecheck(mp, nv->name.i_addr, nv->name.i_len, > + attrp->alfi_attr_filter)) > return -EFSCORRUPTED; > > error = xlog_recover_iget(mp, attrp->alfi_ino, &ip); > @@ -742,7 +743,8 @@ xlog_recover_attri_commit_pass2( > return -EFSCORRUPTED; > } > > - if (!xfs_attr_namecheck(attr_name, attri_formatp->alfi_name_len)) { > + if (!xfs_attr_namecheck(mp, attr_name, attri_formatp->alfi_name_len, > + attri_formatp->alfi_attr_filter)) { > XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp); > return -EFSCORRUPTED; > } > diff --git a/fs/xfs/xfs_attr_list.c b/fs/xfs/xfs_attr_list.c > index 90a14e85e76d..3bac0647a927 100644 > --- a/fs/xfs/xfs_attr_list.c > +++ b/fs/xfs/xfs_attr_list.c > @@ -58,9 +58,13 @@ xfs_attr_shortform_list( > struct xfs_attr_sf_sort *sbuf, *sbp; > struct xfs_attr_shortform *sf; > struct xfs_attr_sf_entry *sfe; > + struct xfs_mount *mp; > int sbsize, nsbuf, count, i; > int error = 0; > > + ASSERT(context != NULL); > + ASSERT(dp != NULL); > + mp = dp->i_mount; > ASSERT(dp->i_afp != NULL); > sf = (struct xfs_attr_shortform *)dp->i_afp->if_u1.if_data; > ASSERT(sf != NULL); > @@ -83,8 +87,9 @@ xfs_attr_shortform_list( > (dp->i_afp->if_bytes + sf->hdr.count * 16) < context->bufsize)) { > for (i = 0, sfe = &sf->list[0]; i < sf->hdr.count; i++) { > if (XFS_IS_CORRUPT(context->dp->i_mount, > - !xfs_attr_namecheck(sfe->nameval, > - sfe->namelen))) > + !xfs_attr_namecheck(mp, sfe->nameval, > + sfe->namelen, > + sfe->flags))) > return -EFSCORRUPTED; > context->put_listent(context, > sfe->flags, > @@ -175,8 +180,9 @@ xfs_attr_shortform_list( > cursor->offset = 0; > } > if (XFS_IS_CORRUPT(context->dp->i_mount, > - !xfs_attr_namecheck(sbp->name, > - sbp->namelen))) { > + !xfs_attr_namecheck(mp, sbp->name, > + sbp->namelen, > + sbp->flags))) { > error = -EFSCORRUPTED; > goto out; > } > @@ -466,7 +472,8 @@ xfs_attr3_leaf_list_int( > } > > if (XFS_IS_CORRUPT(context->dp->i_mount, > - !xfs_attr_namecheck(name, namelen))) > + !xfs_attr_namecheck(mp, name, namelen, > + entry->flags))) > return -EFSCORRUPTED; > context->put_listent(context, entry->flags, > name, namelen, valuelen); > -- > 2.25.1 >
diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c index ee5dfebcf163..30c8d9e9c2f1 100644 --- a/fs/xfs/libxfs/xfs_attr.c +++ b/fs/xfs/libxfs/xfs_attr.c @@ -1606,9 +1606,29 @@ xfs_attr_node_get( return error; } -/* Returns true if the attribute entry name is valid. */ -bool -xfs_attr_namecheck( +/* + * Verify parent pointer attribute is valid. + * Return true on success or false on failure + */ +STATIC bool +xfs_verify_pptr(struct xfs_mount *mp, struct xfs_parent_name_rec *rec) +{ + xfs_ino_t p_ino = (xfs_ino_t)be64_to_cpu(rec->p_ino); + xfs_dir2_dataptr_t p_diroffset = + (xfs_dir2_dataptr_t)be32_to_cpu(rec->p_diroffset); + + if (!xfs_verify_ino(mp, p_ino)) + return false; + + if (p_diroffset > XFS_DIR2_MAX_DATAPTR) + return false; + + return true; +} + +/* Returns true if the string attribute entry name is valid. */ +static bool +xfs_str_attr_namecheck( const void *name, size_t length) { @@ -1623,6 +1643,23 @@ xfs_attr_namecheck( return !memchr(name, 0, length); } +/* Returns true if the attribute entry name is valid. */ +bool +xfs_attr_namecheck( + struct xfs_mount *mp, + const void *name, + size_t length, + int flags) +{ + if (flags & XFS_ATTR_PARENT) { + if (length != sizeof(struct xfs_parent_name_rec)) + return false; + return xfs_verify_pptr(mp, (struct xfs_parent_name_rec *)name); + } + + return xfs_str_attr_namecheck(name, length); +} + int __init xfs_attr_intent_init_cache(void) { diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h index 7600eac74db7..a87bc503976b 100644 --- a/fs/xfs/libxfs/xfs_attr.h +++ b/fs/xfs/libxfs/xfs_attr.h @@ -562,7 +562,8 @@ int xfs_attr_get(struct xfs_da_args *args); int xfs_attr_set(struct xfs_da_args *args); int xfs_attr_set_iter(struct xfs_attr_intent *attr); int xfs_attr_remove_iter(struct xfs_attr_intent *attr); -bool xfs_attr_namecheck(const void *name, size_t length); +bool xfs_attr_namecheck(struct xfs_mount *mp, const void *name, size_t length, + int flags); int xfs_attr_calc_size(struct xfs_da_args *args, int *local); void xfs_init_attr_trans(struct xfs_da_args *args, struct xfs_trans_res *tres, unsigned int *total); diff --git a/fs/xfs/scrub/attr.c b/fs/xfs/scrub/attr.c index b6f0c9f3f124..d3e75c077fab 100644 --- a/fs/xfs/scrub/attr.c +++ b/fs/xfs/scrub/attr.c @@ -128,7 +128,7 @@ xchk_xattr_listent( } /* Does this name make sense? */ - if (!xfs_attr_namecheck(name, namelen)) { + if (!xfs_attr_namecheck(sx->sc->mp, name, namelen, flags)) { xchk_fblock_set_corrupt(sx->sc, XFS_ATTR_FORK, args.blkno); return; } diff --git a/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c index f524dbbb42d3..60fee5814655 100644 --- a/fs/xfs/xfs_attr_item.c +++ b/fs/xfs/xfs_attr_item.c @@ -587,7 +587,8 @@ xfs_attri_item_recover( */ attrp = &attrip->attri_format; if (!xfs_attri_validate(mp, attrp) || - !xfs_attr_namecheck(nv->name.i_addr, nv->name.i_len)) + !xfs_attr_namecheck(mp, nv->name.i_addr, nv->name.i_len, + attrp->alfi_attr_filter)) return -EFSCORRUPTED; error = xlog_recover_iget(mp, attrp->alfi_ino, &ip); @@ -742,7 +743,8 @@ xlog_recover_attri_commit_pass2( return -EFSCORRUPTED; } - if (!xfs_attr_namecheck(attr_name, attri_formatp->alfi_name_len)) { + if (!xfs_attr_namecheck(mp, attr_name, attri_formatp->alfi_name_len, + attri_formatp->alfi_attr_filter)) { XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp); return -EFSCORRUPTED; } diff --git a/fs/xfs/xfs_attr_list.c b/fs/xfs/xfs_attr_list.c index 90a14e85e76d..3bac0647a927 100644 --- a/fs/xfs/xfs_attr_list.c +++ b/fs/xfs/xfs_attr_list.c @@ -58,9 +58,13 @@ xfs_attr_shortform_list( struct xfs_attr_sf_sort *sbuf, *sbp; struct xfs_attr_shortform *sf; struct xfs_attr_sf_entry *sfe; + struct xfs_mount *mp; int sbsize, nsbuf, count, i; int error = 0; + ASSERT(context != NULL); + ASSERT(dp != NULL); + mp = dp->i_mount; ASSERT(dp->i_afp != NULL); sf = (struct xfs_attr_shortform *)dp->i_afp->if_u1.if_data; ASSERT(sf != NULL); @@ -83,8 +87,9 @@ xfs_attr_shortform_list( (dp->i_afp->if_bytes + sf->hdr.count * 16) < context->bufsize)) { for (i = 0, sfe = &sf->list[0]; i < sf->hdr.count; i++) { if (XFS_IS_CORRUPT(context->dp->i_mount, - !xfs_attr_namecheck(sfe->nameval, - sfe->namelen))) + !xfs_attr_namecheck(mp, sfe->nameval, + sfe->namelen, + sfe->flags))) return -EFSCORRUPTED; context->put_listent(context, sfe->flags, @@ -175,8 +180,9 @@ xfs_attr_shortform_list( cursor->offset = 0; } if (XFS_IS_CORRUPT(context->dp->i_mount, - !xfs_attr_namecheck(sbp->name, - sbp->namelen))) { + !xfs_attr_namecheck(mp, sbp->name, + sbp->namelen, + sbp->flags))) { error = -EFSCORRUPTED; goto out; } @@ -466,7 +472,8 @@ xfs_attr3_leaf_list_int( } if (XFS_IS_CORRUPT(context->dp->i_mount, - !xfs_attr_namecheck(name, namelen))) + !xfs_attr_namecheck(mp, name, namelen, + entry->flags))) return -EFSCORRUPTED; context->put_listent(context, entry->flags, name, namelen, valuelen);
Attribute names of parent pointers are not strings. So we need to modify attr_namecheck to verify parent pointer records when the XFS_ATTR_PARENT flag is set. Signed-off-by: Allison Henderson <allison.henderson@oracle.com> --- fs/xfs/libxfs/xfs_attr.c | 43 +++++++++++++++++++++++++++++++++++++--- fs/xfs/libxfs/xfs_attr.h | 3 ++- fs/xfs/scrub/attr.c | 2 +- fs/xfs/xfs_attr_item.c | 6 ++++-- fs/xfs/xfs_attr_list.c | 17 +++++++++++----- 5 files changed, 59 insertions(+), 12 deletions(-)