~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/kernel/fail_function.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

Diff markup

Differences between /kernel/fail_function.c (Version linux-6.11.5) and /kernel/fail_function.c (Version linux-4.11.12)


  1 // SPDX-License-Identifier: GPL-2.0                 1 
  2 /*                                                
  3  * fail_function.c: Function-based error injec    
  4  */                                               
  5 #include <linux/error-injection.h>                
  6 #include <linux/debugfs.h>                        
  7 #include <linux/fault-inject.h>                   
  8 #include <linux/kallsyms.h>                       
  9 #include <linux/kprobes.h>                        
 10 #include <linux/module.h>                         
 11 #include <linux/mutex.h>                          
 12 #include <linux/slab.h>                           
 13 #include <linux/uaccess.h>                        
 14                                                   
 15 static int fei_kprobe_handler(struct kprobe *k    
 16                                                   
 17 static void fei_post_handler(struct kprobe *kp    
 18                              unsigned long fla    
 19 {                                                 
 20         /*                                        
 21          * A dummy post handler is required to    
 22          * jump optimization does not support     
 23          */                                       
 24 }                                                 
 25                                                   
 26 struct fei_attr {                                 
 27         struct list_head list;                    
 28         struct kprobe kp;                         
 29         unsigned long retval;                     
 30 };                                                
 31 static DEFINE_MUTEX(fei_lock);                    
 32 static LIST_HEAD(fei_attr_list);                  
 33 static DECLARE_FAULT_ATTR(fei_fault_attr);        
 34 static struct dentry *fei_debugfs_dir;            
 35                                                   
 36 static unsigned long adjust_error_retval(unsig    
 37 {                                                 
 38         switch (get_injectable_error_type(addr    
 39         case EI_ETYPE_NULL:                       
 40                 return 0;                         
 41         case EI_ETYPE_ERRNO:                      
 42                 if (retv < (unsigned long)-MAX    
 43                         return (unsigned long)    
 44                 break;                            
 45         case EI_ETYPE_ERRNO_NULL:                 
 46                 if (retv != 0 && retv < (unsig    
 47                         return (unsigned long)    
 48                 break;                            
 49         case EI_ETYPE_TRUE:                       
 50                 return 1;                         
 51         }                                         
 52                                                   
 53         return retv;                              
 54 }                                                 
 55                                                   
 56 static struct fei_attr *fei_attr_new(const cha    
 57 {                                                 
 58         struct fei_attr *attr;                    
 59                                                   
 60         attr = kzalloc(sizeof(*attr), GFP_KERN    
 61         if (attr) {                               
 62                 attr->kp.symbol_name = kstrdup    
 63                 if (!attr->kp.symbol_name) {      
 64                         kfree(attr);              
 65                         return NULL;              
 66                 }                                 
 67                 attr->kp.pre_handler = fei_kpr    
 68                 attr->kp.post_handler = fei_po    
 69                 attr->retval = adjust_error_re    
 70                 INIT_LIST_HEAD(&attr->list);      
 71         }                                         
 72         return attr;                              
 73 }                                                 
 74                                                   
 75 static void fei_attr_free(struct fei_attr *att    
 76 {                                                 
 77         if (attr) {                               
 78                 kfree(attr->kp.symbol_name);      
 79                 kfree(attr);                      
 80         }                                         
 81 }                                                 
 82                                                   
 83 static struct fei_attr *fei_attr_lookup(const     
 84 {                                                 
 85         struct fei_attr *attr;                    
 86                                                   
 87         list_for_each_entry(attr, &fei_attr_li    
 88                 if (!strcmp(attr->kp.symbol_na    
 89                         return attr;              
 90         }                                         
 91                                                   
 92         return NULL;                              
 93 }                                                 
 94                                                   
 95 static bool fei_attr_is_valid(struct fei_attr     
 96 {                                                 
 97         struct fei_attr *attr;                    
 98                                                   
 99         list_for_each_entry(attr, &fei_attr_li    
100                 if (attr == _attr)                
101                         return true;              
102         }                                         
103                                                   
104         return false;                             
105 }                                                 
106                                                   
107 static int fei_retval_set(void *data, u64 val)    
108 {                                                 
109         struct fei_attr *attr = data;             
110         unsigned long retv = (unsigned long)va    
111         int err = 0;                              
112                                                   
113         mutex_lock(&fei_lock);                    
114         /*                                        
115          * Since this operation can be done af    
116          * It is safer to check the attr is st    
117          * its member.                            
118          */                                       
119         if (!fei_attr_is_valid(attr)) {           
120                 err = -ENOENT;                    
121                 goto out;                         
122         }                                         
123                                                   
124         if (attr->kp.addr) {                      
125                 if (adjust_error_retval((unsig    
126                                         val) !    
127                         err = -EINVAL;            
128         }                                         
129         if (!err)                                 
130                 attr->retval = val;               
131 out:                                              
132         mutex_unlock(&fei_lock);                  
133                                                   
134         return err;                               
135 }                                                 
136                                                   
137 static int fei_retval_get(void *data, u64 *val    
138 {                                                 
139         struct fei_attr *attr = data;             
140         int err = 0;                              
141                                                   
142         mutex_lock(&fei_lock);                    
143         /* Here we also validate @attr to ensu    
144         if (!fei_attr_is_valid(attr))             
145                 err = -ENOENT;                    
146         else                                      
147                 *val = attr->retval;              
148         mutex_unlock(&fei_lock);                  
149                                                   
150         return err;                               
151 }                                                 
152 DEFINE_DEBUGFS_ATTRIBUTE(fei_retval_ops, fei_r    
153                          "%llx\n");               
154                                                   
155 static void fei_debugfs_add_attr(struct fei_at    
156 {                                                 
157         struct dentry *dir;                       
158                                                   
159         dir = debugfs_create_dir(attr->kp.symb    
160                                                   
161         debugfs_create_file("retval", 0600, di    
162 }                                                 
163                                                   
164 static void fei_debugfs_remove_attr(struct fei    
165 {                                                 
166         debugfs_lookup_and_remove(attr->kp.sym    
167 }                                                 
168                                                   
169 static int fei_kprobe_handler(struct kprobe *k    
170 {                                                 
171         struct fei_attr *attr = container_of(k    
172                                                   
173         if (should_fail(&fei_fault_attr, 1)) {    
174                 regs_set_return_value(regs, at    
175                 override_function_with_return(    
176                 return 1;                         
177         }                                         
178                                                   
179         return 0;                                 
180 }                                                 
181 NOKPROBE_SYMBOL(fei_kprobe_handler)               
182                                                   
183 static void *fei_seq_start(struct seq_file *m,    
184 {                                                 
185         mutex_lock(&fei_lock);                    
186         return seq_list_start(&fei_attr_list,     
187 }                                                 
188                                                   
189 static void fei_seq_stop(struct seq_file *m, v    
190 {                                                 
191         mutex_unlock(&fei_lock);                  
192 }                                                 
193                                                   
194 static void *fei_seq_next(struct seq_file *m,     
195 {                                                 
196         return seq_list_next(v, &fei_attr_list    
197 }                                                 
198                                                   
199 static int fei_seq_show(struct seq_file *m, vo    
200 {                                                 
201         struct fei_attr *attr = list_entry(v,     
202                                                   
203         seq_printf(m, "%ps\n", attr->kp.addr);    
204         return 0;                                 
205 }                                                 
206                                                   
207 static const struct seq_operations fei_seq_ops    
208         .start  = fei_seq_start,                  
209         .next   = fei_seq_next,                   
210         .stop   = fei_seq_stop,                   
211         .show   = fei_seq_show,                   
212 };                                                
213                                                   
214 static int fei_open(struct inode *inode, struc    
215 {                                                 
216         return seq_open(file, &fei_seq_ops);      
217 }                                                 
218                                                   
219 static void fei_attr_remove(struct fei_attr *a    
220 {                                                 
221         fei_debugfs_remove_attr(attr);            
222         unregister_kprobe(&attr->kp);             
223         list_del(&attr->list);                    
224         fei_attr_free(attr);                      
225 }                                                 
226                                                   
227 static void fei_attr_remove_all(void)             
228 {                                                 
229         struct fei_attr *attr, *n;                
230                                                   
231         list_for_each_entry_safe(attr, n, &fei    
232                 fei_attr_remove(attr);            
233         }                                         
234 }                                                 
235                                                   
236 static ssize_t fei_write(struct file *file, co    
237                          size_t count, loff_t     
238 {                                                 
239         struct fei_attr *attr;                    
240         unsigned long addr;                       
241         char *buf, *sym;                          
242         int ret;                                  
243                                                   
244         /* cut off if it is too long */           
245         if (count > KSYM_NAME_LEN)                
246                 count = KSYM_NAME_LEN;            
247                                                   
248         buf = memdup_user_nul(buffer, count);     
249         if (IS_ERR(buf))                          
250                 return PTR_ERR(buf);              
251                                                   
252         sym = strstrip(buf);                      
253                                                   
254         mutex_lock(&fei_lock);                    
255                                                   
256         /* Writing just spaces will remove all    
257         if (sym[0] == '\0') {                     
258                 fei_attr_remove_all();            
259                 ret = count;                      
260                 goto out;                         
261         }                                         
262         /* Writing !function will remove one i    
263         if (sym[0] == '!') {                      
264                 attr = fei_attr_lookup(sym + 1    
265                 if (!attr) {                      
266                         ret = -ENOENT;            
267                         goto out;                 
268                 }                                 
269                 fei_attr_remove(attr);            
270                 ret = count;                      
271                 goto out;                         
272         }                                         
273                                                   
274         addr = kallsyms_lookup_name(sym);         
275         if (!addr) {                              
276                 ret = -EINVAL;                    
277                 goto out;                         
278         }                                         
279         if (!within_error_injection_list(addr)    
280                 ret = -ERANGE;                    
281                 goto out;                         
282         }                                         
283         if (fei_attr_lookup(sym)) {               
284                 ret = -EBUSY;                     
285                 goto out;                         
286         }                                         
287         attr = fei_attr_new(sym, addr);           
288         if (!attr) {                              
289                 ret = -ENOMEM;                    
290                 goto out;                         
291         }                                         
292                                                   
293         ret = register_kprobe(&attr->kp);         
294         if (ret) {                                
295                 fei_attr_free(attr);              
296                 goto out;                         
297         }                                         
298         fei_debugfs_add_attr(attr);               
299         list_add_tail(&attr->list, &fei_attr_l    
300         ret = count;                              
301 out:                                              
302         mutex_unlock(&fei_lock);                  
303         kfree(buf);                               
304         return ret;                               
305 }                                                 
306                                                   
307 static const struct file_operations fei_ops =     
308         .open =         fei_open,                 
309         .read =         seq_read,                 
310         .write =        fei_write,                
311         .llseek =       seq_lseek,                
312         .release =      seq_release,              
313 };                                                
314                                                   
315 static int __init fei_debugfs_init(void)          
316 {                                                 
317         struct dentry *dir;                       
318                                                   
319         dir = fault_create_debugfs_attr("fail_    
320                                         &fei_f    
321         if (IS_ERR(dir))                          
322                 return PTR_ERR(dir);              
323                                                   
324         /* injectable attribute is just a syml    
325         debugfs_create_symlink("injectable", d    
326                                                   
327         debugfs_create_file("inject", 0600, di    
328                                                   
329         fei_debugfs_dir = dir;                    
330                                                   
331         return 0;                                 
332 }                                                 
333                                                   
334 late_initcall(fei_debugfs_init);                  
335                                                   

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php