xref: /linux-6.15/include/linux/sched/task_stack.h (revision fd7b4f9f)
1b2441318SGreg Kroah-Hartman /* SPDX-License-Identifier: GPL-2.0 */
268db0cf1SIngo Molnar #ifndef _LINUX_SCHED_TASK_STACK_H
368db0cf1SIngo Molnar #define _LINUX_SCHED_TASK_STACK_H
468db0cf1SIngo Molnar 
5f3ac6067SIngo Molnar /*
6f3ac6067SIngo Molnar  * task->stack (kernel stack) handling interfaces:
7f3ac6067SIngo Molnar  */
8f3ac6067SIngo Molnar 
968db0cf1SIngo Molnar #include <linux/sched.h>
1050d34394SIngo Molnar #include <linux/magic.h>
11f6120d52SKent Overstreet #include <linux/refcount.h>
12*fd7b4f9fSQun-Wei Lin #include <linux/kasan.h>
1368db0cf1SIngo Molnar 
14f3ac6067SIngo Molnar #ifdef CONFIG_THREAD_INFO_IN_TASK
15f3ac6067SIngo Molnar 
16f3ac6067SIngo Molnar /*
17f3ac6067SIngo Molnar  * When accessing the stack of a non-current task that might exit, use
18f3ac6067SIngo Molnar  * try_get_task_stack() instead.  task_stack_page will return a pointer
19f3ac6067SIngo Molnar  * that could get freed out from under you.
20f3ac6067SIngo Molnar  */
task_stack_page(const struct task_struct * task)21e87f4152SBorislav Petkov static __always_inline void *task_stack_page(const struct task_struct *task)
22f3ac6067SIngo Molnar {
23f3ac6067SIngo Molnar 	return task->stack;
24f3ac6067SIngo Molnar }
25f3ac6067SIngo Molnar 
26f3ac6067SIngo Molnar #define setup_thread_stack(new,old)	do { } while(0)
27f3ac6067SIngo Molnar 
end_of_stack(const struct task_struct * task)28e0b081d1SJosh Poimboeuf static __always_inline unsigned long *end_of_stack(const struct task_struct *task)
29f3ac6067SIngo Molnar {
309cc2fa4fSHelge Deller #ifdef CONFIG_STACK_GROWSUP
319cc2fa4fSHelge Deller 	return (unsigned long *)((unsigned long)task->stack + THREAD_SIZE) - 1;
329cc2fa4fSHelge Deller #else
33f3ac6067SIngo Molnar 	return task->stack;
349cc2fa4fSHelge Deller #endif
35f3ac6067SIngo Molnar }
36f3ac6067SIngo Molnar 
37f3ac6067SIngo Molnar #else
38f3ac6067SIngo Molnar 
39f3ac6067SIngo Molnar #define task_stack_page(task)	((void *)(task)->stack)
40f3ac6067SIngo Molnar 
setup_thread_stack(struct task_struct * p,struct task_struct * org)41f3ac6067SIngo Molnar static inline void setup_thread_stack(struct task_struct *p, struct task_struct *org)
42f3ac6067SIngo Molnar {
43f3ac6067SIngo Molnar 	*task_thread_info(p) = *task_thread_info(org);
44f3ac6067SIngo Molnar 	task_thread_info(p)->task = p;
45f3ac6067SIngo Molnar }
46f3ac6067SIngo Molnar 
47f3ac6067SIngo Molnar /*
48f3ac6067SIngo Molnar  * Return the address of the last usable long on the stack.
49f3ac6067SIngo Molnar  *
50f3ac6067SIngo Molnar  * When the stack grows down, this is just above the thread
51f3ac6067SIngo Molnar  * info struct. Going any lower will corrupt the threadinfo.
52f3ac6067SIngo Molnar  *
53f3ac6067SIngo Molnar  * When the stack grows up, this is the highest address.
54f3ac6067SIngo Molnar  * Beyond that position, we corrupt data on the next page.
55f3ac6067SIngo Molnar  */
end_of_stack(struct task_struct * p)56f3ac6067SIngo Molnar static inline unsigned long *end_of_stack(struct task_struct *p)
57f3ac6067SIngo Molnar {
58f3ac6067SIngo Molnar #ifdef CONFIG_STACK_GROWSUP
59f3ac6067SIngo Molnar 	return (unsigned long *)((unsigned long)task_thread_info(p) + THREAD_SIZE) - 1;
60f3ac6067SIngo Molnar #else
61f3ac6067SIngo Molnar 	return (unsigned long *)(task_thread_info(p) + 1);
62f3ac6067SIngo Molnar #endif
63f3ac6067SIngo Molnar }
64f3ac6067SIngo Molnar 
65f3ac6067SIngo Molnar #endif
66f3ac6067SIngo Molnar 
67f3ac6067SIngo Molnar #ifdef CONFIG_THREAD_INFO_IN_TASK
try_get_task_stack(struct task_struct * tsk)68f3ac6067SIngo Molnar static inline void *try_get_task_stack(struct task_struct *tsk)
69f3ac6067SIngo Molnar {
70f0b89d39SElena Reshetova 	return refcount_inc_not_zero(&tsk->stack_refcount) ?
71f3ac6067SIngo Molnar 		task_stack_page(tsk) : NULL;
72f3ac6067SIngo Molnar }
73f3ac6067SIngo Molnar 
74f3ac6067SIngo Molnar extern void put_task_stack(struct task_struct *tsk);
75f3ac6067SIngo Molnar #else
try_get_task_stack(struct task_struct * tsk)76f3ac6067SIngo Molnar static inline void *try_get_task_stack(struct task_struct *tsk)
77f3ac6067SIngo Molnar {
78f3ac6067SIngo Molnar 	return task_stack_page(tsk);
79f3ac6067SIngo Molnar }
80f3ac6067SIngo Molnar 
put_task_stack(struct task_struct * tsk)81f3ac6067SIngo Molnar static inline void put_task_stack(struct task_struct *tsk) {}
82f3ac6067SIngo Molnar #endif
83f3ac6067SIngo Molnar 
841a03d3f1SSebastian Andrzej Siewior void exit_task_stack_account(struct task_struct *tsk);
851a03d3f1SSebastian Andrzej Siewior 
86f3ac6067SIngo Molnar #define task_stack_end_corrupted(task) \
87f3ac6067SIngo Molnar 		(*(end_of_stack(task)) != STACK_END_MAGIC)
88f3ac6067SIngo Molnar 
object_is_on_stack(const void * obj)8900ef0ef2SSascha Hauer static inline int object_is_on_stack(const void *obj)
90f3ac6067SIngo Molnar {
91f3ac6067SIngo Molnar 	void *stack = task_stack_page(current);
92f3ac6067SIngo Molnar 
93*fd7b4f9fSQun-Wei Lin 	obj = kasan_reset_tag(obj);
94f3ac6067SIngo Molnar 	return (obj >= stack) && (obj < (stack + THREAD_SIZE));
95f3ac6067SIngo Molnar }
96f3ac6067SIngo Molnar 
97f3ac6067SIngo Molnar extern void thread_stack_cache_init(void);
98f3ac6067SIngo Molnar 
99f3ac6067SIngo Molnar #ifdef CONFIG_DEBUG_STACK_USAGE
100fbe76a65SPasha Tatashin unsigned long stack_not_used(struct task_struct *p);
101fbe76a65SPasha Tatashin #else
stack_not_used(struct task_struct * p)102f3ac6067SIngo Molnar static inline unsigned long stack_not_used(struct task_struct *p)
103f3ac6067SIngo Molnar {
104fbe76a65SPasha Tatashin 	return 0;
105f3ac6067SIngo Molnar }
106f3ac6067SIngo Molnar #endif
107f3ac6067SIngo Molnar extern void set_task_stack_end_magic(struct task_struct *tsk);
108f3ac6067SIngo Molnar 
1099049863aSIngo Molnar #ifndef __HAVE_ARCH_KSTACK_END
kstack_end(void * addr)1109049863aSIngo Molnar static inline int kstack_end(void *addr)
1119049863aSIngo Molnar {
1129049863aSIngo Molnar 	/* Reliable end of stack detection:
1139049863aSIngo Molnar 	 * Some APM bios versions misalign the stack
1149049863aSIngo Molnar 	 */
1159049863aSIngo Molnar 	return !(((unsigned long)addr+sizeof(void*)-1) & (THREAD_SIZE-sizeof(void*)));
1169049863aSIngo Molnar }
1179049863aSIngo Molnar #endif
1189049863aSIngo Molnar 
11968db0cf1SIngo Molnar #endif /* _LINUX_SCHED_TASK_STACK_H */
120