aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWang Nan <wangnan0@huawei.com>2015-01-05 06:29:18 -0500
committerJon Medhurst <tixy@linaro.org>2015-01-09 04:36:51 -0500
commit83803d97dae1eaf6850a45ef8ee179cc66e147dc (patch)
treee2b1124f1c7896dcadb2af471a0570b019dad551
parent832607e79d7423c67ef8a3de8dfa3d25b5b0bf86 (diff)
ARM: kprobes: introduces checker
This patch introdces 'checker' to decoding phase, and calls checkers when instruction decoding. This allows further decoding for specific instructions. This patch introduces a stub call of checkers in kprobe arch_prepare_kprobe() as an example and for further expansion. Signed-off-by: Wang Nan <wangnan0@huawei.com> Reviewed-by: Jon Medhurst <tixy@linaro.org> Reviewed-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> Signed-off-by: Jon Medhurst <tixy@linaro.org>
-rw-r--r--arch/arm/probes/decode-arm.c5
-rw-r--r--arch/arm/probes/decode-arm.h3
-rw-r--r--arch/arm/probes/decode-thumb.c10
-rw-r--r--arch/arm/probes/decode-thumb.h6
-rw-r--r--arch/arm/probes/decode.c60
-rw-r--r--arch/arm/probes/decode.h11
-rw-r--r--arch/arm/probes/kprobes/actions-arm.c2
-rw-r--r--arch/arm/probes/kprobes/actions-thumb.c3
-rw-r--r--arch/arm/probes/kprobes/core.c6
-rw-r--r--arch/arm/probes/kprobes/core.h7
-rw-r--r--arch/arm/probes/uprobes/core.c2
11 files changed, 95 insertions, 20 deletions
diff --git a/arch/arm/probes/decode-arm.c b/arch/arm/probes/decode-arm.c
index 04114f74a2d2..f72c33a2dcfb 100644
--- a/arch/arm/probes/decode-arm.c
+++ b/arch/arm/probes/decode-arm.c
@@ -726,10 +726,11 @@ static void __kprobes arm_singlestep(probes_opcode_t insn,
726 */ 726 */
727enum probes_insn __kprobes 727enum probes_insn __kprobes
728arm_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, 728arm_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
729 bool emulate, const union decode_action *actions) 729 bool emulate, const union decode_action *actions,
730 const struct decode_checker *checkers[])
730{ 731{
731 asi->insn_singlestep = arm_singlestep; 732 asi->insn_singlestep = arm_singlestep;
732 asi->insn_check_cc = probes_condition_checks[insn>>28]; 733 asi->insn_check_cc = probes_condition_checks[insn>>28];
733 return probes_decode_insn(insn, asi, probes_decode_arm_table, false, 734 return probes_decode_insn(insn, asi, probes_decode_arm_table, false,
734 emulate, actions); 735 emulate, actions, checkers);
735} 736}
diff --git a/arch/arm/probes/decode-arm.h b/arch/arm/probes/decode-arm.h
index cb0b26331930..b3b80f6d414b 100644
--- a/arch/arm/probes/decode-arm.h
+++ b/arch/arm/probes/decode-arm.h
@@ -68,6 +68,7 @@ extern const union decode_item probes_decode_arm_table[];
68 68
69enum probes_insn arm_probes_decode_insn(probes_opcode_t, 69enum probes_insn arm_probes_decode_insn(probes_opcode_t,
70 struct arch_probes_insn *, bool emulate, 70 struct arch_probes_insn *, bool emulate,
71 const union decode_action *actions); 71 const union decode_action *actions,
72 const struct decode_checker *checkers[]);
72 73
73#endif 74#endif
diff --git a/arch/arm/probes/decode-thumb.c b/arch/arm/probes/decode-thumb.c
index 2f0453a895dc..985e7dd4cac6 100644
--- a/arch/arm/probes/decode-thumb.c
+++ b/arch/arm/probes/decode-thumb.c
@@ -863,20 +863,22 @@ static void __kprobes thumb32_singlestep(probes_opcode_t opcode,
863 863
864enum probes_insn __kprobes 864enum probes_insn __kprobes
865thumb16_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, 865thumb16_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
866 bool emulate, const union decode_action *actions) 866 bool emulate, const union decode_action *actions,
867 const struct decode_checker *checkers[])
867{ 868{
868 asi->insn_singlestep = thumb16_singlestep; 869 asi->insn_singlestep = thumb16_singlestep;
869 asi->insn_check_cc = thumb_check_cc; 870 asi->insn_check_cc = thumb_check_cc;
870 return probes_decode_insn(insn, asi, probes_decode_thumb16_table, true, 871 return probes_decode_insn(insn, asi, probes_decode_thumb16_table, true,
871 emulate, actions); 872 emulate, actions, checkers);
872} 873}
873 874
874enum probes_insn __kprobes 875enum probes_insn __kprobes
875thumb32_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, 876thumb32_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
876 bool emulate, const union decode_action *actions) 877 bool emulate, const union decode_action *actions,
878 const struct decode_checker *checkers[])
877{ 879{
878 asi->insn_singlestep = thumb32_singlestep; 880 asi->insn_singlestep = thumb32_singlestep;
879 asi->insn_check_cc = thumb_check_cc; 881 asi->insn_check_cc = thumb_check_cc;
880 return probes_decode_insn(insn, asi, probes_decode_thumb32_table, true, 882 return probes_decode_insn(insn, asi, probes_decode_thumb32_table, true,
881 emulate, actions); 883 emulate, actions, checkers);
882} 884}
diff --git a/arch/arm/probes/decode-thumb.h b/arch/arm/probes/decode-thumb.h
index 039013c7131d..8457add0a2d8 100644
--- a/arch/arm/probes/decode-thumb.h
+++ b/arch/arm/probes/decode-thumb.h
@@ -91,9 +91,11 @@ extern const union decode_item probes_decode_thumb16_table[];
91 91
92enum probes_insn __kprobes 92enum probes_insn __kprobes
93thumb16_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, 93thumb16_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
94 bool emulate, const union decode_action *actions); 94 bool emulate, const union decode_action *actions,
95 const struct decode_checker *checkers[]);
95enum probes_insn __kprobes 96enum probes_insn __kprobes
96thumb32_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, 97thumb32_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
97 bool emulate, const union decode_action *actions); 98 bool emulate, const union decode_action *actions,
99 const struct decode_checker *checkers[]);
98 100
99#endif 101#endif
diff --git a/arch/arm/probes/decode.c b/arch/arm/probes/decode.c
index 3b05d5742359..c7d442018902 100644
--- a/arch/arm/probes/decode.c
+++ b/arch/arm/probes/decode.c
@@ -342,6 +342,31 @@ static const int decode_struct_sizes[NUM_DECODE_TYPES] = {
342 [DECODE_TYPE_REJECT] = sizeof(struct decode_reject) 342 [DECODE_TYPE_REJECT] = sizeof(struct decode_reject)
343}; 343};
344 344
345static int run_checkers(const struct decode_checker *checkers[],
346 int action, probes_opcode_t insn,
347 struct arch_probes_insn *asi,
348 const struct decode_header *h)
349{
350 const struct decode_checker **p;
351
352 if (!checkers)
353 return INSN_GOOD;
354
355 p = checkers;
356 while (*p != NULL) {
357 int retval;
358 probes_check_t *checker_func = (*p)[action].checker;
359
360 retval = INSN_GOOD;
361 if (checker_func)
362 retval = checker_func(insn, asi, h);
363 if (retval == INSN_REJECTED)
364 return retval;
365 p++;
366 }
367 return INSN_GOOD;
368}
369
345/* 370/*
346 * probes_decode_insn operates on data tables in order to decode an ARM 371 * probes_decode_insn operates on data tables in order to decode an ARM
347 * architecture instruction onto which a kprobe has been placed. 372 * architecture instruction onto which a kprobe has been placed.
@@ -388,11 +413,17 @@ static const int decode_struct_sizes[NUM_DECODE_TYPES] = {
388int __kprobes 413int __kprobes
389probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, 414probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
390 const union decode_item *table, bool thumb, 415 const union decode_item *table, bool thumb,
391 bool emulate, const union decode_action *actions) 416 bool emulate, const union decode_action *actions,
417 const struct decode_checker *checkers[])
392{ 418{
393 const struct decode_header *h = (struct decode_header *)table; 419 const struct decode_header *h = (struct decode_header *)table;
394 const struct decode_header *next; 420 const struct decode_header *next;
395 bool matched = false; 421 bool matched = false;
422 /*
423 * @insn can be modified by decode_regs. Save its original
424 * value for checkers.
425 */
426 probes_opcode_t origin_insn = insn;
396 427
397 if (emulate) 428 if (emulate)
398 insn = prepare_emulated_insn(insn, asi, thumb); 429 insn = prepare_emulated_insn(insn, asi, thumb);
@@ -422,24 +453,41 @@ probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
422 } 453 }
423 454
424 case DECODE_TYPE_CUSTOM: { 455 case DECODE_TYPE_CUSTOM: {
456 int err;
425 struct decode_custom *d = (struct decode_custom *)h; 457 struct decode_custom *d = (struct decode_custom *)h;
426 return actions[d->decoder.action].decoder(insn, asi, h); 458 int action = d->decoder.action;
459
460 err = run_checkers(checkers, action, origin_insn, asi, h);
461 if (err == INSN_REJECTED)
462 return INSN_REJECTED;
463 return actions[action].decoder(insn, asi, h);
427 } 464 }
428 465
429 case DECODE_TYPE_SIMULATE: { 466 case DECODE_TYPE_SIMULATE: {
467 int err;
430 struct decode_simulate *d = (struct decode_simulate *)h; 468 struct decode_simulate *d = (struct decode_simulate *)h;
431 asi->insn_handler = actions[d->handler.action].handler; 469 int action = d->handler.action;
470
471 err = run_checkers(checkers, action, origin_insn, asi, h);
472 if (err == INSN_REJECTED)
473 return INSN_REJECTED;
474 asi->insn_handler = actions[action].handler;
432 return INSN_GOOD_NO_SLOT; 475 return INSN_GOOD_NO_SLOT;
433 } 476 }
434 477
435 case DECODE_TYPE_EMULATE: { 478 case DECODE_TYPE_EMULATE: {
479 int err;
436 struct decode_emulate *d = (struct decode_emulate *)h; 480 struct decode_emulate *d = (struct decode_emulate *)h;
481 int action = d->handler.action;
482
483 err = run_checkers(checkers, action, origin_insn, asi, h);
484 if (err == INSN_REJECTED)
485 return INSN_REJECTED;
437 486
438 if (!emulate) 487 if (!emulate)
439 return actions[d->handler.action].decoder(insn, 488 return actions[action].decoder(insn, asi, h);
440 asi, h);
441 489
442 asi->insn_handler = actions[d->handler.action].handler; 490 asi->insn_handler = actions[action].handler;
443 set_emulated_insn(insn, asi, thumb); 491 set_emulated_insn(insn, asi, thumb);
444 return INSN_GOOD; 492 return INSN_GOOD;
445 } 493 }
diff --git a/arch/arm/probes/decode.h b/arch/arm/probes/decode.h
index 1d0b53169080..f9b08ba7fe73 100644
--- a/arch/arm/probes/decode.h
+++ b/arch/arm/probes/decode.h
@@ -314,6 +314,14 @@ union decode_action {
314 probes_custom_decode_t *decoder; 314 probes_custom_decode_t *decoder;
315}; 315};
316 316
317typedef enum probes_insn (probes_check_t)(probes_opcode_t,
318 struct arch_probes_insn *,
319 const struct decode_header *);
320
321struct decode_checker {
322 probes_check_t *checker;
323};
324
317#define DECODE_END \ 325#define DECODE_END \
318 {.bits = DECODE_TYPE_END} 326 {.bits = DECODE_TYPE_END}
319 327
@@ -402,6 +410,7 @@ probes_insn_handler_t probes_emulate_none;
402int __kprobes 410int __kprobes
403probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, 411probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
404 const union decode_item *table, bool thumb, bool emulate, 412 const union decode_item *table, bool thumb, bool emulate,
405 const union decode_action *actions); 413 const union decode_action *actions,
414 const struct decode_checker **checkers);
406 415
407#endif 416#endif
diff --git a/arch/arm/probes/kprobes/actions-arm.c b/arch/arm/probes/kprobes/actions-arm.c
index 2206f2d80c76..fbd93a9ada75 100644
--- a/arch/arm/probes/kprobes/actions-arm.c
+++ b/arch/arm/probes/kprobes/actions-arm.c
@@ -339,3 +339,5 @@ const union decode_action kprobes_arm_actions[NUM_PROBES_ARM_ACTIONS] = {
339 [PROBES_BRANCH] = {.handler = simulate_bbl}, 339 [PROBES_BRANCH] = {.handler = simulate_bbl},
340 [PROBES_LDMSTM] = {.decoder = kprobe_decode_ldmstm} 340 [PROBES_LDMSTM] = {.decoder = kprobe_decode_ldmstm}
341}; 341};
342
343const struct decode_checker *kprobes_arm_checkers[] = {NULL};
diff --git a/arch/arm/probes/kprobes/actions-thumb.c b/arch/arm/probes/kprobes/actions-thumb.c
index 6c4e60b62826..2796121fe90e 100644
--- a/arch/arm/probes/kprobes/actions-thumb.c
+++ b/arch/arm/probes/kprobes/actions-thumb.c
@@ -664,3 +664,6 @@ const union decode_action kprobes_t32_actions[NUM_PROBES_T32_ACTIONS] = {
664 [PROBES_T32_MUL_ADD_LONG] = { 664 [PROBES_T32_MUL_ADD_LONG] = {
665 .handler = t32_emulate_rdlo12rdhi8rn16rm0_noflags}, 665 .handler = t32_emulate_rdlo12rdhi8rn16rm0_noflags},
666}; 666};
667
668const struct decode_checker *kprobes_t32_checkers[] = {NULL};
669const struct decode_checker *kprobes_t16_checkers[] = {NULL};
diff --git a/arch/arm/probes/kprobes/core.c b/arch/arm/probes/kprobes/core.c
index 701f49d74c35..74f3dc3ac212 100644
--- a/arch/arm/probes/kprobes/core.c
+++ b/arch/arm/probes/kprobes/core.c
@@ -61,6 +61,7 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
61 kprobe_decode_insn_t *decode_insn; 61 kprobe_decode_insn_t *decode_insn;
62 const union decode_action *actions; 62 const union decode_action *actions;
63 int is; 63 int is;
64 const struct decode_checker **checkers;
64 65
65 if (in_exception_text(addr)) 66 if (in_exception_text(addr))
66 return -EINVAL; 67 return -EINVAL;
@@ -74,9 +75,11 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
74 insn = __opcode_thumb32_compose(insn, inst2); 75 insn = __opcode_thumb32_compose(insn, inst2);
75 decode_insn = thumb32_probes_decode_insn; 76 decode_insn = thumb32_probes_decode_insn;
76 actions = kprobes_t32_actions; 77 actions = kprobes_t32_actions;
78 checkers = kprobes_t32_checkers;
77 } else { 79 } else {
78 decode_insn = thumb16_probes_decode_insn; 80 decode_insn = thumb16_probes_decode_insn;
79 actions = kprobes_t16_actions; 81 actions = kprobes_t16_actions;
82 checkers = kprobes_t16_checkers;
80 } 83 }
81#else /* !CONFIG_THUMB2_KERNEL */ 84#else /* !CONFIG_THUMB2_KERNEL */
82 thumb = false; 85 thumb = false;
@@ -85,12 +88,13 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
85 insn = __mem_to_opcode_arm(*p->addr); 88 insn = __mem_to_opcode_arm(*p->addr);
86 decode_insn = arm_probes_decode_insn; 89 decode_insn = arm_probes_decode_insn;
87 actions = kprobes_arm_actions; 90 actions = kprobes_arm_actions;
91 checkers = kprobes_arm_checkers;
88#endif 92#endif
89 93
90 p->opcode = insn; 94 p->opcode = insn;
91 p->ainsn.insn = tmp_insn; 95 p->ainsn.insn = tmp_insn;
92 96
93 switch ((*decode_insn)(insn, &p->ainsn, true, actions)) { 97 switch ((*decode_insn)(insn, &p->ainsn, true, actions, checkers)) {
94 case INSN_REJECTED: /* not supported */ 98 case INSN_REJECTED: /* not supported */
95 return -EINVAL; 99 return -EINVAL;
96 100
diff --git a/arch/arm/probes/kprobes/core.h b/arch/arm/probes/kprobes/core.h
index 2e1e5a3d9155..f88c79fe632a 100644
--- a/arch/arm/probes/kprobes/core.h
+++ b/arch/arm/probes/kprobes/core.h
@@ -37,16 +37,19 @@ kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_probes_insn *asi,
37typedef enum probes_insn (kprobe_decode_insn_t)(probes_opcode_t, 37typedef enum probes_insn (kprobe_decode_insn_t)(probes_opcode_t,
38 struct arch_probes_insn *, 38 struct arch_probes_insn *,
39 bool, 39 bool,
40 const union decode_action *); 40 const union decode_action *,
41 const struct decode_checker *[*]);
41 42
42#ifdef CONFIG_THUMB2_KERNEL 43#ifdef CONFIG_THUMB2_KERNEL
43 44
44extern const union decode_action kprobes_t32_actions[]; 45extern const union decode_action kprobes_t32_actions[];
45extern const union decode_action kprobes_t16_actions[]; 46extern const union decode_action kprobes_t16_actions[];
46 47extern const struct decode_checker *kprobes_t32_checkers[];
48extern const struct decode_checker *kprobes_t16_checkers[];
47#else /* !CONFIG_THUMB2_KERNEL */ 49#else /* !CONFIG_THUMB2_KERNEL */
48 50
49extern const union decode_action kprobes_arm_actions[]; 51extern const union decode_action kprobes_arm_actions[];
52extern const struct decode_checker *kprobes_arm_checkers[];
50 53
51#endif 54#endif
52 55
diff --git a/arch/arm/probes/uprobes/core.c b/arch/arm/probes/uprobes/core.c
index b2954f6d3abe..d1329f1ba4e4 100644
--- a/arch/arm/probes/uprobes/core.c
+++ b/arch/arm/probes/uprobes/core.c
@@ -88,7 +88,7 @@ int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm,
88 auprobe->ixol[1] = __opcode_to_mem_arm(UPROBE_SS_ARM_INSN); 88 auprobe->ixol[1] = __opcode_to_mem_arm(UPROBE_SS_ARM_INSN);
89 89
90 ret = arm_probes_decode_insn(insn, &auprobe->asi, false, 90 ret = arm_probes_decode_insn(insn, &auprobe->asi, false,
91 uprobes_probes_actions); 91 uprobes_probes_actions, NULL);
92 switch (ret) { 92 switch (ret) {
93 case INSN_REJECTED: 93 case INSN_REJECTED:
94 return -EINVAL; 94 return -EINVAL;