]> git.karo-electronics.de Git - linux-beck.git/commitdiff
Merge branch 'for-next/kprobes' into for-next/core
authorCatalin Marinas <catalin.marinas@arm.com>
Thu, 21 Jul 2016 17:20:41 +0000 (18:20 +0100)
committerCatalin Marinas <catalin.marinas@arm.com>
Thu, 21 Jul 2016 17:20:41 +0000 (18:20 +0100)
* kprobes:
  arm64: kprobes: Add KASAN instrumentation around stack accesses
  arm64: kprobes: Cleanup jprobe_return
  arm64: kprobes: Fix overflow when saving stack
  arm64: kprobes: WARN if attempting to step with PSTATE.D=1
  kprobes: Add arm64 case in kprobe example module
  arm64: Add kernel return probes support (kretprobes)
  arm64: Add trampoline code for kretprobes
  arm64: kprobes instruction simulation support
  arm64: Treat all entry code as non-kprobe-able
  arm64: Blacklist non-kprobe-able symbol
  arm64: Kprobes with single stepping support
  arm64: add conditional instruction simulation support
  arm64: Add more test functions to insn.c
  arm64: Add HAVE_REGS_AND_STACK_ACCESS_API feature

1  2 
arch/arm64/Kconfig
arch/arm64/include/asm/ptrace.h
arch/arm64/kernel/Makefile
arch/arm64/kernel/arm64ksyms.c
arch/arm64/kernel/armv8_deprecated.c
arch/arm64/kernel/asm-offsets.c
arch/arm64/kernel/debug-monitors.c
arch/arm64/kernel/entry.S
arch/arm64/kernel/vmlinux.lds.S
arch/arm64/mm/fault.c

diff --combined arch/arm64/Kconfig
index 1b196bf9932078bf16c702ca91608fc5a1e4beb8,6af0e2e5c7103345ca666d9e3fbfc3d1ec7073c6..ac4746f454ed9265887228b6453ed31eeab04806
@@@ -7,7 -7,6 +7,7 @@@ config ARM6
        select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
        select ARCH_HAS_ELF_RANDOMIZE
        select ARCH_HAS_GCOV_PROFILE_ALL
 +      select ARCH_HAS_KCOV
        select ARCH_HAS_SG_CHAIN
        select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
        select ARCH_USE_CMPXCHG_LOCKREF
        select HAVE_PERF_EVENTS
        select HAVE_PERF_REGS
        select HAVE_PERF_USER_STACK_DUMP
+       select HAVE_REGS_AND_STACK_ACCESS_API
        select HAVE_RCU_TABLE_FREE
        select HAVE_SYSCALL_TRACEPOINTS
+       select HAVE_KPROBES
+       select HAVE_KRETPROBES if HAVE_KPROBES
        select IOMMU_DMA if IOMMU_SUPPORT
        select IRQ_DOMAIN
        select IRQ_FORCED_THREADING
@@@ -665,16 -667,6 +668,16 @@@ config PARAVIRT_TIME_ACCOUNTIN
  
          If in doubt, say N here.
  
 +config KEXEC
 +      depends on PM_SLEEP_SMP
 +      select KEXEC_CORE
 +      bool "kexec system call"
 +      ---help---
 +        kexec is a system call that implements the ability to shutdown your
 +        current kernel, and to start another kernel.  It is like a reboot
 +        but it is independent of the system firmware.   And like a reboot
 +        you can start any kernel with it, not just Linux.
 +
  config XEN_DOM0
        def_bool y
        depends on XEN
index 10e6f1d7269cc95366835d2a19406536dea843bc,baf938135986ad827700c7708fe0551cef4b4df4..3fd15fdf4181b43995fedb3ddfc2cbbf1800ecae
@@@ -46,6 -46,7 +46,6 @@@
  #define COMPAT_PSR_MODE_UND   0x0000001b
  #define COMPAT_PSR_MODE_SYS   0x0000001f
  #define COMPAT_PSR_T_BIT      0x00000020
 -#define COMPAT_PSR_E_BIT      0x00000200
  #define COMPAT_PSR_F_BIT      0x00000040
  #define COMPAT_PSR_I_BIT      0x00000080
  #define COMPAT_PSR_A_BIT      0x00000100
@@@ -73,6 -74,7 +73,7 @@@
  #define COMPAT_PT_DATA_ADDR           0x10004
  #define COMPAT_PT_TEXT_END_ADDR               0x10008
  #ifndef __ASSEMBLY__
+ #include <linux/bug.h>
  
  /* sizeof(struct user) for AArch32 */
  #define COMPAT_USER_SZ        296
@@@ -118,6 -120,8 +119,8 @@@ struct pt_regs 
        u64 syscallno;
  };
  
+ #define MAX_REG_OFFSET offsetof(struct pt_regs, pstate)
  #define arch_has_single_step()        (1)
  
  #ifdef CONFIG_COMPAT
  #define fast_interrupts_enabled(regs) \
        (!((regs)->pstate & PSR_F_BIT))
  
- #define user_stack_pointer(regs) \
+ #define GET_USP(regs) \
        (!compat_user_mode(regs) ? (regs)->sp : (regs)->compat_sp)
  
+ #define SET_USP(ptregs, value) \
+       (!compat_user_mode(regs) ? ((regs)->sp = value) : ((regs)->compat_sp = value))
+ extern int regs_query_register_offset(const char *name);
+ extern const char *regs_query_register_name(unsigned int offset);
+ extern unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs,
+                                              unsigned int n);
+ /**
+  * regs_get_register() - get register value from its offset
+  * @regs:     pt_regs from which register value is gotten
+  * @offset:   offset of the register.
+  *
+  * regs_get_register returns the value of a register whose offset from @regs.
+  * The @offset is the offset of the register in struct pt_regs.
+  * If @offset is bigger than MAX_REG_OFFSET, this returns 0.
+  */
+ static inline u64 regs_get_register(struct pt_regs *regs, unsigned int offset)
+ {
+       u64 val = 0;
+       WARN_ON(offset & 7);
+       offset >>= 3;
+       switch (offset) {
+       case 0 ... 30:
+               val = regs->regs[offset];
+               break;
+       case offsetof(struct pt_regs, sp) >> 3:
+               val = regs->sp;
+               break;
+       case offsetof(struct pt_regs, pc) >> 3:
+               val = regs->pc;
+               break;
+       case offsetof(struct pt_regs, pstate) >> 3:
+               val = regs->pstate;
+               break;
+       default:
+               val = 0;
+       }
+       return val;
+ }
+ /* Valid only for Kernel mode traps. */
+ static inline unsigned long kernel_stack_pointer(struct pt_regs *regs)
+ {
+       return regs->sp;
+ }
  static inline unsigned long regs_return_value(struct pt_regs *regs)
  {
        return regs->regs[0];
  struct task_struct;
  int valid_user_regs(struct user_pt_regs *regs, struct task_struct *task);
  
- #define instruction_pointer(regs)     ((unsigned long)(regs)->pc)
+ #define GET_IP(regs)          ((unsigned long)(regs)->pc)
+ #define SET_IP(regs, value)   ((regs)->pc = ((u64) (value)))
+ #define GET_FP(ptregs)                ((unsigned long)(ptregs)->regs[29])
+ #define SET_FP(ptregs, value) ((ptregs)->regs[29] = ((u64) (value)))
+ #include <asm-generic/ptrace.h>
  
+ #undef profile_pc
  extern unsigned long profile_pc(struct pt_regs *regs);
  
  #endif /* __ASSEMBLY__ */
index 9ef8ec681e30f4a2fc851f8b8a7abe640778055b,367673e38700d6c6a86f047748d55e7c78a06b98..0b9e49a92c47e8011140a54005602b91971a4d1d
@@@ -26,8 -26,7 +26,7 @@@ $(obj)/%.stub.o: $(obj)/%.o FORC
        $(call if_changed,objcopy)
  
  arm64-obj-$(CONFIG_COMPAT)            += sys32.o kuser32.o signal32.o         \
-                                          sys_compat.o entry32.o               \
-                                          ../../arm/kernel/opcodes.o
+                                          sys_compat.o entry32.o
  arm64-obj-$(CONFIG_FUNCTION_TRACER)   += ftrace.o entry-ftrace.o
  arm64-obj-$(CONFIG_MODULES)           += arm64ksyms.o module.o
  arm64-obj-$(CONFIG_ARM64_MODULE_PLTS) += module-plts.o
@@@ -46,10 -45,12 +45,10 @@@ arm64-obj-$(CONFIG_ARM64_ACPI_PARKING_P
  arm64-obj-$(CONFIG_PARAVIRT)          += paravirt.o
  arm64-obj-$(CONFIG_RANDOMIZE_BASE)    += kaslr.o
  arm64-obj-$(CONFIG_HIBERNATION)               += hibernate.o hibernate-asm.o
 +arm64-obj-$(CONFIG_KEXEC)             += machine_kexec.o relocate_kernel.o    \
 +                                         cpu-reset.o
  
- obj-y                                 += $(arm64-obj-y) vdso/
+ obj-y                                 += $(arm64-obj-y) vdso/ probes/
  obj-m                                 += $(arm64-obj-m)
  head-y                                        := head.o
  extra-y                                       += $(head-y) vmlinux.lds
 -
 -# vDSO - this must be built first to generate the symbol offsets
 -$(call objectify,$(arm64-obj-y)): $(obj)/vdso/vdso-offsets.h
 -$(obj)/vdso/vdso-offsets.h: $(obj)/vdso
index 2dc44406a7adb68fd6eae408a24dcdc724405a14,b96ff1ae2786015a1d72f3558297321b41a366a2..78f368039c79a76d45d7256ed64dd7535f198ed6
@@@ -27,6 -27,7 +27,7 @@@
  #include <linux/uaccess.h>
  #include <linux/io.h>
  #include <linux/arm-smccc.h>
+ #include <linux/kprobes.h>
  
  #include <asm/checksum.h>
  
@@@ -34,8 -35,8 +35,8 @@@ EXPORT_SYMBOL(copy_page)
  EXPORT_SYMBOL(clear_page);
  
        /* user mem (segment) */
 -EXPORT_SYMBOL(__copy_from_user);
 -EXPORT_SYMBOL(__copy_to_user);
 +EXPORT_SYMBOL(__arch_copy_from_user);
 +EXPORT_SYMBOL(__arch_copy_to_user);
  EXPORT_SYMBOL(__clear_user);
  EXPORT_SYMBOL(__copy_in_user);
  
@@@ -68,6 -69,7 +69,7 @@@ EXPORT_SYMBOL(test_and_change_bit)
  
  #ifdef CONFIG_FUNCTION_TRACER
  EXPORT_SYMBOL(_mcount);
+ NOKPROBE_SYMBOL(_mcount);
  #endif
  
        /* arm-smccc */
index fab5603f57ea845bde619879cb132b16d9057a57,29348947652985e1556e4c7225cbfd17774a4d87..5f72475e2e3b2f6ab213e81d2b123424d9323014
@@@ -316,6 -316,28 +316,6 @@@ static void __init register_insn_emulat
   */
  #define TYPE_SWPB (1 << 22)
  
 -/*
 - * Set up process info to signal segmentation fault - called on access error.
 - */
 -static void set_segfault(struct pt_regs *regs, unsigned long addr)
 -{
 -      siginfo_t info;
 -
 -      down_read(&current->mm->mmap_sem);
 -      if (find_vma(current->mm, addr) == NULL)
 -              info.si_code = SEGV_MAPERR;
 -      else
 -              info.si_code = SEGV_ACCERR;
 -      up_read(&current->mm->mmap_sem);
 -
 -      info.si_signo = SIGSEGV;
 -      info.si_errno = 0;
 -      info.si_addr  = (void *) instruction_pointer(regs);
 -
 -      pr_debug("SWP{B} emulation: access caused memory abort!\n");
 -      arm64_notify_die("Illegal memory access", regs, &info, 0);
 -}
 -
  static int emulate_swpX(unsigned int address, unsigned int *data,
                        unsigned int type)
  {
        return res;
  }
  
+ #define       ARM_OPCODE_CONDITION_UNCOND     0xf
+ static unsigned int __kprobes aarch32_check_condition(u32 opcode, u32 psr)
+ {
+       u32 cc_bits  = opcode >> 28;
+       if (cc_bits != ARM_OPCODE_CONDITION_UNCOND) {
+               if ((*aarch32_opcode_cond_checks[cc_bits])(psr))
+                       return ARM_OPCODE_CONDTEST_PASS;
+               else
+                       return ARM_OPCODE_CONDTEST_FAIL;
+       }
+       return ARM_OPCODE_CONDTEST_UNCOND;
+ }
  /*
   * swp_handler logs the id of calling process, dissects the instruction, sanity
   * checks the memory location, calls emulate_swpX for the actual operation and
@@@ -358,7 -395,7 +373,7 @@@ static int swp_handler(struct pt_regs *
  
        type = instr & TYPE_SWPB;
  
-       switch (arm_check_condition(instr, regs->pstate)) {
+       switch (aarch32_check_condition(instr, regs->pstate)) {
        case ARM_OPCODE_CONDTEST_PASS:
                break;
        case ARM_OPCODE_CONDTEST_FAIL:
@@@ -408,8 -445,7 +423,8 @@@ ret
        return 0;
  
  fault:
 -      set_segfault(regs, address);
 +      pr_debug("SWP{B} emulation: access caused memory abort!\n");
 +      arm64_notify_segfault(regs, address);
  
        return 0;
  }
@@@ -440,7 -476,7 +455,7 @@@ static int cp15barrier_handler(struct p
  {
        perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, regs->pc);
  
-       switch (arm_check_condition(instr, regs->pstate)) {
+       switch (aarch32_check_condition(instr, regs->pstate)) {
        case ARM_OPCODE_CONDTEST_PASS:
                break;
        case ARM_OPCODE_CONDTEST_FAIL:
index 334a1cd7a942ac4e4857c7ed88ec0bbd885ed8a5,03dfa27ccf0f2e05b8243ad11d87cf1945aed418..93ff5922debb0ff3cbf9d6df288f74ef79ec8dba
@@@ -51,6 -51,17 +51,17 @@@ int main(void
    DEFINE(S_X5,                        offsetof(struct pt_regs, regs[5]));
    DEFINE(S_X6,                        offsetof(struct pt_regs, regs[6]));
    DEFINE(S_X7,                        offsetof(struct pt_regs, regs[7]));
+   DEFINE(S_X8,                        offsetof(struct pt_regs, regs[8]));
+   DEFINE(S_X10,                       offsetof(struct pt_regs, regs[10]));
+   DEFINE(S_X12,                       offsetof(struct pt_regs, regs[12]));
+   DEFINE(S_X14,                       offsetof(struct pt_regs, regs[14]));
+   DEFINE(S_X16,                       offsetof(struct pt_regs, regs[16]));
+   DEFINE(S_X18,                       offsetof(struct pt_regs, regs[18]));
+   DEFINE(S_X20,                       offsetof(struct pt_regs, regs[20]));
+   DEFINE(S_X22,                       offsetof(struct pt_regs, regs[22]));
+   DEFINE(S_X24,                       offsetof(struct pt_regs, regs[24]));
+   DEFINE(S_X26,                       offsetof(struct pt_regs, regs[26]));
+   DEFINE(S_X28,                       offsetof(struct pt_regs, regs[28]));
    DEFINE(S_LR,                        offsetof(struct pt_regs, regs[30]));
    DEFINE(S_SP,                        offsetof(struct pt_regs, sp));
  #ifdef CONFIG_COMPAT
@@@ -77,7 -88,6 +88,7 @@@
    BLANK();
    DEFINE(CLOCK_REALTIME,      CLOCK_REALTIME);
    DEFINE(CLOCK_MONOTONIC,     CLOCK_MONOTONIC);
 +  DEFINE(CLOCK_MONOTONIC_RAW, CLOCK_MONOTONIC_RAW);
    DEFINE(CLOCK_REALTIME_RES,  MONOTONIC_RES_NSEC);
    DEFINE(CLOCK_REALTIME_COARSE,       CLOCK_REALTIME_COARSE);
    DEFINE(CLOCK_MONOTONIC_COARSE,CLOCK_MONOTONIC_COARSE);
@@@ -85,8 -95,6 +96,8 @@@
    DEFINE(NSEC_PER_SEC,                NSEC_PER_SEC);
    BLANK();
    DEFINE(VDSO_CS_CYCLE_LAST,  offsetof(struct vdso_data, cs_cycle_last));
 +  DEFINE(VDSO_RAW_TIME_SEC,   offsetof(struct vdso_data, raw_time_sec));
 +  DEFINE(VDSO_RAW_TIME_NSEC,  offsetof(struct vdso_data, raw_time_nsec));
    DEFINE(VDSO_XTIME_CLK_SEC,  offsetof(struct vdso_data, xtime_clock_sec));
    DEFINE(VDSO_XTIME_CLK_NSEC, offsetof(struct vdso_data, xtime_clock_nsec));
    DEFINE(VDSO_XTIME_CRS_SEC,  offsetof(struct vdso_data, xtime_coarse_sec));
    DEFINE(VDSO_WTM_CLK_SEC,    offsetof(struct vdso_data, wtm_clock_sec));
    DEFINE(VDSO_WTM_CLK_NSEC,   offsetof(struct vdso_data, wtm_clock_nsec));
    DEFINE(VDSO_TB_SEQ_COUNT,   offsetof(struct vdso_data, tb_seq_count));
 -  DEFINE(VDSO_CS_MULT,                offsetof(struct vdso_data, cs_mult));
 +  DEFINE(VDSO_CS_MONO_MULT,   offsetof(struct vdso_data, cs_mono_mult));
 +  DEFINE(VDSO_CS_RAW_MULT,    offsetof(struct vdso_data, cs_raw_mult));
    DEFINE(VDSO_CS_SHIFT,               offsetof(struct vdso_data, cs_shift));
    DEFINE(VDSO_TZ_MINWEST,     offsetof(struct vdso_data, tz_minuteswest));
    DEFINE(VDSO_TZ_DSTTIME,     offsetof(struct vdso_data, tz_dsttime));
index f17134d39e6bcbbd6210d67be235e9672d90a915,2fbc1b99e8fb6d42015843fd10e577e8af9c8acf..91fff48d0f574c5060525d87b1fe85185ee178ef
@@@ -23,6 -23,7 +23,7 @@@
  #include <linux/hardirq.h>
  #include <linux/init.h>
  #include <linux/ptrace.h>
+ #include <linux/kprobes.h>
  #include <linux/stat.h>
  #include <linux/uaccess.h>
  
@@@ -48,6 -49,7 +49,7 @@@ static void mdscr_write(u32 mdscr
        asm volatile("msr mdscr_el1, %0" :: "r" (mdscr));
        local_dbg_restore(flags);
  }
+ NOKPROBE_SYMBOL(mdscr_write);
  
  static u32 mdscr_read(void)
  {
@@@ -55,6 -57,7 +57,7 @@@
        asm volatile("mrs %0, mdscr_el1" : "=r" (mdscr));
        return mdscr;
  }
+ NOKPROBE_SYMBOL(mdscr_read);
  
  /*
   * Allow root to disable self-hosted debug from userspace.
@@@ -103,6 -106,7 +106,7 @@@ void enable_debug_monitors(enum dbg_act
                mdscr_write(mdscr);
        }
  }
+ NOKPROBE_SYMBOL(enable_debug_monitors);
  
  void disable_debug_monitors(enum dbg_active_el el)
  {
                mdscr_write(mdscr);
        }
  }
+ NOKPROBE_SYMBOL(disable_debug_monitors);
  
  /*
   * OS lock clearing.
@@@ -151,6 -156,7 +156,6 @@@ static int debug_monitors_init(void
        /* Clear the OS lock. */
        on_each_cpu(clear_os_lock, NULL, 1);
        isb();
 -      local_dbg_enable();
  
        /* Register hotplug handler. */
        __register_cpu_notifier(&os_lock_nb);
@@@ -165,13 -171,24 +170,15 @@@ postcore_initcall(debug_monitors_init)
   */
  static void set_regs_spsr_ss(struct pt_regs *regs)
  {
 -      unsigned long spsr;
 -
 -      spsr = regs->pstate;
 -      spsr &= ~DBG_SPSR_SS;
 -      spsr |= DBG_SPSR_SS;
 -      regs->pstate = spsr;
 +      regs->pstate |= DBG_SPSR_SS;
  }
+ NOKPROBE_SYMBOL(set_regs_spsr_ss);
  
  static void clear_regs_spsr_ss(struct pt_regs *regs)
  {
 -      unsigned long spsr;
 -
 -      spsr = regs->pstate;
 -      spsr &= ~DBG_SPSR_SS;
 -      regs->pstate = spsr;
 +      regs->pstate &= ~DBG_SPSR_SS;
  }
+ NOKPROBE_SYMBOL(clear_regs_spsr_ss);
  
  /* EL1 Single Step Handler hooks */
  static LIST_HEAD(step_hook);
@@@ -215,6 -232,7 +222,7 @@@ static int call_step_hook(struct pt_reg
  
        return retval;
  }
+ NOKPROBE_SYMBOL(call_step_hook);
  
  static void send_user_sigtrap(int si_code)
  {
@@@ -256,6 -274,10 +264,10 @@@ static int single_step_handler(unsigne
                 */
                user_rewind_single_step(current);
        } else {
+ #ifdef        CONFIG_KPROBES
+               if (kprobe_single_step_handler(regs, esr) == DBG_HOOK_HANDLED)
+                       return 0;
+ #endif
                if (call_step_hook(regs, esr) == DBG_HOOK_HANDLED)
                        return 0;
  
  
        return 0;
  }
+ NOKPROBE_SYMBOL(single_step_handler);
  
  /*
   * Breakpoint handler is re-entrant as another breakpoint can
@@@ -306,19 -329,28 +319,28 @@@ static int call_break_hook(struct pt_re
  
        return fn ? fn(regs, esr) : DBG_HOOK_ERROR;
  }
+ NOKPROBE_SYMBOL(call_break_hook);
  
  static int brk_handler(unsigned long addr, unsigned int esr,
                       struct pt_regs *regs)
  {
        if (user_mode(regs)) {
                send_user_sigtrap(TRAP_BRKPT);
-       } else if (call_break_hook(regs, esr) != DBG_HOOK_HANDLED) {
-               pr_warning("Unexpected kernel BRK exception at EL1\n");
+       }
+ #ifdef        CONFIG_KPROBES
+       else if ((esr & BRK64_ESR_MASK) == BRK64_ESR_KPROBES) {
+               if (kprobe_breakpoint_handler(regs, esr) != DBG_HOOK_HANDLED)
+                       return -EFAULT;
+       }
+ #endif
+       else if (call_break_hook(regs, esr) != DBG_HOOK_HANDLED) {
+               pr_warn("Unexpected kernel BRK exception at EL1\n");
                return -EFAULT;
        }
  
        return 0;
  }
+ NOKPROBE_SYMBOL(brk_handler);
  
  int aarch32_break_handler(struct pt_regs *regs)
  {
        send_user_sigtrap(TRAP_BRKPT);
        return 0;
  }
+ NOKPROBE_SYMBOL(aarch32_break_handler);
  
  static int __init debug_traps_init(void)
  {
@@@ -376,6 -409,7 +399,7 @@@ void user_rewind_single_step(struct tas
        if (test_ti_thread_flag(task_thread_info(task), TIF_SINGLESTEP))
                set_regs_spsr_ss(task_pt_regs(task));
  }
+ NOKPROBE_SYMBOL(user_rewind_single_step);
  
  void user_fastforward_single_step(struct task_struct *task)
  {
@@@ -391,6 -425,7 +415,7 @@@ void kernel_enable_single_step(struct p
        mdscr_write(mdscr_read() | DBG_MDSCR_SS);
        enable_debug_monitors(DBG_ACTIVE_EL1);
  }
+ NOKPROBE_SYMBOL(kernel_enable_single_step);
  
  void kernel_disable_single_step(void)
  {
        mdscr_write(mdscr_read() & ~DBG_MDSCR_SS);
        disable_debug_monitors(DBG_ACTIVE_EL1);
  }
+ NOKPROBE_SYMBOL(kernel_disable_single_step);
  
  int kernel_active_single_step(void)
  {
        WARN_ON(!irqs_disabled());
        return mdscr_read() & DBG_MDSCR_SS;
  }
+ NOKPROBE_SYMBOL(kernel_active_single_step);
  
  /* ptrace API */
  void user_enable_single_step(struct task_struct *task)
        set_ti_thread_flag(task_thread_info(task), TIF_SINGLESTEP);
        set_regs_spsr_ss(task_pt_regs(task));
  }
+ NOKPROBE_SYMBOL(user_enable_single_step);
  
  void user_disable_single_step(struct task_struct *task)
  {
        clear_ti_thread_flag(task_thread_info(task), TIF_SINGLESTEP);
  }
+ NOKPROBE_SYMBOL(user_disable_single_step);
index 3eca5d34f7a682245e1ef4e7210a0b214e87cfac,492a2655fea47ddc5404b16a4ce6ae78ad57e03f..a03eb49cfeeb7638de20527c3554b80bbdbf0d51
@@@ -242,6 -242,7 +242,7 @@@ tsk        .req    x28             // current thread_inf
  /*
   * Exception vectors.
   */
+       .pushsection ".entry.text", "ax"
  
        .align  11
  ENTRY(vectors)
@@@ -451,7 -452,7 +452,7 @@@ el0_sync
        cmp     x24, #ESR_ELx_EC_FP_EXC64       // FP/ASIMD exception
        b.eq    el0_fpsimd_exc
        cmp     x24, #ESR_ELx_EC_SYS64          // configurable trap
 -      b.eq    el0_undef
 +      b.eq    el0_sys
        cmp     x24, #ESR_ELx_EC_SP_ALIGN       // stack alignment exception
        b.eq    el0_sp_pc
        cmp     x24, #ESR_ELx_EC_PC_ALIGN       // pc alignment exception
@@@ -532,7 -533,7 +533,7 @@@ el0_ia
        enable_dbg_and_irq
        ct_user_exit
        mov     x0, x26
 -      orr     x1, x25, #1 << 24               // use reserved ISS bit for instruction aborts
 +      mov     x1, x25
        mov     x2, sp
        bl      do_mem_abort
        b       ret_to_user
@@@ -579,16 -580,6 +580,16 @@@ el0_undef
        mov     x0, sp
        bl      do_undefinstr
        b       ret_to_user
 +el0_sys:
 +      /*
 +       * System instructions, for trapped cache maintenance instructions
 +       */
 +      enable_dbg_and_irq
 +      ct_user_exit
 +      mov     x0, x25
 +      mov     x1, sp
 +      bl      do_sysinstr
 +      b       ret_to_user
  el0_dbg:
        /*
         * Debug exception handling
@@@ -784,6 -775,8 +785,8 @@@ __ni_sys_trace
        bl      do_ni_syscall
        b       __sys_trace_return
  
+       .popsection                             // .entry.text
  /*
   * Special system call wrappers.
   */
index 0de7be4f1a9d34f010fe22d05d0812df6eecc26a,9f5939469ef60725c06995032a93caa2178d4b23..89d6e177ecbd4ade288f9c139df57a937820adfe
@@@ -118,9 -118,11 +118,11 @@@ SECTION
                        __exception_text_end = .;
                        IRQENTRY_TEXT
                        SOFTIRQENTRY_TEXT
+                       ENTRY_TEXT
                        TEXT_TEXT
                        SCHED_TEXT
                        LOCK_TEXT
+                       KPROBES_TEXT
                        HYPERVISOR_TEXT
                        IDMAP_TEXT
                        HIBERNATE_TEXT
        }
  
        . = ALIGN(SEGMENT_ALIGN);
 -      RO_DATA(PAGE_SIZE)              /* everything from this point to */
 -      EXCEPTION_TABLE(8)              /* _etext will be marked RO NX   */
 +      _etext = .;                     /* End of text section */
 +
 +      RO_DATA(PAGE_SIZE)              /* everything from this point to     */
 +      EXCEPTION_TABLE(8)              /* __init_begin will be marked RO NX */
        NOTES
  
        . = ALIGN(SEGMENT_ALIGN);
 -      _etext = .;                     /* End of text and rodata section */
        __init_begin = .;
  
        INIT_TEXT_SECTION(8)
diff --combined arch/arm64/mm/fault.c
index fc5a34a72c6d978786538bedd3a46cf206eac441,2408e51d781fa3012eb620cc5e219427d1a85565..4ebda515a016e280be6214644b59a5b70d2123ca
  
  static const char *fault_name(unsigned int esr);
  
+ #ifdef CONFIG_KPROBES
+ static inline int notify_page_fault(struct pt_regs *regs, unsigned int esr)
+ {
+       int ret = 0;
+       /* kprobe_running() needs smp_processor_id() */
+       if (!user_mode(regs)) {
+               preempt_disable();
+               if (kprobe_running() && kprobe_fault_handler(regs, esr))
+                       ret = 1;
+               preempt_enable();
+       }
+       return ret;
+ }
+ #else
+ static inline int notify_page_fault(struct pt_regs *regs, unsigned int esr)
+ {
+       return 0;
+ }
+ #endif
  /*
   * Dump out the page tables associated with 'addr' in mm 'mm'.
   */
@@@ -202,6 -224,8 +224,6 @@@ static void do_bad_area(unsigned long a
  #define VM_FAULT_BADMAP               0x010000
  #define VM_FAULT_BADACCESS    0x020000
  
 -#define ESR_LNX_EXEC          (1 << 24)
 -
  static int __do_page_fault(struct mm_struct *mm, unsigned long addr,
                           unsigned int mm_flags, unsigned long vm_flags,
                           struct task_struct *tsk)
@@@ -240,19 -264,14 +262,19 @@@ out
        return fault;
  }
  
 -static inline int permission_fault(unsigned int esr)
 +static inline bool is_permission_fault(unsigned int esr)
  {
 -      unsigned int ec       = (esr & ESR_ELx_EC_MASK) >> ESR_ELx_EC_SHIFT;
 +      unsigned int ec       = ESR_ELx_EC(esr);
        unsigned int fsc_type = esr & ESR_ELx_FSC_TYPE;
  
        return (ec == ESR_ELx_EC_DABT_CUR && fsc_type == ESR_ELx_FSC_PERM);
  }
  
 +static bool is_el0_instruction_abort(unsigned int esr)
 +{
 +      return ESR_ELx_EC(esr) == ESR_ELx_EC_IABT_LOW;
 +}
 +
  static int __kprobes do_page_fault(unsigned long addr, unsigned int esr,
                                   struct pt_regs *regs)
  {
        unsigned long vm_flags = VM_READ | VM_WRITE | VM_EXEC;
        unsigned int mm_flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
  
+       if (notify_page_fault(regs, esr))
+               return 0;
        tsk = current;
        mm  = tsk->mm;
  
        if (user_mode(regs))
                mm_flags |= FAULT_FLAG_USER;
  
 -      if (esr & ESR_LNX_EXEC) {
 +      if (is_el0_instruction_abort(esr)) {
                vm_flags = VM_EXEC;
        } else if ((esr & ESR_ELx_WNR) && !(esr & ESR_ELx_CM)) {
                vm_flags = VM_WRITE;
                mm_flags |= FAULT_FLAG_WRITE;
        }
  
 -      if (permission_fault(esr) && (addr < USER_DS)) {
 +      if (is_permission_fault(esr) && (addr < USER_DS)) {
                if (get_fs() == KERNEL_DS)
                        die("Accessing user space memory with fs=KERNEL_DS", regs, esr);
  
@@@ -632,6 -654,7 +657,7 @@@ asmlinkage int __exception do_debug_exc
  
        return rv;
  }
+ NOKPROBE_SYMBOL(do_debug_exception);
  
  #ifdef CONFIG_ARM64_PAN
  void cpu_enable_pan(void *__unused)