linux/arch/x86/kernel/ptrace.c

// SPDX-License-Identifier: GPL-2.0-only
/* By Ross Biro 1/23/92 */
/*
 * Pentium III FXSR, SSE support
 *	Gareth Hughes <[email protected]>, May 2000
 */

#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/sched/task_stack.h>
#include <linux/mm.h>
#include <linux/smp.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/ptrace.h>
#include <linux/user.h>
#include <linux/elf.h>
#include <linux/security.h>
#include <linux/audit.h>
#include <linux/seccomp.h>
#include <linux/signal.h>
#include <linux/perf_event.h>
#include <linux/hw_breakpoint.h>
#include <linux/rcupdate.h>
#include <linux/export.h>
#include <linux/context_tracking.h>
#include <linux/nospec.h>

#include <linux/uaccess.h>
#include <asm/processor.h>
#include <asm/fpu/signal.h>
#include <asm/fpu/regset.h>
#include <asm/fpu/xstate.h>
#include <asm/debugreg.h>
#include <asm/ldt.h>
#include <asm/desc.h>
#include <asm/prctl.h>
#include <asm/proto.h>
#include <asm/hw_breakpoint.h>
#include <asm/traps.h>
#include <asm/syscall.h>
#include <asm/fsgsbase.h>
#include <asm/io_bitmap.h>

#include "tls.h"

enum x86_regset_32 {};

enum x86_regset_64 {};

#define REGSET_GENERAL

#define REGSET_FP


struct pt_regs_offset {};

#define REG_OFFSET_NAME(r)
#define REG_OFFSET_END

static const struct pt_regs_offset regoffset_table[] =;

/**
 * regs_query_register_offset() - query register offset from its name
 * @name:	the name of a register
 *
 * regs_query_register_offset() returns the offset of a register in struct
 * pt_regs from its name. If the name is invalid, this returns -EINVAL;
 */
int regs_query_register_offset(const char *name)
{}

/**
 * regs_query_register_name() - query register name from its offset
 * @offset:	the offset of a register in struct pt_regs.
 *
 * regs_query_register_name() returns the name of a register from its
 * offset in struct pt_regs. If the @offset is invalid, this returns NULL;
 */
const char *regs_query_register_name(unsigned int offset)
{}

/*
 * does not yet catch signals sent when the child dies.
 * in exit.c or in signal.c.
 */

/*
 * Determines which flags the user has access to [1 = access, 0 = no access].
 */
#define FLAG_MASK_32

/*
 * Determines whether a value may be installed in a segment register.
 */
static inline bool invalid_selector(u16 value)
{}

#ifdef CONFIG_X86_32

#define FLAG_MASK

static unsigned long *pt_regs_access(struct pt_regs *regs, unsigned long regno)
{
	BUILD_BUG_ON(offsetof(struct pt_regs, bx) != 0);
	return &regs->bx + (regno >> 2);
}

static u16 get_segment_reg(struct task_struct *task, unsigned long offset)
{
	/*
	 * Returning the value truncates it to 16 bits.
	 */
	unsigned int retval;
	if (offset != offsetof(struct user_regs_struct, gs))
		retval = *pt_regs_access(task_pt_regs(task), offset);
	else {
		if (task == current)
			savesegment(gs, retval);
		else
			retval = task->thread.gs;
	}
	return retval;
}

static int set_segment_reg(struct task_struct *task,
			   unsigned long offset, u16 value)
{
	if (WARN_ON_ONCE(task == current))
		return -EIO;

	/*
	 * The value argument was already truncated to 16 bits.
	 */
	if (invalid_selector(value))
		return -EIO;

	/*
	 * For %cs and %ss we cannot permit a null selector.
	 * We can permit a bogus selector as long as it has USER_RPL.
	 * Null selectors are fine for other segment registers, but
	 * we will never get back to user mode with invalid %cs or %ss
	 * and will take the trap in iret instead.  Much code relies
	 * on user_mode() to distinguish a user trap frame (which can
	 * safely use invalid selectors) from a kernel trap frame.
	 */
	switch (offset) {
	case offsetof(struct user_regs_struct, cs):
	case offsetof(struct user_regs_struct, ss):
		if (unlikely(value == 0))
			return -EIO;
		fallthrough;

	default:
		*pt_regs_access(task_pt_regs(task), offset) = value;
		break;

	case offsetof(struct user_regs_struct, gs):
		task->thread.gs = value;
	}

	return 0;
}

#else  /* CONFIG_X86_64 */

#define FLAG_MASK

static unsigned long *pt_regs_access(struct pt_regs *regs, unsigned long offset)
{}

static u16 get_segment_reg(struct task_struct *task, unsigned long offset)
{}

static int set_segment_reg(struct task_struct *task,
			   unsigned long offset, u16 value)
{}

#endif	/* CONFIG_X86_32 */

static unsigned long get_flags(struct task_struct *task)
{}

static int set_flags(struct task_struct *task, unsigned long value)
{}

static int putreg(struct task_struct *child,
		  unsigned long offset, unsigned long value)
{}

static unsigned long getreg(struct task_struct *task, unsigned long offset)
{}

static int genregs_get(struct task_struct *target,
		       const struct user_regset *regset,
		       struct membuf to)
{}

static int genregs_set(struct task_struct *target,
		       const struct user_regset *regset,
		       unsigned int pos, unsigned int count,
		       const void *kbuf, const void __user *ubuf)
{}

static void ptrace_triggered(struct perf_event *bp,
			     struct perf_sample_data *data,
			     struct pt_regs *regs)
{}

/*
 * Walk through every ptrace breakpoints for this thread and
 * build the dr7 value on top of their attributes.
 *
 */
static unsigned long ptrace_get_dr7(struct perf_event *bp[])
{}

static int ptrace_fill_bp_fields(struct perf_event_attr *attr,
					int len, int type, bool disabled)
{}

static struct perf_event *
ptrace_register_breakpoint(struct task_struct *tsk, int len, int type,
				unsigned long addr, bool disabled)
{}

static int ptrace_modify_breakpoint(struct perf_event *bp, int len, int type,
					int disabled)
{}

/*
 * Handle ptrace writes to debug register 7.
 */
static int ptrace_write_dr7(struct task_struct *tsk, unsigned long data)
{}

/*
 * Handle PTRACE_PEEKUSR calls for the debug register area.
 */
static unsigned long ptrace_get_debugreg(struct task_struct *tsk, int n)
{}

static int ptrace_set_breakpoint_addr(struct task_struct *tsk, int nr,
				      unsigned long addr)
{}

/*
 * Handle PTRACE_POKEUSR calls for the debug register area.
 */
static int ptrace_set_debugreg(struct task_struct *tsk, int n,
			       unsigned long val)
{}

/*
 * These access the current or another (stopped) task's io permission
 * bitmap for debugging or core dump.
 */
static int ioperm_active(struct task_struct *target,
			 const struct user_regset *regset)
{}

static int ioperm_get(struct task_struct *target,
		      const struct user_regset *regset,
		      struct membuf to)
{}

/*
 * Called by kernel/ptrace.c when detaching..
 *
 * Make sure the single step bit is not set.
 */
void ptrace_disable(struct task_struct *child)
{}

#if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION
static const struct user_regset_view user_x86_32_view; /* Initialized below. */
#endif
#ifdef CONFIG_X86_64
static const struct user_regset_view user_x86_64_view; /* Initialized below. */
#endif

long arch_ptrace(struct task_struct *child, long request,
		 unsigned long addr, unsigned long data)
{}

#ifdef CONFIG_IA32_EMULATION

#include <linux/compat.h>
#include <linux/syscalls.h>
#include <asm/ia32.h>
#include <asm/user32.h>

#define R32

#define SEG32

static int putreg32(struct task_struct *child, unsigned regno, u32 value)
{}

#undef R32
#undef SEG32

#define R32

#define SEG32

static int getreg32(struct task_struct *child, unsigned regno, u32 *val)
{}

#undef R32
#undef SEG32

static int genregs32_get(struct task_struct *target,
			 const struct user_regset *regset,
			 struct membuf to)
{}

static int genregs32_set(struct task_struct *target,
			 const struct user_regset *regset,
			 unsigned int pos, unsigned int count,
			 const void *kbuf, const void __user *ubuf)
{}

static long ia32_arch_ptrace(struct task_struct *child, compat_long_t request,
			     compat_ulong_t caddr, compat_ulong_t cdata)
{}
#endif /* CONFIG_IA32_EMULATION */

#ifdef CONFIG_X86_X32_ABI
static long x32_arch_ptrace(struct task_struct *child,
			    compat_long_t request, compat_ulong_t caddr,
			    compat_ulong_t cdata)
{}
#endif

#ifdef CONFIG_COMPAT
long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
			compat_ulong_t caddr, compat_ulong_t cdata)
{}
#endif	/* CONFIG_COMPAT */

#ifdef CONFIG_X86_64

static struct user_regset x86_64_regsets[] __ro_after_init =;

static const struct user_regset_view user_x86_64_view =;

#else  /* CONFIG_X86_32 */

#define user_regs_struct32
#define genregs32_get
#define genregs32_set

#endif	/* CONFIG_X86_64 */

#if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION
static struct user_regset x86_32_regsets[] __ro_after_init =;

static const struct user_regset_view user_x86_32_view =;
#endif

/*
 * This represents bytes 464..511 in the memory layout exported through
 * the REGSET_XSTATE interface.
 */
u64 xstate_fx_sw_bytes[USER_XSTATE_FX_SW_WORDS];

void __init update_regset_xstate_info(unsigned int size, u64 xstate_mask)
{}

/*
 * This is used by the core dump code to decide which regset to dump.  The
 * core dump code writes out the resulting .e_machine and the corresponding
 * regsets.  This is suboptimal if the task is messing around with its CS.L
 * field, but at worst the core dump will end up missing some information.
 *
 * Unfortunately, it is also used by the broken PTRACE_GETREGSET and
 * PTRACE_SETREGSET APIs.  These APIs look at the .regsets field but have
 * no way to make sure that the e_machine they use matches the caller's
 * expectations.  The result is that the data format returned by
 * PTRACE_GETREGSET depends on the returned CS field (and even the offset
 * of the returned CS field depends on its value!) and the data format
 * accepted by PTRACE_SETREGSET is determined by the old CS value.  The
 * upshot is that it is basically impossible to use these APIs correctly.
 *
 * The best way to fix it in the long run would probably be to add new
 * improved ptrace() APIs to read and write registers reliably, possibly by
 * allowing userspace to select the ELF e_machine variant that they expect.
 */
const struct user_regset_view *task_user_regset_view(struct task_struct *task)
{}

void send_sigtrap(struct pt_regs *regs, int error_code, int si_code)
{}

void user_single_step_report(struct pt_regs *regs)
{}