From: Ihor Solodrai <ihor.solodrai@linux.dev>
To: Borislav Petkov <bp@alien8.de>
Cc: Dave Hansen <dave.hansen@intel.com>,
Alexei Starovoitov <ast@kernel.org>,
Andrii Nakryiko <andrii@kernel.org>,
Daniel Borkmann <daniel@iogearbox.net>,
Eduard Zingerman <eddyz87@gmail.com>,
Kumar Kartikeya Dwivedi <memxor@gmail.com>,
Andrey Ryabinin <ryabinin.a.a@gmail.com>,
Andrew Morton <akpm@linux-foundation.org>,
bpf@vger.kernel.org, kasan-dev@googlegroups.com,
linux-mm@kvack.org, linux-kernel@vger.kernel.org,
Thomas Gleixner <tglx@kernel.org>, Ingo Molnar <mingo@redhat.com>,
Dave Hansen <dave.hansen@linux.intel.com>,
x86@kernel.org, "H. Peter Anvin" <hpa@zytor.com>,
Andrey Konovalov <andreyknvl@gmail.com>
Subject: Re: [PATCH v1] kasan: Fix false-positive wild-memory-access on x86 under 5-level paging
Date: Wed, 24 Jun 2026 15:45:15 -0700 [thread overview]
Message-ID: <c49b1499-6aa0-4e17-8385-cd2bcd2220cc@linux.dev> (raw)
In-Reply-To: <20260624025732.GDajtHnB1Jc21kQnl_@fat_crate.local>
On 6/23/26 7:57 PM, Borislav Petkov wrote:
> On Mon, Jun 22, 2026 at 05:29:12PM -0700, Ihor Solodrai wrote:
>> On 6/18/26 11:38 AM, Borislav Petkov wrote:
>>> On Thu, Jun 18, 2026 at 11:12:09AM -0700, Dave Hansen wrote:
>>>> On 6/18/26 10:09, Borislav Petkov wrote:
>>>>> On Wed, Jun 17, 2026 at 03:13:33PM -0700, Ihor Solodrai wrote:
>>>>>> So my question to maintainers is what approach seems best?
>>>>> The CPUID stuff is being rewritten currently and it should address your issue
>>>>> too. If not, then we need to rewrite it better.
>>>>>
>>>>> Can you reproduce with this set applied ontop:
>>>>>
>>>>> https://lore.kernel.org/r/20260528153923.403473-1-darwi@linutronix.de
>>>>
>>>> Thinking about this a bit more... If Ahmed's series does fix this, I
>>>> think it will be accidental. It still uses identify_cpu() and also does
>>>> a memset() of the new c->cpuid structure in addition to the old
>>>> c->x86_capability structure.
>>>>
>>>> I'm not knocking Ahmed's series by any means. It just probably won't fix
>>>> this issue.
>>>>
>>>> In a perfect world early_identify_cpu() and identify_cpu() would either
>>>> get consolidated into one thing. Or at least become two discrete things
>>>> that initialize two completely disjoint sets of data. That way,
>>>> identify_cpu() wouldn't memset() anything.
>>>>
>>>> Isn't that the _real_ fix? Instead of trying to hide the inconsistency
>>>> when good data is blown away, we stop blowing it away in the first place?
>>>
>>> early_ is only on the BSP and you want to scan all CPUs.
>>>
>>> AFAIR, the last time I was looking at how we scan the CPUID leafs, we do have
>>> cases where there's blips in time when cap bits get disappeared to be
>>> rescanned again. The toggling of MSR bits which control feature flags is one
>>> thing that comes to mind.
>>>
>>> But I'm with you on the consolidation approach. I think this is what we should
>>
>> Hello Dave, Boris. Thank you for the input.
>>
>> I tried a slight refactoring of the identify_cpu() machinery to
>> eliminate the memset(x86_capability) from the boot cpu, and it fixes
>> the splat that I reported.
>>
>> identify_cpu() is split into two parts:
>> * identify_cpu_scan() - the top part, up to and including the
>> generic_identify() call
>> * identify_cpu() proper with the rest, no memset here
>>
>> Then (gated on x86_64) identify_boot_cpu() *skips* the
>> identify_cpu_scan() call, only executing the bottom part of current
>> identify_cpu(). We can do that because boot cpu already did the _scan
>> part in early_identify_cpu(), when interrupts are still disabled.
>>
>> One caveat: get_model_name() is moved from generic_identify() into
>> identify_cpu(), otherwise it wouldn't be called on boot cpu. Same for
>> c->loops_per_jiffy = loops_per_jiffy; - it's moved to the "bottom"
>> identify_cpu().
>>
>> The behavior for secondary cpus is unchanged: identify_secondary_cpu()
>> calls identify_cpu_scan() then immediately identify_cpu().
>>
>> Please take a look at the diff below and let me know if this is a good
>> way to proceed. I don't know exactly what I'm doing, so concerns and
>> corrections are welcome.
>>
>>
>> diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
>> index a4268c47f2bc..4a655109cacf 100644
>> --- a/arch/x86/kernel/cpu/common.c
>> +++ b/arch/x86/kernel/cpu/common.c
>> @@ -1978,8 +1978,6 @@ static void generic_identify(struct cpuinfo_x86 *c)
>>
>> get_cpu_address_sizes(c);
>>
>> - get_model_name(c); /* Default name */
>> -
>> /*
>> * ESPFIX is a strange bug. All real CPUs have it. Paravirt
>> * systems that run Linux at CPL > 0 may or may not have the
>> @@ -1999,13 +1997,12 @@ static void generic_identify(struct cpuinfo_x86 *c)
>> }
>>
>> /*
>> - * This does the hard work of actually picking apart the CPU stuff...
>> + * Rebuild capability set from CPUID and re-apply the forced-cap overrides
>> + * through generic_identify(). This *should* run with interrupts off, otherwise
>> + * an interrupt handler might see the capability bits cleared.
>
> And yet it doesn't run with IRQs off. So that comment doesn't need to be here.
> The point of the whole exercise is to not disable ugly interrupts in that path
> at all.
>
>> */
>> -static void identify_cpu(struct cpuinfo_x86 *c)
>> +static void identify_cpu_scan(struct cpuinfo_x86 *c)
>> {
>> - int i;
>> -
>> - c->loops_per_jiffy = loops_per_jiffy;
>> c->x86_cache_size = 0;
>> c->x86_vendor = X86_VENDOR_UNKNOWN;
>> c->x86_model = c->x86_stepping = 0; /* So far unknown... */
>> @@ -2028,6 +2025,19 @@ static void identify_cpu(struct cpuinfo_x86 *c)
>> #endif
>>
>> generic_identify(c);
>> +}
>> +
>> +/*
>> + * This is safe to run with interrupts on.
>> + * The boot CPU can run just this from arch_cpu_finalize_init(), because
>> + * the scan part already happened in early_identify_cpu().
>> + */
>> +static void identify_cpu(struct cpuinfo_x86 *c)
>> +{
>> + int i;
>> +
>> + c->loops_per_jiffy = loops_per_jiffy;
>> + get_model_name(c); /* Default name */
>>
>> cpu_parse_topology(c);
>>
>> @@ -2154,6 +2164,17 @@ void enable_sep_cpu(void)
>>
>> static __init void identify_boot_cpu(void)
>> {
>> + /*
>> + * The boot CPU's capabilities were already scanned by early_identify_cpu().
>> + * Here identify_cpu() only finalizes them.
>> + *
>> + * 32-bit still needs the full scan here: it sets X86_BUG_ESPFIX (via
>> + * generic_identify()) and the no-CPUID cpuid_level default, which the early
>> + * path does not.
>> + */
>> +#ifndef CONFIG_X86_64
>> + identify_cpu_scan(&boot_cpu_data);
>> +#endif
>> identify_cpu(&boot_cpu_data);
>> if (HAS_KERNEL_IBT && cpu_feature_enabled(X86_FEATURE_IBT))
>> pr_info("CET detected: Indirect Branch Tracking enabled\n");
>> @@ -2178,6 +2199,7 @@ void identify_secondary_cpu(unsigned int cpu)
>> *c = boot_cpu_data;
>> c->cpu_index = cpu;
>>
>> + identify_cpu_scan(c);
>> identify_cpu(c);
>> #ifdef CONFIG_X86_32
>> enable_sep_cpu();
>> --
>
> Ok, thanks for that, that's a good first try. I did poke at it a bit and
> here's what I think should happen:
>
> 1. The part which initializes struct cpuinfo_x86 up and including the memsets
> should be one function called init_cpu_info() or so.
>
> 2. Then, generic_identify() should be merged into identify_cpu() basically
> turning the latter into a single function which does a generic CPU
> identification both on the BSP and on the APs.
>
> 3. #ifdef CONFIG_X86_32
> enable_sep_cpu();
> #endif
> that gunk should be stuck into a function called identify_cpu_32() and
> you'll have at the beginning of it
>
> if (!IS_ENABLED(CONFIG_X86_32))
> return;
>
> and then you call that function both in identify_boot_cpu() and
> identify_secondary_cpu(). This way you streamline the paths and drop all
> that ugly ifdeffery.
>
> 4. When you do 3. above, you should be able to move this gunk
>
> #ifdef CONFIG_X86_32
> set_cpu_bug(c, X86_BUG_ESPFIX);
> #endif
>
> to it too. And now everything is nicely encapsulated and straight-forward.
>
> 5. The above will allow you to have the init_cpu_info() only on 32-bit.
>
> Oh and, looking at the ifdeffery on identify_cpu():
>
> #ifdef CONFIG_X86_64
> c->x86_clflush_size = 64;
> c->x86_phys_bits = 36;
> c->x86_virt_bits = 48;
> #else
>
> you could probably add a identify_cpu_64() too. Or maybe the init parts should
> be called separately init_cpu_info_32() and init_cpu_info_64(). You probably
> need to see how it looks like when you write it.
>
> Oh, and each 1., 2., ...step above is a single patch. This'll make the review
> very easy too.
>
> How does that sound? Willing to give it a try? :-)
The instructions are quite detailed, thank you.
I'll try it and will send a separate series as soon as I can (likely next week).
>
> If not, I could try to find some time and do it myself but I thought you might
> be willing to try it...
>
> :-)
>
> Thx.
>
next prev parent reply other threads:[~2026-06-24 22:46 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-10 17:56 [PATCH v1] kasan: Fix false-positive wild-memory-access on x86 under 5-level paging Ihor Solodrai
2026-06-10 18:17 ` sashiko-bot
2026-06-10 18:28 ` Ihor Solodrai
2026-06-10 18:39 ` Andrey Konovalov
2026-06-10 21:55 ` Ihor Solodrai
2026-06-12 16:30 ` Kiryl Shutsemau
2026-06-12 19:42 ` Ihor Solodrai
2026-06-17 22:13 ` Ihor Solodrai
2026-06-18 16:55 ` Andrey Ryabinin
2026-06-18 17:09 ` Borislav Petkov
2026-06-18 18:12 ` Dave Hansen
2026-06-18 18:38 ` Borislav Petkov
2026-06-23 0:29 ` Ihor Solodrai
2026-06-24 2:57 ` Borislav Petkov
2026-06-24 22:45 ` Ihor Solodrai [this message]
2026-06-24 23:45 ` Borislav Petkov
2026-06-23 0:35 ` Ihor Solodrai
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=c49b1499-6aa0-4e17-8385-cd2bcd2220cc@linux.dev \
--to=ihor.solodrai@linux.dev \
--cc=akpm@linux-foundation.org \
--cc=andreyknvl@gmail.com \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bp@alien8.de \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=dave.hansen@intel.com \
--cc=dave.hansen@linux.intel.com \
--cc=eddyz87@gmail.com \
--cc=hpa@zytor.com \
--cc=kasan-dev@googlegroups.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=memxor@gmail.com \
--cc=mingo@redhat.com \
--cc=ryabinin.a.a@gmail.com \
--cc=tglx@kernel.org \
--cc=x86@kernel.org \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.