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


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
      4 */
      5
      6#include <linux/audit.h>
      7#include <linux/ptrace.h>
      8#include <linux/sched.h>
      9#include <linux/uaccess.h>
     10#include <asm/ptrace-abi.h>
     11
     12void user_enable_single_step(struct task_struct *child)
     13{
     14	set_tsk_thread_flag(child, TIF_SINGLESTEP);
     15	child->thread.singlestep_syscall = 0;
     16
     17#ifdef SUBARCH_SET_SINGLESTEPPING
     18	SUBARCH_SET_SINGLESTEPPING(child, 1);
     19#endif
     20}
     21
     22void user_disable_single_step(struct task_struct *child)
     23{
     24	clear_tsk_thread_flag(child, TIF_SINGLESTEP);
     25	child->thread.singlestep_syscall = 0;
     26
     27#ifdef SUBARCH_SET_SINGLESTEPPING
     28	SUBARCH_SET_SINGLESTEPPING(child, 0);
     29#endif
     30}
     31
     32/*
     33 * Called by kernel/ptrace.c when detaching..
     34 */
     35void ptrace_disable(struct task_struct *child)
     36{
     37	user_disable_single_step(child);
     38}
     39
     40extern int peek_user(struct task_struct * child, long addr, long data);
     41extern int poke_user(struct task_struct * child, long addr, long data);
     42
     43long arch_ptrace(struct task_struct *child, long request,
     44		 unsigned long addr, unsigned long data)
     45{
     46	int i, ret;
     47	unsigned long __user *p = (void __user *)data;
     48	void __user *vp = p;
     49
     50	switch (request) {
     51	/* read the word at location addr in the USER area. */
     52	case PTRACE_PEEKUSR:
     53		ret = peek_user(child, addr, data);
     54		break;
     55
     56	/* write the word at location addr in the USER area */
     57	case PTRACE_POKEUSR:
     58		ret = poke_user(child, addr, data);
     59		break;
     60
     61	case PTRACE_SYSEMU:
     62	case PTRACE_SYSEMU_SINGLESTEP:
     63		ret = -EIO;
     64		break;
     65
     66#ifdef PTRACE_GETREGS
     67	case PTRACE_GETREGS: { /* Get all gp regs from the child. */
     68		if (!access_ok(p, MAX_REG_OFFSET)) {
     69			ret = -EIO;
     70			break;
     71		}
     72		for ( i = 0; i < MAX_REG_OFFSET; i += sizeof(long) ) {
     73			__put_user(getreg(child, i), p);
     74			p++;
     75		}
     76		ret = 0;
     77		break;
     78	}
     79#endif
     80#ifdef PTRACE_SETREGS
     81	case PTRACE_SETREGS: { /* Set all gp regs in the child. */
     82		unsigned long tmp = 0;
     83		if (!access_ok(p, MAX_REG_OFFSET)) {
     84			ret = -EIO;
     85			break;
     86		}
     87		for ( i = 0; i < MAX_REG_OFFSET; i += sizeof(long) ) {
     88			__get_user(tmp, p);
     89			putreg(child, i, tmp);
     90			p++;
     91		}
     92		ret = 0;
     93		break;
     94	}
     95#endif
     96	case PTRACE_GET_THREAD_AREA:
     97		ret = ptrace_get_thread_area(child, addr, vp);
     98		break;
     99
    100	case PTRACE_SET_THREAD_AREA:
    101		ret = ptrace_set_thread_area(child, addr, vp);
    102		break;
    103
    104	default:
    105		ret = ptrace_request(child, request, addr, data);
    106		if (ret == -EIO)
    107			ret = subarch_ptrace(child, request, addr, data);
    108		break;
    109	}
    110
    111	return ret;
    112}
    113
    114static void send_sigtrap(struct uml_pt_regs *regs, int error_code)
    115{
    116	/* Send us the fake SIGTRAP */
    117	force_sig_fault(SIGTRAP, TRAP_BRKPT,
    118			/* User-mode eip? */
    119			UPT_IS_USER(regs) ? (void __user *) UPT_IP(regs) : NULL);
    120}
    121
    122/*
    123 * XXX Check TIF_SINGLESTEP for singlestepping check and
    124 * PT_PTRACED vs TIF_SYSCALL_TRACE for syscall tracing check
    125 */
    126int syscall_trace_enter(struct pt_regs *regs)
    127{
    128	audit_syscall_entry(UPT_SYSCALL_NR(&regs->regs),
    129			    UPT_SYSCALL_ARG1(&regs->regs),
    130			    UPT_SYSCALL_ARG2(&regs->regs),
    131			    UPT_SYSCALL_ARG3(&regs->regs),
    132			    UPT_SYSCALL_ARG4(&regs->regs));
    133
    134	if (!test_thread_flag(TIF_SYSCALL_TRACE))
    135		return 0;
    136
    137	return ptrace_report_syscall_entry(regs);
    138}
    139
    140void syscall_trace_leave(struct pt_regs *regs)
    141{
    142	int ptraced = current->ptrace;
    143
    144	audit_syscall_exit(regs);
    145
    146	/* Fake a debug trap */
    147	if (test_thread_flag(TIF_SINGLESTEP))
    148		send_sigtrap(&regs->regs, 0);
    149
    150	if (!test_thread_flag(TIF_SYSCALL_TRACE))
    151		return;
    152
    153	ptrace_report_syscall_exit(regs, 0);
    154	/* force do_signal() --> is_syscall() */
    155	if (ptraced & PT_PTRACED)
    156		set_thread_flag(TIF_SIGPENDING);
    157}