This patch use previous introduced checker on store instructions,
record stack consumption informations to arch_probes_insn. With such
information, kprobe opt can decide how much stack needs to be
protected.

Signed-off-by: Wang Nan <wangn...@huawei.com>
---
 arch/arm/include/asm/probes.h   |  1 +
 arch/arm/kernel/kprobes-arm.c   |  8 ++---
 arch/arm/kernel/kprobes-thumb.c |  8 ++---
 arch/arm/kernel/probes-arm.c    | 19 +++++++++++
 arch/arm/kernel/probes-arm.h    |  7 +++++
 arch/arm/kernel/probes-thumb.c  | 70 +++++++++++++++++++++++++++++++++++++++++
 arch/arm/kernel/probes-thumb.h  |  9 ++++++
 arch/arm/kernel/probes.c        | 64 +++++++++++++++++++++++++++++++++++++
 arch/arm/kernel/probes.h        | 13 ++++++++
 arch/arm/kernel/uprobes-arm.c   |  8 ++---
 10 files changed, 195 insertions(+), 12 deletions(-)

diff --git a/arch/arm/include/asm/probes.h b/arch/arm/include/asm/probes.h
index 806cfe6..ccf9af3 100644
--- a/arch/arm/include/asm/probes.h
+++ b/arch/arm/include/asm/probes.h
@@ -38,6 +38,7 @@ struct arch_probes_insn {
        probes_check_cc                 *insn_check_cc;
        probes_insn_singlestep_t        *insn_singlestep;
        probes_insn_fn_t                *insn_fn;
+       int stack_space;
 };
 
 #endif
diff --git a/arch/arm/kernel/kprobes-arm.c b/arch/arm/kernel/kprobes-arm.c
index 1094ff1..bb1bec3 100644
--- a/arch/arm/kernel/kprobes-arm.c
+++ b/arch/arm/kernel/kprobes-arm.c
@@ -316,11 +316,11 @@ const struct decode_action 
kprobes_arm_actions[NUM_PROBES_ARM_ACTIONS] = {
        [PROBES_MUL2] = {.handler = emulate_rd16rn12rm0rs8_rwflags_nopc},
        [PROBES_SWP] = {.handler = emulate_rd12rn16rm0_rwflags_nopc},
        [PROBES_LDRD] = {.handler = emulate_ldrdstrd},
-       [PROBES_STRD] = {.handler = emulate_ldrdstrd},
+       [PROBES_STRD] = {.checker = probes_check_arm_store_extra, .handler = 
emulate_ldrdstrd},
        [PROBES_LOAD_EXTRA] = {.handler = emulate_ldr},
        [PROBES_LOAD] = {.handler = emulate_ldr},
-       [PROBES_STORE_EXTRA] = {.handler = emulate_str},
-       [PROBES_STORE] = {.handler = emulate_str},
+       [PROBES_STORE_EXTRA] = {.checker = probes_check_arm_store_extra, 
.handler = emulate_str},
+       [PROBES_STORE] = {.checker = probes_check_arm_store, .handler = 
emulate_str},
        [PROBES_MOV_IP_SP] = {.handler = simulate_mov_ipsp},
        [PROBES_DATA_PROCESSING_REG] = {
                .handler = emulate_rd12rn16rm0rs8_rwflags},
@@ -341,5 +341,5 @@ const struct decode_action 
kprobes_arm_actions[NUM_PROBES_ARM_ACTIONS] = {
        [PROBES_BITFIELD] = {.handler = emulate_rd12rm0_noflags_nopc},
        [PROBES_BRANCH] = {.handler = simulate_bbl},
        [PROBES_LDM] = {.decoder = kprobe_decode_ldmstm},
-       [PROBES_STM] = {.decoder = kprobe_decode_ldmstm},
+       [PROBES_STM] = {.checker = probes_check_stm, .decoder = 
kprobe_decode_ldmstm},
 };
diff --git a/arch/arm/kernel/kprobes-thumb.c b/arch/arm/kernel/kprobes-thumb.c
index c6426b6..5da4231 100644
--- a/arch/arm/kernel/kprobes-thumb.c
+++ b/arch/arm/kernel/kprobes-thumb.c
@@ -615,7 +615,7 @@ const struct decode_action 
kprobes_t16_actions[NUM_PROBES_T16_ACTIONS] = {
        [PROBES_T16_ADD_SP] = {.handler = t16_simulate_add_sp_imm},
        [PROBES_T16_CBZ] = {.handler = t16_simulate_cbz},
        [PROBES_T16_SIGN_EXTEND] = {.handler = t16_emulate_loregs_rwflags},
-       [PROBES_T16_PUSH] = {.decoder = t16_decode_push},
+       [PROBES_T16_PUSH] = {.checker = t16_check_push, .decoder = 
t16_decode_push},
        [PROBES_T16_POP] = {.decoder = t16_decode_pop},
        [PROBES_T16_SEV] = {.handler = probes_emulate_none},
        [PROBES_T16_WFE] = {.handler = probes_simulate_nop},
@@ -639,9 +639,9 @@ const struct decode_action 
kprobes_t16_actions[NUM_PROBES_T16_ACTIONS] = {
 
 const struct decode_action kprobes_t32_actions[NUM_PROBES_T32_ACTIONS] = {
        [PROBES_T32_LDM] = {.decoder = t32_decode_ldmstm},
-       [PROBES_T32_STM] = {.decoder = t32_decode_ldmstm},
+       [PROBES_T32_STM] = {.checker = probes_check_stm, .decoder = 
t32_decode_ldmstm},
        [PROBES_T32_LDRD] = {.handler = t32_emulate_ldrdstrd},
-       [PROBES_T32_STRD] = {.handler = t32_emulate_ldrdstrd},
+       [PROBES_T32_STRD] = {.checker = t32_check_strd, .handler = 
t32_emulate_ldrdstrd},
        [PROBES_T32_TABLE_BRANCH] = {.handler = t32_simulate_table_branch},
        [PROBES_T32_TST] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
        [PROBES_T32_MOV] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
@@ -661,7 +661,7 @@ const struct decode_action 
kprobes_t32_actions[NUM_PROBES_T32_ACTIONS] = {
        [PROBES_T32_PLDI] = {.handler = probes_simulate_nop},
        [PROBES_T32_LDR_LIT] = {.handler = t32_simulate_ldr_literal},
        [PROBES_T32_LDR] = {.handler = t32_emulate_ldrstr},
-       [PROBES_T32_STR] = {.handler = t32_emulate_ldrstr},
+       [PROBES_T32_STR] = {.checker = t32_check_str, .handler = 
t32_emulate_ldrstr},
        [PROBES_T32_SIGN_EXTEND] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
        [PROBES_T32_MEDIA] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
        [PROBES_T32_REVERSE] = {.handler = t32_emulate_rd8rn16_noflags},
diff --git a/arch/arm/kernel/probes-arm.c b/arch/arm/kernel/probes-arm.c
index 148153e..90d2f29 100644
--- a/arch/arm/kernel/probes-arm.c
+++ b/arch/arm/kernel/probes-arm.c
@@ -109,6 +109,25 @@ void __kprobes simulate_mov_ipsp(probes_opcode_t insn,
        regs->uregs[12] = regs->uregs[13];
 }
 
+enum probes_insn __kprobes probes_check_arm_store(probes_opcode_t insn,
+                      struct arch_probes_insn *asi,
+                      const struct decode_header *h)
+{
+       int imm = insn & 0xfff;
+       check_insn_stack_regs(insn, asi, h, imm);
+       return INSN_GOOD;
+}
+
+enum probes_insn __kprobes probes_check_arm_store_extra(probes_opcode_t insn,
+                      struct arch_probes_insn *asi,
+                      const struct decode_header *h)
+{
+       int imm = ((insn & 0xf00) >> 4) + (insn & 0xf);
+       check_insn_stack_regs(insn, asi, h, imm);
+       return INSN_GOOD;
+}
+
+
 /*
  * For the instruction masking and comparisons in all the "space_*"
  * functions below, Do _not_ rearrange the order of tests unless
diff --git a/arch/arm/kernel/probes-arm.h b/arch/arm/kernel/probes-arm.h
index 18ffc9a..d0ad9a4 100644
--- a/arch/arm/kernel/probes-arm.h
+++ b/arch/arm/kernel/probes-arm.h
@@ -66,6 +66,13 @@ void __kprobes simulate_mrs(probes_opcode_t opcode,
 void __kprobes simulate_mov_ipsp(probes_opcode_t opcode,
        struct arch_probes_insn *asi, struct pt_regs *regs);
 
+enum probes_insn __kprobes probes_check_arm_store(probes_opcode_t,
+       struct arch_probes_insn *,
+       const struct decode_header *);
+enum probes_insn __kprobes probes_check_arm_store_extra(probes_opcode_t,
+       struct arch_probes_insn *,
+       const struct decode_header *);
+
 extern const union decode_item probes_decode_arm_table[];
 
 enum probes_insn arm_probes_decode_insn(probes_opcode_t,
diff --git a/arch/arm/kernel/probes-thumb.c b/arch/arm/kernel/probes-thumb.c
index 749d4cd..5d0c936 100644
--- a/arch/arm/kernel/probes-thumb.c
+++ b/arch/arm/kernel/probes-thumb.c
@@ -15,6 +15,76 @@
 #include "probes.h"
 #include "probes-thumb.h"
 
+enum probes_insn __kprobes t32_check_strd(probes_opcode_t insn,
+               struct arch_probes_insn *asi,
+               const struct decode_header *h)
+{
+       int imm = insn & 0xff;
+       check_insn_stack_regs(insn, asi, h, imm);
+       return INSN_GOOD;
+}
+
+/*
+ * Note: This function doesn't process PROBES_T32_STRD.
+ */
+enum probes_insn __kprobes t32_check_str(probes_opcode_t insn,
+               struct arch_probes_insn *asi,
+               const struct decode_header *h)
+{
+       int rn = -1, rm = -1;
+       u32 regs = h->type_regs.bits >> DECODE_TYPE_BITS;
+       int index, add;
+
+       /* Rn is used in every cases */
+       BUG_ON((regs & 0xf0000) == 0);
+       rn = (insn & 0xf0000) >> 16;
+       if ((regs & 0xf) != 0)
+               rm = insn & 0xf;
+
+       /*
+        * Rn is not SP. Rm can't be sp in any case.
+        * So it is not a stack store.
+        */
+       if (rn != 0xd)
+               return INSN_GOOD;
+
+       /*
+        * For 'str? rx, [sp, ry]', ry can be negative. In addition,
+        * index is true in every cases, so unable to determine stack
+        * consumption.
+        */
+       if (rm != -1) {
+               asi->stack_space = -1;
+               return INSN_GOOD;
+       }
+
+       /*
+        * For 'str? rx, [sp, #+/-<imm>]', if bit 23 is set, index
+        * and add are both set. Else, index and add are determined
+        * by P bit and U bit (bit 10, 9)
+        */
+       if (insn & 0x800000)
+               index = add = 1;
+       else {
+               index = (insn & (1 << 10));
+               add = (insn &(1 << 9));
+       }
+
+       if (!index || add)
+               return INSN_GOOD;
+
+       asi->stack_space = insn & 0xff;
+       return INSN_GOOD;
+}
+
+enum probes_insn __kprobes t16_check_push(probes_opcode_t insn,
+               struct arch_probes_insn *asi,
+               const struct decode_header *h)
+{
+       unsigned int reglist = insn & 0x1ff;
+       asi->stack_space = hweight32(reglist) * 4;
+       return INSN_GOOD;
+}
 
 static const union decode_item t32_table_1110_100x_x0xx[] = {
        /* Load/store multiple instructions */
diff --git a/arch/arm/kernel/probes-thumb.h b/arch/arm/kernel/probes-thumb.h
index a9c65c9..f908b12 100644
--- a/arch/arm/kernel/probes-thumb.h
+++ b/arch/arm/kernel/probes-thumb.h
@@ -100,4 +100,13 @@ enum probes_insn __kprobes
 thumb32_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
                bool emulate, const struct decode_action *actions);
 
+enum probes_insn __kprobes t32_check_strd(probes_opcode_t insn,
+               struct arch_probes_insn *asi,
+               const struct decode_header *h);
+enum probes_insn __kprobes t32_check_str(probes_opcode_t insn,
+               struct arch_probes_insn *asi,
+               const struct decode_header *h);
+enum probes_insn __kprobes t16_check_push(probes_opcode_t insn,
+               struct arch_probes_insn *asi,
+               const struct decode_header *h);
 #endif
diff --git a/arch/arm/kernel/probes.c b/arch/arm/kernel/probes.c
index 6164b4d..8428fe8 100644
--- a/arch/arm/kernel/probes.c
+++ b/arch/arm/kernel/probes.c
@@ -188,6 +188,25 @@ void __kprobes probes_emulate_none(probes_opcode_t opcode,
        asi->insn_fn();
 }
 
+/* ARM and Thumb can share this checker */
+enum probes_insn __kprobes probes_check_stm(probes_opcode_t insn,
+                      struct arch_probes_insn *asi,
+                      const struct decode_header *h)
+{
+       unsigned int reglist = insn & 0xffff;
+       int ubit = insn & (1 << 23);
+       int pbit = insn & (1 << 24);
+       int rn = (insn >> 16) & 0xf;
+
+       /* This is stmi?, doesn't require extra stack */
+       if (ubit)
+               return INSN_GOOD;
+       /* If pbit == ubit (== 0), this is stmda, one dword is saved */
+       asi->stack_space = (rn == 0xd) ?
+               (hweight32(reglist) - ((!pbit == !ubit) ? 1 : 0)) * 4 : 0;
+       return INSN_GOOD;
+}
+
 /*
  * Prepare an instruction slot to receive an instruction for emulating.
  * This is done by placing a subroutine return after the location where the
@@ -395,6 +414,8 @@ probes_decode_insn(probes_opcode_t insn, struct 
arch_probes_insn *asi,
        bool matched = false;
        probes_opcode_t origin_insn = insn;
 
+       asi->stack_space = 0;
+
        if (emulate)
                insn = prepare_emulated_insn(insn, asi, thumb);
 
@@ -464,3 +485,46 @@ probes_decode_insn(probes_opcode_t insn, struct 
arch_probes_insn *asi,
                }
        }
 }
+
+int __kprobes check_insn_stack_regs(probes_opcode_t insn,
+               struct arch_probes_insn *asi,
+               const struct decode_header *h,
+               int imm)
+{
+       u32 regs = h->type_regs.bits >> DECODE_TYPE_BITS;
+       int rn = -1, rm = -1, index, add;
+       asi->stack_space = 0;
+
+       if (((regs >> 16) & 0xf) != REG_TYPE_NONE)
+               rn = (insn >> 16) & 0xf;
+
+       if ((regs & 0xf) != REG_TYPE_NONE)
+               rm = insn & 0xf;
+
+       if ((rn != 13) && (rm != 13))
+               return NOT_STACK_STORE;
+
+       index = insn & (1 << 24);
+       add = insn & (1 << 23);
+
+       if (!index)
+               return NOT_STACK_STORE;
+
+       /*
+        * Even if insn is 'str r0, [sp], +<Rm>', Rm may less than 0.
+        * Therefore if both Rn and Rm are registers and !index,
+        * We are unable to determine whether it is a stack store.
+        */
+       if ((rn != -1) && (rm != -1)) {
+               asi->stack_space = -1;
+               return STACK_REG;
+       }
+
+       /*    'str(d/h) r0, [sp], #+/-<imm>' */
+       /* or 'str(d/h) r0, [sp, #+<imm>'] */
+       if (add)
+               return NOT_STACK_STORE;
+
+       asi->stack_space = imm;
+       return STACK_IMM;
+}
diff --git a/arch/arm/kernel/probes.h b/arch/arm/kernel/probes.h
index c56dd3d..4c0a04a 100644
--- a/arch/arm/kernel/probes.h
+++ b/arch/arm/kernel/probes.h
@@ -410,4 +410,17 @@ probes_decode_insn(probes_opcode_t insn, struct 
arch_probes_insn *asi,
                const union decode_item *table, bool thumb, bool emulate,
                const struct decode_action *actions);
 
+enum probes_insn __kprobes probes_check_stm(probes_opcode_t,
+       struct arch_probes_insn *,
+       const struct decode_header *);
+
+enum {
+       NOT_STACK_STORE,
+       STACK_REG,
+       STACK_IMM,
+};
+int __kprobes check_insn_stack_regs(probes_opcode_t insn,
+               struct arch_probes_insn *asi,
+               const struct decode_header *h,
+               int imm);
 #endif
diff --git a/arch/arm/kernel/uprobes-arm.c b/arch/arm/kernel/uprobes-arm.c
index 0a8caa3..1da524d 100644
--- a/arch/arm/kernel/uprobes-arm.c
+++ b/arch/arm/kernel/uprobes-arm.c
@@ -208,11 +208,11 @@ const struct decode_action uprobes_probes_actions[] = {
        [PROBES_MUL2] = {.handler = probes_simulate_nop},
        [PROBES_SWP] = {.handler = probes_simulate_nop},
        [PROBES_LDRD] = {.decoder = decode_pc_ro},
-       [PROBES_STRD] = {.decoder = decode_pc_ro},
+       [PROBES_STRD] = {.checker = probes_check_arm_store_extra, .decoder = 
decode_pc_ro},
        [PROBES_LOAD_EXTRA] = {.decoder = decode_pc_ro},
        [PROBES_LOAD] = {.decoder = decode_ldr},
-       [PROBES_STORE_EXTRA] = {.decoder = decode_pc_ro},
-       [PROBES_STORE] = {.decoder = decode_pc_ro},
+       [PROBES_STORE_EXTRA] = {.checker = probes_check_arm_store_extra, 
.decoder = decode_pc_ro},
+       [PROBES_STORE] = {.checker = probes_check_arm_store, .decoder = 
decode_pc_ro},
        [PROBES_MOV_IP_SP] = {.handler = simulate_mov_ipsp},
        [PROBES_DATA_PROCESSING_REG] = {
                .decoder = decode_rd12rn16rm0rs8_rwflags},
@@ -232,5 +232,5 @@ const struct decode_action uprobes_probes_actions[] = {
        [PROBES_BITFIELD] = {.handler = probes_simulate_nop},
        [PROBES_BRANCH] = {.handler = simulate_bbl},
        [PROBES_LDM] = {.decoder = uprobe_decode_ldmstm},
-       [PROBES_STM] = {.decoder = uprobe_decode_ldmstm}
+       [PROBES_STM] = {.checker = probes_check_stm, .decoder = 
uprobe_decode_ldmstm}
 };
-- 
1.8.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to