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

callchain_32.c (4630B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Performance counter callchain support - powerpc architecture code
      4 *
      5 * Copyright © 2009 Paul Mackerras, IBM Corporation.
      6 */
      7#include <linux/kernel.h>
      8#include <linux/sched.h>
      9#include <linux/perf_event.h>
     10#include <linux/percpu.h>
     11#include <linux/uaccess.h>
     12#include <linux/mm.h>
     13#include <asm/ptrace.h>
     14#include <asm/sigcontext.h>
     15#include <asm/ucontext.h>
     16#include <asm/vdso.h>
     17#include <asm/pte-walk.h>
     18
     19#include "callchain.h"
     20
     21#ifdef CONFIG_PPC64
     22#include "../kernel/ppc32.h"
     23#else  /* CONFIG_PPC64 */
     24
     25#define __SIGNAL_FRAMESIZE32	__SIGNAL_FRAMESIZE
     26#define sigcontext32		sigcontext
     27#define mcontext32		mcontext
     28#define ucontext32		ucontext
     29#define compat_siginfo_t	struct siginfo
     30
     31#endif /* CONFIG_PPC64 */
     32
     33static int read_user_stack_32(const unsigned int __user *ptr, unsigned int *ret)
     34{
     35	return __read_user_stack(ptr, ret, sizeof(*ret));
     36}
     37
     38/*
     39 * Layout for non-RT signal frames
     40 */
     41struct signal_frame_32 {
     42	char			dummy[__SIGNAL_FRAMESIZE32];
     43	struct sigcontext32	sctx;
     44	struct mcontext32	mctx;
     45	int			abigap[56];
     46};
     47
     48/*
     49 * Layout for RT signal frames
     50 */
     51struct rt_signal_frame_32 {
     52	char			dummy[__SIGNAL_FRAMESIZE32 + 16];
     53	compat_siginfo_t	info;
     54	struct ucontext32	uc;
     55	int			abigap[56];
     56};
     57
     58static int is_sigreturn_32_address(unsigned int nip, unsigned int fp)
     59{
     60	if (nip == fp + offsetof(struct signal_frame_32, mctx.mc_pad))
     61		return 1;
     62	if (current->mm->context.vdso &&
     63	    nip == VDSO32_SYMBOL(current->mm->context.vdso, sigtramp32))
     64		return 1;
     65	return 0;
     66}
     67
     68static int is_rt_sigreturn_32_address(unsigned int nip, unsigned int fp)
     69{
     70	if (nip == fp + offsetof(struct rt_signal_frame_32,
     71				 uc.uc_mcontext.mc_pad))
     72		return 1;
     73	if (current->mm->context.vdso &&
     74	    nip == VDSO32_SYMBOL(current->mm->context.vdso, sigtramp_rt32))
     75		return 1;
     76	return 0;
     77}
     78
     79static int sane_signal_32_frame(unsigned int sp)
     80{
     81	struct signal_frame_32 __user *sf;
     82	unsigned int regs;
     83
     84	sf = (struct signal_frame_32 __user *) (unsigned long) sp;
     85	if (read_user_stack_32((unsigned int __user *) &sf->sctx.regs, &regs))
     86		return 0;
     87	return regs == (unsigned long) &sf->mctx;
     88}
     89
     90static int sane_rt_signal_32_frame(unsigned int sp)
     91{
     92	struct rt_signal_frame_32 __user *sf;
     93	unsigned int regs;
     94
     95	sf = (struct rt_signal_frame_32 __user *) (unsigned long) sp;
     96	if (read_user_stack_32((unsigned int __user *) &sf->uc.uc_regs, &regs))
     97		return 0;
     98	return regs == (unsigned long) &sf->uc.uc_mcontext;
     99}
    100
    101static unsigned int __user *signal_frame_32_regs(unsigned int sp,
    102				unsigned int next_sp, unsigned int next_ip)
    103{
    104	struct mcontext32 __user *mctx = NULL;
    105	struct signal_frame_32 __user *sf;
    106	struct rt_signal_frame_32 __user *rt_sf;
    107
    108	/*
    109	 * Note: the next_sp - sp >= signal frame size check
    110	 * is true when next_sp < sp, for example, when
    111	 * transitioning from an alternate signal stack to the
    112	 * normal stack.
    113	 */
    114	if (next_sp - sp >= sizeof(struct signal_frame_32) &&
    115	    is_sigreturn_32_address(next_ip, sp) &&
    116	    sane_signal_32_frame(sp)) {
    117		sf = (struct signal_frame_32 __user *) (unsigned long) sp;
    118		mctx = &sf->mctx;
    119	}
    120
    121	if (!mctx && next_sp - sp >= sizeof(struct rt_signal_frame_32) &&
    122	    is_rt_sigreturn_32_address(next_ip, sp) &&
    123	    sane_rt_signal_32_frame(sp)) {
    124		rt_sf = (struct rt_signal_frame_32 __user *) (unsigned long) sp;
    125		mctx = &rt_sf->uc.uc_mcontext;
    126	}
    127
    128	if (!mctx)
    129		return NULL;
    130	return mctx->mc_gregs;
    131}
    132
    133void perf_callchain_user_32(struct perf_callchain_entry_ctx *entry,
    134			    struct pt_regs *regs)
    135{
    136	unsigned int sp, next_sp;
    137	unsigned int next_ip;
    138	unsigned int lr;
    139	long level = 0;
    140	unsigned int __user *fp, *uregs;
    141
    142	next_ip = perf_instruction_pointer(regs);
    143	lr = regs->link;
    144	sp = regs->gpr[1];
    145	perf_callchain_store(entry, next_ip);
    146
    147	while (entry->nr < entry->max_stack) {
    148		fp = (unsigned int __user *) (unsigned long) sp;
    149		if (invalid_user_sp(sp) || read_user_stack_32(fp, &next_sp))
    150			return;
    151		if (level > 0 && read_user_stack_32(&fp[1], &next_ip))
    152			return;
    153
    154		uregs = signal_frame_32_regs(sp, next_sp, next_ip);
    155		if (!uregs && level <= 1)
    156			uregs = signal_frame_32_regs(sp, next_sp, lr);
    157		if (uregs) {
    158			/*
    159			 * This looks like an signal frame, so restart
    160			 * the stack trace with the values in it.
    161			 */
    162			if (read_user_stack_32(&uregs[PT_NIP], &next_ip) ||
    163			    read_user_stack_32(&uregs[PT_LNK], &lr) ||
    164			    read_user_stack_32(&uregs[PT_R1], &sp))
    165				return;
    166			level = 0;
    167			perf_callchain_store_context(entry, PERF_CONTEXT_USER);
    168			perf_callchain_store(entry, next_ip);
    169			continue;
    170		}
    171
    172		if (level == 0)
    173			next_ip = lr;
    174		perf_callchain_store(entry, next_ip);
    175		++level;
    176		sp = next_sp;
    177	}
    178}