mirror of
git://git.yoctoproject.org/linux-yocto.git
synced 2025-07-04 21:05:23 +02:00

When CONFIG_KASAN_SW_TAGS and CONFIG_KASAN_STACK are enabled, the object_is_on_stack() function may produce incorrect results due to the presence of tags in the obj pointer, while the stack pointer does not have tags. This discrepancy can lead to incorrect stack object detection and subsequently trigger warnings if CONFIG_DEBUG_OBJECTS is also enabled. Example of the warning: ODEBUG: object 3eff800082ea7bb0 is NOT on stack ffff800082ea0000, but annotated. ------------[ cut here ]------------ WARNING: CPU: 0 PID: 1 at lib/debugobjects.c:557 __debug_object_init+0x330/0x364 Modules linked in: CPU: 0 UID: 0 PID: 1 Comm: swapper/0 Not tainted 6.12.0-rc5 #4 Hardware name: linux,dummy-virt (DT) pstate: 600000c5 (nZCv daIF -PAN -UAO -TCO -DIT -SSBS BTYPE=--) pc : __debug_object_init+0x330/0x364 lr : __debug_object_init+0x330/0x364 sp : ffff800082ea7b40 x29: ffff800082ea7b40 x28: 98ff0000c0164518 x27: 98ff0000c0164534 x26: ffff800082d93ec8 x25: 0000000000000001 x24: 1cff0000c00172a0 x23: 0000000000000000 x22: ffff800082d93ed0 x21: ffff800081a24418 x20: 3eff800082ea7bb0 x19: efff800000000000 x18: 0000000000000000 x17: 00000000000000ff x16: 0000000000000047 x15: 206b63617473206e x14: 0000000000000018 x13: ffff800082ea7780 x12: 0ffff800082ea78e x11: 0ffff800082ea790 x10: 0ffff800082ea79d x9 : 34d77febe173e800 x8 : 34d77febe173e800 x7 : 0000000000000001 x6 : 0000000000000001 x5 : feff800082ea74b8 x4 : ffff800082870a90 x3 : ffff80008018d3c4 x2 : 0000000000000001 x1 : ffff800082858810 x0 : 0000000000000050 Call trace: __debug_object_init+0x330/0x364 debug_object_init_on_stack+0x30/0x3c schedule_hrtimeout_range_clock+0xac/0x26c schedule_hrtimeout+0x1c/0x30 wait_task_inactive+0x1d4/0x25c kthread_bind_mask+0x28/0x98 init_rescuer+0x1e8/0x280 workqueue_init+0x1a0/0x3cc kernel_init_freeable+0x118/0x200 kernel_init+0x28/0x1f0 ret_from_fork+0x10/0x20 ---[ end trace 0000000000000000 ]--- ODEBUG: object 3eff800082ea7bb0 is NOT on stack ffff800082ea0000, but annotated. ------------[ cut here ]------------ Link: https://lkml.kernel.org/r/20241113042544.19095-1-qun-wei.lin@mediatek.com Signed-off-by: Qun-Wei Lin <qun-wei.lin@mediatek.com> Cc: Andrew Yang <andrew.yang@mediatek.com> Cc: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com> Cc: Casper Li <casper.li@mediatek.com> Cc: Catalin Marinas <catalin.marinas@arm.com> Cc: Chinwen Chang <chinwen.chang@mediatek.com> Cc: Kent Overstreet <kent.overstreet@linux.dev> Cc: Matthias Brugger <matthias.bgg@gmail.com> Cc: Pasha Tatashin <pasha.tatashin@soleen.com> Cc: Shakeel Butt <shakeel.butt@linux.dev> Cc: <stable@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
120 lines
3.0 KiB
C
120 lines
3.0 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
#ifndef _LINUX_SCHED_TASK_STACK_H
|
|
#define _LINUX_SCHED_TASK_STACK_H
|
|
|
|
/*
|
|
* task->stack (kernel stack) handling interfaces:
|
|
*/
|
|
|
|
#include <linux/sched.h>
|
|
#include <linux/magic.h>
|
|
#include <linux/refcount.h>
|
|
#include <linux/kasan.h>
|
|
|
|
#ifdef CONFIG_THREAD_INFO_IN_TASK
|
|
|
|
/*
|
|
* When accessing the stack of a non-current task that might exit, use
|
|
* try_get_task_stack() instead. task_stack_page will return a pointer
|
|
* that could get freed out from under you.
|
|
*/
|
|
static __always_inline void *task_stack_page(const struct task_struct *task)
|
|
{
|
|
return task->stack;
|
|
}
|
|
|
|
#define setup_thread_stack(new,old) do { } while(0)
|
|
|
|
static __always_inline unsigned long *end_of_stack(const struct task_struct *task)
|
|
{
|
|
#ifdef CONFIG_STACK_GROWSUP
|
|
return (unsigned long *)((unsigned long)task->stack + THREAD_SIZE) - 1;
|
|
#else
|
|
return task->stack;
|
|
#endif
|
|
}
|
|
|
|
#elif !defined(__HAVE_THREAD_FUNCTIONS)
|
|
|
|
#define task_stack_page(task) ((void *)(task)->stack)
|
|
|
|
static inline void setup_thread_stack(struct task_struct *p, struct task_struct *org)
|
|
{
|
|
*task_thread_info(p) = *task_thread_info(org);
|
|
task_thread_info(p)->task = p;
|
|
}
|
|
|
|
/*
|
|
* Return the address of the last usable long on the stack.
|
|
*
|
|
* When the stack grows down, this is just above the thread
|
|
* info struct. Going any lower will corrupt the threadinfo.
|
|
*
|
|
* When the stack grows up, this is the highest address.
|
|
* Beyond that position, we corrupt data on the next page.
|
|
*/
|
|
static inline unsigned long *end_of_stack(struct task_struct *p)
|
|
{
|
|
#ifdef CONFIG_STACK_GROWSUP
|
|
return (unsigned long *)((unsigned long)task_thread_info(p) + THREAD_SIZE) - 1;
|
|
#else
|
|
return (unsigned long *)(task_thread_info(p) + 1);
|
|
#endif
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef CONFIG_THREAD_INFO_IN_TASK
|
|
static inline void *try_get_task_stack(struct task_struct *tsk)
|
|
{
|
|
return refcount_inc_not_zero(&tsk->stack_refcount) ?
|
|
task_stack_page(tsk) : NULL;
|
|
}
|
|
|
|
extern void put_task_stack(struct task_struct *tsk);
|
|
#else
|
|
static inline void *try_get_task_stack(struct task_struct *tsk)
|
|
{
|
|
return task_stack_page(tsk);
|
|
}
|
|
|
|
static inline void put_task_stack(struct task_struct *tsk) {}
|
|
#endif
|
|
|
|
void exit_task_stack_account(struct task_struct *tsk);
|
|
|
|
#define task_stack_end_corrupted(task) \
|
|
(*(end_of_stack(task)) != STACK_END_MAGIC)
|
|
|
|
static inline int object_is_on_stack(const void *obj)
|
|
{
|
|
void *stack = task_stack_page(current);
|
|
|
|
obj = kasan_reset_tag(obj);
|
|
return (obj >= stack) && (obj < (stack + THREAD_SIZE));
|
|
}
|
|
|
|
extern void thread_stack_cache_init(void);
|
|
|
|
#ifdef CONFIG_DEBUG_STACK_USAGE
|
|
unsigned long stack_not_used(struct task_struct *p);
|
|
#else
|
|
static inline unsigned long stack_not_used(struct task_struct *p)
|
|
{
|
|
return 0;
|
|
}
|
|
#endif
|
|
extern void set_task_stack_end_magic(struct task_struct *tsk);
|
|
|
|
#ifndef __HAVE_ARCH_KSTACK_END
|
|
static inline int kstack_end(void *addr)
|
|
{
|
|
/* Reliable end of stack detection:
|
|
* Some APM bios versions misalign the stack
|
|
*/
|
|
return !(((unsigned long)addr+sizeof(void*)-1) & (THREAD_SIZE-sizeof(void*)));
|
|
}
|
|
#endif
|
|
|
|
#endif /* _LINUX_SCHED_TASK_STACK_H */
|