cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ptrace.c (8731B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright 2010 Tilera Corporation. All Rights Reserved.
      4 * Copyright 2015 Regents of the University of California
      5 * Copyright 2017 SiFive
      6 *
      7 * Copied from arch/tile/kernel/ptrace.c
      8 */
      9
     10#include <asm/ptrace.h>
     11#include <asm/syscall.h>
     12#include <asm/thread_info.h>
     13#include <asm/switch_to.h>
     14#include <linux/audit.h>
     15#include <linux/compat.h>
     16#include <linux/ptrace.h>
     17#include <linux/elf.h>
     18#include <linux/regset.h>
     19#include <linux/sched.h>
     20#include <linux/sched/task_stack.h>
     21
     22#define CREATE_TRACE_POINTS
     23#include <trace/events/syscalls.h>
     24
     25enum riscv_regset {
     26	REGSET_X,
     27#ifdef CONFIG_FPU
     28	REGSET_F,
     29#endif
     30};
     31
     32static int riscv_gpr_get(struct task_struct *target,
     33			 const struct user_regset *regset,
     34			 struct membuf to)
     35{
     36	return membuf_write(&to, task_pt_regs(target),
     37			    sizeof(struct user_regs_struct));
     38}
     39
     40static int riscv_gpr_set(struct task_struct *target,
     41			 const struct user_regset *regset,
     42			 unsigned int pos, unsigned int count,
     43			 const void *kbuf, const void __user *ubuf)
     44{
     45	struct pt_regs *regs;
     46
     47	regs = task_pt_regs(target);
     48	return user_regset_copyin(&pos, &count, &kbuf, &ubuf, regs, 0, -1);
     49}
     50
     51#ifdef CONFIG_FPU
     52static int riscv_fpr_get(struct task_struct *target,
     53			 const struct user_regset *regset,
     54			 struct membuf to)
     55{
     56	struct __riscv_d_ext_state *fstate = &target->thread.fstate;
     57
     58	if (target == current)
     59		fstate_save(current, task_pt_regs(current));
     60
     61	membuf_write(&to, fstate, offsetof(struct __riscv_d_ext_state, fcsr));
     62	membuf_store(&to, fstate->fcsr);
     63	return membuf_zero(&to, 4);	// explicitly pad
     64}
     65
     66static int riscv_fpr_set(struct task_struct *target,
     67			 const struct user_regset *regset,
     68			 unsigned int pos, unsigned int count,
     69			 const void *kbuf, const void __user *ubuf)
     70{
     71	int ret;
     72	struct __riscv_d_ext_state *fstate = &target->thread.fstate;
     73
     74	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, fstate, 0,
     75				 offsetof(struct __riscv_d_ext_state, fcsr));
     76	if (!ret) {
     77		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, fstate, 0,
     78					 offsetof(struct __riscv_d_ext_state, fcsr) +
     79					 sizeof(fstate->fcsr));
     80	}
     81
     82	return ret;
     83}
     84#endif
     85
     86static const struct user_regset riscv_user_regset[] = {
     87	[REGSET_X] = {
     88		.core_note_type = NT_PRSTATUS,
     89		.n = ELF_NGREG,
     90		.size = sizeof(elf_greg_t),
     91		.align = sizeof(elf_greg_t),
     92		.regset_get = riscv_gpr_get,
     93		.set = riscv_gpr_set,
     94	},
     95#ifdef CONFIG_FPU
     96	[REGSET_F] = {
     97		.core_note_type = NT_PRFPREG,
     98		.n = ELF_NFPREG,
     99		.size = sizeof(elf_fpreg_t),
    100		.align = sizeof(elf_fpreg_t),
    101		.regset_get = riscv_fpr_get,
    102		.set = riscv_fpr_set,
    103	},
    104#endif
    105};
    106
    107static const struct user_regset_view riscv_user_native_view = {
    108	.name = "riscv",
    109	.e_machine = EM_RISCV,
    110	.regsets = riscv_user_regset,
    111	.n = ARRAY_SIZE(riscv_user_regset),
    112};
    113
    114struct pt_regs_offset {
    115	const char *name;
    116	int offset;
    117};
    118
    119#define REG_OFFSET_NAME(r) {.name = #r, .offset = offsetof(struct pt_regs, r)}
    120#define REG_OFFSET_END {.name = NULL, .offset = 0}
    121
    122static const struct pt_regs_offset regoffset_table[] = {
    123	REG_OFFSET_NAME(epc),
    124	REG_OFFSET_NAME(ra),
    125	REG_OFFSET_NAME(sp),
    126	REG_OFFSET_NAME(gp),
    127	REG_OFFSET_NAME(tp),
    128	REG_OFFSET_NAME(t0),
    129	REG_OFFSET_NAME(t1),
    130	REG_OFFSET_NAME(t2),
    131	REG_OFFSET_NAME(s0),
    132	REG_OFFSET_NAME(s1),
    133	REG_OFFSET_NAME(a0),
    134	REG_OFFSET_NAME(a1),
    135	REG_OFFSET_NAME(a2),
    136	REG_OFFSET_NAME(a3),
    137	REG_OFFSET_NAME(a4),
    138	REG_OFFSET_NAME(a5),
    139	REG_OFFSET_NAME(a6),
    140	REG_OFFSET_NAME(a7),
    141	REG_OFFSET_NAME(s2),
    142	REG_OFFSET_NAME(s3),
    143	REG_OFFSET_NAME(s4),
    144	REG_OFFSET_NAME(s5),
    145	REG_OFFSET_NAME(s6),
    146	REG_OFFSET_NAME(s7),
    147	REG_OFFSET_NAME(s8),
    148	REG_OFFSET_NAME(s9),
    149	REG_OFFSET_NAME(s10),
    150	REG_OFFSET_NAME(s11),
    151	REG_OFFSET_NAME(t3),
    152	REG_OFFSET_NAME(t4),
    153	REG_OFFSET_NAME(t5),
    154	REG_OFFSET_NAME(t6),
    155	REG_OFFSET_NAME(status),
    156	REG_OFFSET_NAME(badaddr),
    157	REG_OFFSET_NAME(cause),
    158	REG_OFFSET_NAME(orig_a0),
    159	REG_OFFSET_END,
    160};
    161
    162/**
    163 * regs_query_register_offset() - query register offset from its name
    164 * @name:	the name of a register
    165 *
    166 * regs_query_register_offset() returns the offset of a register in struct
    167 * pt_regs from its name. If the name is invalid, this returns -EINVAL;
    168 */
    169int regs_query_register_offset(const char *name)
    170{
    171	const struct pt_regs_offset *roff;
    172
    173	for (roff = regoffset_table; roff->name != NULL; roff++)
    174		if (!strcmp(roff->name, name))
    175			return roff->offset;
    176	return -EINVAL;
    177}
    178
    179/**
    180 * regs_within_kernel_stack() - check the address in the stack
    181 * @regs:      pt_regs which contains kernel stack pointer.
    182 * @addr:      address which is checked.
    183 *
    184 * regs_within_kernel_stack() checks @addr is within the kernel stack page(s).
    185 * If @addr is within the kernel stack, it returns true. If not, returns false.
    186 */
    187static bool regs_within_kernel_stack(struct pt_regs *regs, unsigned long addr)
    188{
    189	return (addr & ~(THREAD_SIZE - 1))  ==
    190		(kernel_stack_pointer(regs) & ~(THREAD_SIZE - 1));
    191}
    192
    193/**
    194 * regs_get_kernel_stack_nth() - get Nth entry of the stack
    195 * @regs:	pt_regs which contains kernel stack pointer.
    196 * @n:		stack entry number.
    197 *
    198 * regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which
    199 * is specified by @regs. If the @n th entry is NOT in the kernel stack,
    200 * this returns 0.
    201 */
    202unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, unsigned int n)
    203{
    204	unsigned long *addr = (unsigned long *)kernel_stack_pointer(regs);
    205
    206	addr += n;
    207	if (regs_within_kernel_stack(regs, (unsigned long)addr))
    208		return *addr;
    209	else
    210		return 0;
    211}
    212
    213void ptrace_disable(struct task_struct *child)
    214{
    215	clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
    216}
    217
    218long arch_ptrace(struct task_struct *child, long request,
    219		 unsigned long addr, unsigned long data)
    220{
    221	long ret = -EIO;
    222
    223	switch (request) {
    224	default:
    225		ret = ptrace_request(child, request, addr, data);
    226		break;
    227	}
    228
    229	return ret;
    230}
    231
    232/*
    233 * Allows PTRACE_SYSCALL to work.  These are called from entry.S in
    234 * {handle,ret_from}_syscall.
    235 */
    236__visible int do_syscall_trace_enter(struct pt_regs *regs)
    237{
    238	if (test_thread_flag(TIF_SYSCALL_TRACE))
    239		if (ptrace_report_syscall_entry(regs))
    240			return -1;
    241
    242	/*
    243	 * Do the secure computing after ptrace; failures should be fast.
    244	 * If this fails we might have return value in a0 from seccomp
    245	 * (via SECCOMP_RET_ERRNO/TRACE).
    246	 */
    247	if (secure_computing() == -1)
    248		return -1;
    249
    250#ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS
    251	if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
    252		trace_sys_enter(regs, syscall_get_nr(current, regs));
    253#endif
    254
    255	audit_syscall_entry(regs->a7, regs->a0, regs->a1, regs->a2, regs->a3);
    256	return 0;
    257}
    258
    259__visible void do_syscall_trace_exit(struct pt_regs *regs)
    260{
    261	audit_syscall_exit(regs);
    262
    263	if (test_thread_flag(TIF_SYSCALL_TRACE))
    264		ptrace_report_syscall_exit(regs, 0);
    265
    266#ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS
    267	if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
    268		trace_sys_exit(regs, regs_return_value(regs));
    269#endif
    270}
    271
    272#ifdef CONFIG_COMPAT
    273static int compat_riscv_gpr_get(struct task_struct *target,
    274				const struct user_regset *regset,
    275				struct membuf to)
    276{
    277	struct compat_user_regs_struct cregs;
    278
    279	regs_to_cregs(&cregs, task_pt_regs(target));
    280
    281	return membuf_write(&to, &cregs,
    282			    sizeof(struct compat_user_regs_struct));
    283}
    284
    285static int compat_riscv_gpr_set(struct task_struct *target,
    286				const struct user_regset *regset,
    287				unsigned int pos, unsigned int count,
    288				const void *kbuf, const void __user *ubuf)
    289{
    290	int ret;
    291	struct compat_user_regs_struct cregs;
    292
    293	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &cregs, 0, -1);
    294
    295	cregs_to_regs(&cregs, task_pt_regs(target));
    296
    297	return ret;
    298}
    299
    300static const struct user_regset compat_riscv_user_regset[] = {
    301	[REGSET_X] = {
    302		.core_note_type = NT_PRSTATUS,
    303		.n = ELF_NGREG,
    304		.size = sizeof(compat_elf_greg_t),
    305		.align = sizeof(compat_elf_greg_t),
    306		.regset_get = compat_riscv_gpr_get,
    307		.set = compat_riscv_gpr_set,
    308	},
    309#ifdef CONFIG_FPU
    310	[REGSET_F] = {
    311		.core_note_type = NT_PRFPREG,
    312		.n = ELF_NFPREG,
    313		.size = sizeof(elf_fpreg_t),
    314		.align = sizeof(elf_fpreg_t),
    315		.regset_get = riscv_fpr_get,
    316		.set = riscv_fpr_set,
    317	},
    318#endif
    319};
    320
    321static const struct user_regset_view compat_riscv_user_native_view = {
    322	.name = "riscv",
    323	.e_machine = EM_RISCV,
    324	.regsets = compat_riscv_user_regset,
    325	.n = ARRAY_SIZE(compat_riscv_user_regset),
    326};
    327
    328long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
    329			compat_ulong_t caddr, compat_ulong_t cdata)
    330{
    331	long ret = -EIO;
    332
    333	switch (request) {
    334	default:
    335		ret = compat_ptrace_request(child, request, caddr, cdata);
    336		break;
    337	}
    338
    339	return ret;
    340}
    341#endif /* CONFIG_COMPAT */
    342
    343const struct user_regset_view *task_user_regset_view(struct task_struct *task)
    344{
    345#ifdef CONFIG_COMPAT
    346	if (test_tsk_thread_flag(task, TIF_32BIT))
    347		return &compat_riscv_user_native_view;
    348	else
    349#endif
    350		return &riscv_user_native_view;
    351}