From: Masami Hiramatsu <mhiramat@kernel.org>
To: Alexei Starovoitov <ast@fb.com>, Josef Bacik <jbacik@fb.com>
Cc: rostedt@goodmis.org, mingo@redhat.com, davem@davemloft.net,
netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
ast@kernel.org, kernel-team@fb.com, daniel@iogearbox.net,
linux-btrfs@vger.kernel.org, darrick.wong@oracle.com,
mhiramat@kernel.org, Josef Bacik <josef@toxicpanda.com>,
Akinobu Mita <akinobu.mita@gmail.com>
Subject: [RFC PATCH bpf-next v2 4/4] error-injection: Support fault injection framework
Date: Tue, 26 Dec 2017 16:48:25 +0900 [thread overview]
Message-ID: <151427450538.32561.2776225740675148782.stgit@devbox> (raw)
In-Reply-To: <151427438796.32561.4235654585430455286.stgit@devbox>
Support in-kernel fault-injection framework via debugfs.
This allows you to inject a conditional error to specified
function using debugfs interfaces.
Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
Documentation/fault-injection/fault-injection.txt | 5 +
kernel/Makefile | 1
kernel/fail_function.c | 169 +++++++++++++++++++++
lib/Kconfig.debug | 10 +
4 files changed, 185 insertions(+)
create mode 100644 kernel/fail_function.c
diff --git a/Documentation/fault-injection/fault-injection.txt b/Documentation/fault-injection/fault-injection.txt
index 918972babcd8..6243a588dd71 100644
--- a/Documentation/fault-injection/fault-injection.txt
+++ b/Documentation/fault-injection/fault-injection.txt
@@ -30,6 +30,11 @@ o fail_mmc_request
injects MMC data errors on devices permitted by setting
debugfs entries under /sys/kernel/debug/mmc0/fail_mmc_request
+o fail_function
+
+ injects error return on specific functions by setting debugfs entries
+ under /sys/kernel/debug/fail_function. No boot option supported.
+
Configure fault-injection capabilities behavior
-----------------------------------------------
diff --git a/kernel/Makefile b/kernel/Makefile
index 172d151d429c..f85ae5dfa474 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -81,6 +81,7 @@ obj-$(CONFIG_AUDIT_TREE) += audit_tree.o
obj-$(CONFIG_GCOV_KERNEL) += gcov/
obj-$(CONFIG_KCOV) += kcov.o
obj-$(CONFIG_KPROBES) += kprobes.o
+obj-$(CONFIG_FAIL_FUNCTION) += fail_function.o
obj-$(CONFIG_KGDB) += debug/
obj-$(CONFIG_DETECT_HUNG_TASK) += hung_task.o
obj-$(CONFIG_LOCKUP_DETECTOR) += watchdog.o
diff --git a/kernel/fail_function.c b/kernel/fail_function.c
new file mode 100644
index 000000000000..203d3582487a
--- /dev/null
+++ b/kernel/fail_function.c
@@ -0,0 +1,169 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * fail_function.c: Function-based error injection
+ */
+#include <linux/error-injection.h>
+#include <linux/debugfs.h>
+#include <linux/fault-inject.h>
+#include <linux/kallsyms.h>
+#include <linux/kprobes.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+
+static int fei_kprobe_handler(struct kprobe *kp, struct pt_regs *regs);
+
+static DEFINE_MUTEX(fei_lock);
+static struct {
+ struct kprobe kp;
+ unsigned long retval;
+ struct fault_attr attr;
+} fei_attr = {
+ .kp = { .pre_handler = fei_kprobe_handler, },
+ .retval = ~0UL, /* This indicates -1 in long/int return value */
+ .attr = FAULT_ATTR_INITIALIZER,
+};
+
+static int fei_kprobe_handler(struct kprobe *kp, struct pt_regs *regs)
+{
+ if (should_fail(&fei_attr.attr, 1)) {
+ regs_set_return_value(regs, fei_attr.retval);
+ override_function_with_return(regs);
+ /* Kprobe specific fixup */
+ reset_current_kprobe();
+ preempt_enable_no_resched();
+ return 1;
+ }
+
+ return 0;
+}
+NOKPROBE_SYMBOL(fei_kprobe_handler)
+
+static void *fei_seq_start(struct seq_file *m, loff_t *pos)
+{
+ mutex_lock(&fei_lock);
+ return *pos == 0 ? (void *)1 : NULL;
+}
+
+static void fei_seq_stop(struct seq_file *m, void *v)
+{
+ mutex_unlock(&fei_lock);
+}
+
+static void *fei_seq_next(struct seq_file *m, void *v, loff_t *pos)
+{
+ return NULL;
+}
+
+static int fei_seq_show(struct seq_file *m, void *v)
+{
+ if (fei_attr.kp.addr)
+ seq_printf(m, "%pf\n", fei_attr.kp.addr);
+ else
+ seq_puts(m, "# not specified\n");
+ return 0;
+}
+
+static const struct seq_operations fei_seq_ops = {
+ .start = fei_seq_start,
+ .next = fei_seq_next,
+ .stop = fei_seq_stop,
+ .show = fei_seq_show,
+};
+
+static int fei_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &fei_seq_ops);
+}
+
+static ssize_t fei_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ unsigned long addr;
+ char *buf, *sym;
+ int ret;
+
+ /* cut off if it is too long */
+ if (count > KSYM_NAME_LEN)
+ count = KSYM_NAME_LEN;
+ buf = kmalloc(sizeof(char) * (count + 1), GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ if (copy_from_user(buf, buffer, count)) {
+ ret = -EFAULT;
+ goto out;
+ }
+ buf[count] = '\0';
+ sym = strstrip(buf);
+
+ if (strlen(sym) == 0 || sym[0] == '0') {
+ if (fei_attr.kp.addr) {
+ unregister_kprobe(&fei_attr.kp);
+ fei_attr.kp.addr = NULL;
+ }
+ ret = count;
+ goto out;
+ }
+
+ addr = kallsyms_lookup_name(sym);
+ if (!addr) {
+ ret = -EINVAL;
+ goto out;
+ }
+ if (!within_error_injection_list(addr)) {
+ ret = -ERANGE;
+ goto out;
+ }
+
+ if (fei_attr.kp.addr) {
+ unregister_kprobe(&fei_attr.kp);
+ fei_attr.kp.addr = NULL;
+ }
+ fei_attr.kp.addr = (void *)addr;
+ ret = register_kprobe(&fei_attr.kp);
+ if (ret < 0)
+ fei_attr.kp.addr = NULL;
+ else
+ ret = count;
+out:
+ kfree(buf);
+ return ret;
+}
+
+static const struct file_operations fei_ops = {
+ .open = fei_open,
+ .read = seq_read,
+ .write = fei_write,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+static int __init fei_debugfs_init(void)
+{
+ struct dentry *dir;
+
+ dir = fault_create_debugfs_attr("fail_function", NULL,
+ &fei_attr.attr);
+ if (IS_ERR(dir))
+ return PTR_ERR(dir);
+
+ // injectable attribute is just a symlink of error_inject/list
+ if (!debugfs_create_symlink("injectable", dir,
+ "../error_injection/list"))
+ goto error;
+
+ if (!debugfs_create_file("inject", 0600, dir, NULL, &fei_ops))
+ goto error;
+
+ if (!debugfs_create_ulong("retval", 0600, dir, &fei_attr.retval))
+ goto error;
+
+ return 0;
+error:
+ debugfs_remove_recursive(dir);
+ return -ENOMEM;
+}
+
+late_initcall(fei_debugfs_init);
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index fe88ac0f003c..15c6609a1bb8 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -1551,6 +1551,16 @@ config FAIL_FUTEX
help
Provide fault-injection capability for futexes.
+config FAIL_FUNCTION
+ bool "Fault-injection capability for functions"
+ depends on FAULT_INJECTION_DEBUG_FS && FUNCTION_ERROR_INJECTION
+ help
+ Provide function-based fault-injection capability.
+ This will allow you to override a specific function with a return
+ with given return value. As a result, function caller will see
+ an error value and have to handle it. This is useful to test the
+ error handling in various subsystems.
+
config FAULT_INJECTION_DEBUG_FS
bool "Debugfs entries for fault-injection capabilities"
depends on FAULT_INJECTION && SYSFS && DEBUG_FS
next prev parent reply other threads:[~2017-12-26 7:48 UTC|newest]
Thread overview: 30+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-12-26 7:46 [RFC PATCH bpf-next v2 0/4] Separate error injection table from kprobes Masami Hiramatsu
2017-12-26 7:46 ` [RFC PATCH bpf-next v2 1/4] tracing/kprobe: bpf: Check error injectable event is on function entry Masami Hiramatsu
2017-12-27 1:57 ` Alexei Starovoitov
2017-12-27 5:56 ` Masami Hiramatsu
2017-12-27 22:46 ` Alexei Starovoitov
2017-12-28 2:34 ` Masami Hiramatsu
2017-12-28 3:45 ` Alexei Starovoitov
2017-12-28 4:16 ` Steven Rostedt
2017-12-28 4:32 ` Alexei Starovoitov
2017-12-28 8:20 ` Masami Hiramatsu
2017-12-29 1:03 ` Alexei Starovoitov
2017-12-29 8:20 ` Masami Hiramatsu
2018-01-08 3:01 ` Alexei Starovoitov
2018-01-08 13:21 ` Masami Hiramatsu
2017-12-28 7:56 ` Masami Hiramatsu
2017-12-26 7:47 ` [RFC PATCH bpf-next v2 2/4] tracing/kprobe: bpf: Compare instruction pointer with original one Masami Hiramatsu
2017-12-27 2:00 ` Alexei Starovoitov
2017-12-26 7:47 ` [RFC PATCH bpf-next v2 3/4] error-injection: Separate error-injection from kprobe Masami Hiramatsu
2017-12-27 2:07 ` Alexei Starovoitov
2017-12-26 7:48 ` Masami Hiramatsu [this message]
2017-12-27 2:12 ` [RFC PATCH bpf-next v2 4/4] error-injection: Support fault injection framework Alexei Starovoitov
2017-12-27 8:09 ` Masami Hiramatsu
2017-12-27 22:49 ` Alexei Starovoitov
2017-12-28 1:38 ` Masami Hiramatsu
2017-12-28 3:49 ` Alexei Starovoitov
2017-12-28 7:51 ` Masami Hiramatsu
2017-12-29 1:11 ` Alexei Starovoitov
2017-12-29 7:34 ` Masami Hiramatsu
2018-01-04 16:07 ` [RFC PATCH bpf-next v2 0/4] Separate error injection table from kprobes Josef Bacik
2018-01-09 1:17 ` Masami Hiramatsu
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=151427450538.32561.2776225740675148782.stgit@devbox \
--to=mhiramat@kernel.org \
--cc=akinobu.mita@gmail.com \
--cc=ast@fb.com \
--cc=ast@kernel.org \
--cc=daniel@iogearbox.net \
--cc=darrick.wong@oracle.com \
--cc=davem@davemloft.net \
--cc=jbacik@fb.com \
--cc=josef@toxicpanda.com \
--cc=kernel-team@fb.com \
--cc=linux-btrfs@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@redhat.com \
--cc=netdev@vger.kernel.org \
--cc=rostedt@goodmis.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).