On Thu, May 07, 2026 at 11:49PM +0200, 'Harry Yoo (Oracle)' via kasan-dev wrote:
> On Wed, May 06, 2026 at 03:03:27PM +0100, Marco Elver wrote:
> > On Mon, 4 May 2026 at 23:23, Marco Elver <[email protected]> wrote:
> > > On Thu, Apr 30, 2026 at 03:03PM +0200, Vlastimil Babka (SUSE) wrote:
> > > > On 4/24/26 15:24, Marco Elver wrote:
> > > > > @@ -948,14 +978,16 @@ static __always_inline __alloc_size(1) void
> > > > > *kmalloc_noprof(size_t size, gfp_t f
> > > > >
> > > > > index = kmalloc_index(size);
> > > > > return __kmalloc_cache_noprof(
> > > > > - kmalloc_caches[kmalloc_type(flags,
> > > > > _RET_IP_)][index],
> > > > > + kmalloc_caches[kmalloc_type(flags,
> > > > > token)][index],
> > > >
> > > > While reviewing this, it occured to me we might have been using _RET_IP_
> > > > here in a suboptimal way ever since this was introduced. Since this is
> > > > all
> > > > inlined, shouldn't have we been using _THIS_IP_ to really randomize
> > > > using
> > > > the kmalloc() callsite, and not its parent?
> > > >
> > > > And after this patch, we get the token passed to _kmalloc_noprof()...
> > > >
> > > > > flags, size);
> > > > > }
> > > > > - return __kmalloc_noprof(size, flags);
> > > > > + return __kmalloc_noprof(PASS_KMALLOC_PARAMS(size, NULL, token),
> > > > > flags);
> > > >
> > > > ... and used also here for the non-constant-size, where previously
> > > > __kmalloc_noprof() (not inline function) would correctly use _RET_IP_
> > > > on its
> > > > own ...
> > > >
> > > > > }
> > > > > +#define kmalloc_noprof(...)
> > > > > _kmalloc_noprof(__VA_ARGS__, __kmalloc_token(__VA_ARGS__))
> > > >
> > > > ... and the token comes from here. With random partitioning that's
> > > > #define __kmalloc_token(...) ((kmalloc_token_t){ .v = _RET_IP_ })
> > > >
> > > > so that AFAIK makes the situation worse as now the cases without
> > > > constant
> > > > size also start randomizing by the parent callsite and not the kmalloc
> > > > callsite.
> > > >
> > > > But there are many users of __kmalloc_token() and maybe some are
> > > > corrent in
> > > > using _RET_IP_, I haven't checked, maybe we'll need two variants, or
> > > > further
> > > > change things around.
> > >
> > > Good catch. I don't think we need multiple variants (otherwise the TYPED
> > > variant would be broken) - we're moving token generation to the callers
> > > (not even inlined anymore) with all this macro magic.
> > >
> > > I think this is all we need:
> > >
> > > --- a/include/linux/slab.h
> > > +++ b/include/linux/slab.h
> > > @@ -503,7 +503,7 @@ int kmem_cache_shrink(struct kmem_cache *s);
> > > typedef struct { unsigned long v; } kmalloc_token_t;
> > > #ifdef CONFIG_KMALLOC_PARTITION_RANDOM
> > > extern unsigned long random_kmalloc_seed;
> > > -#define __kmalloc_token(...) ((kmalloc_token_t){ .v = _RET_IP_ })
> > > +#define __kmalloc_token(...) ((kmalloc_token_t){ .v = _THIS_IP_ })
> > > #elif defined(CONFIG_KMALLOC_PARTITION_TYPED)
> > > #define __kmalloc_token(...) ((kmalloc_token_t){ .v =
> > > __builtin_infer_alloc_token(__VA_ARGS__) })
> > > #endif
> > >
> > > Plus a paragraph in the commit message. Let me add that.
>
> Err, I was like "yes, this is the way to go!"
>
> and then...
>
> > Bah, this is why it doesn't work:
> >
> > >> drivers/gpu/drm/msm/msm_gpu.c:272:4: error: cannot jump from this
> > >> indirect goto statement to one of its possible targets
> > 272 | drm_exec_retry_on_contention(&exec);
> > | ^
> > include/drm/drm_exec.h:123:4: note: expanded from macro
> > 'drm_exec_retry_on_contention'
> > 123 | goto *__drm_exec_retry_ptr; \
> > | ^
> > drivers/gpu/drm/msm/msm_gpu.c:304:16: note: possible target of
> > indirect goto statement
> > 304 | state->bos = kcalloc(submit->nr_bos,
> > | ^
> > include/linux/slab.h:1173:34: note: expanded from macro 'kcalloc'
> > 1173 | #define kcalloc(n, size, flags) kmalloc_array(n,
> > size, (flags) | __GFP_ZERO)
> > | ^
> > include/linux/slab.h:1133:42: note: expanded from macro 'kmalloc_array'
> > 1133 | #define kmalloc_array(...)
> > alloc_hooks(kmalloc_array_noprof(__VA_ARGS__))
> > | ^
> > include/linux/slab.h:1132:71: note: expanded from macro
> > 'kmalloc_array_noprof'
> > 1132 | #define kmalloc_array_noprof(...)
> > _kmalloc_array_noprof(__VA_ARGS__, __kmalloc_token(__VA_ARGS__))
> > |
> > ^
> > include/linux/slab.h:506:55: note: expanded from macro '__kmalloc_token'
> > 506 | #define __kmalloc_token(...) ((kmalloc_token_t){ .v = _THIS_IP_
> > })
> > | ^
> > include/linux/instruction_pointer.h:10:41: note: expanded from
> > macro '_THIS_IP_'
> > 10 | #define _THIS_IP_ ({ __label__ __here; __here: (unsigned
> > long)&&__here; })
> > | ^
> > drivers/gpu/drm/msm/msm_gpu.c:304:16: note: jump enters a statement
> > expression
> >
> > Apparently using _THIS_IP_ creates a possible indirect jump target,
>
> Didn't even realize people use indirect gotos, heh :)
>
> > but because it's in a statement expression, it's invalid, so the
> > compiler complains. This is obviously nonsense, because the actual
> > indirect jump in this gpu driver code would never jump to the
> > _THIS_IP_ __here label, but that's what it is.
>
> Yeah, I guess it's quite tricky to handle when you don't know where
> it'd jump to as it's an indirect one, and there's an invalid jump
> label...
>
> > Given this pre-existing issue, we probably need to continue using
> > _RET_IP_, as before.
I think I have a solution for this mess, see below.
I would not send it as 1 series, but only include the slab changes (+
instruction_pointer.h change to introduce _CODE_LOCATION_) as one
series, to go through the slab tree. The rest of the patches would go to
respective arch maintainers.
------ >8 ------
diff --git a/arch/alpha/include/asm/linkage.h b/arch/alpha/include/asm/linkage.h
index aa8661fa60dc..88617cfaa0f7 100644
--- a/arch/alpha/include/asm/linkage.h
+++ b/arch/alpha/include/asm/linkage.h
@@ -6,4 +6,6 @@
#define SYSCALL_ALIAS(alias, name) \
asm ( #alias " = " #name "\n\t.globl " #alias)
+#define _THIS_IP_ ({ unsigned long __ip; asm volatile("br %0, 1f\n1:" : "=r"
(__ip)); __ip; })
+
#endif
diff --git a/arch/arc/include/asm/linkage.h b/arch/arc/include/asm/linkage.h
index ba3cb65b5eaa..3fb91d1672ba 100644
--- a/arch/arc/include/asm/linkage.h
+++ b/arch/arc/include/asm/linkage.h
@@ -75,6 +75,8 @@
#define __arcfp_data __section(".data")
#endif
+#define _THIS_IP_ ({ unsigned long __ip; asm volatile("mov %0, pcl" : "=r"
(__ip)); __ip; })
+
#endif /* __ASSEMBLER__ */
#endif
diff --git a/arch/arm/include/asm/linkage.h b/arch/arm/include/asm/linkage.h
index c4670694ada7..416e6a242dc4 100644
--- a/arch/arm/include/asm/linkage.h
+++ b/arch/arm/include/asm/linkage.h
@@ -9,4 +9,6 @@
.type name, %function; \
END(name)
+#define _THIS_IP_ ({ unsigned long __ip; asm volatile("1: adr %0, 1b" : "=r"
(__ip)); __ip; })
+
#endif
diff --git a/arch/arm64/include/asm/linkage.h b/arch/arm64/include/asm/linkage.h
index 40bd17add539..73eabc82a6bb 100644
--- a/arch/arm64/include/asm/linkage.h
+++ b/arch/arm64/include/asm/linkage.h
@@ -43,4 +43,6 @@
SYM_TYPED_START(name, SYM_L_GLOBAL, SYM_A_ALIGN) \
bti c ;
+#define _THIS_IP_ ({ unsigned long __ip; asm volatile("adr %0, ." : "=r"
(__ip)); __ip; })
+
#endif
diff --git a/arch/csky/include/asm/linkage.h b/arch/csky/include/asm/linkage.h
new file mode 100644
index 000000000000..04afd3583e25
--- /dev/null
+++ b/arch/csky/include/asm/linkage.h
@@ -0,0 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ASM_CSKY_LINKAGE_H
+#define __ASM_CSKY_LINKAGE_H
+
+#define _THIS_IP_ ({ unsigned long __ip; asm volatile("grs %0, ." : "=r"
(__ip)); __ip; })
+
+#endif /* __ASM_CSKY_LINKAGE_H */
diff --git a/arch/hexagon/include/asm/linkage.h
b/arch/hexagon/include/asm/linkage.h
index ebdb581939e8..b3808f093e62 100644
--- a/arch/hexagon/include/asm/linkage.h
+++ b/arch/hexagon/include/asm/linkage.h
@@ -9,4 +9,6 @@
#define __ALIGN .align 4
#define __ALIGN_STR ".align 4"
+#define _THIS_IP_ ({ unsigned long __ip; asm volatile("call 1f\n1: %0 = r31" :
"=r" (__ip) : : "r31"); __ip; })
+
#endif
diff --git a/arch/loongarch/include/asm/linkage.h
b/arch/loongarch/include/asm/linkage.h
index a1bd6a3ee03a..f175b25068d7 100644
--- a/arch/loongarch/include/asm/linkage.h
+++ b/arch/loongarch/include/asm/linkage.h
@@ -77,4 +77,6 @@
#define SYM_SIGFUNC_END(name) SYM_FUNC_END(name)
+#define _THIS_IP_ ({ unsigned long __ip; asm volatile("pcaddi %0, 0" : "=r"
(__ip)); __ip; })
+
#endif
diff --git a/arch/m68k/include/asm/linkage.h b/arch/m68k/include/asm/linkage.h
index c8b84282764c..9ed2f36830d0 100644
--- a/arch/m68k/include/asm/linkage.h
+++ b/arch/m68k/include/asm/linkage.h
@@ -35,4 +35,6 @@
__asmlinkage_protect_n(ret, "m" (arg1), "m" (arg2), "m" (arg3), \
"m" (arg4), "m" (arg5), "m" (arg6))
+#define _THIS_IP_ ({ unsigned long __ip; asm volatile("lea %%pc@(.), %0" :
"=a" (__ip)); __ip; })
+
#endif
diff --git a/arch/microblaze/include/asm/linkage.h
b/arch/microblaze/include/asm/linkage.h
new file mode 100644
index 000000000000..fc3873e0e9b6
--- /dev/null
+++ b/arch/microblaze/include/asm/linkage.h
@@ -0,0 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_MICROBLAZE_LINKAGE_H
+#define _ASM_MICROBLAZE_LINKAGE_H
+
+#define _THIS_IP_ ({ unsigned long __ip; asm volatile("mfs %0, rpc" : "=r"
(__ip)); __ip; })
+
+#endif /* _ASM_MICROBLAZE_LINKAGE_H */
diff --git a/arch/mips/include/asm/linkage.h b/arch/mips/include/asm/linkage.h
index fd44ba754f1a..0579eac57def 100644
--- a/arch/mips/include/asm/linkage.h
+++ b/arch/mips/include/asm/linkage.h
@@ -10,4 +10,14 @@
#define SYSCALL_ALIAS(alias, name) \
asm ( #alias " = " #name "\n\t.globl " #alias)
+#define _THIS_IP_ ({ \
+ unsigned long __ip; \
+ asm volatile("bal 1f\n\t" \
+ " nop\n\t" \
+ "1: move %0, $ra" \
+ : "=r" (__ip) : : "$ra" \
+ ); \
+ __ip; \
+})
+
#endif
diff --git a/arch/nios2/include/asm/linkage.h b/arch/nios2/include/asm/linkage.h
index 211302301a8a..c4073235852b 100644
--- a/arch/nios2/include/asm/linkage.h
+++ b/arch/nios2/include/asm/linkage.h
@@ -12,4 +12,6 @@
#define __ALIGN .align 4
#define __ALIGN_STR ".align 4"
+#define _THIS_IP_ ({ unsigned long __ip; asm volatile("nextpc %0" : "=r"
(__ip)); __ip; })
+
#endif
diff --git a/arch/openrisc/include/asm/linkage.h
b/arch/openrisc/include/asm/linkage.h
index 25aa449ac30e..a96e808b5d1a 100644
--- a/arch/openrisc/include/asm/linkage.h
+++ b/arch/openrisc/include/asm/linkage.h
@@ -18,4 +18,14 @@
#define __ALIGN .align 0
#define __ALIGN_STR ".align 0"
+#define _THIS_IP_ ({ \
+ unsigned long __ip; \
+ asm volatile("l.jal 1f\n\t" \
+ " l.nop\n\t" \
+ "1: l.ori %0, r9, 0" \
+ : "=r" (__ip) : : "r9" \
+ ); \
+ __ip; \
+})
+
#endif /* __ASM_OPENRISC_LINKAGE_H */
diff --git a/arch/parisc/include/asm/linkage.h
b/arch/parisc/include/asm/linkage.h
index d4cad492b971..d4d8ff7735c7 100644
--- a/arch/parisc/include/asm/linkage.h
+++ b/arch/parisc/include/asm/linkage.h
@@ -37,4 +37,12 @@ name: ASM_NL\
#endif /* __ASSEMBLER__ */
+#define _THIS_IP_ ({ \
+ unsigned long __ip; \
+ asm volatile("b,l 1f, %0\n\t" \
+ " nop\n\t" \
+ "1:" : "=r" (__ip)); \
+ __ip; \
+})
+
#endif /* __ASM_PARISC_LINKAGE_H */
diff --git a/arch/powerpc/include/asm/linkage.h
b/arch/powerpc/include/asm/linkage.h
index b71b9582e754..aa469e7bef0b 100644
--- a/arch/powerpc/include/asm/linkage.h
+++ b/arch/powerpc/include/asm/linkage.h
@@ -13,4 +13,13 @@
"\t.globl ." #alias "\n\t.set ." #alias ", ." #name)
#endif
+#define _THIS_IP_ ({ \
+ unsigned long __ip; \
+ asm volatile("bcl 20,31,1f\n\t" \
+ "1: mflr %0" \
+ : "=r" (__ip) : : "lr" \
+ ); \
+ __ip; \
+})
+
#endif /* _ASM_POWERPC_LINKAGE_H */
diff --git a/arch/riscv/include/asm/linkage.h b/arch/riscv/include/asm/linkage.h
index 9e88ba23cd2b..7e0210ef4eb4 100644
--- a/arch/riscv/include/asm/linkage.h
+++ b/arch/riscv/include/asm/linkage.h
@@ -9,4 +9,6 @@
#define __ALIGN .balign 4
#define __ALIGN_STR ".balign 4"
+#define _THIS_IP_ ({ unsigned long __ip; asm volatile("auipc %0, 0" : "=r"
(__ip)); __ip; })
+
#endif /* _ASM_RISCV_LINKAGE_H */
diff --git a/arch/s390/include/asm/linkage.h b/arch/s390/include/asm/linkage.h
index df3fb7d8227b..1b3ac553a642 100644
--- a/arch/s390/include/asm/linkage.h
+++ b/arch/s390/include/asm/linkage.h
@@ -7,4 +7,6 @@
#define __ALIGN .balign CONFIG_FUNCTION_ALIGNMENT, 0x07
#define __ALIGN_STR __stringify(__ALIGN)
+#define _THIS_IP_ ({ unsigned long __ip; asm volatile("larl %0, ." : "=d"
(__ip)); __ip; })
+
#endif
diff --git a/arch/sh/include/asm/linkage.h b/arch/sh/include/asm/linkage.h
index 7c2fa27a43f8..af56b38b6001 100644
--- a/arch/sh/include/asm/linkage.h
+++ b/arch/sh/include/asm/linkage.h
@@ -5,4 +5,6 @@
#define __ALIGN .balign 4
#define __ALIGN_STR ".balign 4"
+#define _THIS_IP_ ({ unsigned long __ip; asm volatile("mova 1f, %0\n1:" : "=z"
(__ip)); __ip; })
+
#endif
diff --git a/arch/sparc/include/asm/linkage.h b/arch/sparc/include/asm/linkage.h
new file mode 100644
index 000000000000..3f24e2da88be
--- /dev/null
+++ b/arch/sparc/include/asm/linkage.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_SPARC_LINKAGE_H
+#define _ASM_SPARC_LINKAGE_H
+
+#ifdef CONFIG_SPARC64
+#define _THIS_IP_ ({ unsigned long __ip; asm volatile("rd %%pc, %0" : "=r"
(__ip)); __ip; })
+#else
+#define _THIS_IP_ ({ \
+ unsigned long __ip; \
+ asm volatile("call 1f\n\t" \
+ " nop\n\t" \
+ "1: mov %%o7, %0" \
+ : "=r" (__ip) : : "o7" \
+ ); \
+ __ip; \
+})
+#endif
+
+#endif /* _ASM_SPARC_LINKAGE_H */
diff --git a/arch/x86/include/asm/linkage.h b/arch/x86/include/asm/linkage.h
index a7294656ad90..bce3c6f4b94f 100644
--- a/arch/x86/include/asm/linkage.h
+++ b/arch/x86/include/asm/linkage.h
@@ -13,11 +13,12 @@
* The generic version tends to create spurious ENDBR instructions under
* certain conditions.
*/
-#define _THIS_IP_ ({ unsigned long __here; asm ("lea 0(%%rip), %0" : "=r"
(__here)); __here; })
+#define _THIS_IP_ ({ unsigned long __here; asm volatile("lea 0(%%rip), %0" :
"=r" (__here)); __here; })
#endif
#ifdef CONFIG_X86_32
#define asmlinkage CPP_ASMLINKAGE __attribute__((regparm(0)))
+#define _THIS_IP_ ({ unsigned long __ip; asm volatile("call 1f\n1: pop %0" :
"=r" (__ip)); __ip; })
#endif /* CONFIG_X86_32 */
#define __ALIGN .balign CONFIG_FUNCTION_ALIGNMENT, 0x90;
diff --git a/arch/xtensa/include/asm/linkage.h
b/arch/xtensa/include/asm/linkage.h
index 0ba9973235d9..9e6f5cc81964 100644
--- a/arch/xtensa/include/asm/linkage.h
+++ b/arch/xtensa/include/asm/linkage.h
@@ -6,4 +6,6 @@
#define __ALIGN .align 4
#define __ALIGN_STR ".align 4"
+#define _THIS_IP_ ({ unsigned long __ip; asm volatile("call0 1f\n1: mov %0,
a0" : "=r" (__ip) : : "a0"); __ip; })
+
#endif
diff --git a/include/linux/instruction_pointer.h
b/include/linux/instruction_pointer.h
index aa0b3ffea935..dfe73aafddb8 100644
--- a/include/linux/instruction_pointer.h
+++ b/include/linux/instruction_pointer.h
@@ -8,6 +8,30 @@
#ifndef _THIS_IP_
#define _THIS_IP_ ({ __label__ __here; __here: (unsigned long)&&__here; })
+/*
+ * The current generic definition of _THIS_IP_ is considered broken by GCC [1]
+ * and Clang [2]. In particular, the address of a label is only expected to be
+ * used with a computed goto.
+ *
+ * [1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120071
+ * [2] https://github.com/llvm/llvm-project/issues/138272
+ *
+ * Mark it as broken, so that appropriate fallback options can be implemented
+ * for architectures that do not define their won _THIS_IP_.
+ */
+#define HAS_BROKEN_THIS_IP
+#endif
+
+/*
+ * _CODE_LOCATION_ provides a unique identifier for the current code location.
+ * When _THIS_IP_ is broken (generic version), we fall back to a static marker
+ * which guarantees uniqueness and resolves to a constant address at link time,
+ * avoiding runtime overhead and compiler optimizations breaking it.
+ */
+#ifdef HAS_BROKEN_THIS_IP
+#define _CODE_LOCATION_ ({ static const char __here; (unsigned long)&__here; })
+#else
+#define _CODE_LOCATION_ _THIS_IP_
#endif
#endif /* _LINUX_INSTRUCTION_POINTER_H */
diff --git a/include/linux/slab.h b/include/linux/slab.h
index 5e1249e36b0d..a4bf1585411f 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -503,7 +503,7 @@ int kmem_cache_shrink(struct kmem_cache *s);
typedef struct { unsigned long v; } kmalloc_token_t;
#ifdef CONFIG_KMALLOC_PARTITION_RANDOM
extern unsigned long random_kmalloc_seed;
-#define __kmalloc_token(...) ((kmalloc_token_t){ .v = _RET_IP_ })
+#define __kmalloc_token(...) ((kmalloc_token_t){ .v = _CODE_LOCATION_ })
#elif defined(CONFIG_KMALLOC_PARTITION_TYPED)
#define __kmalloc_token(...) ((kmalloc_token_t){ .v =
__builtin_infer_alloc_token(__VA_ARGS__) })
#endif