xref: /linux/lib/error-inject.c (revision a1c613ae4c322ddd58d5a8539dbfba2a0380a8c0)
1540adea3SMasami Hiramatsu // SPDX-License-Identifier: GPL-2.0
2540adea3SMasami Hiramatsu // error-inject.c: Function-level error injection table
3540adea3SMasami Hiramatsu #include <linux/error-injection.h>
4540adea3SMasami Hiramatsu #include <linux/debugfs.h>
5540adea3SMasami Hiramatsu #include <linux/kallsyms.h>
6540adea3SMasami Hiramatsu #include <linux/kprobes.h>
7540adea3SMasami Hiramatsu #include <linux/module.h>
8540adea3SMasami Hiramatsu #include <linux/mutex.h>
9540adea3SMasami Hiramatsu #include <linux/list.h>
10540adea3SMasami Hiramatsu #include <linux/slab.h>
11f2ec8d9aSMasami Hiramatsu #include <asm/sections.h>
12540adea3SMasami Hiramatsu 
13540adea3SMasami Hiramatsu /* Whitelist of symbols that can be overridden for error injection. */
14540adea3SMasami Hiramatsu static LIST_HEAD(error_injection_list);
15540adea3SMasami Hiramatsu static DEFINE_MUTEX(ei_mutex);
16540adea3SMasami Hiramatsu struct ei_entry {
17540adea3SMasami Hiramatsu 	struct list_head list;
18540adea3SMasami Hiramatsu 	unsigned long start_addr;
19540adea3SMasami Hiramatsu 	unsigned long end_addr;
20663faf9fSMasami Hiramatsu 	int etype;
21540adea3SMasami Hiramatsu 	void *priv;
22540adea3SMasami Hiramatsu };
23540adea3SMasami Hiramatsu 
within_error_injection_list(unsigned long addr)24540adea3SMasami Hiramatsu bool within_error_injection_list(unsigned long addr)
25540adea3SMasami Hiramatsu {
26540adea3SMasami Hiramatsu 	struct ei_entry *ent;
27540adea3SMasami Hiramatsu 	bool ret = false;
28540adea3SMasami Hiramatsu 
29540adea3SMasami Hiramatsu 	mutex_lock(&ei_mutex);
30540adea3SMasami Hiramatsu 	list_for_each_entry(ent, &error_injection_list, list) {
31540adea3SMasami Hiramatsu 		if (addr >= ent->start_addr && addr < ent->end_addr) {
32540adea3SMasami Hiramatsu 			ret = true;
33540adea3SMasami Hiramatsu 			break;
34540adea3SMasami Hiramatsu 		}
35540adea3SMasami Hiramatsu 	}
36540adea3SMasami Hiramatsu 	mutex_unlock(&ei_mutex);
37540adea3SMasami Hiramatsu 	return ret;
38540adea3SMasami Hiramatsu }
39540adea3SMasami Hiramatsu 
get_injectable_error_type(unsigned long addr)40663faf9fSMasami Hiramatsu int get_injectable_error_type(unsigned long addr)
41663faf9fSMasami Hiramatsu {
42663faf9fSMasami Hiramatsu 	struct ei_entry *ent;
43*6338bb05SMasami Hiramatsu (Google) 	int ei_type = -EINVAL;
44663faf9fSMasami Hiramatsu 
4586e5908eSwuchi 	mutex_lock(&ei_mutex);
46663faf9fSMasami Hiramatsu 	list_for_each_entry(ent, &error_injection_list, list) {
4786e5908eSwuchi 		if (addr >= ent->start_addr && addr < ent->end_addr) {
4886e5908eSwuchi 			ei_type = ent->etype;
4986e5908eSwuchi 			break;
50663faf9fSMasami Hiramatsu 		}
5186e5908eSwuchi 	}
5286e5908eSwuchi 	mutex_unlock(&ei_mutex);
5386e5908eSwuchi 
5486e5908eSwuchi 	return ei_type;
55663faf9fSMasami Hiramatsu }
56663faf9fSMasami Hiramatsu 
57540adea3SMasami Hiramatsu /*
58540adea3SMasami Hiramatsu  * Lookup and populate the error_injection_list.
59540adea3SMasami Hiramatsu  *
60540adea3SMasami Hiramatsu  * For safety reasons we only allow certain functions to be overridden with
61540adea3SMasami Hiramatsu  * bpf_error_injection, so we need to populate the list of the symbols that have
62540adea3SMasami Hiramatsu  * been marked as safe for overriding.
63540adea3SMasami Hiramatsu  */
populate_error_injection_list(struct error_injection_entry * start,struct error_injection_entry * end,void * priv)64663faf9fSMasami Hiramatsu static void populate_error_injection_list(struct error_injection_entry *start,
65663faf9fSMasami Hiramatsu 					  struct error_injection_entry *end,
66663faf9fSMasami Hiramatsu 					  void *priv)
67540adea3SMasami Hiramatsu {
68663faf9fSMasami Hiramatsu 	struct error_injection_entry *iter;
69540adea3SMasami Hiramatsu 	struct ei_entry *ent;
70540adea3SMasami Hiramatsu 	unsigned long entry, offset = 0, size = 0;
71540adea3SMasami Hiramatsu 
72540adea3SMasami Hiramatsu 	mutex_lock(&ei_mutex);
73540adea3SMasami Hiramatsu 	for (iter = start; iter < end; iter++) {
74f2ec8d9aSMasami Hiramatsu 		entry = (unsigned long)dereference_symbol_descriptor((void *)iter->addr);
75540adea3SMasami Hiramatsu 
76540adea3SMasami Hiramatsu 		if (!kernel_text_address(entry) ||
77540adea3SMasami Hiramatsu 		    !kallsyms_lookup_size_offset(entry, &size, &offset)) {
78540adea3SMasami Hiramatsu 			pr_err("Failed to find error inject entry at %p\n",
79540adea3SMasami Hiramatsu 				(void *)entry);
80540adea3SMasami Hiramatsu 			continue;
81540adea3SMasami Hiramatsu 		}
82540adea3SMasami Hiramatsu 
83540adea3SMasami Hiramatsu 		ent = kmalloc(sizeof(*ent), GFP_KERNEL);
84540adea3SMasami Hiramatsu 		if (!ent)
85540adea3SMasami Hiramatsu 			break;
86540adea3SMasami Hiramatsu 		ent->start_addr = entry;
87540adea3SMasami Hiramatsu 		ent->end_addr = entry + size;
88663faf9fSMasami Hiramatsu 		ent->etype = iter->etype;
89540adea3SMasami Hiramatsu 		ent->priv = priv;
90540adea3SMasami Hiramatsu 		INIT_LIST_HEAD(&ent->list);
91540adea3SMasami Hiramatsu 		list_add_tail(&ent->list, &error_injection_list);
92540adea3SMasami Hiramatsu 	}
93540adea3SMasami Hiramatsu 	mutex_unlock(&ei_mutex);
94540adea3SMasami Hiramatsu }
95540adea3SMasami Hiramatsu 
96540adea3SMasami Hiramatsu /* Markers of the _error_inject_whitelist section */
97663faf9fSMasami Hiramatsu extern struct error_injection_entry __start_error_injection_whitelist[];
98663faf9fSMasami Hiramatsu extern struct error_injection_entry __stop_error_injection_whitelist[];
99540adea3SMasami Hiramatsu 
populate_kernel_ei_list(void)100540adea3SMasami Hiramatsu static void __init populate_kernel_ei_list(void)
101540adea3SMasami Hiramatsu {
102540adea3SMasami Hiramatsu 	populate_error_injection_list(__start_error_injection_whitelist,
103540adea3SMasami Hiramatsu 				      __stop_error_injection_whitelist,
104540adea3SMasami Hiramatsu 				      NULL);
105540adea3SMasami Hiramatsu }
106540adea3SMasami Hiramatsu 
107540adea3SMasami Hiramatsu #ifdef CONFIG_MODULES
module_load_ei_list(struct module * mod)108540adea3SMasami Hiramatsu static void module_load_ei_list(struct module *mod)
109540adea3SMasami Hiramatsu {
110540adea3SMasami Hiramatsu 	if (!mod->num_ei_funcs)
111540adea3SMasami Hiramatsu 		return;
112540adea3SMasami Hiramatsu 
113540adea3SMasami Hiramatsu 	populate_error_injection_list(mod->ei_funcs,
114540adea3SMasami Hiramatsu 				      mod->ei_funcs + mod->num_ei_funcs, mod);
115540adea3SMasami Hiramatsu }
116540adea3SMasami Hiramatsu 
module_unload_ei_list(struct module * mod)117540adea3SMasami Hiramatsu static void module_unload_ei_list(struct module *mod)
118540adea3SMasami Hiramatsu {
119540adea3SMasami Hiramatsu 	struct ei_entry *ent, *n;
120540adea3SMasami Hiramatsu 
121540adea3SMasami Hiramatsu 	if (!mod->num_ei_funcs)
122540adea3SMasami Hiramatsu 		return;
123540adea3SMasami Hiramatsu 
124540adea3SMasami Hiramatsu 	mutex_lock(&ei_mutex);
125540adea3SMasami Hiramatsu 	list_for_each_entry_safe(ent, n, &error_injection_list, list) {
126540adea3SMasami Hiramatsu 		if (ent->priv == mod) {
127540adea3SMasami Hiramatsu 			list_del_init(&ent->list);
128540adea3SMasami Hiramatsu 			kfree(ent);
129540adea3SMasami Hiramatsu 		}
130540adea3SMasami Hiramatsu 	}
131540adea3SMasami Hiramatsu 	mutex_unlock(&ei_mutex);
132540adea3SMasami Hiramatsu }
133540adea3SMasami Hiramatsu 
134540adea3SMasami Hiramatsu /* Module notifier call back, checking error injection table on the module */
ei_module_callback(struct notifier_block * nb,unsigned long val,void * data)135540adea3SMasami Hiramatsu static int ei_module_callback(struct notifier_block *nb,
136540adea3SMasami Hiramatsu 			      unsigned long val, void *data)
137540adea3SMasami Hiramatsu {
138540adea3SMasami Hiramatsu 	struct module *mod = data;
139540adea3SMasami Hiramatsu 
140540adea3SMasami Hiramatsu 	if (val == MODULE_STATE_COMING)
141540adea3SMasami Hiramatsu 		module_load_ei_list(mod);
142540adea3SMasami Hiramatsu 	else if (val == MODULE_STATE_GOING)
143540adea3SMasami Hiramatsu 		module_unload_ei_list(mod);
144540adea3SMasami Hiramatsu 
145540adea3SMasami Hiramatsu 	return NOTIFY_DONE;
146540adea3SMasami Hiramatsu }
147540adea3SMasami Hiramatsu 
148540adea3SMasami Hiramatsu static struct notifier_block ei_module_nb = {
149540adea3SMasami Hiramatsu 	.notifier_call = ei_module_callback,
150540adea3SMasami Hiramatsu 	.priority = 0
151540adea3SMasami Hiramatsu };
152540adea3SMasami Hiramatsu 
module_ei_init(void)153540adea3SMasami Hiramatsu static __init int module_ei_init(void)
154540adea3SMasami Hiramatsu {
155540adea3SMasami Hiramatsu 	return register_module_notifier(&ei_module_nb);
156540adea3SMasami Hiramatsu }
157540adea3SMasami Hiramatsu #else /* !CONFIG_MODULES */
158540adea3SMasami Hiramatsu #define module_ei_init()	(0)
159540adea3SMasami Hiramatsu #endif
160540adea3SMasami Hiramatsu 
161540adea3SMasami Hiramatsu /*
162540adea3SMasami Hiramatsu  * error_injection/whitelist -- shows which functions can be overridden for
163540adea3SMasami Hiramatsu  * error injection.
164540adea3SMasami Hiramatsu  */
ei_seq_start(struct seq_file * m,loff_t * pos)165540adea3SMasami Hiramatsu static void *ei_seq_start(struct seq_file *m, loff_t *pos)
166540adea3SMasami Hiramatsu {
167540adea3SMasami Hiramatsu 	mutex_lock(&ei_mutex);
168540adea3SMasami Hiramatsu 	return seq_list_start(&error_injection_list, *pos);
169540adea3SMasami Hiramatsu }
170540adea3SMasami Hiramatsu 
ei_seq_stop(struct seq_file * m,void * v)171540adea3SMasami Hiramatsu static void ei_seq_stop(struct seq_file *m, void *v)
172540adea3SMasami Hiramatsu {
173540adea3SMasami Hiramatsu 	mutex_unlock(&ei_mutex);
174540adea3SMasami Hiramatsu }
175540adea3SMasami Hiramatsu 
ei_seq_next(struct seq_file * m,void * v,loff_t * pos)176540adea3SMasami Hiramatsu static void *ei_seq_next(struct seq_file *m, void *v, loff_t *pos)
177540adea3SMasami Hiramatsu {
178540adea3SMasami Hiramatsu 	return seq_list_next(v, &error_injection_list, pos);
179540adea3SMasami Hiramatsu }
180540adea3SMasami Hiramatsu 
error_type_string(int etype)181663faf9fSMasami Hiramatsu static const char *error_type_string(int etype)
182663faf9fSMasami Hiramatsu {
183663faf9fSMasami Hiramatsu 	switch (etype) {
184663faf9fSMasami Hiramatsu 	case EI_ETYPE_NULL:
185663faf9fSMasami Hiramatsu 		return "NULL";
186663faf9fSMasami Hiramatsu 	case EI_ETYPE_ERRNO:
187663faf9fSMasami Hiramatsu 		return "ERRNO";
188663faf9fSMasami Hiramatsu 	case EI_ETYPE_ERRNO_NULL:
189663faf9fSMasami Hiramatsu 		return "ERRNO_NULL";
190537cd894SBarnabás Pőcze 	case EI_ETYPE_TRUE:
191537cd894SBarnabás Pőcze 		return "TRUE";
192663faf9fSMasami Hiramatsu 	default:
193663faf9fSMasami Hiramatsu 		return "(unknown)";
194663faf9fSMasami Hiramatsu 	}
195663faf9fSMasami Hiramatsu }
196663faf9fSMasami Hiramatsu 
ei_seq_show(struct seq_file * m,void * v)197540adea3SMasami Hiramatsu static int ei_seq_show(struct seq_file *m, void *v)
198540adea3SMasami Hiramatsu {
199540adea3SMasami Hiramatsu 	struct ei_entry *ent = list_entry(v, struct ei_entry, list);
200540adea3SMasami Hiramatsu 
201d75f773cSSakari Ailus 	seq_printf(m, "%ps\t%s\n", (void *)ent->start_addr,
202663faf9fSMasami Hiramatsu 		   error_type_string(ent->etype));
203540adea3SMasami Hiramatsu 	return 0;
204540adea3SMasami Hiramatsu }
205540adea3SMasami Hiramatsu 
20600c9d563Swuchi static const struct seq_operations ei_sops = {
207540adea3SMasami Hiramatsu 	.start = ei_seq_start,
208540adea3SMasami Hiramatsu 	.next  = ei_seq_next,
209540adea3SMasami Hiramatsu 	.stop  = ei_seq_stop,
210540adea3SMasami Hiramatsu 	.show  = ei_seq_show,
211540adea3SMasami Hiramatsu };
212540adea3SMasami Hiramatsu 
21300c9d563Swuchi DEFINE_SEQ_ATTRIBUTE(ei);
214540adea3SMasami Hiramatsu 
ei_debugfs_init(void)215540adea3SMasami Hiramatsu static int __init ei_debugfs_init(void)
216540adea3SMasami Hiramatsu {
217540adea3SMasami Hiramatsu 	struct dentry *dir, *file;
218540adea3SMasami Hiramatsu 
219540adea3SMasami Hiramatsu 	dir = debugfs_create_dir("error_injection", NULL);
220540adea3SMasami Hiramatsu 
22100c9d563Swuchi 	file = debugfs_create_file("list", 0444, dir, NULL, &ei_fops);
222540adea3SMasami Hiramatsu 	if (!file) {
223540adea3SMasami Hiramatsu 		debugfs_remove(dir);
224540adea3SMasami Hiramatsu 		return -ENOMEM;
225540adea3SMasami Hiramatsu 	}
226540adea3SMasami Hiramatsu 
227540adea3SMasami Hiramatsu 	return 0;
228540adea3SMasami Hiramatsu }
229540adea3SMasami Hiramatsu 
init_error_injection(void)230540adea3SMasami Hiramatsu static int __init init_error_injection(void)
231540adea3SMasami Hiramatsu {
232540adea3SMasami Hiramatsu 	populate_kernel_ei_list();
233540adea3SMasami Hiramatsu 
234540adea3SMasami Hiramatsu 	if (!module_ei_init())
235540adea3SMasami Hiramatsu 		ei_debugfs_init();
236540adea3SMasami Hiramatsu 
237540adea3SMasami Hiramatsu 	return 0;
238540adea3SMasami Hiramatsu }
239540adea3SMasami Hiramatsu late_initcall(init_error_injection);
240