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


      1/*
      2 * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
      3 * Licensed under the GPL
      4 */
      5
      6#include <linux/mm.h>
      7#include <linux/sched.h>
      8#include <linux/uaccess.h>
      9#include <asm/ptrace-abi.h>
     10#include <registers.h>
     11#include <skas.h>
     12
     13extern int arch_switch_tls(struct task_struct *to);
     14
     15void arch_switch_to(struct task_struct *to)
     16{
     17	int err = arch_switch_tls(to);
     18	if (!err)
     19		return;
     20
     21	if (err != -EINVAL)
     22		printk(KERN_WARNING "arch_switch_tls failed, errno %d, "
     23		       "not EINVAL\n", -err);
     24	else
     25		printk(KERN_WARNING "arch_switch_tls failed, errno = EINVAL\n");
     26}
     27
     28int is_syscall(unsigned long addr)
     29{
     30	unsigned short instr;
     31	int n;
     32
     33	n = copy_from_user(&instr, (void __user *) addr, sizeof(instr));
     34	if (n) {
     35		/* access_process_vm() grants access to vsyscall and stub,
     36		 * while copy_from_user doesn't. Maybe access_process_vm is
     37		 * slow, but that doesn't matter, since it will be called only
     38		 * in case of singlestepping, if copy_from_user failed.
     39		 */
     40		n = access_process_vm(current, addr, &instr, sizeof(instr),
     41				FOLL_FORCE);
     42		if (n != sizeof(instr)) {
     43			printk(KERN_ERR "is_syscall : failed to read "
     44			       "instruction from 0x%lx\n", addr);
     45			return 1;
     46		}
     47	}
     48	/* int 0x80 or sysenter */
     49	return (instr == 0x80cd) || (instr == 0x340f);
     50}
     51
     52/* determines which flags the user has access to. */
     53/* 1 = access 0 = no access */
     54#define FLAG_MASK 0x00044dd5
     55
     56static const int reg_offsets[] = {
     57	[EBX] = HOST_BX,
     58	[ECX] = HOST_CX,
     59	[EDX] = HOST_DX,
     60	[ESI] = HOST_SI,
     61	[EDI] = HOST_DI,
     62	[EBP] = HOST_BP,
     63	[EAX] = HOST_AX,
     64	[DS] = HOST_DS,
     65	[ES] = HOST_ES,
     66	[FS] = HOST_FS,
     67	[GS] = HOST_GS,
     68	[EIP] = HOST_IP,
     69	[CS] = HOST_CS,
     70	[EFL] = HOST_EFLAGS,
     71	[UESP] = HOST_SP,
     72	[SS] = HOST_SS,
     73	[ORIG_EAX] = HOST_ORIG_AX,
     74};
     75
     76int putreg(struct task_struct *child, int regno, unsigned long value)
     77{
     78	regno >>= 2;
     79	switch (regno) {
     80	case EBX:
     81	case ECX:
     82	case EDX:
     83	case ESI:
     84	case EDI:
     85	case EBP:
     86	case EAX:
     87	case EIP:
     88	case UESP:
     89		break;
     90	case ORIG_EAX:
     91		/* Update the syscall number. */
     92		UPT_SYSCALL_NR(&child->thread.regs.regs) = value;
     93		break;
     94	case FS:
     95		if (value && (value & 3) != 3)
     96			return -EIO;
     97		break;
     98	case GS:
     99		if (value && (value & 3) != 3)
    100			return -EIO;
    101		break;
    102	case DS:
    103	case ES:
    104		if (value && (value & 3) != 3)
    105			return -EIO;
    106		value &= 0xffff;
    107		break;
    108	case SS:
    109	case CS:
    110		if ((value & 3) != 3)
    111			return -EIO;
    112		value &= 0xffff;
    113		break;
    114	case EFL:
    115		value &= FLAG_MASK;
    116		child->thread.regs.regs.gp[HOST_EFLAGS] |= value;
    117		return 0;
    118	default :
    119		panic("Bad register in putreg() : %d\n", regno);
    120	}
    121	child->thread.regs.regs.gp[reg_offsets[regno]] = value;
    122	return 0;
    123}
    124
    125int poke_user(struct task_struct *child, long addr, long data)
    126{
    127	if ((addr & 3) || addr < 0)
    128		return -EIO;
    129
    130	if (addr < MAX_REG_OFFSET)
    131		return putreg(child, addr, data);
    132	else if ((addr >= offsetof(struct user, u_debugreg[0])) &&
    133		 (addr <= offsetof(struct user, u_debugreg[7]))) {
    134		addr -= offsetof(struct user, u_debugreg[0]);
    135		addr = addr >> 2;
    136		if ((addr == 4) || (addr == 5))
    137			return -EIO;
    138		child->thread.arch.debugregs[addr] = data;
    139		return 0;
    140	}
    141	return -EIO;
    142}
    143
    144unsigned long getreg(struct task_struct *child, int regno)
    145{
    146	unsigned long mask = ~0UL;
    147
    148	regno >>= 2;
    149	switch (regno) {
    150	case FS:
    151	case GS:
    152	case DS:
    153	case ES:
    154	case SS:
    155	case CS:
    156		mask = 0xffff;
    157		break;
    158	case EIP:
    159	case UESP:
    160	case EAX:
    161	case EBX:
    162	case ECX:
    163	case EDX:
    164	case ESI:
    165	case EDI:
    166	case EBP:
    167	case EFL:
    168	case ORIG_EAX:
    169		break;
    170	default:
    171		panic("Bad register in getreg() : %d\n", regno);
    172	}
    173	return mask & child->thread.regs.regs.gp[reg_offsets[regno]];
    174}
    175
    176/* read the word at location addr in the USER area. */
    177int peek_user(struct task_struct *child, long addr, long data)
    178{
    179	unsigned long tmp;
    180
    181	if ((addr & 3) || addr < 0)
    182		return -EIO;
    183
    184	tmp = 0;  /* Default return condition */
    185	if (addr < MAX_REG_OFFSET) {
    186		tmp = getreg(child, addr);
    187	}
    188	else if ((addr >= offsetof(struct user, u_debugreg[0])) &&
    189		 (addr <= offsetof(struct user, u_debugreg[7]))) {
    190		addr -= offsetof(struct user, u_debugreg[0]);
    191		addr = addr >> 2;
    192		tmp = child->thread.arch.debugregs[addr];
    193	}
    194	return put_user(tmp, (unsigned long __user *) data);
    195}
    196
    197static int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *child)
    198{
    199	int err, n, cpu = task_cpu(child);
    200	struct user_i387_struct fpregs;
    201
    202	err = save_i387_registers(userspace_pid[cpu],
    203				  (unsigned long *) &fpregs);
    204	if (err)
    205		return err;
    206
    207	n = copy_to_user(buf, &fpregs, sizeof(fpregs));
    208	if(n > 0)
    209		return -EFAULT;
    210
    211	return n;
    212}
    213
    214static int set_fpregs(struct user_i387_struct __user *buf, struct task_struct *child)
    215{
    216	int n, cpu = task_cpu(child);
    217	struct user_i387_struct fpregs;
    218
    219	n = copy_from_user(&fpregs, buf, sizeof(fpregs));
    220	if (n > 0)
    221		return -EFAULT;
    222
    223	return restore_i387_registers(userspace_pid[cpu],
    224				    (unsigned long *) &fpregs);
    225}
    226
    227static int get_fpxregs(struct user_fxsr_struct __user *buf, struct task_struct *child)
    228{
    229	int err, n, cpu = task_cpu(child);
    230	struct user_fxsr_struct fpregs;
    231
    232	err = save_fpx_registers(userspace_pid[cpu], (unsigned long *) &fpregs);
    233	if (err)
    234		return err;
    235
    236	n = copy_to_user(buf, &fpregs, sizeof(fpregs));
    237	if(n > 0)
    238		return -EFAULT;
    239
    240	return n;
    241}
    242
    243static int set_fpxregs(struct user_fxsr_struct __user *buf, struct task_struct *child)
    244{
    245	int n, cpu = task_cpu(child);
    246	struct user_fxsr_struct fpregs;
    247
    248	n = copy_from_user(&fpregs, buf, sizeof(fpregs));
    249	if (n > 0)
    250		return -EFAULT;
    251
    252	return restore_fpx_registers(userspace_pid[cpu],
    253				     (unsigned long *) &fpregs);
    254}
    255
    256long subarch_ptrace(struct task_struct *child, long request,
    257		    unsigned long addr, unsigned long data)
    258{
    259	int ret = -EIO;
    260	void __user *datap = (void __user *) data;
    261	switch (request) {
    262	case PTRACE_GETFPREGS: /* Get the child FPU state. */
    263		ret = get_fpregs(datap, child);
    264		break;
    265	case PTRACE_SETFPREGS: /* Set the child FPU state. */
    266		ret = set_fpregs(datap, child);
    267		break;
    268	case PTRACE_GETFPXREGS: /* Get the child FPU state. */
    269		ret = get_fpxregs(datap, child);
    270		break;
    271	case PTRACE_SETFPXREGS: /* Set the child FPU state. */
    272		ret = set_fpxregs(datap, child);
    273		break;
    274	default:
    275		ret = -EIO;
    276	}
    277	return ret;
    278}