aboutsummaryrefslogtreecommitdiffstats
path: root/lib/error-inject.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2018-01-16 22:42:14 -0500
committerDavid S. Miller <davem@davemloft.net>2018-01-16 22:42:14 -0500
commit7018d1b3f20fb4308ed9bc577160cb8ffb79b62a (patch)
treeb61a17c694d3cdc3490b190c35104b936bcc6638 /lib/error-inject.c
parente7e70fa6784b48a811fdd4253c41fc7195300570 (diff)
parente8a9d9683c8a62f917c19e57f1618363fb9ed04e (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next
Daniel Borkmann says: ==================== pull-request: bpf-next 2018-01-17 The following pull-request contains BPF updates for your *net-next* tree. The main changes are: 1) Add initial BPF map offloading for nfp driver. Currently only programs were supported so far w/o being able to access maps. Offloaded programs are right now only allowed to perform map lookups, and control path is responsible for populating the maps. BPF core infrastructure along with nfp implementation is provided, from Jakub. 2) Various follow-ups to Josef's BPF error injections. More specifically that includes: properly check whether the error injectable event is on function entry or not, remove the percpu bpf_kprobe_override and rather compare instruction pointer with original one, separate error-injection from kprobes since it's not limited to it, add injectable error types in order to specify what is the expected type of failure, and last but not least also support the kernel's fault injection framework, all from Masami. 3) Various misc improvements and cleanups to the libbpf Makefile. That is, fix permissions when installing BPF header files, remove unused variables and functions, and also install the libbpf.h header, from Jesper. 4) When offloading to nfp JIT and the BPF insn is unsupported in the JIT, then reject right at verification time. Also fix libbpf with regards to ELF section name matching by properly treating the program type as prefix. Both from Quentin. 5) Add -DPACKAGE to bpftool when including bfd.h for the disassembler. This is needed, for example, when building libfd from source as bpftool doesn't supply a config.h for bfd.h. Fix from Jiong. 6) xdp_convert_ctx_access() is simplified since it doesn't need to set target size during verification, from Jesper. 7) Let bpftool properly recognize BPF_PROG_TYPE_CGROUP_DEVICE program types, from Roman. 8) Various functions in BPF cpumap were not declared static, from Wei. 9) Fix a double semicolon in BPF samples, from Luis. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'lib/error-inject.c')
-rw-r--r--lib/error-inject.c242
1 files changed, 242 insertions, 0 deletions
diff --git a/lib/error-inject.c b/lib/error-inject.c
new file mode 100644
index 000000000000..c0d4600f4896
--- /dev/null
+++ b/lib/error-inject.c
@@ -0,0 +1,242 @@
1// SPDX-License-Identifier: GPL-2.0
2// error-inject.c: Function-level error injection table
3#include <linux/error-injection.h>
4#include <linux/debugfs.h>
5#include <linux/kallsyms.h>
6#include <linux/kprobes.h>
7#include <linux/module.h>
8#include <linux/mutex.h>
9#include <linux/list.h>
10#include <linux/slab.h>
11
12/* Whitelist of symbols that can be overridden for error injection. */
13static LIST_HEAD(error_injection_list);
14static DEFINE_MUTEX(ei_mutex);
15struct ei_entry {
16 struct list_head list;
17 unsigned long start_addr;
18 unsigned long end_addr;
19 int etype;
20 void *priv;
21};
22
23bool within_error_injection_list(unsigned long addr)
24{
25 struct ei_entry *ent;
26 bool ret = false;
27
28 mutex_lock(&ei_mutex);
29 list_for_each_entry(ent, &error_injection_list, list) {
30 if (addr >= ent->start_addr && addr < ent->end_addr) {
31 ret = true;
32 break;
33 }
34 }
35 mutex_unlock(&ei_mutex);
36 return ret;
37}
38
39int get_injectable_error_type(unsigned long addr)
40{
41 struct ei_entry *ent;
42
43 list_for_each_entry(ent, &error_injection_list, list) {
44 if (addr >= ent->start_addr && addr < ent->end_addr)
45 return ent->etype;
46 }
47 return EI_ETYPE_NONE;
48}
49
50/*
51 * Lookup and populate the error_injection_list.
52 *
53 * For safety reasons we only allow certain functions to be overridden with
54 * bpf_error_injection, so we need to populate the list of the symbols that have
55 * been marked as safe for overriding.
56 */
57static void populate_error_injection_list(struct error_injection_entry *start,
58 struct error_injection_entry *end,
59 void *priv)
60{
61 struct error_injection_entry *iter;
62 struct ei_entry *ent;
63 unsigned long entry, offset = 0, size = 0;
64
65 mutex_lock(&ei_mutex);
66 for (iter = start; iter < end; iter++) {
67 entry = arch_deref_entry_point((void *)iter->addr);
68
69 if (!kernel_text_address(entry) ||
70 !kallsyms_lookup_size_offset(entry, &size, &offset)) {
71 pr_err("Failed to find error inject entry at %p\n",
72 (void *)entry);
73 continue;
74 }
75
76 ent = kmalloc(sizeof(*ent), GFP_KERNEL);
77 if (!ent)
78 break;
79 ent->start_addr = entry;
80 ent->end_addr = entry + size;
81 ent->etype = iter->etype;
82 ent->priv = priv;
83 INIT_LIST_HEAD(&ent->list);
84 list_add_tail(&ent->list, &error_injection_list);
85 }
86 mutex_unlock(&ei_mutex);
87}
88
89/* Markers of the _error_inject_whitelist section */
90extern struct error_injection_entry __start_error_injection_whitelist[];
91extern struct error_injection_entry __stop_error_injection_whitelist[];
92
93static void __init populate_kernel_ei_list(void)
94{
95 populate_error_injection_list(__start_error_injection_whitelist,
96 __stop_error_injection_whitelist,
97 NULL);
98}
99
100#ifdef CONFIG_MODULES
101static void module_load_ei_list(struct module *mod)
102{
103 if (!mod->num_ei_funcs)
104 return;
105
106 populate_error_injection_list(mod->ei_funcs,
107 mod->ei_funcs + mod->num_ei_funcs, mod);
108}
109
110static void module_unload_ei_list(struct module *mod)
111{
112 struct ei_entry *ent, *n;
113
114 if (!mod->num_ei_funcs)
115 return;
116
117 mutex_lock(&ei_mutex);
118 list_for_each_entry_safe(ent, n, &error_injection_list, list) {
119 if (ent->priv == mod) {
120 list_del_init(&ent->list);
121 kfree(ent);
122 }
123 }
124 mutex_unlock(&ei_mutex);
125}
126
127/* Module notifier call back, checking error injection table on the module */
128static int ei_module_callback(struct notifier_block *nb,
129 unsigned long val, void *data)
130{
131 struct module *mod = data;
132
133 if (val == MODULE_STATE_COMING)
134 module_load_ei_list(mod);
135 else if (val == MODULE_STATE_GOING)
136 module_unload_ei_list(mod);
137
138 return NOTIFY_DONE;
139}
140
141static struct notifier_block ei_module_nb = {
142 .notifier_call = ei_module_callback,
143 .priority = 0
144};
145
146static __init int module_ei_init(void)
147{
148 return register_module_notifier(&ei_module_nb);
149}
150#else /* !CONFIG_MODULES */
151#define module_ei_init() (0)
152#endif
153
154/*
155 * error_injection/whitelist -- shows which functions can be overridden for
156 * error injection.
157 */
158static void *ei_seq_start(struct seq_file *m, loff_t *pos)
159{
160 mutex_lock(&ei_mutex);
161 return seq_list_start(&error_injection_list, *pos);
162}
163
164static void ei_seq_stop(struct seq_file *m, void *v)
165{
166 mutex_unlock(&ei_mutex);
167}
168
169static void *ei_seq_next(struct seq_file *m, void *v, loff_t *pos)
170{
171 return seq_list_next(v, &error_injection_list, pos);
172}
173
174static const char *error_type_string(int etype)
175{
176 switch (etype) {
177 case EI_ETYPE_NULL:
178 return "NULL";
179 case EI_ETYPE_ERRNO:
180 return "ERRNO";
181 case EI_ETYPE_ERRNO_NULL:
182 return "ERRNO_NULL";
183 default:
184 return "(unknown)";
185 }
186}
187
188static int ei_seq_show(struct seq_file *m, void *v)
189{
190 struct ei_entry *ent = list_entry(v, struct ei_entry, list);
191
192 seq_printf(m, "%pf\t%s\n", (void *)ent->start_addr,
193 error_type_string(ent->etype));
194 return 0;
195}
196
197static const struct seq_operations ei_seq_ops = {
198 .start = ei_seq_start,
199 .next = ei_seq_next,
200 .stop = ei_seq_stop,
201 .show = ei_seq_show,
202};
203
204static int ei_open(struct inode *inode, struct file *filp)
205{
206 return seq_open(filp, &ei_seq_ops);
207}
208
209static const struct file_operations debugfs_ei_ops = {
210 .open = ei_open,
211 .read = seq_read,
212 .llseek = seq_lseek,
213 .release = seq_release,
214};
215
216static int __init ei_debugfs_init(void)
217{
218 struct dentry *dir, *file;
219
220 dir = debugfs_create_dir("error_injection", NULL);
221 if (!dir)
222 return -ENOMEM;
223
224 file = debugfs_create_file("list", 0444, dir, NULL, &debugfs_ei_ops);
225 if (!file) {
226 debugfs_remove(dir);
227 return -ENOMEM;
228 }
229
230 return 0;
231}
232
233static int __init init_error_injection(void)
234{
235 populate_kernel_ei_list();
236
237 if (!module_ei_init())
238 ei_debugfs_init();
239
240 return 0;
241}
242late_initcall(init_error_injection);