mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-28 11:18:45 +07:00
0c389d89ab
Now that we've renamed probe_kernel_address() to get_kernel_nofault() and made it look and behave more in line with get_user(), some of the subtle type behavior differences end up being more obvious and possibly dangerous. When you do get_user(val, user_ptr); the type of the access comes from the "user_ptr" part, and the above basically acts as val = *user_ptr; by design (except, of course, for the fact that the actual dereference is done with a user access). Note how in the above case, the type of the end result comes from the pointer argument, and then the value is cast to the type of 'val' as part of the assignment. So the type of the pointer is ultimately the more important type both for the access itself. But 'get_kernel_nofault()' may now _look_ similar, but it behaves very differently. When you do get_kernel_nofault(val, kernel_ptr); it behaves like val = *(typeof(val) *)kernel_ptr; except, of course, for the fact that the actual dereference is done with exception handling so that a faulting access is suppressed and returned as the error code. But note how different the casting behavior of the two superficially similar accesses are: one does the actual access in the size of the type the pointer points to, while the other does the access in the size of the target, and ignores the pointer type entirely. Actually changing get_kernel_nofault() to act like get_user() is almost certainly the right thing to do eventually, but in the meantime this patch adds logit to at least verify that the pointer type is compatible with the type of the result. In many cases, this involves just casting the pointer to 'void *' to make it obvious that the type of the pointer is not the important part. It's not how 'get_user()' acts, but at least the behavioral difference is now obvious and explicit. Cc: Christoph Hellwig <hch@lst.de> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
107 lines
2.4 KiB
C
107 lines
2.4 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
#ifndef _ASM_POWERPC_SECTIONS_H
|
|
#define _ASM_POWERPC_SECTIONS_H
|
|
#ifdef __KERNEL__
|
|
|
|
#include <linux/elf.h>
|
|
#include <linux/uaccess.h>
|
|
|
|
#define arch_is_kernel_initmem_freed arch_is_kernel_initmem_freed
|
|
|
|
#include <asm-generic/sections.h>
|
|
|
|
extern bool init_mem_is_free;
|
|
|
|
static inline int arch_is_kernel_initmem_freed(unsigned long addr)
|
|
{
|
|
if (!init_mem_is_free)
|
|
return 0;
|
|
|
|
return addr >= (unsigned long)__init_begin &&
|
|
addr < (unsigned long)__init_end;
|
|
}
|
|
|
|
extern char __head_end[];
|
|
|
|
#ifdef __powerpc64__
|
|
|
|
extern char __start_interrupts[];
|
|
extern char __end_interrupts[];
|
|
|
|
extern char __prom_init_toc_start[];
|
|
extern char __prom_init_toc_end[];
|
|
|
|
#ifdef CONFIG_PPC_POWERNV
|
|
extern char start_real_trampolines[];
|
|
extern char end_real_trampolines[];
|
|
extern char start_virt_trampolines[];
|
|
extern char end_virt_trampolines[];
|
|
#endif
|
|
|
|
static inline int in_kernel_text(unsigned long addr)
|
|
{
|
|
if (addr >= (unsigned long)_stext && addr < (unsigned long)__init_end)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static inline unsigned long kernel_toc_addr(void)
|
|
{
|
|
/* Defined by the linker, see vmlinux.lds.S */
|
|
extern unsigned long __toc_start;
|
|
|
|
/*
|
|
* The TOC register (r2) points 32kB into the TOC, so that 64kB of
|
|
* the TOC can be addressed using a single machine instruction.
|
|
*/
|
|
return (unsigned long)(&__toc_start) + 0x8000UL;
|
|
}
|
|
|
|
static inline int overlaps_interrupt_vector_text(unsigned long start,
|
|
unsigned long end)
|
|
{
|
|
unsigned long real_start, real_end;
|
|
real_start = __start_interrupts - _stext;
|
|
real_end = __end_interrupts - _stext;
|
|
|
|
return start < (unsigned long)__va(real_end) &&
|
|
(unsigned long)__va(real_start) < end;
|
|
}
|
|
|
|
static inline int overlaps_kernel_text(unsigned long start, unsigned long end)
|
|
{
|
|
return start < (unsigned long)__init_end &&
|
|
(unsigned long)_stext < end;
|
|
}
|
|
|
|
#ifdef PPC64_ELF_ABI_v1
|
|
|
|
#define HAVE_DEREFERENCE_FUNCTION_DESCRIPTOR 1
|
|
|
|
#undef dereference_function_descriptor
|
|
static inline void *dereference_function_descriptor(void *ptr)
|
|
{
|
|
struct ppc64_opd_entry *desc = ptr;
|
|
void *p;
|
|
|
|
if (!get_kernel_nofault(p, (void *)&desc->funcaddr))
|
|
ptr = p;
|
|
return ptr;
|
|
}
|
|
|
|
#undef dereference_kernel_function_descriptor
|
|
static inline void *dereference_kernel_function_descriptor(void *ptr)
|
|
{
|
|
if (ptr < (void *)__start_opd || ptr >= (void *)__end_opd)
|
|
return ptr;
|
|
|
|
return dereference_function_descriptor(ptr);
|
|
}
|
|
#endif /* PPC64_ELF_ABI_v1 */
|
|
|
|
#endif
|
|
|
|
#endif /* __KERNEL__ */
|
|
#endif /* _ASM_POWERPC_SECTIONS_H */
|