LCOV - code coverage report
Current view: top level - lib - error-inject.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 43 88 48.9 %
Date: 2022-04-01 14:35:51 Functions: 6 14 42.9 %
Branches: 12 40 30.0 %

           Branch data     Line data    Source code
       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. */
      13                 :            : static LIST_HEAD(error_injection_list);
      14                 :            : static DEFINE_MUTEX(ei_mutex);
      15                 :            : struct 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                 :            : 
      23                 :          0 : bool within_error_injection_list(unsigned long addr)
      24                 :            : {
      25                 :          0 :         struct ei_entry *ent;
      26                 :          0 :         bool ret = false;
      27                 :            : 
      28                 :          0 :         mutex_lock(&ei_mutex);
      29         [ #  # ]:          0 :         list_for_each_entry(ent, &error_injection_list, list) {
      30   [ #  #  #  # ]:          0 :                 if (addr >= ent->start_addr && addr < ent->end_addr) {
      31                 :            :                         ret = true;
      32                 :            :                         break;
      33                 :            :                 }
      34                 :            :         }
      35                 :          0 :         mutex_unlock(&ei_mutex);
      36                 :          0 :         return ret;
      37                 :            : }
      38                 :            : 
      39                 :          0 : int get_injectable_error_type(unsigned long addr)
      40                 :            : {
      41                 :          0 :         struct ei_entry *ent;
      42                 :            : 
      43         [ #  # ]:          0 :         list_for_each_entry(ent, &error_injection_list, list) {
      44   [ #  #  #  # ]:          0 :                 if (addr >= ent->start_addr && addr < ent->end_addr)
      45                 :          0 :                         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                 :            :  */
      57                 :         21 : static void populate_error_injection_list(struct error_injection_entry *start,
      58                 :            :                                           struct error_injection_entry *end,
      59                 :            :                                           void *priv)
      60                 :            : {
      61                 :         21 :         struct error_injection_entry *iter;
      62                 :         21 :         struct ei_entry *ent;
      63                 :         21 :         unsigned long entry, offset = 0, size = 0;
      64                 :            : 
      65                 :         21 :         mutex_lock(&ei_mutex);
      66         [ +  + ]:      19383 :         for (iter = start; iter < end; iter++) {
      67                 :      19341 :                 entry = arch_deref_entry_point((void *)iter->addr);
      68                 :            : 
      69   [ +  -  -  + ]:      38682 :                 if (!kernel_text_address(entry) ||
      70                 :      19341 :                     !kallsyms_lookup_size_offset(entry, &size, &offset)) {
      71                 :          0 :                         pr_err("Failed to find error inject entry at %p\n",
      72                 :            :                                 (void *)entry);
      73                 :          0 :                         continue;
      74                 :            :                 }
      75                 :            : 
      76                 :      19341 :                 ent = kmalloc(sizeof(*ent), GFP_KERNEL);
      77         [ +  - ]:      19341 :                 if (!ent)
      78                 :            :                         break;
      79                 :      19341 :                 ent->start_addr = entry;
      80                 :      19341 :                 ent->end_addr = entry + size;
      81                 :      19341 :                 ent->etype = iter->etype;
      82                 :      19341 :                 ent->priv = priv;
      83                 :      19341 :                 INIT_LIST_HEAD(&ent->list);
      84                 :      19341 :                 list_add_tail(&ent->list, &error_injection_list);
      85                 :            :         }
      86                 :         21 :         mutex_unlock(&ei_mutex);
      87                 :         21 : }
      88                 :            : 
      89                 :            : /* Markers of the _error_inject_whitelist section */
      90                 :            : extern struct error_injection_entry __start_error_injection_whitelist[];
      91                 :            : extern struct error_injection_entry __stop_error_injection_whitelist[];
      92                 :            : 
      93                 :         21 : static void __init populate_kernel_ei_list(void)
      94                 :            : {
      95                 :         21 :         populate_error_injection_list(__start_error_injection_whitelist,
      96                 :            :                                       __stop_error_injection_whitelist,
      97                 :            :                                       NULL);
      98                 :         21 : }
      99                 :            : 
     100                 :            : #ifdef CONFIG_MODULES
     101                 :         63 : static void module_load_ei_list(struct module *mod)
     102                 :            : {
     103                 :         63 :         if (!mod->num_ei_funcs)
     104                 :            :                 return;
     105                 :            : 
     106                 :          0 :         populate_error_injection_list(mod->ei_funcs,
     107                 :          0 :                                       mod->ei_funcs + mod->num_ei_funcs, mod);
     108                 :            : }
     109                 :            : 
     110                 :          0 : static void module_unload_ei_list(struct module *mod)
     111                 :            : {
     112                 :          0 :         struct ei_entry *ent, *n;
     113                 :            : 
     114         [ #  # ]:          0 :         if (!mod->num_ei_funcs)
     115                 :            :                 return;
     116                 :            : 
     117                 :          0 :         mutex_lock(&ei_mutex);
     118         [ #  # ]:          0 :         list_for_each_entry_safe(ent, n, &error_injection_list, list) {
     119         [ #  # ]:          0 :                 if (ent->priv == mod) {
     120                 :          0 :                         list_del_init(&ent->list);
     121                 :          0 :                         kfree(ent);
     122                 :            :                 }
     123                 :            :         }
     124                 :          0 :         mutex_unlock(&ei_mutex);
     125                 :            : }
     126                 :            : 
     127                 :            : /* Module notifier call back, checking error injection table on the module */
     128                 :        126 : static int ei_module_callback(struct notifier_block *nb,
     129                 :            :                               unsigned long val, void *data)
     130                 :            : {
     131                 :        126 :         struct module *mod = data;
     132                 :            : 
     133         [ +  + ]:        126 :         if (val == MODULE_STATE_COMING)
     134         [ -  + ]:         63 :                 module_load_ei_list(mod);
     135         [ -  + ]:         63 :         else if (val == MODULE_STATE_GOING)
     136                 :          0 :                 module_unload_ei_list(mod);
     137                 :            : 
     138                 :        126 :         return NOTIFY_DONE;
     139                 :            : }
     140                 :            : 
     141                 :            : static struct notifier_block ei_module_nb = {
     142                 :            :         .notifier_call = ei_module_callback,
     143                 :            :         .priority = 0
     144                 :            : };
     145                 :            : 
     146                 :         21 : static __init int module_ei_init(void)
     147                 :            : {
     148                 :         21 :         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                 :            :  */
     158                 :          0 : static void *ei_seq_start(struct seq_file *m, loff_t *pos)
     159                 :            : {
     160                 :          0 :         mutex_lock(&ei_mutex);
     161                 :          0 :         return seq_list_start(&error_injection_list, *pos);
     162                 :            : }
     163                 :            : 
     164                 :          0 : static void ei_seq_stop(struct seq_file *m, void *v)
     165                 :            : {
     166                 :          0 :         mutex_unlock(&ei_mutex);
     167                 :          0 : }
     168                 :            : 
     169                 :          0 : static void *ei_seq_next(struct seq_file *m, void *v, loff_t *pos)
     170                 :            : {
     171                 :          0 :         return seq_list_next(v, &error_injection_list, pos);
     172                 :            : }
     173                 :            : 
     174                 :          0 : static const char *error_type_string(int etype)
     175                 :            : {
     176                 :          0 :         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                 :            : 
     188                 :          0 : static int ei_seq_show(struct seq_file *m, void *v)
     189                 :            : {
     190                 :          0 :         struct ei_entry *ent = list_entry(v, struct ei_entry, list);
     191                 :            : 
     192         [ #  # ]:          0 :         seq_printf(m, "%ps\t%s\n", (void *)ent->start_addr,
     193                 :            :                    error_type_string(ent->etype));
     194                 :          0 :         return 0;
     195                 :            : }
     196                 :            : 
     197                 :            : static 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                 :            : 
     204                 :          0 : static int ei_open(struct inode *inode, struct file *filp)
     205                 :            : {
     206                 :          0 :         return seq_open(filp, &ei_seq_ops);
     207                 :            : }
     208                 :            : 
     209                 :            : static 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                 :            : 
     216                 :         21 : static int __init ei_debugfs_init(void)
     217                 :            : {
     218                 :         21 :         struct dentry *dir, *file;
     219                 :            : 
     220                 :         21 :         dir = debugfs_create_dir("error_injection", NULL);
     221         [ +  - ]:         21 :         if (!dir)
     222                 :            :                 return -ENOMEM;
     223                 :            : 
     224                 :         21 :         file = debugfs_create_file("list", 0444, dir, NULL, &debugfs_ei_ops);
     225         [ -  + ]:         21 :         if (!file) {
     226                 :          0 :                 debugfs_remove(dir);
     227                 :          0 :                 return -ENOMEM;
     228                 :            :         }
     229                 :            : 
     230                 :            :         return 0;
     231                 :            : }
     232                 :            : 
     233                 :         21 : static int __init init_error_injection(void)
     234                 :            : {
     235                 :         21 :         populate_kernel_ei_list();
     236                 :            : 
     237         [ +  - ]:         21 :         if (!module_ei_init())
     238                 :         21 :                 ei_debugfs_init();
     239                 :            : 
     240                 :         21 :         return 0;
     241                 :            : }
     242                 :            : late_initcall(init_error_injection);

Generated by: LCOV version 1.14