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 (8308B)


      1/*
      2 * ptrace for 32-bit processes running on a 64-bit kernel.
      3 *
      4 *  PowerPC version
      5 *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
      6 *
      7 *  Derived from "arch/m68k/kernel/ptrace.c"
      8 *  Copyright (C) 1994 by Hamish Macdonald
      9 *  Taken from linux/kernel/ptrace.c and modified for M680x0.
     10 *  linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
     11 *
     12 * Modified by Cort Dougan (cort@hq.fsmlabs.com)
     13 * and Paul Mackerras (paulus@samba.org).
     14 *
     15 * This file is subject to the terms and conditions of the GNU General
     16 * Public License.  See the file COPYING in the main directory of
     17 * this archive for more details.
     18 */
     19
     20#include <linux/ptrace.h>
     21#include <linux/regset.h>
     22#include <linux/compat.h>
     23
     24#include <asm/switch_to.h>
     25
     26#include "ptrace-decl.h"
     27
     28/*
     29 * does not yet catch signals sent when the child dies.
     30 * in exit.c or in signal.c.
     31 */
     32
     33/* Macros to workout the correct index for the FPR in the thread struct */
     34#define FPRNUMBER(i) (((i) - PT_FPR0) >> 1)
     35#define FPRHALF(i) (((i) - PT_FPR0) & 1)
     36#define FPRINDEX(i) TS_FPRWIDTH * FPRNUMBER(i) * 2 + FPRHALF(i)
     37
     38long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
     39			compat_ulong_t caddr, compat_ulong_t cdata)
     40{
     41	unsigned long addr = caddr;
     42	unsigned long data = cdata;
     43	int ret;
     44
     45	switch (request) {
     46	/*
     47	 * Read 4 bytes of the other process' storage
     48	 *  data is a pointer specifying where the user wants the
     49	 *	4 bytes copied into
     50	 *  addr is a pointer in the user's storage that contains an 8 byte
     51	 *	address in the other process of the 4 bytes that is to be read
     52	 * (this is run in a 32-bit process looking at a 64-bit process)
     53	 * when I and D space are separate, these will need to be fixed.
     54	 */
     55	case PPC_PTRACE_PEEKTEXT_3264:
     56	case PPC_PTRACE_PEEKDATA_3264: {
     57		u32 tmp;
     58		int copied;
     59		u32 __user * addrOthers;
     60
     61		ret = -EIO;
     62
     63		/* Get the addr in the other process that we want to read */
     64		if (get_user(addrOthers, (u32 __user * __user *)addr) != 0)
     65			break;
     66
     67		copied = ptrace_access_vm(child, (u64)addrOthers, &tmp,
     68				sizeof(tmp), FOLL_FORCE);
     69		if (copied != sizeof(tmp))
     70			break;
     71		ret = put_user(tmp, (u32 __user *)data);
     72		break;
     73	}
     74
     75	/* Read a register (specified by ADDR) out of the "user area" */
     76	case PTRACE_PEEKUSR: {
     77		int index;
     78		unsigned long tmp;
     79
     80		ret = -EIO;
     81		/* convert to index and check */
     82		index = (unsigned long) addr >> 2;
     83		if ((addr & 3) || (index > PT_FPSCR32))
     84			break;
     85
     86		if (index < PT_FPR0) {
     87			ret = ptrace_get_reg(child, index, &tmp);
     88			if (ret)
     89				break;
     90		} else {
     91			flush_fp_to_thread(child);
     92			/*
     93			 * the user space code considers the floating point
     94			 * to be an array of unsigned int (32 bits) - the
     95			 * index passed in is based on this assumption.
     96			 */
     97			tmp = ((unsigned int *)child->thread.fp_state.fpr)
     98				[FPRINDEX(index)];
     99		}
    100		ret = put_user((unsigned int)tmp, (u32 __user *)data);
    101		break;
    102	}
    103  
    104	/*
    105	 * Read 4 bytes out of the other process' pt_regs area
    106	 *  data is a pointer specifying where the user wants the
    107	 *	4 bytes copied into
    108	 *  addr is the offset into the other process' pt_regs structure
    109	 *	that is to be read
    110	 * (this is run in a 32-bit process looking at a 64-bit process)
    111	 */
    112	case PPC_PTRACE_PEEKUSR_3264: {
    113		u32 index;
    114		u32 reg32bits;
    115		u64 tmp;
    116		u32 numReg;
    117		u32 part;
    118
    119		ret = -EIO;
    120		/* Determine which register the user wants */
    121		index = (u64)addr >> 2;
    122		numReg = index / 2;
    123		/* Determine which part of the register the user wants */
    124		if (index % 2)
    125			part = 1;  /* want the 2nd half of the register (right-most). */
    126		else
    127			part = 0;  /* want the 1st half of the register (left-most). */
    128
    129		/* Validate the input - check to see if address is on the wrong boundary
    130		 * or beyond the end of the user area
    131		 */
    132		if ((addr & 3) || numReg > PT_FPSCR)
    133			break;
    134
    135		if (numReg >= PT_FPR0) {
    136			flush_fp_to_thread(child);
    137			/* get 64 bit FPR */
    138			tmp = child->thread.fp_state.fpr[numReg - PT_FPR0][0];
    139		} else { /* register within PT_REGS struct */
    140			unsigned long tmp2;
    141			ret = ptrace_get_reg(child, numReg, &tmp2);
    142			if (ret)
    143				break;
    144			tmp = tmp2;
    145		} 
    146		reg32bits = ((u32*)&tmp)[part];
    147		ret = put_user(reg32bits, (u32 __user *)data);
    148		break;
    149	}
    150
    151	/*
    152	 * Write 4 bytes into the other process' storage
    153	 *  data is the 4 bytes that the user wants written
    154	 *  addr is a pointer in the user's storage that contains an
    155	 *	8 byte address in the other process where the 4 bytes
    156	 *	that is to be written
    157	 * (this is run in a 32-bit process looking at a 64-bit process)
    158	 * when I and D space are separate, these will need to be fixed.
    159	 */
    160	case PPC_PTRACE_POKETEXT_3264:
    161	case PPC_PTRACE_POKEDATA_3264: {
    162		u32 tmp = data;
    163		u32 __user * addrOthers;
    164
    165		/* Get the addr in the other process that we want to write into */
    166		ret = -EIO;
    167		if (get_user(addrOthers, (u32 __user * __user *)addr) != 0)
    168			break;
    169		ret = 0;
    170		if (ptrace_access_vm(child, (u64)addrOthers, &tmp,
    171					sizeof(tmp),
    172					FOLL_FORCE | FOLL_WRITE) == sizeof(tmp))
    173			break;
    174		ret = -EIO;
    175		break;
    176	}
    177
    178	/* write the word at location addr in the USER area */
    179	case PTRACE_POKEUSR: {
    180		unsigned long index;
    181
    182		ret = -EIO;
    183		/* convert to index and check */
    184		index = (unsigned long) addr >> 2;
    185		if ((addr & 3) || (index > PT_FPSCR32))
    186			break;
    187
    188		if (index < PT_FPR0) {
    189			ret = ptrace_put_reg(child, index, data);
    190		} else {
    191			flush_fp_to_thread(child);
    192			/*
    193			 * the user space code considers the floating point
    194			 * to be an array of unsigned int (32 bits) - the
    195			 * index passed in is based on this assumption.
    196			 */
    197			((unsigned int *)child->thread.fp_state.fpr)
    198				[FPRINDEX(index)] = data;
    199			ret = 0;
    200		}
    201		break;
    202	}
    203
    204	/*
    205	 * Write 4 bytes into the other process' pt_regs area
    206	 *  data is the 4 bytes that the user wants written
    207	 *  addr is the offset into the other process' pt_regs structure
    208	 *	that is to be written into
    209	 * (this is run in a 32-bit process looking at a 64-bit process)
    210	 */
    211	case PPC_PTRACE_POKEUSR_3264: {
    212		u32 index;
    213		u32 numReg;
    214
    215		ret = -EIO;
    216		/* Determine which register the user wants */
    217		index = (u64)addr >> 2;
    218		numReg = index / 2;
    219
    220		/*
    221		 * Validate the input - check to see if address is on the
    222		 * wrong boundary or beyond the end of the user area
    223		 */
    224		if ((addr & 3) || (numReg > PT_FPSCR))
    225			break;
    226		if (numReg < PT_FPR0) {
    227			unsigned long freg;
    228			ret = ptrace_get_reg(child, numReg, &freg);
    229			if (ret)
    230				break;
    231			if (index % 2)
    232				freg = (freg & ~0xfffffffful) | (data & 0xfffffffful);
    233			else
    234				freg = (freg & 0xfffffffful) | (data << 32);
    235			ret = ptrace_put_reg(child, numReg, freg);
    236		} else {
    237			u64 *tmp;
    238			flush_fp_to_thread(child);
    239			/* get 64 bit FPR ... */
    240			tmp = &child->thread.fp_state.fpr[numReg - PT_FPR0][0];
    241			/* ... write the 32 bit part we want */
    242			((u32 *)tmp)[index % 2] = data;
    243			ret = 0;
    244		}
    245		break;
    246	}
    247
    248	case PTRACE_GET_DEBUGREG: {
    249#ifndef CONFIG_PPC_ADV_DEBUG_REGS
    250		unsigned long dabr_fake;
    251#endif
    252		ret = -EINVAL;
    253		/* We only support one DABR and no IABRS at the moment */
    254		if (addr > 0)
    255			break;
    256#ifdef CONFIG_PPC_ADV_DEBUG_REGS
    257		ret = put_user(child->thread.debug.dac1, (u32 __user *)data);
    258#else
    259		dabr_fake = (
    260			(child->thread.hw_brk[0].address & (~HW_BRK_TYPE_DABR)) |
    261			(child->thread.hw_brk[0].type & HW_BRK_TYPE_DABR));
    262		ret = put_user(dabr_fake, (u32 __user *)data);
    263#endif
    264		break;
    265	}
    266
    267	case PTRACE_GETREGS:	/* Get all pt_regs from the child. */
    268		return copy_regset_to_user(
    269			child, task_user_regset_view(current), 0,
    270			0, PT_REGS_COUNT * sizeof(compat_long_t),
    271			compat_ptr(data));
    272
    273	case PTRACE_SETREGS:	/* Set all gp regs in the child. */
    274		return copy_regset_from_user(
    275			child, task_user_regset_view(current), 0,
    276			0, PT_REGS_COUNT * sizeof(compat_long_t),
    277			compat_ptr(data));
    278
    279	case PTRACE_GETFPREGS:
    280	case PTRACE_SETFPREGS:
    281	case PTRACE_GETVRREGS:
    282	case PTRACE_SETVRREGS:
    283	case PTRACE_GETVSRREGS:
    284	case PTRACE_SETVSRREGS:
    285	case PTRACE_GETREGS64:
    286	case PTRACE_SETREGS64:
    287	case PTRACE_KILL:
    288	case PTRACE_SINGLESTEP:
    289	case PTRACE_DETACH:
    290	case PTRACE_SET_DEBUGREG:
    291	case PTRACE_SYSCALL:
    292	case PTRACE_CONT:
    293	case PPC_PTRACE_GETHWDBGINFO:
    294	case PPC_PTRACE_SETHWDEBUG:
    295	case PPC_PTRACE_DELHWDEBUG:
    296		ret = arch_ptrace(child, request, addr, data);
    297		break;
    298
    299	default:
    300		ret = compat_ptrace_request(child, request, addr, data);
    301		break;
    302	}
    303
    304	return ret;
    305}