diff options
| author | Darrick J. Wong <djwong@kernel.org> | 2026-10-12 08:23:12 -0700 |
|---|---|---|
| committer | Carlos Maiolino <cem@kernel.org> | 2026-10-14 09:34:54 +0200 |
| commit | 91c41f9524906a8ebd2ae68c98a07b4bd5255ddb (patch) | |
| tree | 16f8f36f6c6a7854ed46c212a885c031b3c1c5eb | |
| parent | 9eb04a6d41c7e474d4665118895c3c2d8e5a2741 (diff) | |
| download | linux-next-91c41f9524906a8ebd2ae68c98a07b4bd5255ddb.tar.gz linux-next-91c41f9524906a8ebd2ae68c98a07b4bd5255ddb.zip | |
xfs: check for buffer overruns when examining local/remote xattr entries
LOLLM noticed that the xattr scrub and repair code can walk off the end
of the buffer if the xattr entry record starts so close to the end of
the buffer that there's not even space for the entry structure itself.
Strengthen the bounds checking here.
Cc: stable@vger.kernel.org # v4.15
Fixes: 13791d3b833428 ("xfs: scrub extended attribute leaf space")
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Assisted-by: LOLLM # finding obvious bugs
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
| -rw-r--r-- | fs/xfs/scrub/attr.c | 12 | ||||
| -rw-r--r-- | fs/xfs/scrub/attr_repair.c | 16 |
2 files changed, 25 insertions, 3 deletions
diff --git a/fs/xfs/scrub/attr.c b/fs/xfs/scrub/attr.c index f7c00ea1af5d..f909e2b25158 100644 --- a/fs/xfs/scrub/attr.c +++ b/fs/xfs/scrub/attr.c @@ -306,6 +306,12 @@ xchk_xattr_local_entry( char *name_end; unsigned int namesize; + name_end = (char *)lentry + offsetof(typeof(*lentry), nameval[0]); + if (name_end > buf_end) { + xchk_da_set_corrupt(ds, level); + return 0; + } + namesize = xfs_attr_leaf_entsize_local(lentry->namelen, be16_to_cpu(lentry->valuelen)); name_end = (char *)lentry + namesize; @@ -335,6 +341,12 @@ xchk_xattr_remote_entry( char *name_end; unsigned int namesize; + name_end = (char *)rentry + offsetof(typeof(*rentry), name[0]); + if (name_end > buf_end) { + xchk_da_set_corrupt(ds, level); + return 0; + } + namesize = xfs_attr_leaf_entsize_remote(rentry->namelen); name_end = (char *)rentry + namesize; if (rentry->namelen == 0) { diff --git a/fs/xfs/scrub/attr_repair.c b/fs/xfs/scrub/attr_repair.c index f2868fb4d27a..720090895c20 100644 --- a/fs/xfs/scrub/attr_repair.c +++ b/fs/xfs/scrub/attr_repair.c @@ -285,6 +285,7 @@ xrep_xattr_salvage_local_attr( struct xfs_attr_leaf_name_local *lentry) { struct xchk_xattr_buf *ab = rx->sc->buf; + char *name_end; unsigned char *value; unsigned int valuelen; unsigned int namesize; @@ -293,10 +294,14 @@ xrep_xattr_salvage_local_attr( * Decode the leaf local entry format. If something seems wrong, we * junk the attribute. */ + name_end = (char *)lentry + offsetof(typeof(*lentry), nameval[0]); + if (name_end > buf_end) + return 0; value = &lentry->nameval[lentry->namelen]; valuelen = be16_to_cpu(lentry->valuelen); namesize = xfs_attr_leaf_entsize_local(lentry->namelen, valuelen); - if ((char *)lentry + namesize > buf_end) + name_end = (char *)lentry + namesize; + if (name_end > buf_end) return 0; if (!xrep_xattr_want_salvage(rx, ent->flags, lentry->nameval, lentry->namelen, value, valuelen)) @@ -333,8 +338,8 @@ xrep_xattr_salvage_remote_attr( .attr_filter = ent->flags & XFS_ATTR_NSP_ONDISK_MASK, .namelen = rentry->namelen, .name = rentry->name, - .valuelen = be32_to_cpu(rentry->valuelen), }; + char *name_end; unsigned int namesize; int error; @@ -343,9 +348,14 @@ xrep_xattr_salvage_remote_attr( * junk the attribute. Note that we should never find a zero-length * remote attribute value. */ + name_end = (char *)rentry + offsetof(typeof(*rentry), name[0]); + if (name_end > buf_end) + return 0; namesize = xfs_attr_leaf_entsize_remote(rentry->namelen); - if ((char *)rentry + namesize > buf_end) + name_end = (char *)rentry + namesize; + if (name_end > buf_end) return 0; + args.valuelen = be32_to_cpu(rentry->valuelen); if (args.valuelen == 0 || !xrep_xattr_want_salvage(rx, ent->flags, rentry->name, rentry->namelen, NULL, args.valuelen)) |
