Re: [PATCH] btrfs: Fix BTRFS arm64 tagged KASAN false-positive

5 views
Skip to first unread message

Qu Wenruo

unread,
Mar 20, 2026, 6:27:02 PMMar 20
to dst...@suse.cz, Daniel J Blueman, Chris Mason, David Sterba, linux...@vger.kernel.org, linux-...@vger.kernel.org, kasa...@googlegroups.com


在 2026/3/21 08:31, David Sterba 写道:
> On Thu, Mar 19, 2026 at 07:26:34PM +1030, Qu Wenruo wrote:
>>
>>
>> 在 2026/3/19 16:04, Daniel J Blueman 写道:
>>> When booting Linux 7.0-rc4 on a Qualcomm Snapdragon X1 with KASAN
>>> software tagging with a BTRFS filesystem, we see:
>>>
>>> BUG: KASAN: invalid-access in xxh64_update (lib/xxhash.c:143 lib/xxhash.c:283)
>>> Read of size 8 at addr 7bff000804fe1000 by task kworker/u49:2/138
>>> Pointer tag: [7b], memory tag: [b2]
>>>
>>> CPU: 0 UID: 0 PID: 138 Comm: kworker/u49:2 Not tainted 7.0.0-rc4+ #34 PREEMPTLAZY
>>> Hardware name: LENOVO 83ED/LNVNB161216, BIOS NHCN60WW 09/11/2025
>>> Workqueue: btrfs-endio-meta simple_end_io_work
>>> Call trace:
>>> show_stack (arch/arm64/kernel/stacktrace.c:501) (C)
>>> dump_stack_lvl (lib/dump_stack.c:122)
>>> print_report (mm/kasan/report.c:379 mm/kasan/report.c:482)
>>> kasan_report (mm/kasan/report.c:597)
>>> kasan_check_range (mm/kasan/sw_tags.c:86 (discriminator 1))
>>> __hwasan_loadN_noabort (mm/kasan/sw_tags.c:158)
>>> xxh64_update (lib/xxhash.c:143 lib/xxhash.c:283)
>>> btrfs_csum_update (fs/btrfs/fs.c:106)
>>> csum_tree_block (fs/btrfs/disk-io.c:103 (discriminator 3))
>>> btrfs_validate_extent_buffer (fs/btrfs/disk-io.c:389)
>>> end_bbio_meta_read (fs/btrfs/extent_io.c:3853 (discriminator 1))
>>> btrfs_bio_end_io (fs/btrfs/bio.c:152)
>>> simple_end_io_work (fs/btrfs/bio.c:388)
>>> process_one_work (./arch/arm64/include/asm/jump_label.h:36 ./include/trace/events/workqueue.h:110 kernel/workqueue.c:3281)
>>> worker_thread (kernel/workqueue.c:3353 (discriminator 2) kernel/workqueue.c:3440 (discriminator 2))
>>> kthread (kernel/kthread.c:436)
>>> ret_from_fork (arch/arm64/kernel/entry.S:861)
>>>
>>> The buggy address belongs to the physical page:
>>> page: refcount:3 mapcount:0 mapping:f1ff00080055dee8 index:0x2467bd pfn:0x884fe1
>>> memcg:51ff000800e68ec0 aops:btree_aops ino:1
>>> flags: 0x9340000000004000(private|zone=2|kasantag=0x4d)
>>> raw: 9340000000004000 0000000000000000 dead000000000122 f1ff00080055dee8
>>> raw: 00000000002467bd 43ff00081d0cc6f0 00000003ffffffff 51ff000800e68ec0
>>> page dumped because: kasan: bad access detected
>>>
>>> Memory state around the buggy address:
>>> ffff000804fe0e00: 7b 7b 7b 7b 7b 7b 7b 7b 7b 7b 7b 7b 7b 7b 7b 7b
>>> ffff000804fe0f00: 7b 7b 7b 7b 7b 7b 7b 7b 7b 7b 7b 7b 7b 7b 7b 7b
>>>> ffff000804fe1000: b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2
>>> ^
>>> ffff000804fe1100: b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2
>>> ffff000804fe1200: b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2 b2
>>>
>>> This occurs as contiguous pages may have different KASAN tags in the upper address
>>> bits, leading to a tag mismatch if linear addressing is used.
>>>
>>> Fix this by treating them as discontiguous.
>>>
>>> Signed-off-by: Daniel J Blueman <dan...@quora.org>
>>> Fixes: 397239ed6a6c ("btrfs: allow extent buffer helpers to skip cross-page handling")
>>>
>>> ---
>>> fs/btrfs/extent_io.c | 12 ++++++++++--
>>> 1 file changed, 10 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
>>> index 5f97a3d2a8d7..e2b241fb6c0e 100644
>>> --- a/fs/btrfs/extent_io.c
>>> +++ b/fs/btrfs/extent_io.c
>>> @@ -3517,8 +3517,16 @@ struct extent_buffer *alloc_extent_buffer(struct btrfs_fs_info *fs_info,
>>> * At this stage, either we allocated a large folio, thus @i
>>> * would only be 0, or we fall back to per-page allocation.
>>> */
>>> - if (i && folio_page(eb->folios[i - 1], 0) + 1 != folio_page(folio, 0))
>>> - page_contig = false;
>>> + if (i > 0) {
>>> + struct page *prev = folio_page(eb->folios[i - 1], 0);
>>> + struct page *curr = folio_page(folio, 0);
>>> +
>>> + /*
>>> + * Contiguous pages may have different tags; can't be treated as contiguous
>>> + */
>>> + if (curr != prev + 1 || page_kasan_tag(curr) != page_kasan_tag(prev))
>>> + page_contig = false;
>>
>> I am not a fan of this solution.
>>
>> Although it doesn't affect end users who don't have KASAN soft tag
>> enabled, I don't get what we can really get from the different tags.
>>
>> I mean all those pages are already contig in physical addresses, why we
>> can not access the range in one go?
>>
>> Maybe it will be better to set all pages with the same random tag if
>> page_contig is true?
>
> I don't know if there's an interface how to change the tags but adding
> one condition that enables a sanitizer to work on some platform does not
> sound like a terrible thing. The contiguous pages on our side is an
> optimization so it's a special case, I'd rather adapt to the sanitizers
> than to let people ignore a warning or have to read a warning that that
> one is harmless.

There is the interface, page_kasan_tag_set()/page_kasan_tag_reset(), and
is already utilized inside MM.

And the deeper problem is, if this is a false alert, shouldn't we fix
the sanitizer?

Especially in this case I didn't see any problem accessing properly
allocated and physically adjacent pages.

If this is really a problem, I think a lot of bio accesses are also
going to cause problems, as one bvec can have multiple physically
adjacent pages, and if they have different tags then drivers copying a
large bvec should lead to the same tag difference.


So to the reporter/KASAN people, what's the problem of accessing
different tags in the first place?

Thanks,
Qu

Daniel J Blueman

unread,
Mar 20, 2026, 10:39:26 PMMar 20
to Qu Wenruo, David Sterba, Chris Mason, dst...@suse.cz, linux...@vger.kernel.org, linux-...@vger.kernel.org, kasa...@googlegroups.com
I agree with this, however BTRFS doesn't have multi-page folios, thus
these pages are from different allocations; from extent_io.c:

/* For now, we should only have single-page folios for btree inode. */
ASSERT(folio_nr_pages(existing_folio) == 1);

The goal of the differing KASAN tags per allocation is to catch UAF
and other lifecycle issues. If preferred, I can test and submit a
patch to set the same KASAN tag in alloc_eb_folio_array()? This would
be removed when multi-page folio support is added and is along the
lines of:

for (int i = 1; i < num_pages; i++)
page_kasan_tag_set(page_array[i], page_kasan_tag(page_array[0]));

It will be less minimal as won't implicitly be compiled out as per my
previous patch.

Thanks,
Dan
--
Daniel J Blueman

Daniel J Blueman

unread,
Mar 23, 2026, 2:20:25 AMMar 23
to Chris Mason, David Sterba, Qu Wenruo, linux...@vger.kernel.org, linux-...@vger.kernel.org, kasa...@googlegroups.com, Daniel J Blueman, sta...@vger.kernel.org
When booting Linux 7.0-rc5 on a Qualcomm Snapdragon X1 with KASAN
This occurs as allocation in btrfs_alloc_page_array is from multiple
discrete pages thus different KASAN tags by design, leading to a tag
mismatch when linear access is used where the pages are physically
contiguous.

Fix this by retagging all the EB pages with the same KASAN tag.

Cc: sta...@vger.kernel.org
Signed-off-by: Daniel J Blueman <dan...@quora.org>
Fixes: 397239ed6a6c ("btrfs: allow extent buffer helpers to skip cross-page handling")
Changelog:
v2: Retag pages rather than bypass linear access optimisation
v1: https://lore.kernel.org/lkml/20260319053413...@quora.org/
---
fs/btrfs/extent_io.c | 13 +++++++++++++
1 file changed, 13 insertions(+)

diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index 5f97a3d2a8d7..37836d685f21 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -10,6 +10,7 @@
#include <linux/spinlock.h>
#include <linux/blkdev.h>
#include <linux/swap.h>
+#include <linux/kasan.h>
#include <linux/writeback.h>
#include <linux/pagevec.h>
#include <linux/prefetch.h>
@@ -706,6 +707,18 @@ static int alloc_eb_folio_array(struct extent_buffer *eb, bool nofail)
if (ret < 0)
return ret;

+ /*
+ * Since separate page allocations are used for the same extent with
+ * linear addressing where physically contiguous, apply the same KASAN
+ * tag to prevent false-positive warnings when crossing page boundaries
+ */
+ u8 tag = page_kasan_tag(page_array[0]);
+
+ for (int i = 1; i < num_pages; i++) {
+ page_kasan_tag_set(page_array[i], tag);
+ kasan_unpoison_range(page_address(page_array[i]), PAGE_SIZE);
+ }
+
for (int i = 0; i < num_pages; i++)
eb->folios[i] = page_folio(page_array[i]);
eb->folio_size = PAGE_SIZE;
--
2.53.0

Qu Wenruo

unread,
Mar 23, 2026, 2:33:32 AMMar 23
to Daniel J Blueman, Chris Mason, David Sterba, linux...@vger.kernel.org, linux-...@vger.kernel.org, kasa...@googlegroups.com, sta...@vger.kernel.org
We do not mix definition and code.

> +
> + for (int i = 1; i < num_pages; i++) {
> + page_kasan_tag_set(page_array[i], tag);

Please note that, at alloc_eb_folio_array() we have no idea if the
folios are contig yet.

And if they are not contig, tagging them with the same tag will mask
some real bugs.

To me, the proper re-tagging timing should be inside
alloc_extent_buffer(), under the "if (page_contig)" branch.

Thanks,
Qu

kernel test robot

unread,
Mar 23, 2026, 5:20:10 PMMar 23
to Daniel J Blueman, Chris Mason, David Sterba, Qu Wenruo, ll...@lists.linux.dev, oe-kbu...@lists.linux.dev, linux...@vger.kernel.org, linux-...@vger.kernel.org, kasa...@googlegroups.com, Daniel J Blueman, sta...@vger.kernel.org
Hi Daniel,

kernel test robot noticed the following build errors:

[auto build test ERROR on kdave/for-next]
[also build test ERROR on linus/master v7.0-rc5 next-20260323]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url: https://github.com/intel-lab-lkp/linux/commits/Daniel-J-Blueman/btrfs-Fix-BTRFS-arm64-tagged-KASAN-false-positive/20260323-181717
base: https://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux.git for-next
patch link: https://lore.kernel.org/r/20260323061827.22903-1-daniel%40quora.org
patch subject: [PATCH v2] btrfs: Fix BTRFS arm64 tagged KASAN false-positive
config: x86_64-randconfig-001-20260323 (https://download.01.org/0day-ci/archive/20260324/202603240559...@intel.com/config)
compiler: clang version 20.1.8 (https://github.com/llvm/llvm-project 87f0227cb60147a26a1eeb4fb06e3b505e9c7261)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260324/202603240559...@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <l...@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202603240559...@intel.com/

All errors (new ones prefixed by >>, old ones prefixed by <<):

>> ERROR: modpost: "__kasan_unpoison_range" [fs/btrfs/btrfs.ko] undefined!

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

Daniel J Blueman

unread,
Mar 27, 2026, 4:24:34 AMMar 27
to Chris Mason, David Sterba, Qu Wenruo, linux...@vger.kernel.org, linux-...@vger.kernel.org, kasa...@googlegroups.com, Daniel J Blueman, sta...@vger.kernel.org
v3: Retag only when contiguous; fix build failure when generic KASAN configured
v2: https://lore.kernel.org/lkml/20260323061827...@quora.org/
- Retag pages rather than bypass linear access optimisation
v1: https://lore.kernel.org/lkml/20260319053413...@quora.org/
---
fs/btrfs/extent_io.c | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index 5f97a3d2a8d7..141092da871b 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -3533,8 +3533,23 @@ struct extent_buffer *alloc_extent_buffer(struct btrfs_fs_info *fs_info,
if (uptodate)
set_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags);
/* All pages are physically contiguous, can skip cross page handling. */
- if (page_contig)
+ if (page_contig) {
+#if defined(CONFIG_KASAN_SW_TAGS) || defined(CONFIG_KASAN_HW_TAGS)
+ struct page *page = folio_page(eb->folios[0], 0);
+ u8 tag = page_kasan_tag(page);
+
+ /*
+ * Since pages are from multiple allocations and physically
+ * contiguous allowing linear access, prevent KASAN warnings
+ * by retagging with the first tag
+ */
+ for (int i = 1; i < num_extent_pages(eb); i++) {
+ page_kasan_tag_set(page + i, tag);
+ kasan_unpoison_range(page_address(page + i), PAGE_SIZE);
+ }
+#endif
eb->addr = folio_address(eb->folios[0]) + offset_in_page(eb->start);
+ }
again:
xa_lock_irq(&fs_info->buffer_tree);
existing_eb = __xa_cmpxchg(&fs_info->buffer_tree,
--
2.53.0

Qu Wenruo

unread,
Mar 27, 2026, 5:46:25 PMMar 27
to Daniel J Blueman, Chris Mason, David Sterba, linux...@vger.kernel.org, linux-...@vger.kernel.org, kasa...@googlegroups.com, sta...@vger.kernel.org
This one looks good to me for btrfs.

But still a question related to kasan_unpoison_range().
There is a LKP report that __kasan_unpoison_range() is not properly
exported thus if btrfs is compiled as a module, we can not properly link
the module.

https://lore.kernel.org/linux-btrfs/202603240559...@intel.com/

You may need to export __kasan_unpoison_range() to fix it, or explain
why kasan_unpoison_range() is needed here.

AFAIK those pages are already unpoisoned at allocation, thus I'm not
sure why we need to call kasan_unpoison_range() here again.

Thanks,
Qu
Reply all
Reply to author
Forward
0 new messages