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

TOMOYO Linux Cross Reference
Linux/kernel/umh.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/umh.c (Version linux-6.11.5) and /kernel/umh.c (Version ccs-tools-1.8.9)


  1 // SPDX-License-Identifier: GPL-2.0-only            1 
  2 /*                                                
  3  * umh - the kernel usermode helper               
  4  */                                               
  5 #include <linux/module.h>                         
  6 #include <linux/sched.h>                          
  7 #include <linux/sched/task.h>                     
  8 #include <linux/binfmts.h>                        
  9 #include <linux/syscalls.h>                       
 10 #include <linux/unistd.h>                         
 11 #include <linux/kmod.h>                           
 12 #include <linux/slab.h>                           
 13 #include <linux/completion.h>                     
 14 #include <linux/cred.h>                           
 15 #include <linux/file.h>                           
 16 #include <linux/fdtable.h>                        
 17 #include <linux/fs_struct.h>                      
 18 #include <linux/workqueue.h>                      
 19 #include <linux/security.h>                       
 20 #include <linux/mount.h>                          
 21 #include <linux/kernel.h>                         
 22 #include <linux/init.h>                           
 23 #include <linux/resource.h>                       
 24 #include <linux/notifier.h>                       
 25 #include <linux/suspend.h>                        
 26 #include <linux/rwsem.h>                          
 27 #include <linux/ptrace.h>                         
 28 #include <linux/async.h>                          
 29 #include <linux/uaccess.h>                        
 30 #include <linux/initrd.h>                         
 31 #include <linux/freezer.h>                        
 32                                                   
 33 #include <trace/events/module.h>                  
 34                                                   
 35 static kernel_cap_t usermodehelper_bset = CAP_    
 36 static kernel_cap_t usermodehelper_inheritable    
 37 static DEFINE_SPINLOCK(umh_sysctl_lock);          
 38 static DECLARE_RWSEM(umhelper_sem);               
 39                                                   
 40 static void call_usermodehelper_freeinfo(struc    
 41 {                                                 
 42         if (info->cleanup)                        
 43                 (*info->cleanup)(info);           
 44         kfree(info);                              
 45 }                                                 
 46                                                   
 47 static void umh_complete(struct subprocess_inf    
 48 {                                                 
 49         struct completion *comp = xchg(&sub_in    
 50         /*                                        
 51          * See call_usermodehelper_exec(). If     
 52          * we own sub_info, the UMH_KILLABLE c    
 53          * or the caller used UMH_NO_WAIT.        
 54          */                                       
 55         if (comp)                                 
 56                 complete(comp);                   
 57         else                                      
 58                 call_usermodehelper_freeinfo(s    
 59 }                                                 
 60                                                   
 61 /*                                                
 62  * This is the task which runs the usermode ap    
 63  */                                               
 64 static int call_usermodehelper_exec_async(void    
 65 {                                                 
 66         struct subprocess_info *sub_info = dat    
 67         struct cred *new;                         
 68         int retval;                               
 69                                                   
 70         spin_lock_irq(&current->sighand->siglo    
 71         flush_signal_handlers(current, 1);        
 72         spin_unlock_irq(&current->sighand->sig    
 73                                                   
 74         /*                                        
 75          * Initial kernel threads share ther F    
 76          * get the init root directory. But we    
 77          * thread that is going to execve a us    
 78          * 'struct fs_struct'. Reset umask to     
 79          */                                       
 80         current->fs->umask = 0022;                
 81                                                   
 82         /*                                        
 83          * Our parent (unbound workqueue) runs    
 84          * priority. Avoid propagating that in    
 85          */                                       
 86         set_user_nice(current, 0);                
 87                                                   
 88         retval = -ENOMEM;                         
 89         new = prepare_kernel_cred(current);       
 90         if (!new)                                 
 91                 goto out;                         
 92                                                   
 93         spin_lock(&umh_sysctl_lock);              
 94         new->cap_bset = cap_intersect(usermode    
 95         new->cap_inheritable = cap_intersect(u    
 96                                              n    
 97         spin_unlock(&umh_sysctl_lock);            
 98                                                   
 99         if (sub_info->init) {                     
100                 retval = sub_info->init(sub_in    
101                 if (retval) {                     
102                         abort_creds(new);         
103                         goto out;                 
104                 }                                 
105         }                                         
106                                                   
107         commit_creds(new);                        
108                                                   
109         wait_for_initramfs();                     
110         retval = kernel_execve(sub_info->path,    
111                                (const char *co    
112                                (const char *co    
113 out:                                              
114         sub_info->retval = retval;                
115         /*                                        
116          * call_usermodehelper_exec_sync() wil    
117          * if UHM_WAIT_PROC.                      
118          */                                       
119         if (!(sub_info->wait & UMH_WAIT_PROC))    
120                 umh_complete(sub_info);           
121         if (!retval)                              
122                 return 0;                         
123         do_exit(0);                               
124 }                                                 
125                                                   
126 /* Handles UMH_WAIT_PROC.  */                     
127 static void call_usermodehelper_exec_sync(stru    
128 {                                                 
129         pid_t pid;                                
130                                                   
131         /* If SIGCLD is ignored do_wait won't     
132         kernel_sigaction(SIGCHLD, SIG_DFL);       
133         pid = user_mode_thread(call_usermodehe    
134         if (pid < 0)                              
135                 sub_info->retval = pid;           
136         else                                      
137                 kernel_wait(pid, &sub_info->re    
138                                                   
139         /* Restore default kernel sig handler     
140         kernel_sigaction(SIGCHLD, SIG_IGN);       
141         umh_complete(sub_info);                   
142 }                                                 
143                                                   
144 /*                                                
145  * We need to create the usermodehelper kernel    
146  * to an optimized set of CPUs (or nohz housek    
147  * inherit a widest affinity irrespective of c    
148  * possibly reduced affinity (eg: per-cpu work    
149  * usermodehelper targets to contend a busy CP    
150  *                                                
151  * Unbound workqueues provide such wide affini    
152  * UMH_WAIT_PROC requests without blocking pen    
153  *                                                
154  * Besides, workqueues provide the privilege l    
155  * to perform the usermodehelper request.         
156  *                                                
157  */                                               
158 static void call_usermodehelper_exec_work(stru    
159 {                                                 
160         struct subprocess_info *sub_info =        
161                 container_of(work, struct subp    
162                                                   
163         if (sub_info->wait & UMH_WAIT_PROC) {     
164                 call_usermodehelper_exec_sync(    
165         } else {                                  
166                 pid_t pid;                        
167                 /*                                
168                  * Use CLONE_PARENT to reparen    
169                  * want to pollute current->ch    
170                  * that always ignores SIGCHLD    
171                  */                               
172                 pid = user_mode_thread(call_us    
173                                        CLONE_P    
174                 if (pid < 0) {                    
175                         sub_info->retval = pid    
176                         umh_complete(sub_info)    
177                 }                                 
178         }                                         
179 }                                                 
180                                                   
181 /*                                                
182  * If set, call_usermodehelper_exec() will exi    
183  * (used for preventing user land processes fr    
184  * land has been frozen during a system-wide h    
185  * Should always be manipulated under umhelper    
186  */                                               
187 static enum umh_disable_depth usermodehelper_d    
188                                                   
189 /* Number of helpers running */                   
190 static atomic_t running_helpers = ATOMIC_INIT(    
191                                                   
192 /*                                                
193  * Wait queue head used by usermodehelper_disa    
194  * helpers to finish.                             
195  */                                               
196 static DECLARE_WAIT_QUEUE_HEAD(running_helpers    
197                                                   
198 /*                                                
199  * Used by usermodehelper_read_lock_wait() to     
200  * to become 'false'.                             
201  */                                               
202 static DECLARE_WAIT_QUEUE_HEAD(usermodehelper_    
203                                                   
204 /*                                                
205  * Time to wait for running_helpers to become     
206  * usermodehelper_disabled in usermodehelper_d    
207  */                                               
208 #define RUNNING_HELPERS_TIMEOUT (5 * HZ)          
209                                                   
210 int usermodehelper_read_trylock(void)             
211 {                                                 
212         DEFINE_WAIT(wait);                        
213         int ret = 0;                              
214                                                   
215         down_read(&umhelper_sem);                 
216         for (;;) {                                
217                 prepare_to_wait(&usermodehelpe    
218                                 TASK_INTERRUPT    
219                 if (!usermodehelper_disabled)     
220                         break;                    
221                                                   
222                 if (usermodehelper_disabled ==    
223                         ret = -EAGAIN;            
224                                                   
225                 up_read(&umhelper_sem);           
226                                                   
227                 if (ret)                          
228                         break;                    
229                                                   
230                 schedule();                       
231                 try_to_freeze();                  
232                                                   
233                 down_read(&umhelper_sem);         
234         }                                         
235         finish_wait(&usermodehelper_disabled_w    
236         return ret;                               
237 }                                                 
238 EXPORT_SYMBOL_GPL(usermodehelper_read_trylock)    
239                                                   
240 long usermodehelper_read_lock_wait(long timeou    
241 {                                                 
242         DEFINE_WAIT(wait);                        
243                                                   
244         if (timeout < 0)                          
245                 return -EINVAL;                   
246                                                   
247         down_read(&umhelper_sem);                 
248         for (;;) {                                
249                 prepare_to_wait(&usermodehelpe    
250                                 TASK_UNINTERRU    
251                 if (!usermodehelper_disabled)     
252                         break;                    
253                                                   
254                 up_read(&umhelper_sem);           
255                                                   
256                 timeout = schedule_timeout(tim    
257                 if (!timeout)                     
258                         break;                    
259                                                   
260                 down_read(&umhelper_sem);         
261         }                                         
262         finish_wait(&usermodehelper_disabled_w    
263         return timeout;                           
264 }                                                 
265 EXPORT_SYMBOL_GPL(usermodehelper_read_lock_wai    
266                                                   
267 void usermodehelper_read_unlock(void)             
268 {                                                 
269         up_read(&umhelper_sem);                   
270 }                                                 
271 EXPORT_SYMBOL_GPL(usermodehelper_read_unlock);    
272                                                   
273 /**                                               
274  * __usermodehelper_set_disable_depth - Modify    
275  * @depth: New value to assign to usermodehelp    
276  *                                                
277  * Change the value of usermodehelper_disabled    
278  * writing) and wakeup tasks waiting for it to    
279  */                                               
280 void __usermodehelper_set_disable_depth(enum u    
281 {                                                 
282         down_write(&umhelper_sem);                
283         usermodehelper_disabled = depth;          
284         wake_up(&usermodehelper_disabled_waitq    
285         up_write(&umhelper_sem);                  
286 }                                                 
287                                                   
288 /**                                               
289  * __usermodehelper_disable - Prevent new help    
290  * @depth: New value to assign to usermodehelp    
291  *                                                
292  * Set usermodehelper_disabled to @depth and w    
293  */                                               
294 int __usermodehelper_disable(enum umh_disable_    
295 {                                                 
296         long retval;                              
297                                                   
298         if (!depth)                               
299                 return -EINVAL;                   
300                                                   
301         down_write(&umhelper_sem);                
302         usermodehelper_disabled = depth;          
303         up_write(&umhelper_sem);                  
304                                                   
305         /*                                        
306          * From now on call_usermodehelper_exe    
307          * helpers, so it is sufficient if run    
308          * be zero at one point (it may be inc    
309          * doesn't matter).                       
310          */                                       
311         retval = wait_event_timeout(running_he    
312                                         atomic    
313                                         RUNNIN    
314         if (retval)                               
315                 return 0;                         
316                                                   
317         __usermodehelper_set_disable_depth(UMH    
318         return -EAGAIN;                           
319 }                                                 
320                                                   
321 static void helper_lock(void)                     
322 {                                                 
323         atomic_inc(&running_helpers);             
324         smp_mb__after_atomic();                   
325 }                                                 
326                                                   
327 static void helper_unlock(void)                   
328 {                                                 
329         if (atomic_dec_and_test(&running_helpe    
330                 wake_up(&running_helpers_waitq    
331 }                                                 
332                                                   
333 /**                                               
334  * call_usermodehelper_setup - prepare to call    
335  * @path: path to usermode executable             
336  * @argv: arg vector for process                  
337  * @envp: environment for process                 
338  * @gfp_mask: gfp mask for memory allocation      
339  * @init: an init function                        
340  * @cleanup: a cleanup function                   
341  * @data: arbitrary context sensitive data        
342  *                                                
343  * Returns either %NULL on allocation failure,    
344  * structure.  This should be passed to call_u    
345  * exec the process and free the structure.       
346  *                                                
347  * The init function is used to customize the     
348  * exec.  A non-zero return code causes the pr    
349  * and return the failure to the calling proce    
350  *                                                
351  * The cleanup function is just before the sub    
352  * be freed.  This can be used for freeing the    
353  * Function must be runnable in either a proce    
354  * context in which call_usermodehelper_exec i    
355  */                                               
356 struct subprocess_info *call_usermodehelper_se    
357                 char **envp, gfp_t gfp_mask,      
358                 int (*init)(struct subprocess_    
359                 void (*cleanup)(struct subproc    
360                 void *data)                       
361 {                                                 
362         struct subprocess_info *sub_info;         
363         sub_info = kzalloc(sizeof(struct subpr    
364         if (!sub_info)                            
365                 goto out;                         
366                                                   
367         INIT_WORK(&sub_info->work, call_usermo    
368                                                   
369 #ifdef CONFIG_STATIC_USERMODEHELPER               
370         sub_info->path = CONFIG_STATIC_USERMOD    
371 #else                                             
372         sub_info->path = path;                    
373 #endif                                            
374         sub_info->argv = argv;                    
375         sub_info->envp = envp;                    
376                                                   
377         sub_info->cleanup = cleanup;              
378         sub_info->init = init;                    
379         sub_info->data = data;                    
380   out:                                            
381         return sub_info;                          
382 }                                                 
383 EXPORT_SYMBOL(call_usermodehelper_setup);         
384                                                   
385 /**                                               
386  * call_usermodehelper_exec - start a usermode    
387  * @sub_info: information about the subprocess    
388  * @wait: wait for the application to finish a    
389  *        when UMH_NO_WAIT don't wait at all,     
390  *        when the program couldn't be exec'ed    
391  *        from interrupt context.                 
392  *                                                
393  * Runs a user-space application.  The applica    
394  * asynchronously if wait is not set, and runs    
395  * (ie. it runs with full root capabilities an    
396  *                                                
397  * Note: successful return value does not guar    
398  * all. You can't rely on sub_info->{init,clea    
399  * UMH_WAIT_* wait modes as STATIC_USERMODEHEL    
400  * into a successful no-op.                       
401  */                                               
402 int call_usermodehelper_exec(struct subprocess    
403 {                                                 
404         unsigned int state = TASK_UNINTERRUPTI    
405         DECLARE_COMPLETION_ONSTACK(done);         
406         int retval = 0;                           
407                                                   
408         if (!sub_info->path) {                    
409                 call_usermodehelper_freeinfo(s    
410                 return -EINVAL;                   
411         }                                         
412         helper_lock();                            
413         if (usermodehelper_disabled) {            
414                 retval = -EBUSY;                  
415                 goto out;                         
416         }                                         
417                                                   
418         /*                                        
419          * If there is no binary for us to cal    
420          * here.  This allows us to set STATIC    
421          * disable all call_usermodehelper() c    
422          */                                       
423         if (strlen(sub_info->path) == 0)          
424                 goto out;                         
425                                                   
426         /*                                        
427          * Set the completion pointer only if     
428          * This makes it possible to use umh_c    
429          * the data structure in case of UMH_N    
430          */                                       
431         sub_info->complete = (wait == UMH_NO_W    
432         sub_info->wait = wait;                    
433                                                   
434         queue_work(system_unbound_wq, &sub_inf    
435         if (wait == UMH_NO_WAIT)        /* tas    
436                 goto unlock;                      
437                                                   
438         if (wait & UMH_FREEZABLE)                 
439                 state |= TASK_FREEZABLE;          
440                                                   
441         if (wait & UMH_KILLABLE) {                
442                 retval = wait_for_completion_s    
443                 if (!retval)                      
444                         goto wait_done;           
445                                                   
446                 /* umh_complete() will see NUL    
447                 if (xchg(&sub_info->complete,     
448                         goto unlock;              
449                                                   
450                 /*                                
451                  * fallthrough; in case of -ER    
452                  * wait_for_completion_state()    
453                  * complete() in a moment if x    
454                  * uninterruptible wait_for_co    
455                  * SIGKILL'ed processes for lo    
456                  */                               
457         }                                         
458         wait_for_completion_state(&done, state    
459                                                   
460 wait_done:                                        
461         retval = sub_info->retval;                
462 out:                                              
463         call_usermodehelper_freeinfo(sub_info)    
464 unlock:                                           
465         helper_unlock();                          
466         return retval;                            
467 }                                                 
468 EXPORT_SYMBOL(call_usermodehelper_exec);          
469                                                   
470 /**                                               
471  * call_usermodehelper() - prepare and start a    
472  * @path: path to usermode executable             
473  * @argv: arg vector for process                  
474  * @envp: environment for process                 
475  * @wait: wait for the application to finish a    
476  *        when UMH_NO_WAIT don't wait at all,     
477  *        when the program couldn't be exec'ed    
478  *        from interrupt context.                 
479  *                                                
480  * This function is the equivalent to use call    
481  * call_usermodehelper_exec().                    
482  */                                               
483 int call_usermodehelper(const char *path, char    
484 {                                                 
485         struct subprocess_info *info;             
486         gfp_t gfp_mask = (wait == UMH_NO_WAIT)    
487                                                   
488         info = call_usermodehelper_setup(path,    
489                                          NULL,    
490         if (info == NULL)                         
491                 return -ENOMEM;                   
492                                                   
493         return call_usermodehelper_exec(info,     
494 }                                                 
495 EXPORT_SYMBOL(call_usermodehelper);               
496                                                   
497 #if defined(CONFIG_SYSCTL)                        
498 static int proc_cap_handler(const struct ctl_t    
499                          void *buffer, size_t     
500 {                                                 
501         struct ctl_table t;                       
502         unsigned long cap_array[2];               
503         kernel_cap_t new_cap, *cap;               
504         int err;                                  
505                                                   
506         if (write && (!capable(CAP_SETPCAP) ||    
507                       !capable(CAP_SYS_MODULE)    
508                 return -EPERM;                    
509                                                   
510         /*                                        
511          * convert from the global kernel_cap_    
512          * userspace if this is a read.           
513          *                                        
514          * Legacy format: capabilities are exp    
515          */                                       
516         cap = table->data;                        
517         spin_lock(&umh_sysctl_lock);              
518         cap_array[0] = (u32) cap->val;            
519         cap_array[1] = cap->val >> 32;            
520         spin_unlock(&umh_sysctl_lock);            
521                                                   
522         t = *table;                               
523         t.data = &cap_array;                      
524                                                   
525         /*                                        
526          * actually read or write and array of    
527          * these are least significant 32 bits    
528          */                                       
529         err = proc_doulongvec_minmax(&t, write    
530         if (err < 0)                              
531                 return err;                       
532                                                   
533         new_cap.val = (u32)cap_array[0];          
534         new_cap.val += (u64)cap_array[1] << 32    
535                                                   
536         /*                                        
537          * Drop everything not in the new_cap     
538          */                                       
539         if (write) {                              
540                 spin_lock(&umh_sysctl_lock);      
541                 *cap = cap_intersect(*cap, new    
542                 spin_unlock(&umh_sysctl_lock);    
543         }                                         
544                                                   
545         return 0;                                 
546 }                                                 
547                                                   
548 static struct ctl_table usermodehelper_table[]    
549         {                                         
550                 .procname       = "bset",         
551                 .data           = &usermodehel    
552                 .maxlen         = 2 * sizeof(u    
553                 .mode           = 0600,           
554                 .proc_handler   = proc_cap_han    
555         },                                        
556         {                                         
557                 .procname       = "inheritable    
558                 .data           = &usermodehel    
559                 .maxlen         = 2 * sizeof(u    
560                 .mode           = 0600,           
561                 .proc_handler   = proc_cap_han    
562         },                                        
563 };                                                
564                                                   
565 static int __init init_umh_sysctls(void)          
566 {                                                 
567         register_sysctl_init("kernel/usermodeh    
568         return 0;                                 
569 }                                                 
570 early_initcall(init_umh_sysctls);                 
571 #endif /* CONFIG_SYSCTL */                        
572                                                   

~ [ 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