1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Copyright (C) 2019-2022 Red Hat, Inc. Daniel Bristot de Oliveira <bristot@kernel.org> |
4 | * |
5 | * Runtime reactor interface. |
6 | * |
7 | * A runtime monitor can cause a reaction to the detection of an |
8 | * exception on the model's execution. By default, the monitors have |
9 | * tracing reactions, printing the monitor output via tracepoints. |
10 | * But other reactions can be added (on-demand) via this interface. |
11 | * |
12 | * == Registering reactors == |
13 | * |
14 | * The struct rv_reactor defines a callback function to be executed |
15 | * in case of a model exception happens. The callback function |
16 | * receives a message to be (optionally) printed before executing |
17 | * the reaction. |
18 | * |
19 | * A RV reactor is registered via: |
20 | * int rv_register_reactor(struct rv_reactor *reactor) |
21 | * And unregistered via: |
22 | * int rv_unregister_reactor(struct rv_reactor *reactor) |
23 | * |
24 | * These functions are exported to modules, enabling reactors to be |
25 | * dynamically loaded. |
26 | * |
27 | * == User interface == |
28 | * |
29 | * The user interface resembles the kernel tracing interface and |
30 | * presents these files: |
31 | * |
32 | * "available_reactors" |
33 | * - List the available reactors, one per line. |
34 | * |
35 | * For example: |
36 | * # cat available_reactors |
37 | * nop |
38 | * panic |
39 | * printk |
40 | * |
41 | * "reacting_on" |
42 | * - It is an on/off general switch for reactors, disabling |
43 | * all reactions. |
44 | * |
45 | * "monitors/MONITOR/reactors" |
46 | * - List available reactors, with the select reaction for the given |
47 | * MONITOR inside []. The default one is the nop (no operation) |
48 | * reactor. |
49 | * - Writing the name of an reactor enables it to the given |
50 | * MONITOR. |
51 | * |
52 | * For example: |
53 | * # cat monitors/wip/reactors |
54 | * [nop] |
55 | * panic |
56 | * printk |
57 | * # echo panic > monitors/wip/reactors |
58 | * # cat monitors/wip/reactors |
59 | * nop |
60 | * [panic] |
61 | * printk |
62 | */ |
63 | |
64 | #include <linux/slab.h> |
65 | |
66 | #include "rv.h" |
67 | |
68 | /* |
69 | * Interface for the reactor register. |
70 | */ |
71 | static LIST_HEAD(rv_reactors_list); |
72 | |
73 | static struct rv_reactor_def *get_reactor_rdef_by_name(char *name) |
74 | { |
75 | struct rv_reactor_def *r; |
76 | |
77 | list_for_each_entry(r, &rv_reactors_list, list) { |
78 | if (strcmp(name, r->reactor->name) == 0) |
79 | return r; |
80 | } |
81 | return NULL; |
82 | } |
83 | |
84 | /* |
85 | * Available reactors seq functions. |
86 | */ |
87 | static int reactors_show(struct seq_file *m, void *p) |
88 | { |
89 | struct rv_reactor_def *rea_def = p; |
90 | |
91 | seq_printf(m, fmt: "%s\n" , rea_def->reactor->name); |
92 | return 0; |
93 | } |
94 | |
95 | static void reactors_stop(struct seq_file *m, void *p) |
96 | { |
97 | mutex_unlock(lock: &rv_interface_lock); |
98 | } |
99 | |
100 | static void *reactors_start(struct seq_file *m, loff_t *pos) |
101 | { |
102 | mutex_lock(&rv_interface_lock); |
103 | return seq_list_start(head: &rv_reactors_list, pos: *pos); |
104 | } |
105 | |
106 | static void *reactors_next(struct seq_file *m, void *p, loff_t *pos) |
107 | { |
108 | return seq_list_next(v: p, head: &rv_reactors_list, ppos: pos); |
109 | } |
110 | |
111 | /* |
112 | * available_reactors seq definition. |
113 | */ |
114 | static const struct seq_operations available_reactors_seq_ops = { |
115 | .start = reactors_start, |
116 | .next = reactors_next, |
117 | .stop = reactors_stop, |
118 | .show = reactors_show |
119 | }; |
120 | |
121 | /* |
122 | * available_reactors interface. |
123 | */ |
124 | static int available_reactors_open(struct inode *inode, struct file *file) |
125 | { |
126 | return seq_open(file, &available_reactors_seq_ops); |
127 | }; |
128 | |
129 | static const struct file_operations available_reactors_ops = { |
130 | .open = available_reactors_open, |
131 | .read = seq_read, |
132 | .llseek = seq_lseek, |
133 | .release = seq_release |
134 | }; |
135 | |
136 | /* |
137 | * Monitor's reactor file. |
138 | */ |
139 | static int monitor_reactor_show(struct seq_file *m, void *p) |
140 | { |
141 | struct rv_monitor_def *mdef = m->private; |
142 | struct rv_reactor_def *rdef = p; |
143 | |
144 | if (mdef->rdef == rdef) |
145 | seq_printf(m, fmt: "[%s]\n" , rdef->reactor->name); |
146 | else |
147 | seq_printf(m, fmt: "%s\n" , rdef->reactor->name); |
148 | return 0; |
149 | } |
150 | |
151 | /* |
152 | * available_reactors seq definition. |
153 | */ |
154 | static const struct seq_operations monitor_reactors_seq_ops = { |
155 | .start = reactors_start, |
156 | .next = reactors_next, |
157 | .stop = reactors_stop, |
158 | .show = monitor_reactor_show |
159 | }; |
160 | |
161 | static void monitor_swap_reactors(struct rv_monitor_def *mdef, struct rv_reactor_def *rdef, |
162 | bool reacting) |
163 | { |
164 | bool monitor_enabled; |
165 | |
166 | /* nothing to do */ |
167 | if (mdef->rdef == rdef) |
168 | return; |
169 | |
170 | monitor_enabled = mdef->monitor->enabled; |
171 | if (monitor_enabled) |
172 | rv_disable_monitor(mdef); |
173 | |
174 | /* swap reactor's usage */ |
175 | mdef->rdef->counter--; |
176 | rdef->counter++; |
177 | |
178 | mdef->rdef = rdef; |
179 | mdef->reacting = reacting; |
180 | mdef->monitor->react = rdef->reactor->react; |
181 | |
182 | if (monitor_enabled) |
183 | rv_enable_monitor(mdef); |
184 | } |
185 | |
186 | static ssize_t |
187 | monitor_reactors_write(struct file *file, const char __user *user_buf, |
188 | size_t count, loff_t *ppos) |
189 | { |
190 | char buff[MAX_RV_REACTOR_NAME_SIZE + 2]; |
191 | struct rv_monitor_def *mdef; |
192 | struct rv_reactor_def *rdef; |
193 | struct seq_file *seq_f; |
194 | int retval = -EINVAL; |
195 | bool enable; |
196 | char *ptr; |
197 | int len; |
198 | |
199 | if (count < 1 || count > MAX_RV_REACTOR_NAME_SIZE + 1) |
200 | return -EINVAL; |
201 | |
202 | memset(buff, 0, sizeof(buff)); |
203 | |
204 | retval = simple_write_to_buffer(to: buff, available: sizeof(buff) - 1, ppos, from: user_buf, count); |
205 | if (retval < 0) |
206 | return -EFAULT; |
207 | |
208 | ptr = strim(buff); |
209 | |
210 | len = strlen(ptr); |
211 | if (!len) |
212 | return count; |
213 | |
214 | /* |
215 | * See monitor_reactors_open() |
216 | */ |
217 | seq_f = file->private_data; |
218 | mdef = seq_f->private; |
219 | |
220 | mutex_lock(&rv_interface_lock); |
221 | |
222 | retval = -EINVAL; |
223 | |
224 | list_for_each_entry(rdef, &rv_reactors_list, list) { |
225 | if (strcmp(ptr, rdef->reactor->name) != 0) |
226 | continue; |
227 | |
228 | if (rdef == get_reactor_rdef_by_name(name: "nop" )) |
229 | enable = false; |
230 | else |
231 | enable = true; |
232 | |
233 | monitor_swap_reactors(mdef, rdef, reacting: enable); |
234 | |
235 | retval = count; |
236 | break; |
237 | } |
238 | |
239 | mutex_unlock(lock: &rv_interface_lock); |
240 | |
241 | return retval; |
242 | } |
243 | |
244 | /* |
245 | * available_reactors interface. |
246 | */ |
247 | static int monitor_reactors_open(struct inode *inode, struct file *file) |
248 | { |
249 | struct rv_monitor_def *mdef = inode->i_private; |
250 | struct seq_file *seq_f; |
251 | int ret; |
252 | |
253 | ret = seq_open(file, &monitor_reactors_seq_ops); |
254 | if (ret < 0) |
255 | return ret; |
256 | |
257 | /* |
258 | * seq_open stores the seq_file on the file->private data. |
259 | */ |
260 | seq_f = file->private_data; |
261 | |
262 | /* |
263 | * Copy the create file "private" data to the seq_file private data. |
264 | */ |
265 | seq_f->private = mdef; |
266 | |
267 | return 0; |
268 | }; |
269 | |
270 | static const struct file_operations monitor_reactors_ops = { |
271 | .open = monitor_reactors_open, |
272 | .read = seq_read, |
273 | .llseek = seq_lseek, |
274 | .release = seq_release, |
275 | .write = monitor_reactors_write |
276 | }; |
277 | |
278 | static int __rv_register_reactor(struct rv_reactor *reactor) |
279 | { |
280 | struct rv_reactor_def *r; |
281 | |
282 | list_for_each_entry(r, &rv_reactors_list, list) { |
283 | if (strcmp(reactor->name, r->reactor->name) == 0) { |
284 | pr_info("Reactor %s is already registered\n" , reactor->name); |
285 | return -EINVAL; |
286 | } |
287 | } |
288 | |
289 | r = kzalloc(size: sizeof(struct rv_reactor_def), GFP_KERNEL); |
290 | if (!r) |
291 | return -ENOMEM; |
292 | |
293 | r->reactor = reactor; |
294 | r->counter = 0; |
295 | |
296 | list_add_tail(new: &r->list, head: &rv_reactors_list); |
297 | |
298 | return 0; |
299 | } |
300 | |
301 | /** |
302 | * rv_register_reactor - register a rv reactor. |
303 | * @reactor: The rv_reactor to be registered. |
304 | * |
305 | * Returns 0 if successful, error otherwise. |
306 | */ |
307 | int rv_register_reactor(struct rv_reactor *reactor) |
308 | { |
309 | int retval = 0; |
310 | |
311 | if (strlen(reactor->name) >= MAX_RV_REACTOR_NAME_SIZE) { |
312 | pr_info("Reactor %s has a name longer than %d\n" , |
313 | reactor->name, MAX_RV_MONITOR_NAME_SIZE); |
314 | return -EINVAL; |
315 | } |
316 | |
317 | mutex_lock(&rv_interface_lock); |
318 | retval = __rv_register_reactor(reactor); |
319 | mutex_unlock(lock: &rv_interface_lock); |
320 | return retval; |
321 | } |
322 | |
323 | /** |
324 | * rv_unregister_reactor - unregister a rv reactor. |
325 | * @reactor: The rv_reactor to be unregistered. |
326 | * |
327 | * Returns 0 if successful, error otherwise. |
328 | */ |
329 | int rv_unregister_reactor(struct rv_reactor *reactor) |
330 | { |
331 | struct rv_reactor_def *ptr, *next; |
332 | int ret = 0; |
333 | |
334 | mutex_lock(&rv_interface_lock); |
335 | |
336 | list_for_each_entry_safe(ptr, next, &rv_reactors_list, list) { |
337 | if (strcmp(reactor->name, ptr->reactor->name) == 0) { |
338 | |
339 | if (!ptr->counter) { |
340 | list_del(entry: &ptr->list); |
341 | } else { |
342 | printk(KERN_WARNING |
343 | "rv: the rv_reactor %s is in use by %d monitor(s)\n" , |
344 | ptr->reactor->name, ptr->counter); |
345 | printk(KERN_WARNING "rv: the rv_reactor %s cannot be removed\n" , |
346 | ptr->reactor->name); |
347 | ret = -EBUSY; |
348 | break; |
349 | } |
350 | } |
351 | } |
352 | |
353 | mutex_unlock(lock: &rv_interface_lock); |
354 | return ret; |
355 | } |
356 | |
357 | /* |
358 | * reacting_on interface. |
359 | */ |
360 | static bool __read_mostly reacting_on; |
361 | |
362 | /** |
363 | * rv_reacting_on - checks if reacting is on |
364 | * |
365 | * Returns 1 if on, 0 otherwise. |
366 | */ |
367 | bool rv_reacting_on(void) |
368 | { |
369 | /* Ensures that concurrent monitors read consistent reacting_on */ |
370 | smp_rmb(); |
371 | return READ_ONCE(reacting_on); |
372 | } |
373 | |
374 | static ssize_t reacting_on_read_data(struct file *filp, |
375 | char __user *user_buf, |
376 | size_t count, loff_t *ppos) |
377 | { |
378 | char *buff; |
379 | |
380 | buff = rv_reacting_on() ? "1\n" : "0\n" ; |
381 | |
382 | return simple_read_from_buffer(to: user_buf, count, ppos, from: buff, strlen(buff)+1); |
383 | } |
384 | |
385 | static void turn_reacting_off(void) |
386 | { |
387 | WRITE_ONCE(reacting_on, false); |
388 | /* Ensures that concurrent monitors read consistent reacting_on */ |
389 | smp_wmb(); |
390 | } |
391 | |
392 | static void turn_reacting_on(void) |
393 | { |
394 | WRITE_ONCE(reacting_on, true); |
395 | /* Ensures that concurrent monitors read consistent reacting_on */ |
396 | smp_wmb(); |
397 | } |
398 | |
399 | static ssize_t reacting_on_write_data(struct file *filp, const char __user *user_buf, |
400 | size_t count, loff_t *ppos) |
401 | { |
402 | int retval; |
403 | bool val; |
404 | |
405 | retval = kstrtobool_from_user(s: user_buf, count, res: &val); |
406 | if (retval) |
407 | return retval; |
408 | |
409 | mutex_lock(&rv_interface_lock); |
410 | |
411 | if (val) |
412 | turn_reacting_on(); |
413 | else |
414 | turn_reacting_off(); |
415 | |
416 | /* |
417 | * Wait for the execution of all events to finish |
418 | * before returning to user-space. |
419 | */ |
420 | tracepoint_synchronize_unregister(); |
421 | |
422 | mutex_unlock(lock: &rv_interface_lock); |
423 | |
424 | return count; |
425 | } |
426 | |
427 | static const struct file_operations reacting_on_fops = { |
428 | .open = simple_open, |
429 | .llseek = no_llseek, |
430 | .write = reacting_on_write_data, |
431 | .read = reacting_on_read_data, |
432 | }; |
433 | |
434 | /** |
435 | * reactor_populate_monitor - creates per monitor reactors file |
436 | * @mdef: monitor's definition. |
437 | * |
438 | * Returns 0 if successful, error otherwise. |
439 | */ |
440 | int reactor_populate_monitor(struct rv_monitor_def *mdef) |
441 | { |
442 | struct dentry *tmp; |
443 | |
444 | tmp = rv_create_file(name: "reactors" , RV_MODE_WRITE, parent: mdef->root_d, data: mdef, fops: &monitor_reactors_ops); |
445 | if (!tmp) |
446 | return -ENOMEM; |
447 | |
448 | /* |
449 | * Configure as the rv_nop reactor. |
450 | */ |
451 | mdef->rdef = get_reactor_rdef_by_name(name: "nop" ); |
452 | mdef->rdef->counter++; |
453 | mdef->reacting = false; |
454 | |
455 | return 0; |
456 | } |
457 | |
458 | /** |
459 | * reactor_cleanup_monitor - cleanup a monitor reference |
460 | * @mdef: monitor's definition. |
461 | */ |
462 | void reactor_cleanup_monitor(struct rv_monitor_def *mdef) |
463 | { |
464 | lockdep_assert_held(&rv_interface_lock); |
465 | mdef->rdef->counter--; |
466 | WARN_ON_ONCE(mdef->rdef->counter < 0); |
467 | } |
468 | |
469 | /* |
470 | * Nop reactor register |
471 | */ |
472 | static void rv_nop_reaction(char *msg) |
473 | { |
474 | } |
475 | |
476 | static struct rv_reactor rv_nop = { |
477 | .name = "nop" , |
478 | .description = "no-operation reactor: do nothing." , |
479 | .react = rv_nop_reaction |
480 | }; |
481 | |
482 | int init_rv_reactors(struct dentry *root_dir) |
483 | { |
484 | struct dentry *available, *reacting; |
485 | int retval; |
486 | |
487 | available = rv_create_file(name: "available_reactors" , RV_MODE_READ, parent: root_dir, NULL, |
488 | fops: &available_reactors_ops); |
489 | if (!available) |
490 | goto out_err; |
491 | |
492 | reacting = rv_create_file(name: "reacting_on" , RV_MODE_WRITE, parent: root_dir, NULL, fops: &reacting_on_fops); |
493 | if (!reacting) |
494 | goto rm_available; |
495 | |
496 | retval = __rv_register_reactor(reactor: &rv_nop); |
497 | if (retval) |
498 | goto rm_reacting; |
499 | |
500 | turn_reacting_on(); |
501 | |
502 | return 0; |
503 | |
504 | rm_reacting: |
505 | rv_remove(dentry: reacting); |
506 | rm_available: |
507 | rv_remove(dentry: available); |
508 | out_err: |
509 | return -ENOMEM; |
510 | } |
511 | |