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, "%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(&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(&rv_reactors_list, *pos); 104 } 105 106 static void *reactors_next(struct seq_file *m, void *p, loff_t *pos) 107 { 108 return seq_list_next(p, &rv_reactors_list, 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, "[%s]\n", rdef->reactor->name); 146 else 147 seq_printf(m, "%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(buff, sizeof(buff) - 1, ppos, 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("nop")) 229 enable = false; 230 else 231 enable = true; 232 233 monitor_swap_reactors(mdef, rdef, enable); 234 235 retval = count; 236 break; 237 } 238 239 mutex_unlock(&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(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(&r->list, &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(&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(&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(&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" : "\n"; 381 382 return simple_read_from_buffer(user_buf, count, ppos, 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(user_buf, count, &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(&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("reactors", RV_MODE_WRITE, mdef->root_d, mdef, &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("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("available_reactors", RV_MODE_READ, root_dir, NULL, 488 &available_reactors_ops); 489 if (!available) 490 goto out_err; 491 492 reacting = rv_create_file("reacting_on", RV_MODE_WRITE, root_dir, NULL, &reacting_on_fops); 493 if (!reacting) 494 goto rm_available; 495 496 retval = __rv_register_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(reacting); 506 rm_available: 507 rv_remove(available); 508 out_err: 509 return -ENOMEM; 510 } 511
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.