0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/kernel.h>
0009 #include <linux/kprobes.h>
0010 #include <linux/module.h>
0011 #include <linux/kallsyms.h>
0012 #include <asm/insn.h>
0013 #include <asm/sections.h>
0014
0015 #include "decode-insn.h"
0016 #include "simulate-insn.h"
0017
0018 static bool __kprobes aarch64_insn_is_steppable(u32 insn)
0019 {
0020
0021
0022
0023
0024
0025
0026
0027 if (aarch64_get_insn_class(insn) == AARCH64_INSN_CLS_BR_SYS) {
0028 if (aarch64_insn_is_branch(insn) ||
0029 aarch64_insn_is_msr_imm(insn) ||
0030 aarch64_insn_is_msr_reg(insn) ||
0031 aarch64_insn_is_exception(insn) ||
0032 aarch64_insn_is_eret(insn) ||
0033 aarch64_insn_is_eret_auth(insn))
0034 return false;
0035
0036
0037
0038
0039
0040
0041 if (aarch64_insn_is_mrs(insn))
0042 return aarch64_insn_extract_system_reg(insn)
0043 != AARCH64_INSN_SPCLREG_DAIF;
0044
0045
0046
0047
0048
0049
0050
0051 if (aarch64_insn_is_hint(insn))
0052 return aarch64_insn_is_steppable_hint(insn);
0053
0054 return true;
0055 }
0056
0057
0058
0059
0060
0061
0062
0063 if (aarch64_insn_uses_literal(insn) ||
0064 aarch64_insn_is_exclusive(insn))
0065 return false;
0066
0067 return true;
0068 }
0069
0070
0071
0072
0073
0074
0075 enum probe_insn __kprobes
0076 arm_probe_decode_insn(probe_opcode_t insn, struct arch_probe_insn *api)
0077 {
0078
0079
0080
0081
0082 if (aarch64_insn_is_steppable(insn))
0083 return INSN_GOOD;
0084
0085 if (aarch64_insn_is_bcond(insn)) {
0086 api->handler = simulate_b_cond;
0087 } else if (aarch64_insn_is_cbz(insn) ||
0088 aarch64_insn_is_cbnz(insn)) {
0089 api->handler = simulate_cbz_cbnz;
0090 } else if (aarch64_insn_is_tbz(insn) ||
0091 aarch64_insn_is_tbnz(insn)) {
0092 api->handler = simulate_tbz_tbnz;
0093 } else if (aarch64_insn_is_adr_adrp(insn)) {
0094 api->handler = simulate_adr_adrp;
0095 } else if (aarch64_insn_is_b(insn) ||
0096 aarch64_insn_is_bl(insn)) {
0097 api->handler = simulate_b_bl;
0098 } else if (aarch64_insn_is_br(insn) ||
0099 aarch64_insn_is_blr(insn) ||
0100 aarch64_insn_is_ret(insn)) {
0101 api->handler = simulate_br_blr_ret;
0102 } else if (aarch64_insn_is_ldr_lit(insn)) {
0103 api->handler = simulate_ldr_literal;
0104 } else if (aarch64_insn_is_ldrsw_lit(insn)) {
0105 api->handler = simulate_ldrsw_literal;
0106 } else {
0107
0108
0109
0110
0111 return INSN_REJECTED;
0112 }
0113
0114 return INSN_GOOD_NO_SLOT;
0115 }
0116
0117 #ifdef CONFIG_KPROBES
0118 static bool __kprobes
0119 is_probed_address_atomic(kprobe_opcode_t *scan_start, kprobe_opcode_t *scan_end)
0120 {
0121 while (scan_start >= scan_end) {
0122
0123
0124
0125
0126 if (aarch64_insn_is_store_ex(le32_to_cpu(*scan_start)))
0127 return false;
0128 else if (aarch64_insn_is_load_ex(le32_to_cpu(*scan_start)))
0129 return true;
0130 scan_start--;
0131 }
0132
0133 return false;
0134 }
0135
0136 enum probe_insn __kprobes
0137 arm_kprobe_decode_insn(kprobe_opcode_t *addr, struct arch_specific_insn *asi)
0138 {
0139 enum probe_insn decoded;
0140 probe_opcode_t insn = le32_to_cpu(*addr);
0141 probe_opcode_t *scan_end = NULL;
0142 unsigned long size = 0, offset = 0;
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154 if (kallsyms_lookup_size_offset((unsigned long) addr, &size, &offset)) {
0155 if (offset < (MAX_ATOMIC_CONTEXT_SIZE*sizeof(kprobe_opcode_t)))
0156 scan_end = addr - (offset / sizeof(kprobe_opcode_t));
0157 else
0158 scan_end = addr - MAX_ATOMIC_CONTEXT_SIZE;
0159 }
0160 decoded = arm_probe_decode_insn(insn, &asi->api);
0161
0162 if (decoded != INSN_REJECTED && scan_end)
0163 if (is_probed_address_atomic(addr - 1, scan_end))
0164 return INSN_REJECTED;
0165
0166 return decoded;
0167 }
0168 #endif