123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340 |
- /*
- * arch/arm/kernel/kprobes-test.c
- *
- * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/kprobes.h>
- #include "kprobes.h"
- /*
- * Test basic API
- */
- static bool test_regs_ok;
- static int test_func_instance;
- static int pre_handler_called;
- static int post_handler_called;
- static int jprobe_func_called;
- static int kretprobe_handler_called;
- #define FUNC_ARG1 0x12345678
- #define FUNC_ARG2 0xabcdef
- #ifndef CONFIG_THUMB2_KERNEL
- long arm_func(long r0, long r1);
- static void __used __naked __arm_kprobes_test_func(void)
- {
- __asm__ __volatile__ (
- ".arm \n\t"
- ".type arm_func, %%function \n\t"
- "arm_func: \n\t"
- "adds r0, r0, r1 \n\t"
- "bx lr \n\t"
- ".code "NORMAL_ISA /* Back to Thumb if necessary */
- : : : "r0", "r1", "cc"
- );
- }
- #else /* CONFIG_THUMB2_KERNEL */
- long thumb16_func(long r0, long r1);
- long thumb32even_func(long r0, long r1);
- long thumb32odd_func(long r0, long r1);
- static void __used __naked __thumb_kprobes_test_funcs(void)
- {
- __asm__ __volatile__ (
- ".type thumb16_func, %%function \n\t"
- "thumb16_func: \n\t"
- "adds.n r0, r0, r1 \n\t"
- "bx lr \n\t"
- ".align \n\t"
- ".type thumb32even_func, %%function \n\t"
- "thumb32even_func: \n\t"
- "adds.w r0, r0, r1 \n\t"
- "bx lr \n\t"
- ".align \n\t"
- "nop.n \n\t"
- ".type thumb32odd_func, %%function \n\t"
- "thumb32odd_func: \n\t"
- "adds.w r0, r0, r1 \n\t"
- "bx lr \n\t"
- : : : "r0", "r1", "cc"
- );
- }
- #endif /* CONFIG_THUMB2_KERNEL */
- static int call_test_func(long (*func)(long, long), bool check_test_regs)
- {
- long ret;
- ++test_func_instance;
- test_regs_ok = false;
- ret = (*func)(FUNC_ARG1, FUNC_ARG2);
- if (ret != FUNC_ARG1 + FUNC_ARG2) {
- pr_err("FAIL: call_test_func: func returned %lx\n", ret);
- return false;
- }
- if (check_test_regs && !test_regs_ok) {
- pr_err("FAIL: test regs not OK\n");
- return false;
- }
- return true;
- }
- static int __kprobes pre_handler(struct kprobe *p, struct pt_regs *regs)
- {
- pre_handler_called = test_func_instance;
- if (regs->ARM_r0 == FUNC_ARG1 && regs->ARM_r1 == FUNC_ARG2)
- test_regs_ok = true;
- return 0;
- }
- static void __kprobes post_handler(struct kprobe *p, struct pt_regs *regs,
- unsigned long flags)
- {
- post_handler_called = test_func_instance;
- if (regs->ARM_r0 != FUNC_ARG1 + FUNC_ARG2 || regs->ARM_r1 != FUNC_ARG2)
- test_regs_ok = false;
- }
- static struct kprobe the_kprobe = {
- .addr = 0,
- .pre_handler = pre_handler,
- .post_handler = post_handler
- };
- static int test_kprobe(long (*func)(long, long))
- {
- int ret;
- the_kprobe.addr = (kprobe_opcode_t *)func;
- ret = register_kprobe(&the_kprobe);
- if (ret < 0) {
- pr_err("FAIL: register_kprobe failed with %d\n", ret);
- return ret;
- }
- ret = call_test_func(func, true);
- unregister_kprobe(&the_kprobe);
- the_kprobe.flags = 0; /* Clear disable flag to allow reuse */
- if (!ret)
- return -EINVAL;
- if (pre_handler_called != test_func_instance) {
- pr_err("FAIL: kprobe pre_handler not called\n");
- return -EINVAL;
- }
- if (post_handler_called != test_func_instance) {
- pr_err("FAIL: kprobe post_handler not called\n");
- return -EINVAL;
- }
- if (!call_test_func(func, false))
- return -EINVAL;
- if (pre_handler_called == test_func_instance ||
- post_handler_called == test_func_instance) {
- pr_err("FAIL: probe called after unregistering\n");
- return -EINVAL;
- }
- return 0;
- }
- static void __kprobes jprobe_func(long r0, long r1)
- {
- jprobe_func_called = test_func_instance;
- if (r0 == FUNC_ARG1 && r1 == FUNC_ARG2)
- test_regs_ok = true;
- jprobe_return();
- }
- static struct jprobe the_jprobe = {
- .entry = jprobe_func,
- };
- static int test_jprobe(long (*func)(long, long))
- {
- int ret;
- the_jprobe.kp.addr = (kprobe_opcode_t *)func;
- ret = register_jprobe(&the_jprobe);
- if (ret < 0) {
- pr_err("FAIL: register_jprobe failed with %d\n", ret);
- return ret;
- }
- ret = call_test_func(func, true);
- unregister_jprobe(&the_jprobe);
- the_jprobe.kp.flags = 0; /* Clear disable flag to allow reuse */
- if (!ret)
- return -EINVAL;
- if (jprobe_func_called != test_func_instance) {
- pr_err("FAIL: jprobe handler function not called\n");
- return -EINVAL;
- }
- if (!call_test_func(func, false))
- return -EINVAL;
- if (jprobe_func_called == test_func_instance) {
- pr_err("FAIL: probe called after unregistering\n");
- return -EINVAL;
- }
- return 0;
- }
- static int __kprobes
- kretprobe_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
- {
- kretprobe_handler_called = test_func_instance;
- if (regs_return_value(regs) == FUNC_ARG1 + FUNC_ARG2)
- test_regs_ok = true;
- return 0;
- }
- static struct kretprobe the_kretprobe = {
- .handler = kretprobe_handler,
- };
- static int test_kretprobe(long (*func)(long, long))
- {
- int ret;
- the_kretprobe.kp.addr = (kprobe_opcode_t *)func;
- ret = register_kretprobe(&the_kretprobe);
- if (ret < 0) {
- pr_err("FAIL: register_kretprobe failed with %d\n", ret);
- return ret;
- }
- ret = call_test_func(func, true);
- unregister_kretprobe(&the_kretprobe);
- the_kretprobe.kp.flags = 0; /* Clear disable flag to allow reuse */
- if (!ret)
- return -EINVAL;
- if (kretprobe_handler_called != test_func_instance) {
- pr_err("FAIL: kretprobe handler not called\n");
- return -EINVAL;
- }
- if (!call_test_func(func, false))
- return -EINVAL;
- if (jprobe_func_called == test_func_instance) {
- pr_err("FAIL: kretprobe called after unregistering\n");
- return -EINVAL;
- }
- return 0;
- }
- static int run_api_tests(long (*func)(long, long))
- {
- int ret;
- pr_info(" kprobe\n");
- ret = test_kprobe(func);
- if (ret < 0)
- return ret;
- pr_info(" jprobe\n");
- ret = test_jprobe(func);
- if (ret < 0)
- return ret;
- pr_info(" kretprobe\n");
- ret = test_kretprobe(func);
- if (ret < 0)
- return ret;
- return 0;
- }
- /*
- * Top level test functions
- */
- static int __init run_all_tests(void)
- {
- int ret = 0;
- pr_info("Begining kprobe tests...\n");
- #ifndef CONFIG_THUMB2_KERNEL
- pr_info("Probe ARM code\n");
- ret = run_api_tests(arm_func);
- if (ret)
- goto out;
- #else /* CONFIG_THUMB2_KERNEL */
- pr_info("Probe 16-bit Thumb code\n");
- ret = run_api_tests(thumb16_func);
- if (ret)
- goto out;
- pr_info("Probe 32-bit Thumb code, even halfword\n");
- ret = run_api_tests(thumb32even_func);
- if (ret)
- goto out;
- pr_info("Probe 32-bit Thumb code, odd halfword\n");
- ret = run_api_tests(thumb32odd_func);
- if (ret)
- goto out;
- #endif
- out:
- if (ret == 0)
- pr_info("Finished kprobe tests OK\n");
- else
- pr_err("kprobe tests failed\n");
- return ret;
- }
- /*
- * Module setup
- */
- #ifdef MODULE
- static void __exit kprobe_test_exit(void)
- {
- }
- module_init(run_all_tests)
- module_exit(kprobe_test_exit)
- MODULE_LICENSE("GPL");
- #else /* !MODULE */
- late_initcall(run_all_tests);
- #endif
|