On Tue, Sep 08, 2026 at 11:59:14AM +0200, Christophe Leroy (CS GROUP) wrote:
> 
>
[...]
> > --- a/arch/powerpc/include/asm/kasan.h
> > +++ b/arch/powerpc/include/asm/kasan.h
> > @@ -2,20 +2,17 @@
> >   #ifndef __ASM_KASAN_H
> >   #define __ASM_KASAN_H
> > -#if defined(CONFIG_KASAN) && 
> > !defined(CONFIG_CC_HAS_KASAN_MEMINTRINSIC_PREFIX)
> > -#define _GLOBAL_KASAN(fn)                  \
> > -   _GLOBAL(fn);                            \
> > -   _GLOBAL(__##fn)
> > -#define _GLOBAL_TOC_KASAN(fn)                      \
> > -   _GLOBAL_TOC(fn);                        \
> > -   _GLOBAL_TOC(__##fn)
> > -#define EXPORT_SYMBOL_KASAN(fn)                    \
> > -   EXPORT_SYMBOL(__##fn)
> > -#else /* CONFIG_KASAN && !CONFIG_CC_HAS_KASAN_MEMINTRINSIC_PREFIX */
> > +/*
> > + * powerpc requires CC_HAS_KASAN_MEMINTRINSIC_PREFIX whenever KASAN is
> > + * enabled (see PPC_CC_HAS_KASAN_MEMINTRINSIC_PREFIX in 
> > arch/powerpc/Kconfig),
> > + * so the compiler always emits __asan_mem*() at instrumented call sites 
> > and
> > + * bare mem*() inside __no_sanitize_address / noinstr code.  The old dual
> > + * entry-point trick (_GLOBAL_KASAN emitting both memset and __memset) is
> > + * therefore never needed.
> > + */
> 
> This explanation belongs to the commit message not to the source code.
> 
Hey Christophe,

Sure i'll move this and rest ahead.

[...]
> > diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c
> > index 6f6801da9dc1..44115f904c2c 100644
> > --- a/arch/powerpc/kernel/cputable.c
> > +++ b/arch/powerpc/kernel/cputable.c
> > @@ -36,8 +36,8 @@ void __init set_cur_cpu_spec(struct cpu_spec *s)
> >     t = PTRRELOC(t);
> >     /*
> > -    * use memcpy() instead of *t = *s so that GCC replaces it
> > -    * by __memcpy() when KASAN is active
> > +    * use memcpy() instead of *t = *s so that the compiler replaces it
> > +    * by __asan_memcpy() when KASAN is active
> >      */
> 
> Does the initial problem still exist with the new __asan_memcpy() approach ?
> If not the comment should be removed.
> 
Hey Christophe,

Thanks for pointing it out, i took a deeper look into this, here's my
understanding on it.

On PowerPC during very early boot the kernel is loaded by the
bootloader/firmware at some physical address, but the kernel was linked
expecting it to run at KERNELBASE(virtual address like
0xc000000000000000). The MMU mapping that makes that virtual address
valid hasn't been set up yet. So far for a window of early boot, code is
executing at the physical load address while all symbol addresses in the
binary refer to the virtual linked address. reloc_offset() computes the
gap between these two and PTRRELOC applies it to any pointer.

So PTRRELOC(&the_cpu_spec) gives the physical address where the struct
actually lives in memory right now, not where the linker thinks it lives.

Why *t = *s would be wrong?

In set_cur_cpu_spec:

struct cpu_spec *t = &the_cpu_spec;  // linked (virtual) address
t = PTRRELOC(t);                     // physical address — where it actually is
memcpy(t, s, sizeof(*t));            // copy into the right place

If you wrote *t = *s instead, the compiler generates a struct assignment.
For a large struct like cpu_spec, GCC is free to implement that however
it likes — including emitting a call to memcpy(). But crucially, a 
compiler-generated memcpy call resolves through the GOT/PLT or direct
symbol — which points to the linked virtual address of memcpy, not the
physical address. At this point in boot, calling through the wrong
address would jump to garbage or an unmapped page.

memcpy(t, s, sizeof(*t)) written explicitly is different: t is already
the corrected physical address, s points into the cpu_specs table which
has also been PTRRELOC'd. The explicit call goes through the normal
early-boot call mechanism which is safe.

The original comment said:

"use memcpy() instead of *t = *s so that GCC replaces it by __memcpy()
when KASAN is active"

This was added because under the old KASAN scheme
(!CC_HAS_KASAN_MEMINTRINSIC_PREFIX), KASAN overrode the memset/memcpy
linker symbols globally with C wrappers that called kasan_check_range().
If the compiler turned *t = *s into an implicit memcpy(), that would hit
the KASAN wrapper — calling kasan_check_range() at a point in early boot
where the KASAN shadow isn't mapped yet, causing a crash.

Writing memcpy(t, s, sizeof(*t)) explicitly made GCC emit __memcpy()
(the raw assembly alias exposed by _GLOBAL_KASAN) instead of the
KASAN-wrapped memcpy(), bypassing the shadow check.

That was the secondary reason. The primary reason that t is a
PTRRELOC-adjusted physical pointer and the copy must go through it
correctly was never stated.

So the KASAN comment is not required but i think we still need to state
why memcpy is required. For PTRRELOC adjustment, comment should reflect
that.

I'll update the comment and commit message and send out a new version.

Regards,
Mukesh

Reply via email to