~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/arm64/kernel/probes/decode-insn.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-only
  2 /*
  3  * arch/arm64/kernel/probes/decode-insn.c
  4  *
  5  * Copyright (C) 2013 Linaro Limited.
  6  */
  7 
  8 #include <linux/kernel.h>
  9 #include <linux/kprobes.h>
 10 #include <linux/module.h>
 11 #include <linux/kallsyms.h>
 12 #include <asm/insn.h>
 13 #include <asm/sections.h>
 14 
 15 #include "decode-insn.h"
 16 #include "simulate-insn.h"
 17 
 18 static bool __kprobes aarch64_insn_is_steppable(u32 insn)
 19 {
 20         /*
 21          * Branch instructions will write a new value into the PC which is
 22          * likely to be relative to the XOL address and therefore invalid.
 23          * Deliberate generation of an exception during stepping is also not
 24          * currently safe. Lastly, MSR instructions can do any number of nasty
 25          * things we can't handle during single-stepping.
 26          */
 27         if (aarch64_insn_is_class_branch_sys(insn)) {
 28                 if (aarch64_insn_is_branch(insn) ||
 29                     aarch64_insn_is_msr_imm(insn) ||
 30                     aarch64_insn_is_msr_reg(insn) ||
 31                     aarch64_insn_is_exception(insn) ||
 32                     aarch64_insn_is_eret(insn) ||
 33                     aarch64_insn_is_eret_auth(insn))
 34                         return false;
 35 
 36                 /*
 37                  * The MRS instruction may not return a correct value when
 38                  * executing in the single-stepping environment. We do make one
 39                  * exception, for reading the DAIF bits.
 40                  */
 41                 if (aarch64_insn_is_mrs(insn))
 42                         return aarch64_insn_extract_system_reg(insn)
 43                              != AARCH64_INSN_SPCLREG_DAIF;
 44 
 45                 /*
 46                  * The HINT instruction is steppable only if it is in whitelist
 47                  * and the rest of other such instructions are blocked for
 48                  * single stepping as they may cause exception or other
 49                  * unintended behaviour.
 50                  */
 51                 if (aarch64_insn_is_hint(insn))
 52                         return aarch64_insn_is_steppable_hint(insn);
 53 
 54                 return true;
 55         }
 56 
 57         /*
 58          * Instructions which load PC relative literals are not going to work
 59          * when executed from an XOL slot. Instructions doing an exclusive
 60          * load/store are not going to complete successfully when single-step
 61          * exception handling happens in the middle of the sequence.
 62          */
 63         if (aarch64_insn_uses_literal(insn) ||
 64             aarch64_insn_is_exclusive(insn))
 65                 return false;
 66 
 67         return true;
 68 }
 69 
 70 /* Return:
 71  *   INSN_REJECTED     If instruction is one not allowed to kprobe,
 72  *   INSN_GOOD         If instruction is supported and uses instruction slot,
 73  *   INSN_GOOD_NO_SLOT If instruction is supported but doesn't use its slot.
 74  */
 75 enum probe_insn __kprobes
 76 arm_probe_decode_insn(probe_opcode_t insn, struct arch_probe_insn *api)
 77 {
 78         /*
 79          * Instructions reading or modifying the PC won't work from the XOL
 80          * slot.
 81          */
 82         if (aarch64_insn_is_steppable(insn))
 83                 return INSN_GOOD;
 84 
 85         if (aarch64_insn_is_bcond(insn)) {
 86                 api->handler = simulate_b_cond;
 87         } else if (aarch64_insn_is_cbz(insn) ||
 88             aarch64_insn_is_cbnz(insn)) {
 89                 api->handler = simulate_cbz_cbnz;
 90         } else if (aarch64_insn_is_tbz(insn) ||
 91             aarch64_insn_is_tbnz(insn)) {
 92                 api->handler = simulate_tbz_tbnz;
 93         } else if (aarch64_insn_is_adr_adrp(insn)) {
 94                 api->handler = simulate_adr_adrp;
 95         } else if (aarch64_insn_is_b(insn) ||
 96             aarch64_insn_is_bl(insn)) {
 97                 api->handler = simulate_b_bl;
 98         } else if (aarch64_insn_is_br(insn) ||
 99             aarch64_insn_is_blr(insn) ||
100             aarch64_insn_is_ret(insn)) {
101                 api->handler = simulate_br_blr_ret;
102         } else {
103                 /*
104                  * Instruction cannot be stepped out-of-line and we don't
105                  * (yet) simulate it.
106                  */
107                 return INSN_REJECTED;
108         }
109 
110         return INSN_GOOD_NO_SLOT;
111 }
112 
113 #ifdef CONFIG_KPROBES
114 static bool __kprobes
115 is_probed_address_atomic(kprobe_opcode_t *scan_start, kprobe_opcode_t *scan_end)
116 {
117         while (scan_start >= scan_end) {
118                 /*
119                  * atomic region starts from exclusive load and ends with
120                  * exclusive store.
121                  */
122                 if (aarch64_insn_is_store_ex(le32_to_cpu(*scan_start)))
123                         return false;
124                 else if (aarch64_insn_is_load_ex(le32_to_cpu(*scan_start)))
125                         return true;
126                 scan_start--;
127         }
128 
129         return false;
130 }
131 
132 enum probe_insn __kprobes
133 arm_kprobe_decode_insn(kprobe_opcode_t *addr, struct arch_specific_insn *asi)
134 {
135         enum probe_insn decoded;
136         probe_opcode_t insn = le32_to_cpu(*addr);
137         probe_opcode_t *scan_end = NULL;
138         unsigned long size = 0, offset = 0;
139         struct arch_probe_insn *api = &asi->api;
140 
141         if (aarch64_insn_is_ldr_lit(insn)) {
142                 api->handler = simulate_ldr_literal;
143                 decoded = INSN_GOOD_NO_SLOT;
144         } else if (aarch64_insn_is_ldrsw_lit(insn)) {
145                 api->handler = simulate_ldrsw_literal;
146                 decoded = INSN_GOOD_NO_SLOT;
147         } else {
148                 decoded = arm_probe_decode_insn(insn, &asi->api);
149         }
150 
151         /*
152          * If there's a symbol defined in front of and near enough to
153          * the probe address assume it is the entry point to this
154          * code and use it to further limit how far back we search
155          * when determining if we're in an atomic sequence. If we could
156          * not find any symbol skip the atomic test altogether as we
157          * could otherwise end up searching irrelevant text/literals.
158          * KPROBES depends on KALLSYMS so this last case should never
159          * happen.
160          */
161         if (kallsyms_lookup_size_offset((unsigned long) addr, &size, &offset)) {
162                 if (offset < (MAX_ATOMIC_CONTEXT_SIZE*sizeof(kprobe_opcode_t)))
163                         scan_end = addr - (offset / sizeof(kprobe_opcode_t));
164                 else
165                         scan_end = addr - MAX_ATOMIC_CONTEXT_SIZE;
166         }
167 
168         if (decoded != INSN_REJECTED && scan_end)
169                 if (is_probed_address_atomic(addr - 1, scan_end))
170                         return INSN_REJECTED;
171 
172         return decoded;
173 }
174 #endif
175 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php