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

uprobes.c (3050B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) 2014-2016 Pratyush Anand <panand@redhat.com>
      4 */
      5#include <linux/highmem.h>
      6#include <linux/ptrace.h>
      7#include <linux/uprobes.h>
      8#include <asm/cacheflush.h>
      9
     10#include "decode-insn.h"
     11
     12#define UPROBE_TRAP_NR	UINT_MAX
     13
     14bool is_swbp_insn(uprobe_opcode_t *insn)
     15{
     16	return (*insn & 0xffff) == UPROBE_SWBP_INSN;
     17}
     18
     19unsigned long uprobe_get_swbp_addr(struct pt_regs *regs)
     20{
     21	return instruction_pointer(regs);
     22}
     23
     24int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm,
     25		unsigned long addr)
     26{
     27	probe_opcode_t insn;
     28
     29	insn = *(probe_opcode_t *)(&auprobe->insn[0]);
     30
     31	auprobe->insn_size = is_insn32(insn) ? 4 : 2;
     32
     33	switch (csky_probe_decode_insn(&insn, &auprobe->api)) {
     34	case INSN_REJECTED:
     35		return -EINVAL;
     36
     37	case INSN_GOOD_NO_SLOT:
     38		auprobe->simulate = true;
     39		break;
     40
     41	default:
     42		break;
     43	}
     44
     45	return 0;
     46}
     47
     48int arch_uprobe_pre_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
     49{
     50	struct uprobe_task *utask = current->utask;
     51
     52	utask->autask.saved_trap_no = current->thread.trap_no;
     53	current->thread.trap_no = UPROBE_TRAP_NR;
     54
     55	instruction_pointer_set(regs, utask->xol_vaddr);
     56
     57	user_enable_single_step(current);
     58
     59	return 0;
     60}
     61
     62int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
     63{
     64	struct uprobe_task *utask = current->utask;
     65
     66	WARN_ON_ONCE(current->thread.trap_no != UPROBE_TRAP_NR);
     67
     68	instruction_pointer_set(regs, utask->vaddr + auprobe->insn_size);
     69
     70	user_disable_single_step(current);
     71
     72	return 0;
     73}
     74
     75bool arch_uprobe_xol_was_trapped(struct task_struct *t)
     76{
     77	if (t->thread.trap_no != UPROBE_TRAP_NR)
     78		return true;
     79
     80	return false;
     81}
     82
     83bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs)
     84{
     85	probe_opcode_t insn;
     86	unsigned long addr;
     87
     88	if (!auprobe->simulate)
     89		return false;
     90
     91	insn = *(probe_opcode_t *)(&auprobe->insn[0]);
     92	addr = instruction_pointer(regs);
     93
     94	if (auprobe->api.handler)
     95		auprobe->api.handler(insn, addr, regs);
     96
     97	return true;
     98}
     99
    100void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
    101{
    102	struct uprobe_task *utask = current->utask;
    103
    104	/*
    105	 * Task has received a fatal signal, so reset back to probed
    106	 * address.
    107	 */
    108	instruction_pointer_set(regs, utask->vaddr);
    109
    110	user_disable_single_step(current);
    111}
    112
    113bool arch_uretprobe_is_alive(struct return_instance *ret, enum rp_check ctx,
    114		struct pt_regs *regs)
    115{
    116	if (ctx == RP_CHECK_CHAIN_CALL)
    117		return regs->usp <= ret->stack;
    118	else
    119		return regs->usp < ret->stack;
    120}
    121
    122unsigned long
    123arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr,
    124				  struct pt_regs *regs)
    125{
    126	unsigned long ra;
    127
    128	ra = regs->lr;
    129
    130	regs->lr = trampoline_vaddr;
    131
    132	return ra;
    133}
    134
    135int arch_uprobe_exception_notify(struct notifier_block *self,
    136				 unsigned long val, void *data)
    137{
    138	return NOTIFY_DONE;
    139}
    140
    141int uprobe_breakpoint_handler(struct pt_regs *regs)
    142{
    143	if (uprobe_pre_sstep_notifier(regs))
    144		return 1;
    145
    146	return 0;
    147}
    148
    149int uprobe_single_step_handler(struct pt_regs *regs)
    150{
    151	if (uprobe_post_sstep_notifier(regs))
    152		return 1;
    153
    154	return 0;
    155}