* [PATCH v2] sched: move stack_canary to the start of the randomizable region
@ 2026-05-09 3:50 Ruidong Tian
2026-05-12 16:16 ` Valentin Schneider
2026-11-06 16:07 ` Peter Zijlstra
0 siblings, 2 replies; 6+ messages in thread
From: Ruidong Tian @ 2026-05-09 3:50 UTC (permalink / raw)
To: mingo, peterz, juri.lelli, vincent.guittot, dietmar.eggemann,
rostedt, bsegall, mgorman, vschneid, kprateek.nayak
Cc: linux-kernel, oliver.yang, Ruidong Tian
task_struct keeps growing over time. On architectures that compute the
per-task stack canary offset from asm-offsets.h and pass it to the
compiler via -mstack-protector-guard-offset=, this growth eventually
pushes stack_canary beyond what the target ISA can encode.
On RISC-V, canary loads are emitted as
ld t0, TSK_STACK_CANARY(tp)
where TSK_STACK_CANARY must fit into a 12-bit signed immediate, i.e.
[-2048, 2047]. Once stack_canary sits past byte 2047 of task_struct,
the build fails with
cc1: error: '<N>' is not a valid offset in
'-mstack-protector-guard-offset='
* On RISC-V, CONFIG_STACKPROTECTOR_PER_TASK depends on !RANDSTRUCT,
so randomized_struct_fields_start/end always expand to nothing and
stack_canary lands at a small, stable offset well within the
12-bit signed immediate range. The build error goes away.
* On architectures that enable RANDSTRUCT for hardening, stack_canary
stays inside the randomized region and is still shuffled together
with the other fields by the layout randomization, so its hardening
coverage is preserved. asm-offsets-based architectures read the
shuffled offset at build time, so the generated canary accesses
remain correct.
pahole on a typical 64-bit config shows that the area around the
wakee_* fields already contains a usable hole:
struct __call_single_node wake_entry; /* 56 16 */
/* --- cacheline 1 boundary (64 bytes) --- */
unsigned int wakee_flips; /* 72 4 */
/* XXX 4 bytes hole, try to pack */
unsigned long int wakee_flip_decay_ts; /* 80 8 */
struct task_struct * last_wakee; /* 88 8 */
Move wakee_flips to sit after last_wakee. That opens up a clean
8-byte slot at offset 72 into which stack_canary fits exactly:
struct __call_single_node wake_entry; /* 56 16 */
/* --- cacheline 1 boundary (64 bytes) --- */
unsigned long stack_canary; /* 72 8 */
unsigned long int wakee_flip_decay_ts; /* 80 8 */
struct task_struct * last_wakee; /* 88 8 */
unsigned int wakee_flips; /* 96 4 */
Suggested-by: K Prateek Nayak <kprateek.nayak@amd.com>
Signed-off-by: Ruidong Tian <tianruidong@linux.alibaba.com>
---
include/linux/sched.h | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 368c7b4d7cb5..5064c4afd19c 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -848,9 +848,15 @@ struct task_struct {
int on_cpu;
struct __call_single_node wake_entry;
- unsigned int wakee_flips;
+
+#ifdef CONFIG_STACKPROTECTOR
+ /* Canary value for the -fstack-protector GCC feature: */
+ unsigned long stack_canary;
+#endif
+
unsigned long wakee_flip_decay_ts;
struct task_struct *last_wakee;
+ unsigned int wakee_flips;
/*
* recent_used_cpu is initially set as the last CPU used by a task
@@ -1060,10 +1066,6 @@ struct task_struct {
pid_t pid;
pid_t tgid;
-#ifdef CONFIG_STACKPROTECTOR
- /* Canary value for the -fstack-protector GCC feature: */
- unsigned long stack_canary;
-#endif
/*
* Pointers to the (original) parent process, youngest child, younger sibling,
* older sibling, respectively. (p->father can be replaced with
--
2.51.2.612.gdc70283dfc
^ permalink raw reply [flat|nested] 6+ messages in thread* Re: [PATCH v2] sched: move stack_canary to the start of the randomizable region 2026-05-09 3:50 [PATCH v2] sched: move stack_canary to the start of the randomizable region Ruidong Tian @ 2026-05-12 16:16 ` Valentin Schneider 2026-08-21 17:11 ` Charles Mirabile 2026-11-06 16:07 ` Peter Zijlstra 1 sibling, 1 reply; 6+ messages in thread From: Valentin Schneider @ 2026-05-12 16:16 UTC (permalink / raw) To: Ruidong Tian, mingo, peterz, juri.lelli, vincent.guittot, dietmar.eggemann, rostedt, bsegall, mgorman, kprateek.nayak Cc: linux-kernel, oliver.yang, Ruidong Tian On 09/05/26 11:50, Ruidong Tian wrote: > task_struct keeps growing over time. On architectures that compute the > per-task stack canary offset from asm-offsets.h and pass it to the > compiler via -mstack-protector-guard-offset=, this growth eventually > pushes stack_canary beyond what the target ISA can encode. > > On RISC-V, canary loads are emitted as > > ld t0, TSK_STACK_CANARY(tp) > > where TSK_STACK_CANARY must fit into a 12-bit signed immediate, i.e. > [-2048, 2047]. Once stack_canary sits past byte 2047 of task_struct, > the build fails with > > cc1: error: '<N>' is not a valid offset in > '-mstack-protector-guard-offset=' > > * On RISC-V, CONFIG_STACKPROTECTOR_PER_TASK depends on !RANDSTRUCT, > so randomized_struct_fields_start/end always expand to nothing and > stack_canary lands at a small, stable offset well within the > 12-bit signed immediate range. The build error goes away. > > * On architectures that enable RANDSTRUCT for hardening, stack_canary > stays inside the randomized region and is still shuffled together > with the other fields by the layout randomization, so its hardening > coverage is preserved. asm-offsets-based architectures read the > shuffled offset at build time, so the generated canary accesses > remain correct. > > pahole on a typical 64-bit config shows that the area around the > wakee_* fields already contains a usable hole: > > struct __call_single_node wake_entry; /* 56 16 */ > /* --- cacheline 1 boundary (64 bytes) --- */ > unsigned int wakee_flips; /* 72 4 */ > /* XXX 4 bytes hole, try to pack */ > unsigned long int wakee_flip_decay_ts; /* 80 8 */ > struct task_struct * last_wakee; /* 88 8 */ > > Move wakee_flips to sit after last_wakee. That opens up a clean > 8-byte slot at offset 72 into which stack_canary fits exactly: > > struct __call_single_node wake_entry; /* 56 16 */ > /* --- cacheline 1 boundary (64 bytes) --- */ > unsigned long stack_canary; /* 72 8 */ > unsigned long int wakee_flip_decay_ts; /* 80 8 */ > struct task_struct * last_wakee; /* 88 8 */ > unsigned int wakee_flips; /* 96 4 */ > > Suggested-by: K Prateek Nayak <kprateek.nayak@amd.com> > Signed-off-by: Ruidong Tian <tianruidong@linux.alibaba.com> Reviewed-by: Valentin Schneider <vschneid@redhat.com> ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v2] sched: move stack_canary to the start of the randomizable region 2026-05-12 16:16 ` Valentin Schneider @ 2026-08-21 17:11 ` Charles Mirabile 2026-11-06 15:29 ` Valentin Schneider 0 siblings, 1 reply; 6+ messages in thread From: Charles Mirabile @ 2026-08-21 17:11 UTC (permalink / raw) To: vschneid Cc: bsegall, dietmar.eggemann, juri.lelli, kprateek.nayak, linux-kernel, mgorman, mingo, oliver.yang, peterz, rostedt, tianruidong, vincent.guittot, pjw, palmer, aou, alex, linux-riscv Hi Ruidong, Valentin, (+ copying in RISC-V list/maintainers)— On Tue, May 12, 2026 at 06:16:43PM +0200, Valentin Schneider wrote: > On 09/05/26 11:50, Ruidong Tian wrote: > > task_struct keeps growing over time. On architectures that compute the > > per-task stack canary offset from asm-offsets.h and pass it to the > > compiler via -mstack-protector-guard-offset=, this growth eventually > > pushes stack_canary beyond what the target ISA can encode. > > > > On RISC-V, canary loads are emitted as > > > > ld t0, TSK_STACK_CANARY(tp) > > > > where TSK_STACK_CANARY must fit into a 12-bit signed immediate, i.e. > > [-2048, 2047]. Once stack_canary sits past byte 2047 of task_struct, > > the build fails with > > > > cc1: error: '<N>' is not a valid offset in > > '-mstack-protector-guard-offset=' Thanks for this patch. We just ran into this exact issue during a CKI build https://datawarehouse.cki-project.org/kcidb/builds/1639782 and this seems like exactly the fix we need. > > > > * On RISC-V, CONFIG_STACKPROTECTOR_PER_TASK depends on !RANDSTRUCT, > > so randomized_struct_fields_start/end always expand to nothing and > > stack_canary lands at a small, stable offset well within the > > 12-bit signed immediate range. The build error goes away. > > > > * On architectures that enable RANDSTRUCT for hardening, stack_canary > > stays inside the randomized region and is still shuffled together > > with the other fields by the layout randomization, so its hardening > > coverage is preserved. asm-offsets-based architectures read the > > shuffled offset at build time, so the generated canary accesses > > remain correct. > > > > pahole on a typical 64-bit config shows that the area around the > > wakee_* fields already contains a usable hole: > > > > struct __call_single_node wake_entry; /* 56 16 */ > > /* --- cacheline 1 boundary (64 bytes) --- */ > > unsigned int wakee_flips; /* 72 4 */ > > /* XXX 4 bytes hole, try to pack */ > > unsigned long int wakee_flip_decay_ts; /* 80 8 */ > > struct task_struct * last_wakee; /* 88 8 */ > > > > Move wakee_flips to sit after last_wakee. That opens up a clean > > 8-byte slot at offset 72 into which stack_canary fits exactly: > > > > struct __call_single_node wake_entry; /* 56 16 */ > > /* --- cacheline 1 boundary (64 bytes) --- */ > > unsigned long stack_canary; /* 72 8 */ > > unsigned long int wakee_flip_decay_ts; /* 80 8 */ > > struct task_struct * last_wakee; /* 88 8 */ > > unsigned int wakee_flips; /* 96 4 */ > > > > Suggested-by: K Prateek Nayak <kprateek.nayak@amd.com> > > Signed-off-by: Ruidong Tian <tianruidong@linux.alibaba.com> > > Reviewed-by: Valentin Schneider <vschneid@redhat.com> > Thanks for the review, is there any hope of this patch going in during the 7.3 merge window? I have also copied the RISC-V list as well, maybe if it is ok with the sched folks, the RISC-V maintainers could take it through their tree as a RISC-V specific urgent fix? Best—Charlie ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v2] sched: move stack_canary to the start of the randomizable region 2026-08-21 17:11 ` Charles Mirabile @ 2026-11-06 15:29 ` Valentin Schneider 0 siblings, 0 replies; 6+ messages in thread From: Valentin Schneider @ 2026-11-06 15:29 UTC (permalink / raw) To: Charles Mirabile Cc: bsegall, dietmar.eggemann, juri.lelli, kprateek.nayak, linux-kernel, mgorman, mingo, oliver.yang, peterz, rostedt, tianruidong, vincent.guittot, pjw, palmer, aou, alex, linux-riscv On 21/08/26 13:11, Charles Mirabile wrote: > Hi Ruidong, Valentin, (+ copying in RISC-V list/maintainers)— > > On Tue, May 12, 2026 at 06:16:43PM +0200, Valentin Schneider wrote: >> On 09/05/26 11:50, Ruidong Tian wrote: >> > task_struct keeps growing over time. On architectures that compute the >> > per-task stack canary offset from asm-offsets.h and pass it to the >> > compiler via -mstack-protector-guard-offset=, this growth eventually >> > pushes stack_canary beyond what the target ISA can encode. >> > >> > On RISC-V, canary loads are emitted as >> > >> > ld t0, TSK_STACK_CANARY(tp) >> > >> > where TSK_STACK_CANARY must fit into a 12-bit signed immediate, i.e. >> > [-2048, 2047]. Once stack_canary sits past byte 2047 of task_struct, >> > the build fails with >> > >> > cc1: error: '<N>' is not a valid offset in >> > '-mstack-protector-guard-offset=' > > Thanks for this patch. We just ran into this exact issue during a CKI build > https://datawarehouse.cki-project.org/kcidb/builds/1639782 and this seems > like exactly the fix we need. > I've also been pinged about this exact failure; Peter, Ingo, do you think you could take this? I couldn't find anything better than to add a LUI instruction to stretch the immediate beyond 2k, which is a bit wasteful. This looks okay for now, until someone smarter can come with a risc-v specific improvement (or the architecture grows scaled immediate offsets). ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v2] sched: move stack_canary to the start of the randomizable region 2026-05-09 3:50 [PATCH v2] sched: move stack_canary to the start of the randomizable region Ruidong Tian 2026-05-12 16:16 ` Valentin Schneider @ 2026-11-06 16:07 ` Peter Zijlstra 2026-11-06 16:14 ` Peter Zijlstra 1 sibling, 1 reply; 6+ messages in thread From: Peter Zijlstra @ 2026-11-06 16:07 UTC (permalink / raw) To: Ruidong Tian Cc: mingo, juri.lelli, vincent.guittot, dietmar.eggemann, rostedt, bsegall, mgorman, vschneid, kprateek.nayak, linux-kernel, oliver.yang On Sat, May 09, 2026 at 11:50:14AM +0800, Ruidong Tian wrote: > task_struct keeps growing over time. On architectures that compute the > per-task stack canary offset from asm-offsets.h and pass it to the > compiler via -mstack-protector-guard-offset=, this growth eventually > pushes stack_canary beyond what the target ISA can encode. > > On RISC-V, canary loads are emitted as > > ld t0, TSK_STACK_CANARY(tp) > > where TSK_STACK_CANARY must fit into a 12-bit signed immediate, i.e. > [-2048, 2047]. Once stack_canary sits past byte 2047 of task_struct, > the build fails with > > cc1: error: '<N>' is not a valid offset in > '-mstack-protector-guard-offset=' > > * On RISC-V, CONFIG_STACKPROTECTOR_PER_TASK depends on !RANDSTRUCT, > so randomized_struct_fields_start/end always expand to nothing and > stack_canary lands at a small, stable offset well within the > 12-bit signed immediate range. The build error goes away. > > * On architectures that enable RANDSTRUCT for hardening, stack_canary > stays inside the randomized region and is still shuffled together > with the other fields by the layout randomization, so its hardening > coverage is preserved. asm-offsets-based architectures read the > shuffled offset at build time, so the generated canary accesses > remain correct. > > pahole on a typical 64-bit config shows that the area around the > wakee_* fields already contains a usable hole: > > struct __call_single_node wake_entry; /* 56 16 */ > /* --- cacheline 1 boundary (64 bytes) --- */ > unsigned int wakee_flips; /* 72 4 */ > /* XXX 4 bytes hole, try to pack */ > unsigned long int wakee_flip_decay_ts; /* 80 8 */ > struct task_struct * last_wakee; /* 88 8 */ > > Move wakee_flips to sit after last_wakee. That opens up a clean > 8-byte slot at offset 72 into which stack_canary fits exactly: > > struct __call_single_node wake_entry; /* 56 16 */ > /* --- cacheline 1 boundary (64 bytes) --- */ > unsigned long stack_canary; /* 72 8 */ > unsigned long int wakee_flip_decay_ts; /* 80 8 */ > struct task_struct * last_wakee; /* 88 8 */ > unsigned int wakee_flips; /* 96 4 */ > > Suggested-by: K Prateek Nayak <kprateek.nayak@amd.com> > Signed-off-by: Ruidong Tian <tianruidong@linux.alibaba.com> > --- > include/linux/sched.h | 12 +++++++----- > 1 file changed, 7 insertions(+), 5 deletions(-) > > diff --git a/include/linux/sched.h b/include/linux/sched.h > index 368c7b4d7cb5..5064c4afd19c 100644 > --- a/include/linux/sched.h > +++ b/include/linux/sched.h > @@ -848,9 +848,15 @@ struct task_struct { > > int on_cpu; > struct __call_single_node wake_entry; > - unsigned int wakee_flips; > + > +#ifdef CONFIG_STACKPROTECTOR > + /* Canary value for the -fstack-protector GCC feature: */ > + unsigned long stack_canary; > +#endif > + > unsigned long wakee_flip_decay_ts; > struct task_struct *last_wakee; > + unsigned int wakee_flips; > > /* > * recent_used_cpu is initially set as the last CPU used by a task > @@ -1060,10 +1066,6 @@ struct task_struct { > pid_t pid; > pid_t tgid; > > -#ifdef CONFIG_STACKPROTECTOR > - /* Canary value for the -fstack-protector GCC feature: */ > - unsigned long stack_canary; > -#endif > /* > * Pointers to the (original) parent process, youngest child, younger sibling, > * older sibling, respectively. (p->father can be replaced with This seems exceedingly random; and very prone to also randomly breaking as task_struct is further modified. Why not do something a little more structured; like so? --- arch/riscv/include/asm/stackprotector.h | 4 ++-- arch/riscv/include/asm/thread_info.h | 7 +++++++ arch/riscv/kernel/asm-offsets.c | 7 +++---- drivers/misc/lkdtm/bugs.c | 4 ++-- include/linux/sched.h | 6 +++++- kernel/fork.c | 2 +- 6 files changed, 20 insertions(+), 10 deletions(-) diff --git a/arch/riscv/include/asm/stackprotector.h b/arch/riscv/include/asm/stackprotector.h index 43895b90fe3f..b56e49ce0580 100644 --- a/arch/riscv/include/asm/stackprotector.h +++ b/arch/riscv/include/asm/stackprotector.h @@ -15,8 +15,8 @@ static __always_inline void boot_init_stack_canary(void) { unsigned long canary = get_random_canary(); - current->stack_canary = canary; + tsk_stack_canary(current) = canary; if (!IS_ENABLED(CONFIG_STACKPROTECTOR_PER_TASK)) - __stack_chk_guard = current->stack_canary; + __stack_chk_guard = tsk_stack_canary(current); } #endif /* _ASM_RISCV_STACKPROTECTOR_H */ diff --git a/arch/riscv/include/asm/thread_info.h b/arch/riscv/include/asm/thread_info.h index 55019fdfa9ec..eed764f06682 100644 --- a/arch/riscv/include/asm/thread_info.h +++ b/arch/riscv/include/asm/thread_info.h @@ -73,6 +73,9 @@ struct thread_info { */ unsigned long a0, a1, a2; #endif +#ifdef CONFIG_STACKPROTECTOR + unsigned long stack_canary; +#endif #ifdef CONFIG_RISCV_USER_CFI struct cfi_state user_cfi_state; #endif @@ -86,6 +89,10 @@ struct thread_info { #define INIT_SCS #endif +#ifdef CONFIG_STACKPROTECTOR +#define tsk_stack_canary(p) ((p)->thread_info.stack_canary) +#endif + /* * macros/functions for gaining access to the thread information structure * diff --git a/arch/riscv/kernel/asm-offsets.c b/arch/riscv/kernel/asm-offsets.c index a75f0cfea1e9..eb694e1215bb 100644 --- a/arch/riscv/kernel/asm-offsets.c +++ b/arch/riscv/kernel/asm-offsets.c @@ -49,7 +49,9 @@ void asm_offsets(void) OFFSET(TASK_TI_A1, task_struct, thread_info.a1); OFFSET(TASK_TI_A2, task_struct, thread_info.a2); #endif - +#ifdef CONFIG_STACKPROTECTOR + OFFSET(TSK_STACK_CANARY, task_struct, thread_info.stack_canary); +#endif OFFSET(TASK_TI_CPU_NUM, task_struct, thread_info.cpu); #ifdef CONFIG_RISCV_USER_CFI OFFSET(TASK_TI_CFI_STATE, task_struct, thread_info.user_cfi_state); @@ -88,9 +90,6 @@ void asm_offsets(void) OFFSET(TASK_THREAD_F30, task_struct, thread.fstate.f[30]); OFFSET(TASK_THREAD_F31, task_struct, thread.fstate.f[31]); OFFSET(TASK_THREAD_FCSR, task_struct, thread.fstate.fcsr); -#ifdef CONFIG_STACKPROTECTOR - OFFSET(TSK_STACK_CANARY, task_struct, stack_canary); -#endif DEFINE(PT_SIZE, sizeof(struct pt_regs)); OFFSET(PT_EPC, pt_regs, epc); diff --git a/drivers/misc/lkdtm/bugs.c b/drivers/misc/lkdtm/bugs.c index 2761685cf4f8..977ee7584249 100644 --- a/drivers/misc/lkdtm/bugs.c +++ b/drivers/misc/lkdtm/bugs.c @@ -247,9 +247,9 @@ static noinline void __lkdtm_REPORT_STACK_CANARY(void *stack) for (i = 1; i < 16; i++) { canary = (unsigned long *)stack + i; #ifdef CONFIG_STACKPROTECTOR - if (*canary == current->stack_canary) + if (*canary == tsk_stack_canary(current)) current_offset = i; - if (*canary == init_task.stack_canary) + if (*canary == tsk_stack_canary(&init_task)) init_offset = i; #endif } diff --git a/include/linux/sched.h b/include/linux/sched.h index e4f6323d7855..b7702fefed63 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1083,7 +1083,7 @@ struct task_struct { pid_t pid; pid_t tgid; -#ifdef CONFIG_STACKPROTECTOR +#if defined(CONFIG_STACKPROTECTOR) && !defined(tsk_stack_canary) /* Canary value for the -fstack-protector GCC feature: */ unsigned long stack_canary; #endif @@ -1697,6 +1697,10 @@ struct task_struct { randomized_struct_fields_end } __attribute__ ((aligned (64))); +#if defined(CONFIG_STACKPROTECTOR) && !defined(tsk_stack_canary) +#define tsk_stack_canary(p) ((p)->stack_canary) +#endif + #ifdef CONFIG_SCHED_PROXY_EXEC DECLARE_STATIC_KEY_TRUE(__sched_proxy_exec); static inline bool sched_proxy_exec(void) diff --git a/kernel/fork.c b/kernel/fork.c index 5efceb8d58a7..878d586bda25 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -964,7 +964,7 @@ static struct task_struct *dup_task_struct(struct task_struct *orig, int node) clear_syscall_work_syscall_user_dispatch(tsk); #ifdef CONFIG_STACKPROTECTOR - tsk->stack_canary = get_random_canary(); + tsk_stack_canary(tsk) = get_random_canary(); #endif if (orig->cpus_ptr == &orig->cpus_mask) tsk->cpus_ptr = &tsk->cpus_mask; ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v2] sched: move stack_canary to the start of the randomizable region 2026-11-06 16:07 ` Peter Zijlstra @ 2026-11-06 16:14 ` Peter Zijlstra 0 siblings, 0 replies; 6+ messages in thread From: Peter Zijlstra @ 2026-11-06 16:14 UTC (permalink / raw) To: Ruidong Tian Cc: mingo, juri.lelli, vincent.guittot, dietmar.eggemann, rostedt, bsegall, mgorman, vschneid, kprateek.nayak, linux-kernel, oliver.yang On Fri, Nov 06, 2026 at 05:07:30PM +0100, Peter Zijlstra wrote: > Why not do something a little more structured; like so? > > --- > arch/riscv/include/asm/stackprotector.h | 4 ++-- > arch/riscv/include/asm/thread_info.h | 7 +++++++ > arch/riscv/kernel/asm-offsets.c | 7 +++---- > drivers/misc/lkdtm/bugs.c | 4 ++-- > include/linux/sched.h | 6 +++++- > kernel/fork.c | 2 +- > 6 files changed, 20 insertions(+), 10 deletions(-) > > diff --git a/arch/riscv/include/asm/stackprotector.h b/arch/riscv/include/asm/stackprotector.h > index 43895b90fe3f..b56e49ce0580 100644 > --- a/arch/riscv/include/asm/stackprotector.h > +++ b/arch/riscv/include/asm/stackprotector.h > @@ -15,8 +15,8 @@ static __always_inline void boot_init_stack_canary(void) > { > unsigned long canary = get_random_canary(); > > - current->stack_canary = canary; > + tsk_stack_canary(current) = canary; > if (!IS_ENABLED(CONFIG_STACKPROTECTOR_PER_TASK)) > - __stack_chk_guard = current->stack_canary; > + __stack_chk_guard = tsk_stack_canary(current); > } > #endif /* _ASM_RISCV_STACKPROTECTOR_H */ > diff --git a/arch/riscv/include/asm/thread_info.h b/arch/riscv/include/asm/thread_info.h > index 55019fdfa9ec..eed764f06682 100644 > --- a/arch/riscv/include/asm/thread_info.h > +++ b/arch/riscv/include/asm/thread_info.h > @@ -73,6 +73,9 @@ struct thread_info { > */ > unsigned long a0, a1, a2; > #endif > +#ifdef CONFIG_STACKPROTECTOR > + unsigned long stack_canary; > +#endif > #ifdef CONFIG_RISCV_USER_CFI > struct cfi_state user_cfi_state; > #endif > @@ -86,6 +89,10 @@ struct thread_info { > #define INIT_SCS > #endif > This should probably have a comment about 12 bit immediates somewhere. > +#ifdef CONFIG_STACKPROTECTOR > +#define tsk_stack_canary(p) ((p)->thread_info.stack_canary) > +#endif > + > /* > * macros/functions for gaining access to the thread information structure > * > diff --git a/arch/riscv/kernel/asm-offsets.c b/arch/riscv/kernel/asm-offsets.c > index a75f0cfea1e9..eb694e1215bb 100644 > --- a/arch/riscv/kernel/asm-offsets.c > +++ b/arch/riscv/kernel/asm-offsets.c > @@ -49,7 +49,9 @@ void asm_offsets(void) > OFFSET(TASK_TI_A1, task_struct, thread_info.a1); > OFFSET(TASK_TI_A2, task_struct, thread_info.a2); > #endif > - > +#ifdef CONFIG_STACKPROTECTOR > + OFFSET(TSK_STACK_CANARY, task_struct, thread_info.stack_canary); > +#endif > OFFSET(TASK_TI_CPU_NUM, task_struct, thread_info.cpu); > #ifdef CONFIG_RISCV_USER_CFI > OFFSET(TASK_TI_CFI_STATE, task_struct, thread_info.user_cfi_state); > @@ -88,9 +90,6 @@ void asm_offsets(void) > OFFSET(TASK_THREAD_F30, task_struct, thread.fstate.f[30]); > OFFSET(TASK_THREAD_F31, task_struct, thread.fstate.f[31]); > OFFSET(TASK_THREAD_FCSR, task_struct, thread.fstate.fcsr); > -#ifdef CONFIG_STACKPROTECTOR > - OFFSET(TSK_STACK_CANARY, task_struct, stack_canary); > -#endif > > DEFINE(PT_SIZE, sizeof(struct pt_regs)); > OFFSET(PT_EPC, pt_regs, epc); > diff --git a/drivers/misc/lkdtm/bugs.c b/drivers/misc/lkdtm/bugs.c > index 2761685cf4f8..977ee7584249 100644 > --- a/drivers/misc/lkdtm/bugs.c > +++ b/drivers/misc/lkdtm/bugs.c > @@ -247,9 +247,9 @@ static noinline void __lkdtm_REPORT_STACK_CANARY(void *stack) > for (i = 1; i < 16; i++) { > canary = (unsigned long *)stack + i; > #ifdef CONFIG_STACKPROTECTOR > - if (*canary == current->stack_canary) > + if (*canary == tsk_stack_canary(current)) > current_offset = i; > - if (*canary == init_task.stack_canary) > + if (*canary == tsk_stack_canary(&init_task)) > init_offset = i; > #endif > } > diff --git a/include/linux/sched.h b/include/linux/sched.h > index e4f6323d7855..b7702fefed63 100644 > --- a/include/linux/sched.h > +++ b/include/linux/sched.h > @@ -1083,7 +1083,7 @@ struct task_struct { > pid_t pid; > pid_t tgid; > > -#ifdef CONFIG_STACKPROTECTOR > +#if defined(CONFIG_STACKPROTECTOR) && !defined(tsk_stack_canary) > /* Canary value for the -fstack-protector GCC feature: */ > unsigned long stack_canary; > #endif > @@ -1697,6 +1697,10 @@ struct task_struct { > randomized_struct_fields_end > } __attribute__ ((aligned (64))); > > +#if defined(CONFIG_STACKPROTECTOR) && !defined(tsk_stack_canary) > +#define tsk_stack_canary(p) ((p)->stack_canary) > +#endif > + > #ifdef CONFIG_SCHED_PROXY_EXEC > DECLARE_STATIC_KEY_TRUE(__sched_proxy_exec); > static inline bool sched_proxy_exec(void) > diff --git a/kernel/fork.c b/kernel/fork.c > index 5efceb8d58a7..878d586bda25 100644 > --- a/kernel/fork.c > +++ b/kernel/fork.c > @@ -964,7 +964,7 @@ static struct task_struct *dup_task_struct(struct task_struct *orig, int node) > clear_syscall_work_syscall_user_dispatch(tsk); > > #ifdef CONFIG_STACKPROTECTOR > - tsk->stack_canary = get_random_canary(); > + tsk_stack_canary(tsk) = get_random_canary(); > #endif > if (orig->cpus_ptr == &orig->cpus_mask) > tsk->cpus_ptr = &tsk->cpus_mask; > > ^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-11-06 16:14 UTC | newest] Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2026-05-09 3:50 [PATCH v2] sched: move stack_canary to the start of the randomizable region Ruidong Tian 2026-05-12 16:16 ` Valentin Schneider 2026-08-21 17:11 ` Charles Mirabile 2026-11-06 15:29 ` Valentin Schneider 2026-11-06 16:07 ` Peter Zijlstra 2026-11-06 16:14 ` Peter Zijlstra
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®