1 // SPDX-License-Identifier: GPL-2.0
3 * fail_function.c: Function-based error injection
5 #include <linux/error-injection.h>
6 #include <linux/debugfs.h>
7 #include <linux/fault-inject.h>
8 #include <linux/kallsyms.h>
9 #include <linux/kprobes.h>
10 #include <linux/module.h>
11 #include <linux/mutex.h>
12 #include <linux/slab.h>
13 #include <linux/uaccess.h>
15 static int fei_kprobe_handler(struct kprobe
*kp
, struct pt_regs
*regs
);
17 static void fei_post_handler(struct kprobe
*kp
, struct pt_regs
*regs
,
21 * A dummy post handler is required to prohibit optimizing, because
22 * jump optimization does not support execution path overriding.
27 struct list_head list
;
31 static DEFINE_MUTEX(fei_lock
);
32 static LIST_HEAD(fei_attr_list
);
33 static DECLARE_FAULT_ATTR(fei_fault_attr
);
34 static struct dentry
*fei_debugfs_dir
;
36 static unsigned long adjust_error_retval(unsigned long addr
, unsigned long retv
)
38 switch (get_injectable_error_type(addr
)) {
44 if (retv
< (unsigned long)-MAX_ERRNO
)
45 return (unsigned long)-EINVAL
;
47 case EI_ETYPE_ERRNO_NULL
:
48 if (retv
!= 0 && retv
< (unsigned long)-MAX_ERRNO
)
49 return (unsigned long)-EINVAL
;
56 static struct fei_attr
*fei_attr_new(const char *sym
, unsigned long addr
)
58 struct fei_attr
*attr
;
60 attr
= kzalloc(sizeof(*attr
), GFP_KERNEL
);
62 attr
->kp
.symbol_name
= kstrdup(sym
, GFP_KERNEL
);
63 if (!attr
->kp
.symbol_name
) {
67 attr
->kp
.pre_handler
= fei_kprobe_handler
;
68 attr
->kp
.post_handler
= fei_post_handler
;
69 attr
->retval
= adjust_error_retval(addr
, 0);
70 INIT_LIST_HEAD(&attr
->list
);
75 static void fei_attr_free(struct fei_attr
*attr
)
78 kfree(attr
->kp
.symbol_name
);
83 static struct fei_attr
*fei_attr_lookup(const char *sym
)
85 struct fei_attr
*attr
;
87 list_for_each_entry(attr
, &fei_attr_list
, list
) {
88 if (!strcmp(attr
->kp
.symbol_name
, sym
))
95 static bool fei_attr_is_valid(struct fei_attr
*_attr
)
97 struct fei_attr
*attr
;
99 list_for_each_entry(attr
, &fei_attr_list
, list
) {
107 static int fei_retval_set(void *data
, u64 val
)
109 struct fei_attr
*attr
= data
;
110 unsigned long retv
= (unsigned long)val
;
113 mutex_lock(&fei_lock
);
115 * Since this operation can be done after retval file is removed,
116 * It is safer to check the attr is still valid before accessing
119 if (!fei_attr_is_valid(attr
)) {
125 if (adjust_error_retval((unsigned long)attr
->kp
.addr
,
132 mutex_unlock(&fei_lock
);
137 static int fei_retval_get(void *data
, u64
*val
)
139 struct fei_attr
*attr
= data
;
142 mutex_lock(&fei_lock
);
143 /* Here we also validate @attr to ensure it still exists. */
144 if (!fei_attr_is_valid(attr
))
148 mutex_unlock(&fei_lock
);
152 DEFINE_DEBUGFS_ATTRIBUTE(fei_retval_ops
, fei_retval_get
, fei_retval_set
,
155 static void fei_debugfs_add_attr(struct fei_attr
*attr
)
159 dir
= debugfs_create_dir(attr
->kp
.symbol_name
, fei_debugfs_dir
);
161 debugfs_create_file("retval", 0600, dir
, attr
, &fei_retval_ops
);
164 static void fei_debugfs_remove_attr(struct fei_attr
*attr
)
168 dir
= debugfs_lookup(attr
->kp
.symbol_name
, fei_debugfs_dir
);
169 debugfs_remove_recursive(dir
);
172 static int fei_kprobe_handler(struct kprobe
*kp
, struct pt_regs
*regs
)
174 struct fei_attr
*attr
= container_of(kp
, struct fei_attr
, kp
);
176 if (should_fail(&fei_fault_attr
, 1)) {
177 regs_set_return_value(regs
, attr
->retval
);
178 override_function_with_return(regs
);
184 NOKPROBE_SYMBOL(fei_kprobe_handler
)
186 static void *fei_seq_start(struct seq_file
*m
, loff_t
*pos
)
188 mutex_lock(&fei_lock
);
189 return seq_list_start(&fei_attr_list
, *pos
);
192 static void fei_seq_stop(struct seq_file
*m
, void *v
)
194 mutex_unlock(&fei_lock
);
197 static void *fei_seq_next(struct seq_file
*m
, void *v
, loff_t
*pos
)
199 return seq_list_next(v
, &fei_attr_list
, pos
);
202 static int fei_seq_show(struct seq_file
*m
, void *v
)
204 struct fei_attr
*attr
= list_entry(v
, struct fei_attr
, list
);
206 seq_printf(m
, "%ps\n", attr
->kp
.addr
);
210 static const struct seq_operations fei_seq_ops
= {
211 .start
= fei_seq_start
,
212 .next
= fei_seq_next
,
213 .stop
= fei_seq_stop
,
214 .show
= fei_seq_show
,
217 static int fei_open(struct inode
*inode
, struct file
*file
)
219 return seq_open(file
, &fei_seq_ops
);
222 static void fei_attr_remove(struct fei_attr
*attr
)
224 fei_debugfs_remove_attr(attr
);
225 unregister_kprobe(&attr
->kp
);
226 list_del(&attr
->list
);
230 static void fei_attr_remove_all(void)
232 struct fei_attr
*attr
, *n
;
234 list_for_each_entry_safe(attr
, n
, &fei_attr_list
, list
) {
235 fei_attr_remove(attr
);
239 static ssize_t
fei_write(struct file
*file
, const char __user
*buffer
,
240 size_t count
, loff_t
*ppos
)
242 struct fei_attr
*attr
;
247 /* cut off if it is too long */
248 if (count
> KSYM_NAME_LEN
)
249 count
= KSYM_NAME_LEN
;
250 buf
= kmalloc(count
+ 1, GFP_KERNEL
);
254 if (copy_from_user(buf
, buffer
, count
)) {
261 mutex_lock(&fei_lock
);
263 /* Writing just spaces will remove all injection points */
264 if (sym
[0] == '\0') {
265 fei_attr_remove_all();
269 /* Writing !function will remove one injection point */
271 attr
= fei_attr_lookup(sym
+ 1);
276 fei_attr_remove(attr
);
281 addr
= kallsyms_lookup_name(sym
);
286 if (!within_error_injection_list(addr
)) {
290 if (fei_attr_lookup(sym
)) {
294 attr
= fei_attr_new(sym
, addr
);
300 ret
= register_kprobe(&attr
->kp
);
302 fei_debugfs_add_attr(attr
);
304 fei_attr_remove(attr
);
306 list_add_tail(&attr
->list
, &fei_attr_list
);
311 mutex_unlock(&fei_lock
);
315 static const struct file_operations fei_ops
= {
320 .release
= seq_release
,
323 static int __init
fei_debugfs_init(void)
327 dir
= fault_create_debugfs_attr("fail_function", NULL
,
332 /* injectable attribute is just a symlink of error_inject/list */
333 debugfs_create_symlink("injectable", dir
, "../error_injection/list");
335 debugfs_create_file("inject", 0600, dir
, NULL
, &fei_ops
);
337 fei_debugfs_dir
= dir
;
342 late_initcall(fei_debugfs_init
);