xref: /openbmc/linux/lib/error-inject.c (revision 537cd89484ab57ca38ae25d9557361c0815977d1)
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>
11540adea3SMasami Hiramatsu 
12540adea3SMasami Hiramatsu /* Whitelist of symbols that can be overridden for error injection. */
13540adea3SMasami Hiramatsu static LIST_HEAD(error_injection_list);
14540adea3SMasami Hiramatsu static DEFINE_MUTEX(ei_mutex);
15540adea3SMasami Hiramatsu struct ei_entry {
16540adea3SMasami Hiramatsu 	struct list_head list;
17540adea3SMasami Hiramatsu 	unsigned long start_addr;
18540adea3SMasami Hiramatsu 	unsigned long end_addr;
19663faf9fSMasami Hiramatsu 	int etype;
20540adea3SMasami Hiramatsu 	void *priv;
21540adea3SMasami Hiramatsu };
22540adea3SMasami Hiramatsu 
23540adea3SMasami Hiramatsu bool within_error_injection_list(unsigned long addr)
24540adea3SMasami Hiramatsu {
25540adea3SMasami Hiramatsu 	struct ei_entry *ent;
26540adea3SMasami Hiramatsu 	bool ret = false;
27540adea3SMasami Hiramatsu 
28540adea3SMasami Hiramatsu 	mutex_lock(&ei_mutex);
29540adea3SMasami Hiramatsu 	list_for_each_entry(ent, &error_injection_list, list) {
30540adea3SMasami Hiramatsu 		if (addr >= ent->start_addr && addr < ent->end_addr) {
31540adea3SMasami Hiramatsu 			ret = true;
32540adea3SMasami Hiramatsu 			break;
33540adea3SMasami Hiramatsu 		}
34540adea3SMasami Hiramatsu 	}
35540adea3SMasami Hiramatsu 	mutex_unlock(&ei_mutex);
36540adea3SMasami Hiramatsu 	return ret;
37540adea3SMasami Hiramatsu }
38540adea3SMasami Hiramatsu 
39663faf9fSMasami Hiramatsu int get_injectable_error_type(unsigned long addr)
40663faf9fSMasami Hiramatsu {
41663faf9fSMasami Hiramatsu 	struct ei_entry *ent;
42663faf9fSMasami Hiramatsu 
43663faf9fSMasami Hiramatsu 	list_for_each_entry(ent, &error_injection_list, list) {
44663faf9fSMasami Hiramatsu 		if (addr >= ent->start_addr && addr < ent->end_addr)
45663faf9fSMasami Hiramatsu 			return ent->etype;
46663faf9fSMasami Hiramatsu 	}
47663faf9fSMasami Hiramatsu 	return EI_ETYPE_NONE;
48663faf9fSMasami Hiramatsu }
49663faf9fSMasami Hiramatsu 
50540adea3SMasami Hiramatsu /*
51540adea3SMasami Hiramatsu  * Lookup and populate the error_injection_list.
52540adea3SMasami Hiramatsu  *
53540adea3SMasami Hiramatsu  * For safety reasons we only allow certain functions to be overridden with
54540adea3SMasami Hiramatsu  * bpf_error_injection, so we need to populate the list of the symbols that have
55540adea3SMasami Hiramatsu  * been marked as safe for overriding.
56540adea3SMasami Hiramatsu  */
57663faf9fSMasami Hiramatsu static void populate_error_injection_list(struct error_injection_entry *start,
58663faf9fSMasami Hiramatsu 					  struct error_injection_entry *end,
59663faf9fSMasami Hiramatsu 					  void *priv)
60540adea3SMasami Hiramatsu {
61663faf9fSMasami Hiramatsu 	struct error_injection_entry *iter;
62540adea3SMasami Hiramatsu 	struct ei_entry *ent;
63540adea3SMasami Hiramatsu 	unsigned long entry, offset = 0, size = 0;
64540adea3SMasami Hiramatsu 
65540adea3SMasami Hiramatsu 	mutex_lock(&ei_mutex);
66540adea3SMasami Hiramatsu 	for (iter = start; iter < end; iter++) {
67663faf9fSMasami Hiramatsu 		entry = arch_deref_entry_point((void *)iter->addr);
68540adea3SMasami Hiramatsu 
69540adea3SMasami Hiramatsu 		if (!kernel_text_address(entry) ||
70540adea3SMasami Hiramatsu 		    !kallsyms_lookup_size_offset(entry, &size, &offset)) {
71540adea3SMasami Hiramatsu 			pr_err("Failed to find error inject entry at %p\n",
72540adea3SMasami Hiramatsu 				(void *)entry);
73540adea3SMasami Hiramatsu 			continue;
74540adea3SMasami Hiramatsu 		}
75540adea3SMasami Hiramatsu 
76540adea3SMasami Hiramatsu 		ent = kmalloc(sizeof(*ent), GFP_KERNEL);
77540adea3SMasami Hiramatsu 		if (!ent)
78540adea3SMasami Hiramatsu 			break;
79540adea3SMasami Hiramatsu 		ent->start_addr = entry;
80540adea3SMasami Hiramatsu 		ent->end_addr = entry + size;
81663faf9fSMasami Hiramatsu 		ent->etype = iter->etype;
82540adea3SMasami Hiramatsu 		ent->priv = priv;
83540adea3SMasami Hiramatsu 		INIT_LIST_HEAD(&ent->list);
84540adea3SMasami Hiramatsu 		list_add_tail(&ent->list, &error_injection_list);
85540adea3SMasami Hiramatsu 	}
86540adea3SMasami Hiramatsu 	mutex_unlock(&ei_mutex);
87540adea3SMasami Hiramatsu }
88540adea3SMasami Hiramatsu 
89540adea3SMasami Hiramatsu /* Markers of the _error_inject_whitelist section */
90663faf9fSMasami Hiramatsu extern struct error_injection_entry __start_error_injection_whitelist[];
91663faf9fSMasami Hiramatsu extern struct error_injection_entry __stop_error_injection_whitelist[];
92540adea3SMasami Hiramatsu 
93540adea3SMasami Hiramatsu static void __init populate_kernel_ei_list(void)
94540adea3SMasami Hiramatsu {
95540adea3SMasami Hiramatsu 	populate_error_injection_list(__start_error_injection_whitelist,
96540adea3SMasami Hiramatsu 				      __stop_error_injection_whitelist,
97540adea3SMasami Hiramatsu 				      NULL);
98540adea3SMasami Hiramatsu }
99540adea3SMasami Hiramatsu 
100540adea3SMasami Hiramatsu #ifdef CONFIG_MODULES
101540adea3SMasami Hiramatsu static void module_load_ei_list(struct module *mod)
102540adea3SMasami Hiramatsu {
103540adea3SMasami Hiramatsu 	if (!mod->num_ei_funcs)
104540adea3SMasami Hiramatsu 		return;
105540adea3SMasami Hiramatsu 
106540adea3SMasami Hiramatsu 	populate_error_injection_list(mod->ei_funcs,
107540adea3SMasami Hiramatsu 				      mod->ei_funcs + mod->num_ei_funcs, mod);
108540adea3SMasami Hiramatsu }
109540adea3SMasami Hiramatsu 
110540adea3SMasami Hiramatsu static void module_unload_ei_list(struct module *mod)
111540adea3SMasami Hiramatsu {
112540adea3SMasami Hiramatsu 	struct ei_entry *ent, *n;
113540adea3SMasami Hiramatsu 
114540adea3SMasami Hiramatsu 	if (!mod->num_ei_funcs)
115540adea3SMasami Hiramatsu 		return;
116540adea3SMasami Hiramatsu 
117540adea3SMasami Hiramatsu 	mutex_lock(&ei_mutex);
118540adea3SMasami Hiramatsu 	list_for_each_entry_safe(ent, n, &error_injection_list, list) {
119540adea3SMasami Hiramatsu 		if (ent->priv == mod) {
120540adea3SMasami Hiramatsu 			list_del_init(&ent->list);
121540adea3SMasami Hiramatsu 			kfree(ent);
122540adea3SMasami Hiramatsu 		}
123540adea3SMasami Hiramatsu 	}
124540adea3SMasami Hiramatsu 	mutex_unlock(&ei_mutex);
125540adea3SMasami Hiramatsu }
126540adea3SMasami Hiramatsu 
127540adea3SMasami Hiramatsu /* Module notifier call back, checking error injection table on the module */
128540adea3SMasami Hiramatsu static int ei_module_callback(struct notifier_block *nb,
129540adea3SMasami Hiramatsu 			      unsigned long val, void *data)
130540adea3SMasami Hiramatsu {
131540adea3SMasami Hiramatsu 	struct module *mod = data;
132540adea3SMasami Hiramatsu 
133540adea3SMasami Hiramatsu 	if (val == MODULE_STATE_COMING)
134540adea3SMasami Hiramatsu 		module_load_ei_list(mod);
135540adea3SMasami Hiramatsu 	else if (val == MODULE_STATE_GOING)
136540adea3SMasami Hiramatsu 		module_unload_ei_list(mod);
137540adea3SMasami Hiramatsu 
138540adea3SMasami Hiramatsu 	return NOTIFY_DONE;
139540adea3SMasami Hiramatsu }
140540adea3SMasami Hiramatsu 
141540adea3SMasami Hiramatsu static struct notifier_block ei_module_nb = {
142540adea3SMasami Hiramatsu 	.notifier_call = ei_module_callback,
143540adea3SMasami Hiramatsu 	.priority = 0
144540adea3SMasami Hiramatsu };
145540adea3SMasami Hiramatsu 
146540adea3SMasami Hiramatsu static __init int module_ei_init(void)
147540adea3SMasami Hiramatsu {
148540adea3SMasami Hiramatsu 	return register_module_notifier(&ei_module_nb);
149540adea3SMasami Hiramatsu }
150540adea3SMasami Hiramatsu #else /* !CONFIG_MODULES */
151540adea3SMasami Hiramatsu #define module_ei_init()	(0)
152540adea3SMasami Hiramatsu #endif
153540adea3SMasami Hiramatsu 
154540adea3SMasami Hiramatsu /*
155540adea3SMasami Hiramatsu  * error_injection/whitelist -- shows which functions can be overridden for
156540adea3SMasami Hiramatsu  * error injection.
157540adea3SMasami Hiramatsu  */
158540adea3SMasami Hiramatsu static void *ei_seq_start(struct seq_file *m, loff_t *pos)
159540adea3SMasami Hiramatsu {
160540adea3SMasami Hiramatsu 	mutex_lock(&ei_mutex);
161540adea3SMasami Hiramatsu 	return seq_list_start(&error_injection_list, *pos);
162540adea3SMasami Hiramatsu }
163540adea3SMasami Hiramatsu 
164540adea3SMasami Hiramatsu static void ei_seq_stop(struct seq_file *m, void *v)
165540adea3SMasami Hiramatsu {
166540adea3SMasami Hiramatsu 	mutex_unlock(&ei_mutex);
167540adea3SMasami Hiramatsu }
168540adea3SMasami Hiramatsu 
169540adea3SMasami Hiramatsu static void *ei_seq_next(struct seq_file *m, void *v, loff_t *pos)
170540adea3SMasami Hiramatsu {
171540adea3SMasami Hiramatsu 	return seq_list_next(v, &error_injection_list, pos);
172540adea3SMasami Hiramatsu }
173540adea3SMasami Hiramatsu 
174663faf9fSMasami Hiramatsu static const char *error_type_string(int etype)
175663faf9fSMasami Hiramatsu {
176663faf9fSMasami Hiramatsu 	switch (etype) {
177663faf9fSMasami Hiramatsu 	case EI_ETYPE_NULL:
178663faf9fSMasami Hiramatsu 		return "NULL";
179663faf9fSMasami Hiramatsu 	case EI_ETYPE_ERRNO:
180663faf9fSMasami Hiramatsu 		return "ERRNO";
181663faf9fSMasami Hiramatsu 	case EI_ETYPE_ERRNO_NULL:
182663faf9fSMasami Hiramatsu 		return "ERRNO_NULL";
183*537cd894SBarnabás Pőcze 	case EI_ETYPE_TRUE:
184*537cd894SBarnabás Pőcze 		return "TRUE";
185663faf9fSMasami Hiramatsu 	default:
186663faf9fSMasami Hiramatsu 		return "(unknown)";
187663faf9fSMasami Hiramatsu 	}
188663faf9fSMasami Hiramatsu }
189663faf9fSMasami Hiramatsu 
190540adea3SMasami Hiramatsu static int ei_seq_show(struct seq_file *m, void *v)
191540adea3SMasami Hiramatsu {
192540adea3SMasami Hiramatsu 	struct ei_entry *ent = list_entry(v, struct ei_entry, list);
193540adea3SMasami Hiramatsu 
194d75f773cSSakari Ailus 	seq_printf(m, "%ps\t%s\n", (void *)ent->start_addr,
195663faf9fSMasami Hiramatsu 		   error_type_string(ent->etype));
196540adea3SMasami Hiramatsu 	return 0;
197540adea3SMasami Hiramatsu }
198540adea3SMasami Hiramatsu 
199540adea3SMasami Hiramatsu static const struct seq_operations ei_seq_ops = {
200540adea3SMasami Hiramatsu 	.start = ei_seq_start,
201540adea3SMasami Hiramatsu 	.next  = ei_seq_next,
202540adea3SMasami Hiramatsu 	.stop  = ei_seq_stop,
203540adea3SMasami Hiramatsu 	.show  = ei_seq_show,
204540adea3SMasami Hiramatsu };
205540adea3SMasami Hiramatsu 
206540adea3SMasami Hiramatsu static int ei_open(struct inode *inode, struct file *filp)
207540adea3SMasami Hiramatsu {
208540adea3SMasami Hiramatsu 	return seq_open(filp, &ei_seq_ops);
209540adea3SMasami Hiramatsu }
210540adea3SMasami Hiramatsu 
211540adea3SMasami Hiramatsu static const struct file_operations debugfs_ei_ops = {
212540adea3SMasami Hiramatsu 	.open           = ei_open,
213540adea3SMasami Hiramatsu 	.read           = seq_read,
214540adea3SMasami Hiramatsu 	.llseek         = seq_lseek,
215540adea3SMasami Hiramatsu 	.release        = seq_release,
216540adea3SMasami Hiramatsu };
217540adea3SMasami Hiramatsu 
218540adea3SMasami Hiramatsu static int __init ei_debugfs_init(void)
219540adea3SMasami Hiramatsu {
220540adea3SMasami Hiramatsu 	struct dentry *dir, *file;
221540adea3SMasami Hiramatsu 
222540adea3SMasami Hiramatsu 	dir = debugfs_create_dir("error_injection", NULL);
223540adea3SMasami Hiramatsu 	if (!dir)
224540adea3SMasami Hiramatsu 		return -ENOMEM;
225540adea3SMasami Hiramatsu 
226540adea3SMasami Hiramatsu 	file = debugfs_create_file("list", 0444, dir, NULL, &debugfs_ei_ops);
227540adea3SMasami Hiramatsu 	if (!file) {
228540adea3SMasami Hiramatsu 		debugfs_remove(dir);
229540adea3SMasami Hiramatsu 		return -ENOMEM;
230540adea3SMasami Hiramatsu 	}
231540adea3SMasami Hiramatsu 
232540adea3SMasami Hiramatsu 	return 0;
233540adea3SMasami Hiramatsu }
234540adea3SMasami Hiramatsu 
235540adea3SMasami Hiramatsu static int __init init_error_injection(void)
236540adea3SMasami Hiramatsu {
237540adea3SMasami Hiramatsu 	populate_kernel_ei_list();
238540adea3SMasami Hiramatsu 
239540adea3SMasami Hiramatsu 	if (!module_ei_init())
240540adea3SMasami Hiramatsu 		ei_debugfs_init();
241540adea3SMasami Hiramatsu 
242540adea3SMasami Hiramatsu 	return 0;
243540adea3SMasami Hiramatsu }
244540adea3SMasami Hiramatsu late_initcall(init_error_injection);
245