Skip to content

Commit fdde5f3

Browse files
author
Alexei Starovoitov
committed
Merge branch 'error-injection'
Masami Hiramatsu says: ==================== Here are the 5th version of patches to moving error injection table from kprobes. This version fixes a bug and update fail-function to support multiple function error injection. Here is the previous version: https://patchwork.ozlabs.org/cover/858663/ Changes in v5: - [3/5] Fix a bug that within_error_injection returns false always. - [5/5] Update to support multiple function error injection. Thank you, ==================== Signed-off-by: Alexei Starovoitov <[email protected]>
2 parents daaf24c + 4b1a29a commit fdde5f3

27 files changed

+819
-245
lines changed

Documentation/fault-injection/fault-injection.txt

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@ o fail_mmc_request
3030
injects MMC data errors on devices permitted by setting
3131
debugfs entries under /sys/kernel/debug/mmc0/fail_mmc_request
3232

33+
o fail_function
34+
35+
injects error return on specific functions, which are marked by
36+
ALLOW_ERROR_INJECTION() macro, by setting debugfs entries
37+
under /sys/kernel/debug/fail_function. No boot option supported.
38+
3339
Configure fault-injection capabilities behavior
3440
-----------------------------------------------
3541

@@ -123,6 +129,29 @@ configuration of fault-injection capabilities.
123129
default is 'N', setting it to 'Y' will disable failure injections
124130
when dealing with private (address space) futexes.
125131

132+
- /sys/kernel/debug/fail_function/inject:
133+
134+
Format: { 'function-name' | '!function-name' | '' }
135+
specifies the target function of error injection by name.
136+
If the function name leads '!' prefix, given function is
137+
removed from injection list. If nothing specified ('')
138+
injection list is cleared.
139+
140+
- /sys/kernel/debug/fail_function/injectable:
141+
142+
(read only) shows error injectable functions and what type of
143+
error values can be specified. The error type will be one of
144+
below;
145+
- NULL: retval must be 0.
146+
- ERRNO: retval must be -1 to -MAX_ERRNO (-4096).
147+
- ERR_NULL: retval must be 0 or -1 to -MAX_ERRNO (-4096).
148+
149+
- /sys/kernel/debug/fail_function/<functiuon-name>/retval:
150+
151+
specifies the "error" return value to inject to the given
152+
function for given function. This will be created when
153+
user specifies new injection entry.
154+
126155
o Boot option
127156

128157
In order to inject faults while debugfs is not available (early boot time),
@@ -268,6 +297,45 @@ trap "echo 0 > /sys/kernel/debug/$FAILTYPE/probability" SIGINT SIGTERM EXIT
268297
echo "Injecting errors into the module $module... (interrupt to stop)"
269298
sleep 1000000
270299

300+
------------------------------------------------------------------------------
301+
302+
o Inject open_ctree error while btrfs mount
303+
304+
#!/bin/bash
305+
306+
rm -f testfile.img
307+
dd if=/dev/zero of=testfile.img bs=1M seek=1000 count=1
308+
DEVICE=$(losetup --show -f testfile.img)
309+
mkfs.btrfs -f $DEVICE
310+
mkdir -p tmpmnt
311+
312+
FAILTYPE=fail_function
313+
FAILFUNC=open_ctree
314+
echo $FAILFUNC > /sys/kernel/debug/$FAILTYPE/inject
315+
echo -12 > /sys/kernel/debug/$FAILTYPE/$FAILFUNC/retval
316+
echo N > /sys/kernel/debug/$FAILTYPE/task-filter
317+
echo 100 > /sys/kernel/debug/$FAILTYPE/probability
318+
echo 0 > /sys/kernel/debug/$FAILTYPE/interval
319+
echo -1 > /sys/kernel/debug/$FAILTYPE/times
320+
echo 0 > /sys/kernel/debug/$FAILTYPE/space
321+
echo 1 > /sys/kernel/debug/$FAILTYPE/verbose
322+
323+
mount -t btrfs $DEVICE tmpmnt
324+
if [ $? -ne 0 ]
325+
then
326+
echo "SUCCESS!"
327+
else
328+
echo "FAILED!"
329+
umount tmpmnt
330+
fi
331+
332+
echo > /sys/kernel/debug/$FAILTYPE/inject
333+
334+
rmdir tmpmnt
335+
losetup -d $DEVICE
336+
rm testfile.img
337+
338+
271339
Tool to run command with failslab or fail_page_alloc
272340
----------------------------------------------------
273341
In order to make it easier to accomplish the tasks mentioned above, we can use

arch/Kconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ config HAVE_OPTPROBES
196196
config HAVE_KPROBES_ON_FTRACE
197197
bool
198198

199-
config HAVE_KPROBE_OVERRIDE
199+
config HAVE_FUNCTION_ERROR_INJECTION
200200
bool
201201

202202
config HAVE_NMI

arch/x86/Kconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ config X86
154154
select HAVE_KERNEL_XZ
155155
select HAVE_KPROBES
156156
select HAVE_KPROBES_ON_FTRACE
157-
select HAVE_KPROBE_OVERRIDE
157+
select HAVE_FUNCTION_ERROR_INJECTION
158158
select HAVE_KRETPROBES
159159
select HAVE_KVM
160160
select HAVE_LIVEPATCH if X86_64
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
#ifndef _ASM_ERROR_INJECTION_H
3+
#define _ASM_ERROR_INJECTION_H
4+
5+
#include <linux/compiler.h>
6+
#include <linux/linkage.h>
7+
#include <asm/ptrace.h>
8+
#include <asm-generic/error-injection.h>
9+
10+
asmlinkage void just_return_func(void);
11+
void override_function_with_return(struct pt_regs *regs);
12+
13+
#endif /* _ASM_ERROR_INJECTION_H */

arch/x86/include/asm/kprobes.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,7 @@ extern const int kretprobe_blacklist_size;
6767
void arch_remove_kprobe(struct kprobe *p);
6868
asmlinkage void kretprobe_trampoline(void);
6969

70-
#ifdef CONFIG_KPROBES_ON_FTRACE
71-
extern void arch_ftrace_kprobe_override_function(struct pt_regs *regs);
72-
#endif
70+
extern void arch_kprobe_override_function(struct pt_regs *regs);
7371

7472
/* Architecture specific copy of original instruction*/
7573
struct arch_specific_insn {

arch/x86/kernel/kprobes/ftrace.c

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -97,17 +97,3 @@ int arch_prepare_kprobe_ftrace(struct kprobe *p)
9797
p->ainsn.boostable = false;
9898
return 0;
9999
}
100-
101-
asmlinkage void override_func(void);
102-
asm(
103-
".type override_func, @function\n"
104-
"override_func:\n"
105-
" ret\n"
106-
".size override_func, .-override_func\n"
107-
);
108-
109-
void arch_ftrace_kprobe_override_function(struct pt_regs *regs)
110-
{
111-
regs->ip = (unsigned long)&override_func;
112-
}
113-
NOKPROBE_SYMBOL(arch_ftrace_kprobe_override_function);

arch/x86/lib/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ lib-y += memcpy_$(BITS).o
2626
lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o
2727
lib-$(CONFIG_INSTRUCTION_DECODER) += insn.o inat.o insn-eval.o
2828
lib-$(CONFIG_RANDOMIZE_BASE) += kaslr.o
29+
lib-$(CONFIG_FUNCTION_ERROR_INJECTION) += error-inject.o
2930

3031
obj-y += msr.o msr-reg.o msr-reg-export.o hweight.o
3132

arch/x86/lib/error-inject.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
#include <linux/error-injection.h>
4+
#include <linux/kprobes.h>
5+
6+
asmlinkage void just_return_func(void);
7+
8+
asm(
9+
".type just_return_func, @function\n"
10+
"just_return_func:\n"
11+
" ret\n"
12+
".size just_return_func, .-just_return_func\n"
13+
);
14+
15+
void override_function_with_return(struct pt_regs *regs)
16+
{
17+
regs->ip = (unsigned long)&just_return_func;
18+
}
19+
NOKPROBE_SYMBOL(override_function_with_return);

fs/btrfs/disk-io.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
#include <linux/ratelimit.h>
3131
#include <linux/uuid.h>
3232
#include <linux/semaphore.h>
33-
#include <linux/bpf.h>
33+
#include <linux/error-injection.h>
3434
#include <asm/unaligned.h>
3535
#include "ctree.h"
3636
#include "disk-io.h"
@@ -3124,7 +3124,7 @@ int open_ctree(struct super_block *sb,
31243124
goto fail_block_groups;
31253125
goto retry_root_backup;
31263126
}
3127-
BPF_ALLOW_ERROR_INJECTION(open_ctree);
3127+
ALLOW_ERROR_INJECTION(open_ctree, ERRNO);
31283128

31293129
static void btrfs_end_buffer_write_sync(struct buffer_head *bh, int uptodate)
31303130
{

fs/btrfs/free-space-cache.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
#include <linux/slab.h>
2323
#include <linux/math64.h>
2424
#include <linux/ratelimit.h>
25-
#include <linux/bpf.h>
25+
#include <linux/error-injection.h>
2626
#include "ctree.h"
2727
#include "free-space-cache.h"
2828
#include "transaction.h"
@@ -333,7 +333,7 @@ static int io_ctl_init(struct btrfs_io_ctl *io_ctl, struct inode *inode,
333333

334334
return 0;
335335
}
336-
BPF_ALLOW_ERROR_INJECTION(io_ctl_init);
336+
ALLOW_ERROR_INJECTION(io_ctl_init, ERRNO);
337337

338338
static void io_ctl_free(struct btrfs_io_ctl *io_ctl)
339339
{

include/asm-generic/error-injection.h

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
#ifndef _ASM_GENERIC_ERROR_INJECTION_H
3+
#define _ASM_GENERIC_ERROR_INJECTION_H
4+
5+
#if defined(__KERNEL__) && !defined(__ASSEMBLY__)
6+
enum {
7+
EI_ETYPE_NONE, /* Dummy value for undefined case */
8+
EI_ETYPE_NULL, /* Return NULL if failure */
9+
EI_ETYPE_ERRNO, /* Return -ERRNO if failure */
10+
EI_ETYPE_ERRNO_NULL, /* Return -ERRNO or NULL if failure */
11+
};
12+
13+
struct error_injection_entry {
14+
unsigned long addr;
15+
int etype;
16+
};
17+
18+
#ifdef CONFIG_FUNCTION_ERROR_INJECTION
19+
/*
20+
* Whitelist ganerating macro. Specify functions which can be
21+
* error-injectable using this macro.
22+
*/
23+
#define ALLOW_ERROR_INJECTION(fname, _etype) \
24+
static struct error_injection_entry __used \
25+
__attribute__((__section__("_error_injection_whitelist"))) \
26+
_eil_addr_##fname = { \
27+
.addr = (unsigned long)fname, \
28+
.etype = EI_ETYPE_##_etype, \
29+
};
30+
#else
31+
#define ALLOW_ERROR_INJECTION(fname, _etype)
32+
#endif
33+
#endif
34+
35+
#endif /* _ASM_GENERIC_ERROR_INJECTION_H */

include/asm-generic/vmlinux.lds.h

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -136,13 +136,13 @@
136136
#define KPROBE_BLACKLIST()
137137
#endif
138138

139-
#ifdef CONFIG_BPF_KPROBE_OVERRIDE
140-
#define ERROR_INJECT_LIST() . = ALIGN(8); \
141-
VMLINUX_SYMBOL(__start_kprobe_error_inject_list) = .; \
142-
KEEP(*(_kprobe_error_inject_list)) \
143-
VMLINUX_SYMBOL(__stop_kprobe_error_inject_list) = .;
139+
#ifdef CONFIG_FUNCTION_ERROR_INJECTION
140+
#define ERROR_INJECT_WHITELIST() STRUCT_ALIGN(); \
141+
VMLINUX_SYMBOL(__start_error_injection_whitelist) = .;\
142+
KEEP(*(_error_injection_whitelist)) \
143+
VMLINUX_SYMBOL(__stop_error_injection_whitelist) = .;
144144
#else
145-
#define ERROR_INJECT_LIST()
145+
#define ERROR_INJECT_WHITELIST()
146146
#endif
147147

148148
#ifdef CONFIG_EVENT_TRACING
@@ -573,7 +573,7 @@
573573
FTRACE_EVENTS() \
574574
TRACE_SYSCALLS() \
575575
KPROBE_BLACKLIST() \
576-
ERROR_INJECT_LIST() \
576+
ERROR_INJECT_WHITELIST() \
577577
MEM_DISCARD(init.rodata) \
578578
CLK_OF_TABLES() \
579579
RESERVEDMEM_OF_TABLES() \

include/linux/bpf.h

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -613,15 +613,4 @@ extern const struct bpf_func_proto bpf_sock_map_update_proto;
613613
void bpf_user_rnd_init_once(void);
614614
u64 bpf_user_rnd_u32(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5);
615615

616-
#if defined(__KERNEL__) && !defined(__ASSEMBLY__)
617-
#ifdef CONFIG_BPF_KPROBE_OVERRIDE
618-
#define BPF_ALLOW_ERROR_INJECTION(fname) \
619-
static unsigned long __used \
620-
__attribute__((__section__("_kprobe_error_inject_list"))) \
621-
_eil_addr_##fname = (unsigned long)fname;
622-
#else
623-
#define BPF_ALLOW_ERROR_INJECTION(fname)
624-
#endif
625-
#endif
626-
627616
#endif /* _LINUX_BPF_H */

include/linux/error-injection.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
#ifndef _LINUX_ERROR_INJECTION_H
3+
#define _LINUX_ERROR_INJECTION_H
4+
5+
#ifdef CONFIG_FUNCTION_ERROR_INJECTION
6+
7+
#include <asm/error-injection.h>
8+
9+
extern bool within_error_injection_list(unsigned long addr);
10+
extern int get_injectable_error_type(unsigned long addr);
11+
12+
#else /* !CONFIG_FUNCTION_ERROR_INJECTION */
13+
14+
#include <asm-generic/error-injection.h>
15+
static inline bool within_error_injection_list(unsigned long addr)
16+
{
17+
return false;
18+
}
19+
20+
static inline int get_injectable_error_type(unsigned long addr)
21+
{
22+
return EI_ETYPE_NONE;
23+
}
24+
25+
#endif
26+
27+
#endif /* _LINUX_ERROR_INJECTION_H */

include/linux/kprobes.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,6 @@ extern bool arch_kprobe_on_func_entry(unsigned long offset);
271271
extern bool kprobe_on_func_entry(kprobe_opcode_t *addr, const char *sym, unsigned long offset);
272272

273273
extern bool within_kprobe_blacklist(unsigned long addr);
274-
extern bool within_kprobe_error_injection_list(unsigned long addr);
275274

276275
struct kprobe_insn_cache {
277276
struct mutex mutex;

include/linux/module.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <linux/jump_label.h>
2020
#include <linux/export.h>
2121
#include <linux/rbtree_latch.h>
22+
#include <linux/error-injection.h>
2223

2324
#include <linux/percpu.h>
2425
#include <asm/module.h>
@@ -476,9 +477,9 @@ struct module {
476477
unsigned int num_ctors;
477478
#endif
478479

479-
#ifdef CONFIG_BPF_KPROBE_OVERRIDE
480-
unsigned int num_kprobe_ei_funcs;
481-
unsigned long *kprobe_ei_funcs;
480+
#ifdef CONFIG_FUNCTION_ERROR_INJECTION
481+
struct error_injection_entry *ei_funcs;
482+
unsigned int num_ei_funcs;
482483
#endif
483484
} ____cacheline_aligned __randomize_layout;
484485
#ifndef MODULE_ARCH_INIT

kernel/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ obj-$(CONFIG_AUDIT_TREE) += audit_tree.o
8181
obj-$(CONFIG_GCOV_KERNEL) += gcov/
8282
obj-$(CONFIG_KCOV) += kcov.o
8383
obj-$(CONFIG_KPROBES) += kprobes.o
84+
obj-$(CONFIG_FAIL_FUNCTION) += fail_function.o
8485
obj-$(CONFIG_KGDB) += debug/
8586
obj-$(CONFIG_DETECT_HUNG_TASK) += hung_task.o
8687
obj-$(CONFIG_LOCKUP_DETECTOR) += watchdog.o

0 commit comments

Comments
 (0)