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 int fei_debugfs_add_attr(struct fei_attr
*attr
)
159 dir
= debugfs_create_dir(attr
->kp
.symbol_name
, fei_debugfs_dir
);
163 if (!debugfs_create_file("retval", 0600, dir
, attr
, &fei_retval_ops
)) {
164 debugfs_remove_recursive(dir
);
171 static void fei_debugfs_remove_attr(struct fei_attr
*attr
)
175 dir
= debugfs_lookup(attr
->kp
.symbol_name
, fei_debugfs_dir
);
176 debugfs_remove_recursive(dir
);
179 static int fei_kprobe_handler(struct kprobe
*kp
, struct pt_regs
*regs
)
181 struct fei_attr
*attr
= container_of(kp
, struct fei_attr
, kp
);
183 if (should_fail(&fei_fault_attr
, 1)) {
184 regs_set_return_value(regs
, attr
->retval
);
185 override_function_with_return(regs
);
191 NOKPROBE_SYMBOL(fei_kprobe_handler
)
193 static void *fei_seq_start(struct seq_file
*m
, loff_t
*pos
)
195 mutex_lock(&fei_lock
);
196 return seq_list_start(&fei_attr_list
, *pos
);
199 static void fei_seq_stop(struct seq_file
*m
, void *v
)
201 mutex_unlock(&fei_lock
);
204 static void *fei_seq_next(struct seq_file
*m
, void *v
, loff_t
*pos
)
206 return seq_list_next(v
, &fei_attr_list
, pos
);
209 static int fei_seq_show(struct seq_file
*m
, void *v
)
211 struct fei_attr
*attr
= list_entry(v
, struct fei_attr
, list
);
213 seq_printf(m
, "%pf\n", attr
->kp
.addr
);
217 static const struct seq_operations fei_seq_ops
= {
218 .start
= fei_seq_start
,
219 .next
= fei_seq_next
,
220 .stop
= fei_seq_stop
,
221 .show
= fei_seq_show
,
224 static int fei_open(struct inode
*inode
, struct file
*file
)
226 return seq_open(file
, &fei_seq_ops
);
229 static void fei_attr_remove(struct fei_attr
*attr
)
231 fei_debugfs_remove_attr(attr
);
232 unregister_kprobe(&attr
->kp
);
233 list_del(&attr
->list
);
237 static void fei_attr_remove_all(void)
239 struct fei_attr
*attr
, *n
;
241 list_for_each_entry_safe(attr
, n
, &fei_attr_list
, list
) {
242 fei_attr_remove(attr
);
246 static ssize_t
fei_write(struct file
*file
, const char __user
*buffer
,
247 size_t count
, loff_t
*ppos
)
249 struct fei_attr
*attr
;
254 /* cut off if it is too long */
255 if (count
> KSYM_NAME_LEN
)
256 count
= KSYM_NAME_LEN
;
257 buf
= kmalloc(count
+ 1, GFP_KERNEL
);
261 if (copy_from_user(buf
, buffer
, count
)) {
268 mutex_lock(&fei_lock
);
270 /* Writing just spaces will remove all injection points */
271 if (sym
[0] == '\0') {
272 fei_attr_remove_all();
276 /* Writing !function will remove one injection point */
278 attr
= fei_attr_lookup(sym
+ 1);
283 fei_attr_remove(attr
);
288 addr
= kallsyms_lookup_name(sym
);
293 if (!within_error_injection_list(addr
)) {
297 if (fei_attr_lookup(sym
)) {
301 attr
= fei_attr_new(sym
, addr
);
307 ret
= register_kprobe(&attr
->kp
);
309 ret
= fei_debugfs_add_attr(attr
);
311 fei_attr_remove(attr
);
313 list_add_tail(&attr
->list
, &fei_attr_list
);
318 mutex_unlock(&fei_lock
);
322 static const struct file_operations fei_ops
= {
327 .release
= seq_release
,
330 static int __init
fei_debugfs_init(void)
334 dir
= fault_create_debugfs_attr("fail_function", NULL
,
339 /* injectable attribute is just a symlink of error_inject/list */
340 if (!debugfs_create_symlink("injectable", dir
,
341 "../error_injection/list"))
344 if (!debugfs_create_file("inject", 0600, dir
, NULL
, &fei_ops
))
347 fei_debugfs_dir
= dir
;
351 debugfs_remove_recursive(dir
);
355 late_initcall(fei_debugfs_init
);