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_32.c (10488B)


      1// SPDX-License-Identifier: GPL-2.0
      2/* ptrace.c: Sparc process tracing support.
      3 *
      4 * Copyright (C) 1996, 2008 David S. Miller (davem@davemloft.net)
      5 *
      6 * Based upon code written by Ross Biro, Linus Torvalds, Bob Manson,
      7 * and David Mosberger.
      8 *
      9 * Added Linux support -miguel (weird, eh?, the original code was meant
     10 * to emulate SunOS).
     11 */
     12
     13#include <linux/kernel.h>
     14#include <linux/sched.h>
     15#include <linux/mm.h>
     16#include <linux/errno.h>
     17#include <linux/ptrace.h>
     18#include <linux/user.h>
     19#include <linux/smp.h>
     20#include <linux/security.h>
     21#include <linux/signal.h>
     22#include <linux/regset.h>
     23#include <linux/elf.h>
     24
     25#include <linux/uaccess.h>
     26#include <asm/cacheflush.h>
     27
     28#include "kernel.h"
     29
     30/* #define ALLOW_INIT_TRACING */
     31
     32/*
     33 * Called by kernel/ptrace.c when detaching..
     34 *
     35 * Make sure single step bits etc are not set.
     36 */
     37void ptrace_disable(struct task_struct *child)
     38{
     39	/* nothing to do */
     40}
     41
     42enum sparc_regset {
     43	REGSET_GENERAL,
     44	REGSET_FP,
     45};
     46
     47static int regwindow32_get(struct task_struct *target,
     48			   const struct pt_regs *regs,
     49			   u32 *uregs)
     50{
     51	unsigned long reg_window = regs->u_regs[UREG_I6];
     52	int size = 16 * sizeof(u32);
     53
     54	if (target == current) {
     55		if (copy_from_user(uregs, (void __user *)reg_window, size))
     56			return -EFAULT;
     57	} else {
     58		if (access_process_vm(target, reg_window, uregs, size,
     59				      FOLL_FORCE) != size)
     60			return -EFAULT;
     61	}
     62	return 0;
     63}
     64
     65static int regwindow32_set(struct task_struct *target,
     66			   const struct pt_regs *regs,
     67			   u32 *uregs)
     68{
     69	unsigned long reg_window = regs->u_regs[UREG_I6];
     70	int size = 16 * sizeof(u32);
     71
     72	if (target == current) {
     73		if (copy_to_user((void __user *)reg_window, uregs, size))
     74			return -EFAULT;
     75	} else {
     76		if (access_process_vm(target, reg_window, uregs, size,
     77				      FOLL_FORCE | FOLL_WRITE) != size)
     78			return -EFAULT;
     79	}
     80	return 0;
     81}
     82
     83static int genregs32_get(struct task_struct *target,
     84			 const struct user_regset *regset,
     85			 struct membuf to)
     86{
     87	const struct pt_regs *regs = target->thread.kregs;
     88	u32 uregs[16];
     89
     90	if (target == current)
     91		flush_user_windows();
     92
     93	membuf_write(&to, regs->u_regs, 16 * sizeof(u32));
     94	if (!to.left)
     95		return 0;
     96	if (regwindow32_get(target, regs, uregs))
     97		return -EFAULT;
     98	membuf_write(&to, uregs, 16 * sizeof(u32));
     99	membuf_store(&to, regs->psr);
    100	membuf_store(&to, regs->pc);
    101	membuf_store(&to, regs->npc);
    102	membuf_store(&to, regs->y);
    103	return membuf_zero(&to, 2 * sizeof(u32));
    104}
    105
    106static int genregs32_set(struct task_struct *target,
    107			 const struct user_regset *regset,
    108			 unsigned int pos, unsigned int count,
    109			 const void *kbuf, const void __user *ubuf)
    110{
    111	struct pt_regs *regs = target->thread.kregs;
    112	u32 uregs[16];
    113	u32 psr;
    114	int ret;
    115
    116	if (target == current)
    117		flush_user_windows();
    118
    119	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
    120				 regs->u_regs,
    121				 0, 16 * sizeof(u32));
    122	if (ret || !count)
    123		return ret;
    124
    125	if (regwindow32_get(target, regs, uregs))
    126		return -EFAULT;
    127	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
    128				 uregs,
    129				 16 * sizeof(u32), 32 * sizeof(u32));
    130	if (ret)
    131		return ret;
    132	if (regwindow32_set(target, regs, uregs))
    133		return -EFAULT;
    134	if (!count)
    135		return 0;
    136
    137	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
    138				 &psr,
    139				 32 * sizeof(u32), 33 * sizeof(u32));
    140	if (ret)
    141		return ret;
    142	regs->psr = (regs->psr & ~(PSR_ICC | PSR_SYSCALL)) |
    143		    (psr & (PSR_ICC | PSR_SYSCALL));
    144	if (!count)
    145		return 0;
    146	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
    147				 &regs->pc,
    148				 33 * sizeof(u32), 34 * sizeof(u32));
    149	if (ret || !count)
    150		return ret;
    151	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
    152				 &regs->npc,
    153				 34 * sizeof(u32), 35 * sizeof(u32));
    154	if (ret || !count)
    155		return ret;
    156	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
    157				 &regs->y,
    158				 35 * sizeof(u32), 36 * sizeof(u32));
    159	if (ret || !count)
    160		return ret;
    161	return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
    162					 36 * sizeof(u32), 38 * sizeof(u32));
    163}
    164
    165static int fpregs32_get(struct task_struct *target,
    166			const struct user_regset *regset,
    167			struct membuf to)
    168{
    169#if 0
    170	if (target == current)
    171		save_and_clear_fpu();
    172#endif
    173
    174	membuf_write(&to, target->thread.float_regs, 32 * sizeof(u32));
    175	membuf_zero(&to, sizeof(u32));
    176	membuf_write(&to, &target->thread.fsr, sizeof(u32));
    177	membuf_store(&to, (u32)((1 << 8) | (8 << 16)));
    178	return membuf_zero(&to, 64 * sizeof(u32));
    179}
    180
    181static int fpregs32_set(struct task_struct *target,
    182			const struct user_regset *regset,
    183			unsigned int pos, unsigned int count,
    184			const void *kbuf, const void __user *ubuf)
    185{
    186	unsigned long *fpregs = target->thread.float_regs;
    187	int ret;
    188
    189#if 0
    190	if (target == current)
    191		save_and_clear_fpu();
    192#endif
    193	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
    194				 fpregs,
    195				 0, 32 * sizeof(u32));
    196	if (!ret)
    197		user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
    198					  32 * sizeof(u32),
    199					  33 * sizeof(u32));
    200	if (!ret)
    201		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
    202					 &target->thread.fsr,
    203					 33 * sizeof(u32),
    204					 34 * sizeof(u32));
    205	if (!ret)
    206		ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
    207						34 * sizeof(u32), -1);
    208	return ret;
    209}
    210
    211static const struct user_regset sparc32_regsets[] = {
    212	/* Format is:
    213	 * 	G0 --> G7
    214	 *	O0 --> O7
    215	 *	L0 --> L7
    216	 *	I0 --> I7
    217	 *	PSR, PC, nPC, Y, WIM, TBR
    218	 */
    219	[REGSET_GENERAL] = {
    220		.core_note_type = NT_PRSTATUS,
    221		.n = 38,
    222		.size = sizeof(u32), .align = sizeof(u32),
    223		.regset_get = genregs32_get, .set = genregs32_set
    224	},
    225	/* Format is:
    226	 *	F0 --> F31
    227	 *	empty 32-bit word
    228	 *	FSR (32--bit word)
    229	 *	FPU QUEUE COUNT (8-bit char)
    230	 *	FPU QUEUE ENTRYSIZE (8-bit char)
    231	 *	FPU ENABLED (8-bit char)
    232	 *	empty 8-bit char
    233	 *	FPU QUEUE (64 32-bit ints)
    234	 */
    235	[REGSET_FP] = {
    236		.core_note_type = NT_PRFPREG,
    237		.n = 99,
    238		.size = sizeof(u32), .align = sizeof(u32),
    239		.regset_get = fpregs32_get, .set = fpregs32_set
    240	},
    241};
    242
    243static int getregs_get(struct task_struct *target,
    244			 const struct user_regset *regset,
    245			 struct membuf to)
    246{
    247	const struct pt_regs *regs = target->thread.kregs;
    248
    249	if (target == current)
    250		flush_user_windows();
    251
    252	membuf_store(&to, regs->psr);
    253	membuf_store(&to, regs->pc);
    254	membuf_store(&to, regs->npc);
    255	membuf_store(&to, regs->y);
    256	return membuf_write(&to, regs->u_regs + 1, 15 * sizeof(u32));
    257}
    258
    259static int setregs_set(struct task_struct *target,
    260			 const struct user_regset *regset,
    261			 unsigned int pos, unsigned int count,
    262			 const void *kbuf, const void __user *ubuf)
    263{
    264	struct pt_regs *regs = target->thread.kregs;
    265	u32 v[4];
    266	int ret;
    267
    268	if (target == current)
    269		flush_user_windows();
    270
    271	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
    272				 v,
    273				 0, 4 * sizeof(u32));
    274	if (ret)
    275		return ret;
    276	regs->psr = (regs->psr & ~(PSR_ICC | PSR_SYSCALL)) |
    277		    (v[0] & (PSR_ICC | PSR_SYSCALL));
    278	regs->pc = v[1];
    279	regs->npc = v[2];
    280	regs->y = v[3];
    281	return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
    282				 regs->u_regs + 1,
    283				 4 * sizeof(u32) , 19 * sizeof(u32));
    284}
    285
    286static int getfpregs_get(struct task_struct *target,
    287			const struct user_regset *regset,
    288			struct membuf to)
    289{
    290#if 0
    291	if (target == current)
    292		save_and_clear_fpu();
    293#endif
    294	membuf_write(&to, &target->thread.float_regs, 32 * sizeof(u32));
    295	membuf_write(&to, &target->thread.fsr, sizeof(u32));
    296	return membuf_zero(&to, 35 * sizeof(u32));
    297}
    298
    299static int setfpregs_set(struct task_struct *target,
    300			const struct user_regset *regset,
    301			unsigned int pos, unsigned int count,
    302			const void *kbuf, const void __user *ubuf)
    303{
    304	unsigned long *fpregs = target->thread.float_regs;
    305	int ret;
    306
    307#if 0
    308	if (target == current)
    309		save_and_clear_fpu();
    310#endif
    311	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
    312				 fpregs,
    313				 0, 32 * sizeof(u32));
    314	if (ret)
    315		return ret;
    316	return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
    317				 &target->thread.fsr,
    318				 32 * sizeof(u32),
    319				 33 * sizeof(u32));
    320}
    321
    322static const struct user_regset ptrace32_regsets[] = {
    323	[REGSET_GENERAL] = {
    324		.n = 19, .size = sizeof(u32),
    325		.regset_get = getregs_get, .set = setregs_set,
    326	},
    327	[REGSET_FP] = {
    328		.n = 68, .size = sizeof(u32),
    329		.regset_get = getfpregs_get, .set = setfpregs_set,
    330	},
    331};
    332
    333static const struct user_regset_view ptrace32_view = {
    334	.regsets = ptrace32_regsets, .n = ARRAY_SIZE(ptrace32_regsets)
    335};
    336
    337static const struct user_regset_view user_sparc32_view = {
    338	.name = "sparc", .e_machine = EM_SPARC,
    339	.regsets = sparc32_regsets, .n = ARRAY_SIZE(sparc32_regsets)
    340};
    341
    342const struct user_regset_view *task_user_regset_view(struct task_struct *task)
    343{
    344	return &user_sparc32_view;
    345}
    346
    347struct fps {
    348	unsigned long regs[32];
    349	unsigned long fsr;
    350	unsigned long flags;
    351	unsigned long extra;
    352	unsigned long fpqd;
    353	struct fq {
    354		unsigned long *insnaddr;
    355		unsigned long insn;
    356	} fpq[16];
    357};
    358
    359long arch_ptrace(struct task_struct *child, long request,
    360		 unsigned long addr, unsigned long data)
    361{
    362	unsigned long addr2 = current->thread.kregs->u_regs[UREG_I4];
    363	void __user *addr2p;
    364	struct pt_regs __user *pregs;
    365	struct fps __user *fps;
    366	int ret;
    367
    368	addr2p = (void __user *) addr2;
    369	pregs = (struct pt_regs __user *) addr;
    370	fps = (struct fps __user *) addr;
    371
    372	switch(request) {
    373	case PTRACE_GETREGS: {
    374		ret = copy_regset_to_user(child, &ptrace32_view,
    375					  REGSET_GENERAL, 0,
    376					  19 * sizeof(u32),
    377					  pregs);
    378		break;
    379	}
    380
    381	case PTRACE_SETREGS: {
    382		ret = copy_regset_from_user(child, &ptrace32_view,
    383					    REGSET_GENERAL, 0,
    384					    19 * sizeof(u32),
    385					    pregs);
    386		break;
    387	}
    388
    389	case PTRACE_GETFPREGS: {
    390		ret = copy_regset_to_user(child, &ptrace32_view,
    391					  REGSET_FP, 0,
    392					  68 * sizeof(u32),
    393					  fps);
    394		break;
    395	}
    396
    397	case PTRACE_SETFPREGS: {
    398		ret = copy_regset_from_user(child, &ptrace32_view,
    399					  REGSET_FP, 0,
    400					  33 * sizeof(u32),
    401					  fps);
    402		break;
    403	}
    404
    405	case PTRACE_READTEXT:
    406	case PTRACE_READDATA:
    407		ret = ptrace_readdata(child, addr, addr2p, data);
    408
    409		if (ret == data)
    410			ret = 0;
    411		else if (ret >= 0)
    412			ret = -EIO;
    413		break;
    414
    415	case PTRACE_WRITETEXT:
    416	case PTRACE_WRITEDATA:
    417		ret = ptrace_writedata(child, addr2p, addr, data);
    418
    419		if (ret == data)
    420			ret = 0;
    421		else if (ret >= 0)
    422			ret = -EIO;
    423		break;
    424
    425	default:
    426		if (request == PTRACE_SPARC_DETACH)
    427			request = PTRACE_DETACH;
    428		ret = ptrace_request(child, request, addr, data);
    429		break;
    430	}
    431
    432	return ret;
    433}
    434
    435asmlinkage int syscall_trace(struct pt_regs *regs, int syscall_exit_p)
    436{
    437	int ret = 0;
    438
    439	if (test_thread_flag(TIF_SYSCALL_TRACE)) {
    440		if (syscall_exit_p)
    441			ptrace_report_syscall_exit(regs, 0);
    442		else
    443			ret = ptrace_report_syscall_entry(regs);
    444	}
    445
    446	return ret;
    447}