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
);
18 struct list_head list
;
22 static DEFINE_MUTEX(fei_lock
);
23 static LIST_HEAD(fei_attr_list
);
24 static DECLARE_FAULT_ATTR(fei_fault_attr
);
25 static struct dentry
*fei_debugfs_dir
;
27 static unsigned long adjust_error_retval(unsigned long addr
, unsigned long retv
)
29 switch (get_injectable_error_type(addr
)) {
35 if (retv
< (unsigned long)-MAX_ERRNO
)
36 return (unsigned long)-EINVAL
;
38 case EI_ETYPE_ERRNO_NULL
:
39 if (retv
!= 0 && retv
< (unsigned long)-MAX_ERRNO
)
40 return (unsigned long)-EINVAL
;
47 static struct fei_attr
*fei_attr_new(const char *sym
, unsigned long addr
)
49 struct fei_attr
*attr
;
51 attr
= kzalloc(sizeof(*attr
), GFP_KERNEL
);
53 attr
->kp
.symbol_name
= kstrdup(sym
, GFP_KERNEL
);
54 if (!attr
->kp
.symbol_name
) {
58 attr
->kp
.pre_handler
= fei_kprobe_handler
;
59 attr
->retval
= adjust_error_retval(addr
, 0);
60 INIT_LIST_HEAD(&attr
->list
);
65 static void fei_attr_free(struct fei_attr
*attr
)
68 kfree(attr
->kp
.symbol_name
);
73 static struct fei_attr
*fei_attr_lookup(const char *sym
)
75 struct fei_attr
*attr
;
77 list_for_each_entry(attr
, &fei_attr_list
, list
) {
78 if (!strcmp(attr
->kp
.symbol_name
, sym
))
85 static bool fei_attr_is_valid(struct fei_attr
*_attr
)
87 struct fei_attr
*attr
;
89 list_for_each_entry(attr
, &fei_attr_list
, list
) {
97 static int fei_retval_set(void *data
, u64 val
)
99 struct fei_attr
*attr
= data
;
100 unsigned long retv
= (unsigned long)val
;
103 mutex_lock(&fei_lock
);
105 * Since this operation can be done after retval file is removed,
106 * It is safer to check the attr is still valid before accessing
109 if (!fei_attr_is_valid(attr
)) {
115 if (adjust_error_retval((unsigned long)attr
->kp
.addr
,
122 mutex_unlock(&fei_lock
);
127 static int fei_retval_get(void *data
, u64
*val
)
129 struct fei_attr
*attr
= data
;
132 mutex_lock(&fei_lock
);
133 /* Here we also validate @attr to ensure it still exists. */
134 if (!fei_attr_is_valid(attr
))
138 mutex_unlock(&fei_lock
);
142 DEFINE_DEBUGFS_ATTRIBUTE(fei_retval_ops
, fei_retval_get
, fei_retval_set
,
145 static int fei_debugfs_add_attr(struct fei_attr
*attr
)
149 dir
= debugfs_create_dir(attr
->kp
.symbol_name
, fei_debugfs_dir
);
153 if (!debugfs_create_file("retval", 0600, dir
, attr
, &fei_retval_ops
)) {
154 debugfs_remove_recursive(dir
);
161 static void fei_debugfs_remove_attr(struct fei_attr
*attr
)
165 dir
= debugfs_lookup(attr
->kp
.symbol_name
, fei_debugfs_dir
);
167 debugfs_remove_recursive(dir
);
170 static int fei_kprobe_handler(struct kprobe
*kp
, struct pt_regs
*regs
)
172 struct fei_attr
*attr
= container_of(kp
, struct fei_attr
, kp
);
174 if (should_fail(&fei_fault_attr
, 1)) {
175 regs_set_return_value(regs
, attr
->retval
);
176 override_function_with_return(regs
);
177 /* Kprobe specific fixup */
178 reset_current_kprobe();
179 preempt_enable_no_resched();
185 NOKPROBE_SYMBOL(fei_kprobe_handler
)
187 static void *fei_seq_start(struct seq_file
*m
, loff_t
*pos
)
189 mutex_lock(&fei_lock
);
190 return seq_list_start(&fei_attr_list
, *pos
);
193 static void fei_seq_stop(struct seq_file
*m
, void *v
)
195 mutex_unlock(&fei_lock
);
198 static void *fei_seq_next(struct seq_file
*m
, void *v
, loff_t
*pos
)
200 return seq_list_next(v
, &fei_attr_list
, pos
);
203 static int fei_seq_show(struct seq_file
*m
, void *v
)
205 struct fei_attr
*attr
= list_entry(v
, struct fei_attr
, list
);
207 seq_printf(m
, "%pf\n", attr
->kp
.addr
);
211 static const struct seq_operations fei_seq_ops
= {
212 .start
= fei_seq_start
,
213 .next
= fei_seq_next
,
214 .stop
= fei_seq_stop
,
215 .show
= fei_seq_show
,
218 static int fei_open(struct inode
*inode
, struct file
*file
)
220 return seq_open(file
, &fei_seq_ops
);
223 static void fei_attr_remove(struct fei_attr
*attr
)
225 fei_debugfs_remove_attr(attr
);
226 unregister_kprobe(&attr
->kp
);
227 list_del(&attr
->list
);
231 static void fei_attr_remove_all(void)
233 struct fei_attr
*attr
, *n
;
235 list_for_each_entry_safe(attr
, n
, &fei_attr_list
, list
) {
236 fei_attr_remove(attr
);
240 static ssize_t
fei_write(struct file
*file
, const char __user
*buffer
,
241 size_t count
, loff_t
*ppos
)
243 struct fei_attr
*attr
;
248 /* cut off if it is too long */
249 if (count
> KSYM_NAME_LEN
)
250 count
= KSYM_NAME_LEN
;
251 buf
= kmalloc(sizeof(char) * (count
+ 1), GFP_KERNEL
);
255 if (copy_from_user(buf
, buffer
, count
)) {
262 mutex_lock(&fei_lock
);
264 /* Writing just spaces will remove all injection points */
265 if (sym
[0] == '\0') {
266 fei_attr_remove_all();
270 /* Writing !function will remove one injection point */
272 attr
= fei_attr_lookup(sym
+ 1);
277 fei_attr_remove(attr
);
282 addr
= kallsyms_lookup_name(sym
);
287 if (!within_error_injection_list(addr
)) {
291 if (fei_attr_lookup(sym
)) {
295 attr
= fei_attr_new(sym
, addr
);
301 ret
= register_kprobe(&attr
->kp
);
303 ret
= fei_debugfs_add_attr(attr
);
305 fei_attr_remove(attr
);
307 list_add_tail(&attr
->list
, &fei_attr_list
);
312 mutex_unlock(&fei_lock
);
316 static const struct file_operations fei_ops
= {
321 .release
= seq_release
,
324 static int __init
fei_debugfs_init(void)
328 dir
= fault_create_debugfs_attr("fail_function", NULL
,
333 /* injectable attribute is just a symlink of error_inject/list */
334 if (!debugfs_create_symlink("injectable", dir
,
335 "../error_injection/list"))
338 if (!debugfs_create_file("inject", 0600, dir
, NULL
, &fei_ops
))
341 fei_debugfs_dir
= dir
;
345 debugfs_remove_recursive(dir
);
349 late_initcall(fei_debugfs_init
);