cregit-Linux how code gets into the kernel

Release 4.14 arch/alpha/kernel/ptrace.c

// SPDX-License-Identifier: GPL-2.0
/* ptrace.c */
/* By Ross Biro 1/23/92 */
/* edited by Linus Torvalds */
/* mangled further by Bob Manson (manson@santafe.edu) */
/* more mutilation by David Mosberger (davidm@azstarnet.com) */

#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/ptrace.h>
#include <linux/user.h>
#include <linux/security.h>
#include <linux/signal.h>
#include <linux/tracehook.h>
#include <linux/audit.h>

#include <linux/uaccess.h>
#include <asm/pgtable.h>
#include <asm/fpu.h>

#include "proto.h"


#define DEBUG	DBG_MEM

#undef DEBUG

#ifdef DEBUG
enum {
	
DBG_MEM		= (1<<0),
	
DBG_BPT		= (1<<1),
	
DBG_MEM_ALL	= (1<<2)
};

#define DBG(fac,args)	{if ((fac) & DEBUG) printk args;}
#else

#define DBG(fac,args)
#endif


#define BREAKINST	0x00000080	
/* call_pal bpt */

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

/*
 * Processes always block with the following stack-layout:
 *
 *  +================================+ <---- task + 2*PAGE_SIZE
 *  | PALcode saved frame (ps, pc,   | ^
 *  | gp, a0, a1, a2)                | |
 *  +================================+ | struct pt_regs
 *  |                                | |
 *  | frame generated by SAVE_ALL    | |
 *  |                                | v
 *  +================================+
 *  |                                | ^
 *  | frame saved by do_switch_stack | | struct switch_stack
 *  |                                | v
 *  +================================+
 */

/* 
 * The following table maps a register index into the stack offset at
 * which the register is saved.  Register indices are 0-31 for integer
 * regs, 32-63 for fp regs, and 64 for the pc.  Notice that sp and
 * zero have no stack-slot and need to be treated specially (see
 * get_reg/put_reg below).
 */
enum {
	



REG_R0 = 0, REG_F0 = 32, REG_FPCR = 63, REG_PC = 64
};


#define PT_REG(reg) \
  (PAGE_SIZE*2 - sizeof(struct pt_regs) + offsetof(struct pt_regs, reg))


#define SW_REG(reg) \
 (PAGE_SIZE*2 - sizeof(struct pt_regs) - sizeof(struct switch_stack) \
  + offsetof(struct switch_stack, reg))


static int regoff[] = {
	PT_REG(	   r0), PT_REG(	   r1), PT_REG(	   r2), PT_REG(	  r3),
	PT_REG(	   r4), PT_REG(	   r5), PT_REG(	   r6), PT_REG(	  r7),
	PT_REG(	   r8), SW_REG(	   r9), SW_REG(	  r10), SW_REG(	 r11),
	SW_REG(	  r12), SW_REG(	  r13), SW_REG(	  r14), SW_REG(	 r15),
	PT_REG(	  r16), PT_REG(	  r17), PT_REG(	  r18), PT_REG(	 r19),
	PT_REG(	  r20), PT_REG(	  r21), PT_REG(	  r22), PT_REG(	 r23),
	PT_REG(	  r24), PT_REG(	  r25), PT_REG(	  r26), PT_REG(	 r27),
	PT_REG(	  r28), PT_REG(	   gp),		   -1,		   -1,
	SW_REG(fp[ 0]), SW_REG(fp[ 1]), SW_REG(fp[ 2]), SW_REG(fp[ 3]),
	SW_REG(fp[ 4]), SW_REG(fp[ 5]), SW_REG(fp[ 6]), SW_REG(fp[ 7]),
	SW_REG(fp[ 8]), SW_REG(fp[ 9]), SW_REG(fp[10]), SW_REG(fp[11]),
	SW_REG(fp[12]), SW_REG(fp[13]), SW_REG(fp[14]), SW_REG(fp[15]),
	SW_REG(fp[16]), SW_REG(fp[17]), SW_REG(fp[18]), SW_REG(fp[19]),
	SW_REG(fp[20]), SW_REG(fp[21]), SW_REG(fp[22]), SW_REG(fp[23]),
	SW_REG(fp[24]), SW_REG(fp[25]), SW_REG(fp[26]), SW_REG(fp[27]),
	SW_REG(fp[28]), SW_REG(fp[29]), SW_REG(fp[30]), SW_REG(fp[31]),
	PT_REG(	   pc)
};


static unsigned long zero;

/*
 * Get address of register REGNO in task TASK.
 */

static unsigned long * get_reg_addr(struct task_struct * task, unsigned long regno) { unsigned long *addr; if (regno == 30) { addr = &task_thread_info(task)->pcb.usp; } else if (regno == 65) { addr = &task_thread_info(task)->pcb.unique; } else if (regno == 31 || regno > 65) { zero = 0; addr = &zero; } else { addr = task_stack_page(task) + regoff[regno]; } return addr; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)7168.93%444.44%
Richard Henderson2322.33%333.33%
Al Viro98.74%222.22%
Total103100.00%9100.00%

/* * Get contents of register REGNO in task TASK. */
static unsigned long get_reg(struct task_struct * task, unsigned long regno) { /* Special hack for fpcr -- combine hardware and software bits. */ if (regno == 63) { unsigned long fpcr = *get_reg_addr(task, regno); unsigned long swcr = task_thread_info(task)->ieee_state & IEEE_SW_MASK; swcr = swcr_update_status(swcr, fpcr); return fpcr | swcr; } return *get_reg_addr(task, regno); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)6791.78%240.00%
Al Viro34.11%120.00%
Richard Henderson34.11%240.00%
Total73100.00%5100.00%

/* * Write contents of register REGNO in task TASK. */
static int put_reg(struct task_struct *task, unsigned long regno, unsigned long data) { if (regno == 63) { task_thread_info(task)->ieee_state = ((task_thread_info(task)->ieee_state & ~IEEE_SW_MASK) | (data & IEEE_SW_MASK)); data = (data & FPCR_DYN_MASK) | ieee_swcr_to_fpcr(data); } *get_reg_addr(task, regno) = data; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)6986.25%562.50%
Al Viro67.50%112.50%
Richard Henderson56.25%225.00%
Total80100.00%8100.00%


static inline int read_int(struct task_struct *task, unsigned long addr, int * data) { int copied = access_process_vm(task, addr, data, sizeof(int), FOLL_FORCE); return (copied == sizeof(int)) ? 0 : -EIO; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)5398.15%375.00%
Lorenzo Stoakes11.85%125.00%
Total54100.00%4100.00%


static inline int write_int(struct task_struct *task, unsigned long addr, int data) { int copied = access_process_vm(task, addr, &data, sizeof(int), FOLL_FORCE | FOLL_WRITE); return (copied == sizeof(int)) ? 0 : -EIO; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)5394.64%480.00%
Lorenzo Stoakes35.36%120.00%
Total56100.00%5100.00%

/* * Set breakpoint. */
int ptrace_set_bpt(struct task_struct * child) { int displ, i, res, reg_b, nsaved = 0; unsigned int insn, op_code; unsigned long pc; pc = get_reg(child, REG_PC); res = read_int(child, pc, (int *) &insn); if (res < 0) return res; op_code = insn >> 26; if (op_code >= 0x30) { /* * It's a branch: instead of trying to figure out * whether the branch will be taken or not, we'll put * a breakpoint at either location. This is simpler, * more reliable, and probably not a whole lot slower * than the alternative approach of emulating the * branch (emulation can be tricky for fp branches). */ displ = ((s32)(insn << 11)) >> 9; task_thread_info(child)->bpt_addr[nsaved++] = pc + 4; if (displ) /* guard against unoptimized code */ task_thread_info(child)->bpt_addr[nsaved++] = pc + 4 + displ; DBG(DBG_BPT, ("execing branch\n")); } else if (op_code == 0x1a) { reg_b = (insn >> 16) & 0x1f; task_thread_info(child)->bpt_addr[nsaved++] = get_reg(child, reg_b); DBG(DBG_BPT, ("execing jump\n")); } else { task_thread_info(child)->bpt_addr[nsaved++] = pc + 4; DBG(DBG_BPT, ("execing normal insn\n")); } /* install breakpoints: */ for (i = 0; i < nsaved; ++i) { res = read_int(child, task_thread_info(child)->bpt_addr[i], (int *) &insn); if (res < 0) return res; task_thread_info(child)->bpt_insn[i] = insn; DBG(DBG_BPT, (" -> next_pc=%lx\n", task_thread_info(child)->bpt_addr[i])); res = write_int(child, task_thread_info(child)->bpt_addr[i], BREAKINST); if (res < 0) return res; } task_thread_info(child)->bpt_nsaved = nsaved; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)29086.31%342.86%
Al Viro278.04%114.29%
Richard Henderson195.65%342.86%
Total336100.00%7100.00%

/* * Ensure no single-step breakpoint is pending. Returns non-zero * value if child was being single-stepped. */
int ptrace_cancel_bpt(struct task_struct * child) { int i, nsaved = task_thread_info(child)->bpt_nsaved; task_thread_info(child)->bpt_nsaved = 0; if (nsaved > 2) { printk("ptrace_cancel_bpt: bogus nsaved: %d!\n", nsaved); nsaved = 2; } for (i = 0; i < nsaved; ++i) { write_int(child, task_thread_info(child)->bpt_addr[i], task_thread_info(child)->bpt_insn[i]); } return (nsaved != 0); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)8183.51%466.67%
Al Viro1212.37%116.67%
Richard Henderson44.12%116.67%
Total97100.00%6100.00%


void user_enable_single_step(struct task_struct *child) { /* Mark single stepping. */ task_thread_info(child)->bpt_nsaved = -1; }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Hellwig21100.00%1100.00%
Total21100.00%1100.00%


void user_disable_single_step(struct task_struct *child) { ptrace_cancel_bpt(child); }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Hellwig15100.00%1100.00%
Total15100.00%1100.00%

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

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds1493.33%150.00%
Christoph Hellwig16.67%150.00%
Total15100.00%2100.00%


long arch_ptrace(struct task_struct *child, long request, unsigned long addr, unsigned long data) { unsigned long tmp; size_t copied; long ret; switch (request) { /* When I and D space are separate, these will need to be fixed. */ case PTRACE_PEEKTEXT: /* read word at location addr. */ case PTRACE_PEEKDATA: copied = ptrace_access_vm(child, addr, &tmp, sizeof(tmp), FOLL_FORCE); ret = -EIO; if (copied != sizeof(tmp)) break; force_successful_syscall_return(); ret = tmp; break; /* Read register number ADDR. */ case PTRACE_PEEKUSR: force_successful_syscall_return(); ret = get_reg(child, addr); DBG(DBG_MEM, ("peek $%lu->%#lx\n", addr, ret)); break; /* When I and D space are separate, this will have to be fixed. */ case PTRACE_POKETEXT: /* write the word at location addr. */ case PTRACE_POKEDATA: ret = generic_ptrace_pokedata(child, addr, data); break; case PTRACE_POKEUSR: /* write the specified register */ DBG(DBG_MEM, ("poke $%lu<-%#lx\n", addr, data)); ret = put_reg(child, addr, data); break; default: ret = ptrace_request(child, request, addr, data); break; } return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)13975.54%956.25%
Richard Henderson158.15%16.25%
Christoph Hellwig115.98%16.25%
Daniel Jacobowitz105.43%16.25%
Namhyung Kim42.17%16.25%
Alexey Dobriyan31.63%16.25%
Eric W. Biedermann10.54%16.25%
Lorenzo Stoakes10.54%16.25%
Total184100.00%16100.00%


asmlinkage unsigned long syscall_trace_enter(void) { unsigned long ret = 0; struct pt_regs *regs = current_pt_regs(); if (test_thread_flag(TIF_SYSCALL_TRACE) && tracehook_report_syscall_entry(current_pt_regs())) ret = -1UL; audit_syscall_entry(regs->r0, regs->r16, regs->r17, regs->r18, regs->r19); return ret ?: current_pt_regs()->r0; }

Contributors

PersonTokensPropCommitsCommitProp
蔡正龙3142.47%120.00%
Al Viro2838.36%120.00%
Linus Torvalds (pre-git)912.33%120.00%
Richard Henderson56.85%240.00%
Total73100.00%5100.00%


asmlinkage void syscall_trace_leave(void) { audit_syscall_exit(current_pt_regs()); if (test_thread_flag(TIF_SYSCALL_TRACE)) tracehook_report_syscall_exit(current_pt_regs(), 0); }

Contributors

PersonTokensPropCommitsCommitProp
Al Viro1551.72%125.00%
Linus Torvalds (pre-git)827.59%250.00%
蔡正龙620.69%125.00%
Total29100.00%4100.00%


Overall Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)139580.82%1336.11%
Al Viro1035.97%38.33%
Richard Henderson784.52%616.67%
Christoph Hellwig482.78%25.56%
蔡正龙402.32%12.78%
Andrew Morton160.93%12.78%
Linus Torvalds160.93%25.56%
Daniel Jacobowitz100.58%12.78%
Lorenzo Stoakes50.29%12.78%
Namhyung Kim40.23%12.78%
Alexey Dobriyan30.17%12.78%
Ingo Molnar30.17%12.78%
Jesper Juhl30.17%12.78%
Greg Kroah-Hartman10.06%12.78%
Eric W. Biedermann10.06%12.78%
Total1726100.00%36100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.