From: "Darrick J. Wong" darrick.wong@oracle.com
mainline inclusion from mainline-v5.1-rc1 commit 3258cb208caba74258ffdd8bd59972bbda9bfee1 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I5BDCU CVE: NA
--------------------------------
The extended attribute scrubber should abort the "read all attrs" loop if there's a fatal signal pending on the process.
Signed-off-by: Darrick J. Wong darrick.wong@oracle.com Reviewed-by: Brian Foster bfoster@redhat.com
Signed-off-by: tangbin tangbin@cmss.chinamobile.com Reviewed-by: Lihong Kou koulihong@huawei.com Reviewed-by: Xuenan Guo guoxuenan@huawei.com Signed-off-by: Laibin Qiu qiulaibin@huawei.com --- fs/xfs/scrub/attr.c | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/fs/xfs/scrub/attr.c b/fs/xfs/scrub/attr.c index 81d5e90547a1..9960bc5b5d76 100644 --- a/fs/xfs/scrub/attr.c +++ b/fs/xfs/scrub/attr.c @@ -82,6 +82,11 @@ xchk_xattr_listent(
sx = container_of(context, struct xchk_xattr, context);
+ if (xchk_should_terminate(sx->sc, &error)) { + context->seen_enough = 1; + return; + } + if (flags & XFS_ATTR_INCOMPLETE) { /* Incomplete attr key, just mark the inode for preening. */ xchk_ino_set_preen(sx->sc, context->dp->i_ino);
From: "Darrick J. Wong" darrick.wong@oracle.com
mainline inclusion from mainline-v5.1-rc1 commit f8c1d7023e252df853efbb3566c6d47b148609fe category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I5BDCU CVE: NA
--------------------------------
Teach scrub to flag extent maps that exceed the range that can be mapped with a xfs_dablk_t.
Signed-off-by: Darrick J. Wong darrick.wong@oracle.com Reviewed-by: Brian Foster bfoster@redhat.com
Signed-off-by: tangbin tangbin@cmss.chinamobile.com Reviewed-by: Lihong Kou koulihong@huawei.com Reviewed-by: Xuenan Guo guoxuenan@huawei.com Signed-off-by: Laibin Qiu qiulaibin@huawei.com --- fs/xfs/libxfs/xfs_types.c | 11 +++++++++++ fs/xfs/libxfs/xfs_types.h | 1 + fs/xfs/scrub/bmap.c | 27 +++++++++++++++++++++++++++ 3 files changed, 39 insertions(+)
diff --git a/fs/xfs/libxfs/xfs_types.c b/fs/xfs/libxfs/xfs_types.c index 9873d2723fd9..61017de3db62 100644 --- a/fs/xfs/libxfs/xfs_types.c +++ b/fs/xfs/libxfs/xfs_types.c @@ -218,3 +218,14 @@ xfs_verify_icount( xfs_icount_range(mp, &min, &max); return icount >= min && icount <= max; } + +/* Sanity-checking of dir/attr block offsets. */ +bool +xfs_verify_dablk( + struct xfs_mount *mp, + xfs_fileoff_t dabno) +{ + xfs_dablk_t max_dablk = -1U; + + return dabno <= max_dablk; +} diff --git a/fs/xfs/libxfs/xfs_types.h b/fs/xfs/libxfs/xfs_types.h index b477dbe8859e..eb69c04f893e 100644 --- a/fs/xfs/libxfs/xfs_types.h +++ b/fs/xfs/libxfs/xfs_types.h @@ -168,5 +168,6 @@ bool xfs_internal_inum(struct xfs_mount *mp, xfs_ino_t ino); bool xfs_verify_dir_ino(struct xfs_mount *mp, xfs_ino_t ino); bool xfs_verify_rtbno(struct xfs_mount *mp, xfs_rtblock_t rtbno); bool xfs_verify_icount(struct xfs_mount *mp, unsigned long long icount); +bool xfs_verify_dablk(struct xfs_mount *mp, xfs_fileoff_t off);
#endif /* __XFS_TYPES_H__ */ diff --git a/fs/xfs/scrub/bmap.c b/fs/xfs/scrub/bmap.c index dcc7e65bb7be..29cc0c43c84f 100644 --- a/fs/xfs/scrub/bmap.c +++ b/fs/xfs/scrub/bmap.c @@ -283,6 +283,31 @@ xchk_bmap_extent_xref( xchk_ag_free(info->sc, &info->sc->sa); }
+/* + * Directories and attr forks should never have blocks that can't be addressed + * by a xfs_dablk_t. + */ +STATIC void +xchk_bmap_dirattr_extent( + struct xfs_inode *ip, + struct xchk_bmap_info *info, + struct xfs_bmbt_irec *irec) +{ + struct xfs_mount *mp = ip->i_mount; + xfs_fileoff_t off; + + if (!S_ISDIR(VFS_I(ip)->i_mode) && info->whichfork != XFS_ATTR_FORK) + return; + + if (!xfs_verify_dablk(mp, irec->br_startoff)) + xchk_fblock_set_corrupt(info->sc, info->whichfork, + irec->br_startoff); + + off = irec->br_startoff + irec->br_blockcount - 1; + if (!xfs_verify_dablk(mp, off)) + xchk_fblock_set_corrupt(info->sc, info->whichfork, off); +} + /* Scrub a single extent record. */ STATIC int xchk_bmap_extent( @@ -307,6 +332,8 @@ xchk_bmap_extent( xchk_fblock_set_corrupt(info->sc, info->whichfork, irec->br_startoff);
+ xchk_bmap_dirattr_extent(ip, info, irec); + /* There should never be a "hole" extent in either extent list. */ if (irec->br_startblock == HOLESTARTBLOCK) xchk_fblock_set_corrupt(info->sc, info->whichfork,
From: "Darrick J. Wong" darrick.wong@oracle.com
mainline inclusion from mainline-v5.1-rc1 commit e5d7d51b340aac0f4cc56677eb8d29d4e164c58c category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I5BDCU CVE: NA
--------------------------------
Check directory entry names for invalid characters.
Signed-off-by: Darrick J. Wong darrick.wong@oracle.com Reviewed-by: Brian Foster bfoster@redhat.com
Signed-off-by: tangbin tangbin@cmss.chinamobile.com Reviewed-by: Lihong Kou koulihong@huawei.com Reviewed-by: Xuenan Guo guoxuenan@huawei.com Signed-off-by: Laibin Qiu qiulaibin@huawei.com --- fs/xfs/libxfs/xfs_dir2.c | 17 +++++++++++++++++ fs/xfs/libxfs/xfs_dir2.h | 1 + fs/xfs/scrub/dir.c | 6 ++++++ 3 files changed, 24 insertions(+)
diff --git a/fs/xfs/libxfs/xfs_dir2.c b/fs/xfs/libxfs/xfs_dir2.c index 229152cd1a24..156ce95c9c45 100644 --- a/fs/xfs/libxfs/xfs_dir2.c +++ b/fs/xfs/libxfs/xfs_dir2.c @@ -703,3 +703,20 @@ xfs_dir2_shrink_inode( xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); return 0; } + +/* Returns true if the directory entry name is valid. */ +bool +xfs_dir2_namecheck( + const void *name, + size_t length) +{ + /* + * MAXNAMELEN includes the trailing null, but (name/length) leave it + * out, so use >= for the length check. + */ + if (length >= MAXNAMELEN) + return false; + + /* There shouldn't be any slashes or nulls here */ + return !memchr(name, '/', length) && !memchr(name, 0, length); +} diff --git a/fs/xfs/libxfs/xfs_dir2.h b/fs/xfs/libxfs/xfs_dir2.h index 155bae585e75..a002bb1163f8 100644 --- a/fs/xfs/libxfs/xfs_dir2.h +++ b/fs/xfs/libxfs/xfs_dir2.h @@ -322,5 +322,6 @@ xfs_dir2_leaf_tail_p(struct xfs_da_geometry *geo, struct xfs_dir2_leaf *lp) unsigned char xfs_dir3_get_dtype(struct xfs_mount *mp, uint8_t filetype); void *xfs_dir3_data_endp(struct xfs_da_geometry *geo, struct xfs_dir2_data_hdr *hdr); +bool xfs_dir2_namecheck(const void *name, size_t length);
#endif /* __XFS_DIR2_H__ */ diff --git a/fs/xfs/scrub/dir.c b/fs/xfs/scrub/dir.c index 33dfcba72c7a..d22e25f1cac9 100644 --- a/fs/xfs/scrub/dir.c +++ b/fs/xfs/scrub/dir.c @@ -129,6 +129,12 @@ xchk_dir_actor( goto out; }
+ /* Does this name make sense? */ + if (!xfs_dir2_namecheck(name, namelen)) { + xchk_fblock_set_corrupt(sdc->sc, XFS_DATA_FORK, offset); + goto out; + } + if (!strncmp(".", name, namelen)) { /* If this is "." then check that the inum matches the dir. */ if (xfs_sb_version_hasftype(&mp->m_sb) && type != DT_DIR)
From: "Darrick J. Wong" darrick.wong@oracle.com
mainline inclusion from mainline-v5.1-rc1 commit 654805367d982cffdb9979453673aab9c3c96d07 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I5BDCU CVE: NA
--------------------------------
Check extended attribute entry names for invalid characters.
Signed-off-by: Darrick J. Wong darrick.wong@oracle.com Reviewed-by: Brian Foster bfoster@redhat.com
Signed-off-by: tangbin tangbin@cmss.chinamobile.com Reviewed-by: Lihong Kou koulihong@huawei.com Reviewed-by: Xuenan Guo guoxuenan@huawei.com Signed-off-by: Laibin Qiu qiulaibin@huawei.com --- fs/xfs/libxfs/xfs_attr.c | 17 +++++++++++++++++ fs/xfs/libxfs/xfs_attr.h | 2 +- fs/xfs/scrub/attr.c | 6 ++++++ 3 files changed, 24 insertions(+), 1 deletion(-)
diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c index 6410d3e00ce0..c441f41f14e8 100644 --- a/fs/xfs/libxfs/xfs_attr.c +++ b/fs/xfs/libxfs/xfs_attr.c @@ -1325,3 +1325,20 @@ xfs_attr_node_get(xfs_da_args_t *args) xfs_da_state_free(state); return retval; } + +/* Returns true if the attribute entry name is valid. */ +bool +xfs_attr_namecheck( + const void *name, + size_t length) +{ + /* + * MAXNAMELEN includes the trailing null, but (name/length) leave it + * out, so use >= for the length check. + */ + if (length >= MAXNAMELEN) + return false; + + /* There shouldn't be any nulls here */ + return !memchr(name, 0, length); +} diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h index cc04ee0aacfb..3b0dce06e454 100644 --- a/fs/xfs/libxfs/xfs_attr.h +++ b/fs/xfs/libxfs/xfs_attr.h @@ -145,6 +145,6 @@ int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name, int flags); int xfs_attr_remove_args(struct xfs_da_args *args); int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize, int flags, struct attrlist_cursor_kern *cursor); - +bool xfs_attr_namecheck(const void *name, size_t length);
#endif /* __XFS_ATTR_H__ */ diff --git a/fs/xfs/scrub/attr.c b/fs/xfs/scrub/attr.c index 9960bc5b5d76..dce74ec57038 100644 --- a/fs/xfs/scrub/attr.c +++ b/fs/xfs/scrub/attr.c @@ -93,6 +93,12 @@ xchk_xattr_listent( return; }
+ /* Does this name make sense? */ + if (!xfs_attr_namecheck(name, namelen)) { + xchk_fblock_set_corrupt(sx->sc, XFS_ATTR_FORK, args.blkno); + return; + } + args.flags = ATTR_KERNOTIME; if (flags & XFS_ATTR_ROOT) args.flags |= ATTR_ROOT;
From: "Darrick J. Wong" darrick.wong@oracle.com
mainline inclusion from mainline-v5.5-rc1 commit c84760659dcf237902d4cc997cd5f55cb3b2807f category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I5BDCU CVE: NA
--------------------------------
Add missing structure checks in the attribute leaf verifier.
Signed-off-by: Darrick J. Wong darrick.wong@oracle.com Reviewed-by: Brian Foster bfoster@redhat.com
Signed-off-by: tangbin tangbin@cmss.chinamobile.com Reviewed-by: Lihong Kou koulihong@huawei.com Reviewed-by: Xuenan Guo guoxuenan@huawei.com Signed-off-by: Laibin Qiu qiulaibin@huawei.com --- fs/xfs/libxfs/xfs_attr_leaf.c | 68 +++++++++++++++++++++++++++++++++-- 1 file changed, 66 insertions(+), 2 deletions(-)
diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c index 880fadb19fc0..ce4f752761cc 100644 --- a/fs/xfs/libxfs/xfs_attr_leaf.c +++ b/fs/xfs/libxfs/xfs_attr_leaf.c @@ -235,6 +235,61 @@ xfs_attr3_leaf_hdr_to_disk( } }
+static xfs_failaddr_t +xfs_attr3_leaf_verify_entry( + struct xfs_mount *mp, + char *buf_end, + struct xfs_attr_leafblock *leaf, + struct xfs_attr3_icleaf_hdr *leafhdr, + struct xfs_attr_leaf_entry *ent, + int idx, + __u32 *last_hashval) +{ + struct xfs_attr_leaf_name_local *lentry; + struct xfs_attr_leaf_name_remote *rentry; + char *name_end; + unsigned int nameidx; + unsigned int namesize; + __u32 hashval; + + /* hash order check */ + hashval = be32_to_cpu(ent->hashval); + if (hashval < *last_hashval) + return __this_address; + *last_hashval = hashval; + + nameidx = be16_to_cpu(ent->nameidx); + if (nameidx < leafhdr->firstused || nameidx >= mp->m_attr_geo->blksize) + return __this_address; + + /* + * Check the name information. The namelen fields are u8 so we can't + * possibly exceed the maximum name length of 255 bytes. + */ + if (ent->flags & XFS_ATTR_LOCAL) { + lentry = xfs_attr3_leaf_name_local(leaf, idx); + namesize = xfs_attr_leaf_entsize_local(lentry->namelen, + be16_to_cpu(lentry->valuelen)); + name_end = (char *)lentry + namesize; + if (lentry->namelen == 0) + return __this_address; + } else { + rentry = xfs_attr3_leaf_name_remote(leaf, idx); + namesize = xfs_attr_leaf_entsize_remote(rentry->namelen); + name_end = (char *)rentry + namesize; + if (rentry->namelen == 0) + return __this_address; + if (!(ent->flags & XFS_ATTR_INCOMPLETE) && + rentry->valueblk == 0) + return __this_address; + } + + if (name_end > buf_end) + return __this_address; + + return NULL; +} + static xfs_failaddr_t xfs_attr3_leaf_verify( struct xfs_buf *bp) @@ -243,8 +298,12 @@ xfs_attr3_leaf_verify( struct xfs_mount *mp = bp->b_target->bt_mount; struct xfs_attr_leafblock *leaf = bp->b_addr; struct xfs_attr_leaf_entry *entries; + struct xfs_attr_leaf_entry *ent; + char *buf_end; uint32_t end; /* must be 32bit - see below */ + __u32 last_hashval = 0; int i; + xfs_failaddr_t fa;
xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &ichdr, leaf);
@@ -287,8 +346,13 @@ xfs_attr3_leaf_verify( (char *)bp->b_addr + ichdr.firstused) return __this_address;
- /* XXX: need to range check rest of attr header values */ - /* XXX: hash order check? */ + buf_end = (char *)bp->b_addr + mp->m_attr_geo->blksize; + for (i = 0, ent = entries; i < ichdr.count; ent++, i++) { + fa = xfs_attr3_leaf_verify_entry(mp, buf_end, leaf, &ichdr, + ent, i, &last_hashval); + if (fa) + return fa; + }
/* * Quickly check the freemap information. Attribute data has to be
From: "Darrick J. Wong" darrick.wong@oracle.com
mainline inclusion from mainline-v5.5-rc1 commit 16c6e92c7e9836ed08db5f9771e75845796bd87f category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I5BDCU CVE: NA
--------------------------------
Actually call namecheck on attribute names before we hand them over to userspace.
Signed-off-by: Darrick J. Wong darrick.wong@oracle.com Reviewed-by: Brian Foster bfoster@redhat.com
Signed-off-by: tangbin tangbin@cmss.chinamobile.com Reviewed-by: Lihong Kou koulihong@huawei.com Reviewed-by: Xuenan Guo guoxuenan@huawei.com Signed-off-by: Laibin Qiu qiulaibin@huawei.com --- fs/xfs/libxfs/xfs_attr_leaf.h | 4 +-- fs/xfs/xfs_attr_list.c | 60 +++++++++++++++++++++++------------ 2 files changed, 41 insertions(+), 23 deletions(-)
diff --git a/fs/xfs/libxfs/xfs_attr_leaf.h b/fs/xfs/libxfs/xfs_attr_leaf.h index 7b74e18becff..bb0880057ee3 100644 --- a/fs/xfs/libxfs/xfs_attr_leaf.h +++ b/fs/xfs/libxfs/xfs_attr_leaf.h @@ -67,8 +67,8 @@ int xfs_attr3_leaf_add(struct xfs_buf *leaf_buffer, struct xfs_da_args *args); int xfs_attr3_leaf_remove(struct xfs_buf *leaf_buffer, struct xfs_da_args *args); -void xfs_attr3_leaf_list_int(struct xfs_buf *bp, - struct xfs_attr_list_context *context); +int xfs_attr3_leaf_list_int(struct xfs_buf *bp, + struct xfs_attr_list_context *context);
/* * Routines used for shrinking the Btree. diff --git a/fs/xfs/xfs_attr_list.c b/fs/xfs/xfs_attr_list.c index 3d213a7394c5..f9c59173d0ad 100644 --- a/fs/xfs/xfs_attr_list.c +++ b/fs/xfs/xfs_attr_list.c @@ -54,14 +54,16 @@ xfs_attr_shortform_compare(const void *a, const void *b) * we can begin returning them to the user. */ static int -xfs_attr_shortform_list(xfs_attr_list_context_t *context) +xfs_attr_shortform_list( + struct xfs_attr_list_context *context) { - attrlist_cursor_kern_t *cursor; - xfs_attr_sf_sort_t *sbuf, *sbp; - xfs_attr_shortform_t *sf; - xfs_attr_sf_entry_t *sfe; - xfs_inode_t *dp; - int sbsize, nsbuf, count, i; + struct attrlist_cursor_kern *cursor; + struct xfs_attr_sf_sort *sbuf, *sbp; + struct xfs_attr_shortform *sf; + struct xfs_attr_sf_entry *sfe; + struct xfs_inode *dp; + int sbsize, nsbuf, count, i; + int error = 0;
ASSERT(context != NULL); dp = context->dp; @@ -89,6 +91,11 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *context) (XFS_ISRESET_CURSOR(cursor) && (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_attr_namecheck(sfe->nameval, sfe->namelen)) { + XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, + context->dp->i_mount); + return -EFSCORRUPTED; + } context->put_listent(context, sfe->flags, sfe->nameval, @@ -166,10 +173,8 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *context) break; } } - if (i == nsbuf) { - kmem_free(sbuf); - return 0; - } + if (i == nsbuf) + goto out;
/* * Loop putting entries into the user buffer. @@ -179,6 +184,12 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *context) cursor->hashval = sbp->hash; cursor->offset = 0; } + if (!xfs_attr_namecheck(sbp->name, sbp->namelen)) { + XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, + context->dp->i_mount); + error = -EFSCORRUPTED; + goto out; + } context->put_listent(context, sbp->flags, sbp->name, @@ -188,9 +199,9 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *context) break; cursor->offset++; } - +out: kmem_free(sbuf); - return 0; + return error; }
/* @@ -289,7 +300,7 @@ xfs_attr_node_list( struct xfs_buf *bp; struct xfs_inode *dp = context->dp; struct xfs_mount *mp = dp->i_mount; - int error; + int error = 0;
trace_xfs_attr_node_list(context);
@@ -363,7 +374,9 @@ xfs_attr_node_list( */ for (;;) { leaf = bp->b_addr; - xfs_attr3_leaf_list_int(bp, context); + error = xfs_attr3_leaf_list_int(bp, context); + if (error) + break; xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf); if (context->seen_enough || leafhdr.forw == 0) break; @@ -374,13 +387,13 @@ xfs_attr_node_list( return error; } xfs_trans_brelse(context->tp, bp); - return 0; + return error; }
/* * Copy out attribute list entries for attr_list(), for leaf attribute lists. */ -void +int xfs_attr3_leaf_list_int( struct xfs_buf *bp, struct xfs_attr_list_context *context) @@ -422,7 +435,7 @@ xfs_attr3_leaf_list_int( } if (i == ichdr.count) { trace_xfs_attr_list_notfound(context); - return; + return 0; } } else { entry = &entries[0]; @@ -462,6 +475,11 @@ xfs_attr3_leaf_list_int( valuelen = be32_to_cpu(name_rmt->valuelen); }
+ if (!xfs_attr_namecheck(name, namelen)) { + XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, + context->dp->i_mount); + return -EFSCORRUPTED; + } context->put_listent(context, entry->flags, name, namelen, valuelen); if (context->seen_enough) @@ -469,7 +487,7 @@ xfs_attr3_leaf_list_int( cursor->offset++; } trace_xfs_attr_list_leaf_end(context); - return; + return 0; }
/* @@ -488,9 +506,9 @@ xfs_attr_leaf_list(xfs_attr_list_context_t *context) if (error) return error;
- xfs_attr3_leaf_list_int(bp, context); + error = xfs_attr3_leaf_list_int(bp, context); xfs_trans_brelse(context->tp, bp); - return 0; + return error; }
int
From: "Darrick J. Wong" darrick.wong@oracle.com
mainline inclusion from mainline-v5.5-rc1 commit 04df34ac6494b216a911c5571bf4ee299cd34164 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I5BDCU CVE: NA
--------------------------------
Actually call namecheck on directory entry names before we hand them over to userspace.
Signed-off-by: Darrick J. Wong darrick.wong@oracle.com Reviewed-by: Christoph Hellwig hch@lst.de Reviewed-by: Brian Foster bfoster@redhat.com
Signed-off-by: tangbin tangbin@cmss.chinamobile.com Reviewed-by: Lihong Kou koulihong@huawei.com Reviewed-by: Xuenan Guo guoxuenan@huawei.com Signed-off-by: Laibin Qiu qiulaibin@huawei.com --- fs/xfs/xfs_dir2_readdir.c | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-)
diff --git a/fs/xfs/xfs_dir2_readdir.c b/fs/xfs/xfs_dir2_readdir.c index 2ae98c272c54..fc389a7f3e1a 100644 --- a/fs/xfs/xfs_dir2_readdir.c +++ b/fs/xfs/xfs_dir2_readdir.c @@ -20,6 +20,7 @@ #include "xfs_trace.h" #include "xfs_bmap.h" #include "xfs_trans.h" +#include "xfs_error.h"
/* * Directory file type support functions @@ -119,6 +120,11 @@ xfs_dir2_sf_getdents( ino = dp->d_ops->sf_get_ino(sfp, sfep); filetype = dp->d_ops->sf_get_ftype(sfep); ctx->pos = off & 0x7fffffff; + if (!xfs_dir2_namecheck(sfep->name, sfep->namelen)) { + XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, + dp->i_mount); + return -EFSCORRUPTED; + } if (!dir_emit(ctx, (char *)sfep->name, sfep->namelen, ino, xfs_dir3_get_dtype(mp, filetype))) return 0; @@ -212,12 +218,16 @@ xfs_dir2_block_getdents( /* * If it didn't fit, set the final offset to here & return. */ + if (!xfs_dir2_namecheck(dep->name, dep->namelen)) { + XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, + dp->i_mount); + error = -EFSCORRUPTED; + goto out_rele; + } if (!dir_emit(ctx, (char *)dep->name, dep->namelen, be64_to_cpu(dep->inumber), - xfs_dir3_get_dtype(dp->i_mount, filetype))) { - xfs_trans_brelse(args->trans, bp); - return 0; - } + xfs_dir3_get_dtype(dp->i_mount, filetype))) + goto out_rele; }
/* @@ -226,8 +236,9 @@ xfs_dir2_block_getdents( */ ctx->pos = xfs_dir2_db_off_to_dataptr(geo, geo->datablk + 1, 0) & 0x7fffffff; +out_rele: xfs_trans_brelse(args->trans, bp); - return 0; + return error; }
/* @@ -460,6 +471,12 @@ xfs_dir2_leaf_getdents( filetype = dp->d_ops->data_get_ftype(dep);
ctx->pos = xfs_dir2_byte_to_dataptr(curoff) & 0x7fffffff; + if (!xfs_dir2_namecheck(dep->name, dep->namelen)) { + XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, + dp->i_mount); + error = -EFSCORRUPTED; + break; + } if (!dir_emit(ctx, (char *)dep->name, dep->namelen, be64_to_cpu(dep->inumber), xfs_dir3_get_dtype(dp->i_mount, filetype)))
From: "Darrick J. Wong" darrick.wong@oracle.com
mainline inclusion from mainline-v5.5-rc1 commit c2414ad6e66ab96b867309454498f7fb29b7e855 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I5BDCU CVE: NA
--------------------------------
There are a few places where we return -EIO instead of -EFSCORRUPTED when we find corrupt metadata. Fix those places.
Signed-off-by: Darrick J. Wong darrick.wong@oracle.com Reviewed-by: Christoph Hellwig hch@lst.de Reviewed-by: Brian Foster bfoster@redhat.com
Signed-off-by: tangbin tangbin@cmss.chinamobile.com Reviewed-by: Lihong Kou koulihong@huawei.com Reviewed-by: Xuenan Guo guoxuenan@huawei.com Signed-off-by: Laibin Qiu qiulaibin@huawei.com --- fs/xfs/libxfs/xfs_bmap.c | 6 +++--- fs/xfs/xfs_attr_inactive.c | 6 +++--- fs/xfs/xfs_dquot.c | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c index 2eb1cb71a43d..e8eb439a910a 100644 --- a/fs/xfs/libxfs/xfs_bmap.c +++ b/fs/xfs/libxfs/xfs_bmap.c @@ -1375,7 +1375,7 @@ xfs_bmap_last_before( case XFS_DINODE_FMT_EXTENTS: break; default: - return -EIO; + return -EFSCORRUPTED; }
if (!(ifp->if_flags & XFS_IFEXTENTS)) { @@ -1476,7 +1476,7 @@ xfs_bmap_last_offset(
if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE && XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS) - return -EIO; + return -EFSCORRUPTED;
error = xfs_bmap_last_extent(NULL, ip, whichfork, &rec, &is_empty); if (error || is_empty) @@ -5869,7 +5869,7 @@ xfs_bmap_insert_extents( del_cursor);
if (stop_fsb >= got.br_startoff + got.br_blockcount) { - error = -EIO; + error = -EFSCORRUPTED; goto del_cursor; }
diff --git a/fs/xfs/xfs_attr_inactive.c b/fs/xfs/xfs_attr_inactive.c index 228821b2ebe0..0f655e5ff0f3 100644 --- a/fs/xfs/xfs_attr_inactive.c +++ b/fs/xfs/xfs_attr_inactive.c @@ -214,7 +214,7 @@ xfs_attr3_node_inactive( */ if (level > XFS_DA_NODE_MAXDEPTH) { xfs_trans_brelse(*trans, bp); /* no locks for later trans */ - return -EIO; + return -EFSCORRUPTED; }
node = bp->b_addr; @@ -263,7 +263,7 @@ xfs_attr3_node_inactive( error = xfs_attr3_leaf_inactive(trans, dp, child_bp); break; default: - error = -EIO; + error = -EFSCORRUPTED; xfs_trans_brelse(*trans, child_bp); break; } @@ -346,7 +346,7 @@ xfs_attr3_root_inactive( error = xfs_attr3_leaf_inactive(trans, dp, bp); break; default: - error = -EIO; + error = -EFSCORRUPTED; xfs_trans_brelse(*trans, bp); break; } diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c index 704f1e2262e2..c1166d65edb5 100644 --- a/fs/xfs/xfs_dquot.c +++ b/fs/xfs/xfs_dquot.c @@ -1129,7 +1129,7 @@ xfs_qm_dqflush( xfs_buf_relse(bp); xfs_dqfunlock(dqp); xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE); - return -EIO; + return -EFSCORRUPTED; }
/* This is the only portion of data that needs to persist */