Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * arch/arm64/kernel/probes/decode-insn.c
0004  *
0005  * Copyright (C) 2013 Linaro Limited.
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      * Branch instructions will write a new value into the PC which is
0022      * likely to be relative to the XOL address and therefore invalid.
0023      * Deliberate generation of an exception during stepping is also not
0024      * currently safe. Lastly, MSR instructions can do any number of nasty
0025      * things we can't handle during single-stepping.
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          * The MRS instruction may not return a correct value when
0038          * executing in the single-stepping environment. We do make one
0039          * exception, for reading the DAIF bits.
0040          */
0041         if (aarch64_insn_is_mrs(insn))
0042             return aarch64_insn_extract_system_reg(insn)
0043                  != AARCH64_INSN_SPCLREG_DAIF;
0044 
0045         /*
0046          * The HINT instruction is steppable only if it is in whitelist
0047          * and the rest of other such instructions are blocked for
0048          * single stepping as they may cause exception or other
0049          * unintended behaviour.
0050          */
0051         if (aarch64_insn_is_hint(insn))
0052             return aarch64_insn_is_steppable_hint(insn);
0053 
0054         return true;
0055     }
0056 
0057     /*
0058      * Instructions which load PC relative literals are not going to work
0059      * when executed from an XOL slot. Instructions doing an exclusive
0060      * load/store are not going to complete successfully when single-step
0061      * exception handling happens in the middle of the sequence.
0062      */
0063     if (aarch64_insn_uses_literal(insn) ||
0064         aarch64_insn_is_exclusive(insn))
0065         return false;
0066 
0067     return true;
0068 }
0069 
0070 /* Return:
0071  *   INSN_REJECTED     If instruction is one not allowed to kprobe,
0072  *   INSN_GOOD         If instruction is supported and uses instruction slot,
0073  *   INSN_GOOD_NO_SLOT If instruction is supported but doesn't use its slot.
0074  */
0075 enum probe_insn __kprobes
0076 arm_probe_decode_insn(probe_opcode_t insn, struct arch_probe_insn *api)
0077 {
0078     /*
0079      * Instructions reading or modifying the PC won't work from the XOL
0080      * slot.
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          * Instruction cannot be stepped out-of-line and we don't
0109          * (yet) simulate it.
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          * atomic region starts from exclusive load and ends with
0124          * exclusive store.
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      * If there's a symbol defined in front of and near enough to
0146      * the probe address assume it is the entry point to this
0147      * code and use it to further limit how far back we search
0148      * when determining if we're in an atomic sequence. If we could
0149      * not find any symbol skip the atomic test altogether as we
0150      * could otherwise end up searching irrelevant text/literals.
0151      * KPROBES depends on KALLSYMS so this last case should never
0152      * happen.
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