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

ptrace32.c (7597B)


      1/*
      2 * This file is subject to the terms and conditions of the GNU General Public
      3 * License.  See the file "COPYING" in the main directory of this archive
      4 * for more details.
      5 *
      6 * Copyright (C) 1992 Ross Biro
      7 * Copyright (C) Linus Torvalds
      8 * Copyright (C) 1994, 95, 96, 97, 98, 2000 Ralf Baechle
      9 * Copyright (C) 1996 David S. Miller
     10 * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
     11 * Copyright (C) 1999 MIPS Technologies, Inc.
     12 * Copyright (C) 2000 Ulf Carlsson
     13 *
     14 * At this time Linux/MIPS64 only supports syscall tracing, even for 32-bit
     15 * binaries.
     16 */
     17#include <linux/compiler.h>
     18#include <linux/compat.h>
     19#include <linux/kernel.h>
     20#include <linux/sched.h>
     21#include <linux/sched/task_stack.h>
     22#include <linux/mm.h>
     23#include <linux/errno.h>
     24#include <linux/ptrace.h>
     25#include <linux/smp.h>
     26#include <linux/security.h>
     27
     28#include <asm/cpu.h>
     29#include <asm/dsp.h>
     30#include <asm/fpu.h>
     31#include <asm/mipsregs.h>
     32#include <asm/mipsmtregs.h>
     33#include <asm/page.h>
     34#include <asm/reg.h>
     35#include <asm/syscall.h>
     36#include <linux/uaccess.h>
     37#include <asm/bootinfo.h>
     38
     39/*
     40 * Tracing a 32-bit process with a 64-bit strace and vice versa will not
     41 * work.  I don't know how to fix this.
     42 */
     43long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
     44			compat_ulong_t caddr, compat_ulong_t cdata)
     45{
     46	int addr = caddr;
     47	int data = cdata;
     48	int ret;
     49
     50	switch (request) {
     51
     52	/*
     53	 * Read 4 bytes of the other process' storage
     54	 *  data is a pointer specifying where the user wants the
     55	 *	4 bytes copied into
     56	 *  addr is a pointer in the user's storage that contains an 8 byte
     57	 *	address in the other process of the 4 bytes that is to be read
     58	 * (this is run in a 32-bit process looking at a 64-bit process)
     59	 * when I and D space are separate, these will need to be fixed.
     60	 */
     61	case PTRACE_PEEKTEXT_3264:
     62	case PTRACE_PEEKDATA_3264: {
     63		u32 tmp;
     64		int copied;
     65		u32 __user * addrOthers;
     66
     67		ret = -EIO;
     68
     69		/* Get the addr in the other process that we want to read */
     70		if (get_user(addrOthers, (u32 __user * __user *) (unsigned long) addr) != 0)
     71			break;
     72
     73		copied = ptrace_access_vm(child, (u64)addrOthers, &tmp,
     74				sizeof(tmp), FOLL_FORCE);
     75		if (copied != sizeof(tmp))
     76			break;
     77		ret = put_user(tmp, (u32 __user *) (unsigned long) data);
     78		break;
     79	}
     80
     81	/* Read the word at location addr in the USER area. */
     82	case PTRACE_PEEKUSR: {
     83		struct pt_regs *regs;
     84		unsigned int tmp;
     85
     86		regs = task_pt_regs(child);
     87		ret = 0;  /* Default return value. */
     88
     89		switch (addr) {
     90		case 0 ... 31:
     91			tmp = regs->regs[addr];
     92			break;
     93#ifdef CONFIG_MIPS_FP_SUPPORT
     94		case FPR_BASE ... FPR_BASE + 31: {
     95			union fpureg *fregs;
     96
     97			if (!tsk_used_math(child)) {
     98				/* FP not yet used */
     99				tmp = -1;
    100				break;
    101			}
    102			fregs = get_fpu_regs(child);
    103			if (test_tsk_thread_flag(child, TIF_32BIT_FPREGS)) {
    104				/*
    105				 * The odd registers are actually the high
    106				 * order bits of the values stored in the even
    107				 * registers.
    108				 */
    109				tmp = get_fpr32(&fregs[(addr & ~1) - FPR_BASE],
    110						addr & 1);
    111				break;
    112			}
    113			tmp = get_fpr64(&fregs[addr - FPR_BASE], 0);
    114			break;
    115		}
    116		case FPC_CSR:
    117			tmp = child->thread.fpu.fcr31;
    118			break;
    119		case FPC_EIR:
    120			/* implementation / version register */
    121			tmp = boot_cpu_data.fpu_id;
    122			break;
    123#endif /* CONFIG_MIPS_FP_SUPPORT */
    124		case PC:
    125			tmp = regs->cp0_epc;
    126			break;
    127		case CAUSE:
    128			tmp = regs->cp0_cause;
    129			break;
    130		case BADVADDR:
    131			tmp = regs->cp0_badvaddr;
    132			break;
    133		case MMHI:
    134			tmp = regs->hi;
    135			break;
    136		case MMLO:
    137			tmp = regs->lo;
    138			break;
    139		case DSP_BASE ... DSP_BASE + 5: {
    140			dspreg_t *dregs;
    141
    142			if (!cpu_has_dsp) {
    143				tmp = 0;
    144				ret = -EIO;
    145				goto out;
    146			}
    147			dregs = __get_dsp_regs(child);
    148			tmp = dregs[addr - DSP_BASE];
    149			break;
    150		}
    151		case DSP_CONTROL:
    152			if (!cpu_has_dsp) {
    153				tmp = 0;
    154				ret = -EIO;
    155				goto out;
    156			}
    157			tmp = child->thread.dsp.dspcontrol;
    158			break;
    159		default:
    160			tmp = 0;
    161			ret = -EIO;
    162			goto out;
    163		}
    164		ret = put_user(tmp, (unsigned __user *) (unsigned long) data);
    165		break;
    166	}
    167
    168	/*
    169	 * Write 4 bytes into the other process' storage
    170	 *  data is the 4 bytes that the user wants written
    171	 *  addr is a pointer in the user's storage that contains an
    172	 *	8 byte address in the other process where the 4 bytes
    173	 *	that is to be written
    174	 * (this is run in a 32-bit process looking at a 64-bit process)
    175	 * when I and D space are separate, these will need to be fixed.
    176	 */
    177	case PTRACE_POKETEXT_3264:
    178	case PTRACE_POKEDATA_3264: {
    179		u32 __user * addrOthers;
    180
    181		/* Get the addr in the other process that we want to write into */
    182		ret = -EIO;
    183		if (get_user(addrOthers, (u32 __user * __user *) (unsigned long) addr) != 0)
    184			break;
    185		ret = 0;
    186		if (ptrace_access_vm(child, (u64)addrOthers, &data,
    187					sizeof(data),
    188					FOLL_FORCE | FOLL_WRITE) == sizeof(data))
    189			break;
    190		ret = -EIO;
    191		break;
    192	}
    193
    194	case PTRACE_POKEUSR: {
    195		struct pt_regs *regs;
    196		ret = 0;
    197		regs = task_pt_regs(child);
    198
    199		switch (addr) {
    200		case 0 ... 31:
    201			regs->regs[addr] = data;
    202			/* System call number may have been changed */
    203			if (addr == 2)
    204				mips_syscall_update_nr(child, regs);
    205			else if (addr == 4 &&
    206				 mips_syscall_is_indirect(child, regs))
    207				mips_syscall_update_nr(child, regs);
    208			break;
    209#ifdef CONFIG_MIPS_FP_SUPPORT
    210		case FPR_BASE ... FPR_BASE + 31: {
    211			union fpureg *fregs = get_fpu_regs(child);
    212
    213			if (!tsk_used_math(child)) {
    214				/* FP not yet used  */
    215				memset(&child->thread.fpu, ~0,
    216				       sizeof(child->thread.fpu));
    217				child->thread.fpu.fcr31 = 0;
    218			}
    219			if (test_tsk_thread_flag(child, TIF_32BIT_FPREGS)) {
    220				/*
    221				 * The odd registers are actually the high
    222				 * order bits of the values stored in the even
    223				 * registers.
    224				 */
    225				set_fpr32(&fregs[(addr & ~1) - FPR_BASE],
    226					  addr & 1, data);
    227				break;
    228			}
    229			set_fpr64(&fregs[addr - FPR_BASE], 0, data);
    230			break;
    231		}
    232		case FPC_CSR:
    233			child->thread.fpu.fcr31 = data;
    234			break;
    235#endif /* CONFIG_MIPS_FP_SUPPORT */
    236		case PC:
    237			regs->cp0_epc = data;
    238			break;
    239		case MMHI:
    240			regs->hi = data;
    241			break;
    242		case MMLO:
    243			regs->lo = data;
    244			break;
    245		case DSP_BASE ... DSP_BASE + 5: {
    246			dspreg_t *dregs;
    247
    248			if (!cpu_has_dsp) {
    249				ret = -EIO;
    250				break;
    251			}
    252
    253			dregs = __get_dsp_regs(child);
    254			dregs[addr - DSP_BASE] = data;
    255			break;
    256		}
    257		case DSP_CONTROL:
    258			if (!cpu_has_dsp) {
    259				ret = -EIO;
    260				break;
    261			}
    262			child->thread.dsp.dspcontrol = data;
    263			break;
    264		default:
    265			/* The rest are not allowed. */
    266			ret = -EIO;
    267			break;
    268		}
    269		break;
    270		}
    271
    272	case PTRACE_GETREGS:
    273		ret = ptrace_getregs(child,
    274				(struct user_pt_regs __user *) (__u64) data);
    275		break;
    276
    277	case PTRACE_SETREGS:
    278		ret = ptrace_setregs(child,
    279				(struct user_pt_regs __user *) (__u64) data);
    280		break;
    281
    282#ifdef CONFIG_MIPS_FP_SUPPORT
    283	case PTRACE_GETFPREGS:
    284		ret = ptrace_getfpregs(child, (__u32 __user *) (__u64) data);
    285		break;
    286
    287	case PTRACE_SETFPREGS:
    288		ret = ptrace_setfpregs(child, (__u32 __user *) (__u64) data);
    289		break;
    290#endif
    291	case PTRACE_GET_THREAD_AREA:
    292		ret = put_user(task_thread_info(child)->tp_value,
    293				(unsigned int __user *) (unsigned long) data);
    294		break;
    295
    296	case PTRACE_GET_THREAD_AREA_3264:
    297		ret = put_user(task_thread_info(child)->tp_value,
    298				(unsigned long __user *) (unsigned long) data);
    299		break;
    300
    301	case PTRACE_GET_WATCH_REGS:
    302		ret = ptrace_get_watch_regs(child,
    303			(struct pt_watch_regs __user *) (unsigned long) addr);
    304		break;
    305
    306	case PTRACE_SET_WATCH_REGS:
    307		ret = ptrace_set_watch_regs(child,
    308			(struct pt_watch_regs __user *) (unsigned long) addr);
    309		break;
    310
    311	default:
    312		ret = compat_ptrace_request(child, request, addr, data);
    313		break;
    314	}
    315out:
    316	return ret;
    317}