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
)) {
42 if (retv
< (unsigned long)-MAX_ERRNO
)
43 return (unsigned long)-EINVAL
;
45 case EI_ETYPE_ERRNO_NULL
:
46 if (retv
!= 0 && retv
< (unsigned long)-MAX_ERRNO
)
47 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
)
166 debugfs_lookup_and_remove(attr
->kp
.symbol_name
, fei_debugfs_dir
);
169 static int fei_kprobe_handler(struct kprobe
*kp
, struct pt_regs
*regs
)
171 struct fei_attr
*attr
= container_of(kp
, struct fei_attr
, kp
);
173 if (should_fail(&fei_fault_attr
, 1)) {
174 regs_set_return_value(regs
, attr
->retval
);
175 override_function_with_return(regs
);
181 NOKPROBE_SYMBOL(fei_kprobe_handler
)
183 static void *fei_seq_start(struct seq_file
*m
, loff_t
*pos
)
185 mutex_lock(&fei_lock
);
186 return seq_list_start(&fei_attr_list
, *pos
);
189 static void fei_seq_stop(struct seq_file
*m
, void *v
)
191 mutex_unlock(&fei_lock
);
194 static void *fei_seq_next(struct seq_file
*m
, void *v
, loff_t
*pos
)
196 return seq_list_next(v
, &fei_attr_list
, pos
);
199 static int fei_seq_show(struct seq_file
*m
, void *v
)
201 struct fei_attr
*attr
= list_entry(v
, struct fei_attr
, list
);
203 seq_printf(m
, "%ps\n", attr
->kp
.addr
);
207 static const struct seq_operations fei_seq_ops
= {
208 .start
= fei_seq_start
,
209 .next
= fei_seq_next
,
210 .stop
= fei_seq_stop
,
211 .show
= fei_seq_show
,
214 static int fei_open(struct inode
*inode
, struct file
*file
)
216 return seq_open(file
, &fei_seq_ops
);
219 static void fei_attr_remove(struct fei_attr
*attr
)
221 fei_debugfs_remove_attr(attr
);
222 unregister_kprobe(&attr
->kp
);
223 list_del(&attr
->list
);
227 static void fei_attr_remove_all(void)
229 struct fei_attr
*attr
, *n
;
231 list_for_each_entry_safe(attr
, n
, &fei_attr_list
, list
) {
232 fei_attr_remove(attr
);
236 static ssize_t
fei_write(struct file
*file
, const char __user
*buffer
,
237 size_t count
, loff_t
*ppos
)
239 struct fei_attr
*attr
;
244 /* cut off if it is too long */
245 if (count
> KSYM_NAME_LEN
)
246 count
= KSYM_NAME_LEN
;
248 buf
= memdup_user_nul(buffer
, count
);
254 mutex_lock(&fei_lock
);
256 /* Writing just spaces will remove all injection points */
257 if (sym
[0] == '\0') {
258 fei_attr_remove_all();
262 /* Writing !function will remove one injection point */
264 attr
= fei_attr_lookup(sym
+ 1);
269 fei_attr_remove(attr
);
274 addr
= kallsyms_lookup_name(sym
);
279 if (!within_error_injection_list(addr
)) {
283 if (fei_attr_lookup(sym
)) {
287 attr
= fei_attr_new(sym
, addr
);
293 ret
= register_kprobe(&attr
->kp
);
298 fei_debugfs_add_attr(attr
);
299 list_add_tail(&attr
->list
, &fei_attr_list
);
302 mutex_unlock(&fei_lock
);
307 static const struct file_operations fei_ops
= {
312 .release
= seq_release
,
315 static int __init
fei_debugfs_init(void)
319 dir
= fault_create_debugfs_attr("fail_function", NULL
,
324 /* injectable attribute is just a symlink of error_inject/list */
325 debugfs_create_symlink("injectable", dir
, "../error_injection/list");
327 debugfs_create_file("inject", 0600, dir
, NULL
, &fei_ops
);
329 fei_debugfs_dir
= dir
;
334 late_initcall(fei_debugfs_init
);