From: Brian Foster <bfoster@redhat.com>
To: Kyle Zeng <kylebot@openai.com>
Cc: linux-xfs@vger.kernel.org, Carlos Maiolino <cem@kernel.org>,
outbounddisclosures@openai.com
Subject: Re: [PATCH] xfs: validate recovered buffer item dirty bitmaps
Date: Tue, 16 Jun 2026 13:03:50 -0400 [thread overview]
Message-ID: <ajGB9o5Ys6itU3Rh@bfoster> (raw)
In-Reply-To: <20260611212314.4610-1-kylebot@openai.com>
On Thu, Jun 11, 2026 at 02:23:14PM -0700, Kyle Zeng wrote:
> XFS buffer log recovery trusts the dirty bitmap in recovered buffer log
> items when replaying logged regions into the buffer. The replay path only
> has debug assertions to check that each bitmap extent fits within the
> buffer described by blf_len.
>
> A corrupted log can therefore set a dirty bit beyond the end of the
> recovered buffer. In non-debug builds, xlog_recover_do_reg_buffer() will
> copy the corresponding logged region to that out-of-range buffer offset.
>
> Validate the recovered dirty bitmap and the associated logged data regions
> before replay. Reject buffer items whose dirty extents extend beyond
> blf_len, whose region count does not match the bitmap, or whose data iovecs
> are malformed.
>
> Assisted-by: Codex:gpt-5.5
> Signed-off-by: Kyle Zeng <kylebot@openai.com>
> ---
This looks reasonable to me at first look, but a few questions..
Do you have a test or reproducer to trigger this issue that we could
incorportate into fstests? That said, I am wondering if that might be
difficult if say checksumming gets in the way, but it can't hurt to
think about at least.
> fs/xfs/xfs_buf_item_recover.c | 63 +++++++++++++++++++++++++++++++++++
> 1 file changed, 63 insertions(+)
>
> diff --git a/fs/xfs/xfs_buf_item_recover.c b/fs/xfs/xfs_buf_item_recover.c
> index 02b95b89d1b5..576d6245e922 100644
> --- a/fs/xfs/xfs_buf_item_recover.c
> +++ b/fs/xfs/xfs_buf_item_recover.c
> @@ -206,6 +206,63 @@ xlog_recover_buf_commit_pass1(
> return 0;
> }
>
> +/*
> + * Make sure the recovered dirty bitmap only describes ranges inside the
> + * recovered buffer and that each logged region is backed by one data iovec.
> + */
> +STATIC int xlog_recover_validate_buf_data_map(struct xfs_mount *mp,
> + struct xlog_recover_item *item,
> + struct xfs_buf_log_format *buf_f)
> +{
> + u64 buf_bytes = BBTOB(buf_f->blf_len);
> + int i = 1;
> + int bit = 0;
> +
> + while (1) {
> + u64 reg_bytes;
> + u64 reg_end;
> + int nbits;
> +
> + bit = xfs_next_bit(buf_f->blf_data_map, buf_f->blf_map_size,
> + bit);
> + if (bit == -1)
> + break;
> +
> + nbits = xfs_contig_bits(buf_f->blf_data_map,
> + buf_f->blf_map_size, bit);
> + if (XFS_IS_CORRUPT(mp, nbits <= 0))
> + return -EFSCORRUPTED;
> +
> + reg_bytes = (u64)nbits << XFS_BLF_SHIFT;
> + reg_end = ((u64)bit << XFS_BLF_SHIFT) + reg_bytes;
> + if (XFS_IS_CORRUPT(mp, reg_end > buf_bytes))
> + return -EFSCORRUPTED;
> +
> + if (XFS_IS_CORRUPT(mp, i >= item->ri_total))
> + return -EFSCORRUPTED;
> + if (XFS_IS_CORRUPT(mp, !item->ri_buf[i].iov_base))
> + return -EFSCORRUPTED;
> + if (XFS_IS_CORRUPT(mp, item->ri_buf[i].iov_len == 0 ||
> + item->ri_buf[i].iov_len % XFS_BLF_CHUNK))
> + return -EFSCORRUPTED;
> + if (XFS_IS_CORRUPT(mp, item->ri_buf[i].iov_len > reg_bytes))
> + return -EFSCORRUPTED;
> +
It looks like these checks are mostly promoted from asserts in
_do_reg_buffer(), right? If so that is worth pointing out in the commit
log. I'm also curious why we'd keep the asserts around at all, at least
the ones that are purely duplicated by the runtime checks, since it
seems we can no longer hit them.
> + /*
> + * A single contiguous dirty range can be split into multiple
> + * log vectors. Advance by the amount covered by this iovec.
> + */
> + nbits = item->ri_buf[i].iov_len >> XFS_BLF_SHIFT;
> + i++;
> + bit += nbits;
Hmm along the same lines, I see something like this being duplicated and
wonder.. why not promote the asserts to runtime checks within the
do_reg_buffer() function where we already walk the vectors (and modify
so it can return error)?
Do we miss any protection by doing that that I'm not seeing? If not,
then at least we're not spinning through the list multiple times or
duplicating logic quirks like the above. Hm?
Brian
> + }
> +
> + if (XFS_IS_CORRUPT(mp, i != item->ri_total))
> + return -EFSCORRUPTED;
> +
> + return 0;
> +}
> +
> /*
> * Validate the recovered buffer is of the correct type and attach the
> * appropriate buffer operations to them for writeback. Magic numbers are in a
> @@ -1033,6 +1090,12 @@ xlog_recover_buf_commit_pass2(
> goto cancelled;
> }
>
> + error = xlog_recover_validate_buf_data_map(mp, item, buf_f);
> + if (error) {
> + ASSERT(error == -EFSCORRUPTED);
> + return error;
> + }
> +
> trace_xfs_log_recover_buf_recover(log, buf_f);
> error = xfs_buf_read(mp->m_ddev_targp, buf_f->blf_blkno, buf_f->blf_len,
> 0, &bp, NULL);
> --
> 2.43.0
>
prev parent reply other threads:[~2026-06-16 17:03 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-11 21:23 [PATCH] xfs: validate recovered buffer item dirty bitmaps Kyle Zeng
2026-06-16 17:03 ` Brian Foster [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=ajGB9o5Ys6itU3Rh@bfoster \
--to=bfoster@redhat.com \
--cc=cem@kernel.org \
--cc=kylebot@openai.com \
--cc=linux-xfs@vger.kernel.org \
--cc=outbounddisclosures@openai.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox