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