2005-04-17 02:20:36 +04:00
/*
kmod , the new module loader ( replaces kerneld )
Kirk Petersen
Reorganized not to be a daemon by Adam Richter , with guidance
from Greg Zornetzer .
Modified to avoid chroot and file sharing problems .
Mikael Pettersson
Limit the concurrent number of kmod modprobes to catch loops from
" modprobe needs a service that is in a module " .
Keith Owens < kaos @ ocs . com . au > December 1999
Unblock all signals when we exec a usermode process .
Shuu Yamaguchi < shuu @ wondernetworkresources . com > December 2000
call_usermodehelper wait flag , and remove exec_usermodehelper .
Rusty Russell < rusty @ rustcorp . com . au > Jan 2003
*/
# include <linux/module.h>
# include <linux/sched.h>
# include <linux/syscalls.h>
# include <linux/unistd.h>
# include <linux/kmod.h>
# include <linux/slab.h>
2006-12-08 13:37:56 +03:00
# include <linux/mnt_namespace.h>
2005-04-17 02:20:36 +04:00
# include <linux/completion.h>
# include <linux/file.h>
# include <linux/workqueue.h>
# include <linux/security.h>
# include <linux/mount.h>
# include <linux/kernel.h>
# include <linux/init.h>
2006-10-01 10:29:28 +04:00
# include <linux/resource.h>
2007-07-19 12:47:36 +04:00
# include <linux/notifier.h>
# include <linux/suspend.h>
2005-04-17 02:20:36 +04:00
# include <asm/uaccess.h>
extern int max_threads ;
static struct workqueue_struct * khelper_wq ;
# ifdef CONFIG_KMOD
/*
modprobe_path is set via / proc / sys .
*/
char modprobe_path [ KMOD_PATH_LEN ] = " /sbin/modprobe " ;
/**
* request_module - try to load a kernel module
* @ fmt : printf style format string for the name of the module
* @ varargs : arguements as specified in the format string
*
* Load a module using the user mode module loader . The function returns
* zero on success or a negative errno code on failure . Note that a
* successful module load does not mean the module did not then unload
* and exit on an error of its own . Callers must check that the service
* they requested is now available not blindly invoke it .
*
* If module auto - loading support is disabled then this function
* becomes a no - operation .
*/
int request_module ( const char * fmt , . . . )
{
va_list args ;
char module_name [ MODULE_NAME_LEN ] ;
unsigned int max_modprobes ;
int ret ;
char * argv [ ] = { modprobe_path , " -q " , " -- " , module_name , NULL } ;
static char * envp [ ] = { " HOME=/ " ,
" TERM=linux " ,
" PATH=/sbin:/usr/sbin:/bin:/usr/bin " ,
NULL } ;
static atomic_t kmod_concurrent = ATOMIC_INIT ( 0 ) ;
# define MAX_KMOD_CONCURRENT 50 /* Completely arbitrary value - KAO */
static int kmod_loop_msg ;
va_start ( args , fmt ) ;
ret = vsnprintf ( module_name , MODULE_NAME_LEN , fmt , args ) ;
va_end ( args ) ;
if ( ret > = MODULE_NAME_LEN )
return - ENAMETOOLONG ;
/* If modprobe needs a service that is in a module, we get a recursive
* loop . Limit the number of running kmod threads to max_threads / 2 or
* MAX_KMOD_CONCURRENT , whichever is the smaller . A cleaner method
* would be to run the parents of this process , counting how many times
* kmod was invoked . That would mean accessing the internals of the
* process tables to get the command line , proc_pid_cmdline is static
* and it is not worth changing the proc code just to handle this case .
* KAO .
*
* " trace the ppid " is simple , but will fail if someone ' s
* parent exits . I think this is as good as it gets . - - RR
*/
max_modprobes = min ( max_threads / 2 , MAX_KMOD_CONCURRENT ) ;
atomic_inc ( & kmod_concurrent ) ;
if ( atomic_read ( & kmod_concurrent ) > max_modprobes ) {
/* We may be blaming an innocent here, but unlikely */
if ( kmod_loop_msg + + < 5 )
printk ( KERN_ERR
" request_module: runaway loop modprobe %s \n " ,
module_name ) ;
atomic_dec ( & kmod_concurrent ) ;
return - ENOMEM ;
}
ret = call_usermodehelper ( modprobe_path , argv , envp , 1 ) ;
atomic_dec ( & kmod_concurrent ) ;
return ret ;
}
EXPORT_SYMBOL ( request_module ) ;
# endif /* CONFIG_KMOD */
struct subprocess_info {
2006-11-22 17:55:48 +03:00
struct work_struct work ;
2005-04-17 02:20:36 +04:00
struct completion * complete ;
char * path ;
char * * argv ;
char * * envp ;
2005-06-24 09:00:51 +04:00
struct key * ring ;
2007-07-18 05:37:03 +04:00
enum umh_wait wait ;
2005-04-17 02:20:36 +04:00
int retval ;
2006-10-01 10:29:27 +04:00
struct file * stdin ;
2007-07-18 05:37:02 +04:00
void ( * cleanup ) ( char * * argv , char * * envp ) ;
2005-04-17 02:20:36 +04:00
} ;
/*
* This is the task which runs the usermode application
*/
static int ____call_usermodehelper ( void * data )
{
struct subprocess_info * sub_info = data ;
2005-10-31 02:02:44 +03:00
struct key * new_session , * old_session ;
2005-04-17 02:20:36 +04:00
int retval ;
2005-06-24 09:00:51 +04:00
/* Unblock all signals and set the session keyring. */
2005-10-31 02:02:44 +03:00
new_session = key_get ( sub_info - > ring ) ;
2005-04-17 02:20:36 +04:00
spin_lock_irq ( & current - > sighand - > siglock ) ;
2005-10-31 02:02:44 +03:00
old_session = __install_session_keyring ( current , new_session ) ;
2005-04-17 02:20:36 +04:00
flush_signal_handlers ( current , 1 ) ;
sigemptyset ( & current - > blocked ) ;
recalc_sigpending ( ) ;
spin_unlock_irq ( & current - > sighand - > siglock ) ;
2005-06-24 09:00:51 +04:00
key_put ( old_session ) ;
2006-10-01 10:29:27 +04:00
/* Install input pipe when needed */
if ( sub_info - > stdin ) {
struct files_struct * f = current - > files ;
struct fdtable * fdt ;
/* no races because files should be private here */
sys_close ( 0 ) ;
fd_install ( 0 , sub_info - > stdin ) ;
spin_lock ( & f - > file_lock ) ;
fdt = files_fdtable ( f ) ;
FD_SET ( 0 , fdt - > open_fds ) ;
FD_CLR ( 0 , fdt - > close_on_exec ) ;
spin_unlock ( & f - > file_lock ) ;
2006-10-01 10:29:28 +04:00
/* and disallow core files too */
current - > signal - > rlim [ RLIMIT_CORE ] = ( struct rlimit ) { 0 , 0 } ;
2006-10-01 10:29:27 +04:00
}
2005-04-17 02:20:36 +04:00
/* We can run anywhere, unlike our parent keventd(). */
2008-04-05 05:11:06 +04:00
set_cpus_allowed_ptr ( current , CPU_MASK_ALL_PTR ) ;
2005-04-17 02:20:36 +04:00
2007-05-08 11:28:24 +04:00
/*
* Our parent is keventd , which runs with elevated scheduling priority .
* Avoid propagating that into the userspace child .
*/
set_user_nice ( current , 0 ) ;
2008-02-15 06:34:29 +03:00
retval = kernel_execve ( sub_info - > path , sub_info - > argv , sub_info - > envp ) ;
2005-04-17 02:20:36 +04:00
/* Exec failed? */
sub_info - > retval = retval ;
do_exit ( 0 ) ;
}
2007-07-18 05:37:02 +04:00
void call_usermodehelper_freeinfo ( struct subprocess_info * info )
{
if ( info - > cleanup )
( * info - > cleanup ) ( info - > argv , info - > envp ) ;
kfree ( info ) ;
}
EXPORT_SYMBOL ( call_usermodehelper_freeinfo ) ;
2005-04-17 02:20:36 +04:00
/* Keventd can't block, but this (a child) can. */
static int wait_for_helper ( void * data )
{
struct subprocess_info * sub_info = data ;
pid_t pid ;
/* Install a handler: if SIGCLD isn't handled sys_wait4 won't
* populate the status , but will return - ECHILD . */
allow_signal ( SIGCHLD ) ;
pid = kernel_thread ( ____call_usermodehelper , sub_info , SIGCHLD ) ;
if ( pid < 0 ) {
sub_info - > retval = pid ;
} else {
2006-09-29 13:00:46 +04:00
int ret ;
2005-04-17 02:20:36 +04:00
/*
* Normally it is bogus to call wait4 ( ) from in - kernel because
* wait4 ( ) wants to write the exit code to a userspace address .
* But wait_for_helper ( ) always runs as keventd , and put_user ( )
* to a kernel address works OK for kernel threads , due to their
* having an mm_segment_t which spans the entire address space .
*
* Thus the __user pointer cast is valid here .
*/
2006-09-29 13:00:46 +04:00
sys_wait4 ( pid , ( int __user * ) & ret , 0 , NULL ) ;
/*
* If ret is 0 , either ____call_usermodehelper failed and the
* real error code is already in sub_info - > retval or
* sub_info - > retval is 0 anyway , so don ' t mess with it then .
*/
if ( ret )
sub_info - > retval = ret ;
2005-04-17 02:20:36 +04:00
}
2007-07-18 05:37:03 +04:00
if ( sub_info - > wait = = UMH_NO_WAIT )
2007-07-18 05:37:02 +04:00
call_usermodehelper_freeinfo ( sub_info ) ;
2007-02-13 15:26:23 +03:00
else
complete ( sub_info - > complete ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
/* This is run by khelper thread */
2006-11-22 17:55:48 +03:00
static void __call_usermodehelper ( struct work_struct * work )
2005-04-17 02:20:36 +04:00
{
2006-11-22 17:55:48 +03:00
struct subprocess_info * sub_info =
container_of ( work , struct subprocess_info , work ) ;
2005-04-17 02:20:36 +04:00
pid_t pid ;
2007-07-18 05:37:03 +04:00
enum umh_wait wait = sub_info - > wait ;
2005-04-17 02:20:36 +04:00
/* CLONE_VFORK: wait until the usermode helper has execve'd
* successfully We need the data structures to stay around
* until that is done . */
2007-07-18 05:37:03 +04:00
if ( wait = = UMH_WAIT_PROC | | wait = = UMH_NO_WAIT )
2005-04-17 02:20:36 +04:00
pid = kernel_thread ( wait_for_helper , sub_info ,
CLONE_FS | CLONE_FILES | SIGCHLD ) ;
else
pid = kernel_thread ( ____call_usermodehelper , sub_info ,
CLONE_VFORK | SIGCHLD ) ;
2007-07-18 05:37:03 +04:00
switch ( wait ) {
case UMH_NO_WAIT :
break ;
2007-02-13 15:26:23 +03:00
2007-07-18 05:37:03 +04:00
case UMH_WAIT_PROC :
if ( pid > 0 )
break ;
2005-04-17 02:20:36 +04:00
sub_info - > retval = pid ;
2007-07-18 05:37:03 +04:00
/* FALLTHROUGH */
case UMH_WAIT_EXEC :
2005-04-17 02:20:36 +04:00
complete ( sub_info - > complete ) ;
2007-07-18 05:37:03 +04:00
}
2005-04-17 02:20:36 +04:00
}
2007-07-19 12:47:37 +04:00
# ifdef CONFIG_PM
/*
* If set , call_usermodehelper_exec ( ) will exit immediately returning - EBUSY
* ( used for preventing user land processes from being created after the user
* land has been frozen during a system - wide hibernation or suspend operation ) .
*/
static int usermodehelper_disabled ;
/* Number of helpers running */
static atomic_t running_helpers = ATOMIC_INIT ( 0 ) ;
/*
* Wait queue head used by usermodehelper_pm_callback ( ) to wait for all running
* helpers to finish .
*/
static DECLARE_WAIT_QUEUE_HEAD ( running_helpers_waitq ) ;
/*
* Time to wait for running_helpers to become zero before the setting of
* usermodehelper_disabled in usermodehelper_pm_callback ( ) fails
*/
# define RUNNING_HELPERS_TIMEOUT (5 * HZ)
2007-07-19 12:47:36 +04:00
static int usermodehelper_pm_callback ( struct notifier_block * nfb ,
unsigned long action ,
void * ignored )
{
2007-07-19 12:47:37 +04:00
long retval ;
2007-07-19 12:47:36 +04:00
switch ( action ) {
case PM_HIBERNATION_PREPARE :
case PM_SUSPEND_PREPARE :
usermodehelper_disabled = 1 ;
2007-07-19 12:47:37 +04:00
smp_mb ( ) ;
/*
* From now on call_usermodehelper_exec ( ) won ' t start any new
* helpers , so it is sufficient if running_helpers turns out to
* be zero at one point ( it may be increased later , but that
* doesn ' t matter ) .
*/
retval = wait_event_timeout ( running_helpers_waitq ,
atomic_read ( & running_helpers ) = = 0 ,
RUNNING_HELPERS_TIMEOUT ) ;
if ( retval ) {
return NOTIFY_OK ;
} else {
usermodehelper_disabled = 0 ;
return NOTIFY_BAD ;
}
2007-07-19 12:47:36 +04:00
case PM_POST_HIBERNATION :
case PM_POST_SUSPEND :
usermodehelper_disabled = 0 ;
return NOTIFY_OK ;
}
return NOTIFY_DONE ;
}
2007-07-19 12:47:37 +04:00
static void helper_lock ( void )
{
atomic_inc ( & running_helpers ) ;
smp_mb__after_atomic_inc ( ) ;
}
static void helper_unlock ( void )
{
if ( atomic_dec_and_test ( & running_helpers ) )
wake_up ( & running_helpers_waitq ) ;
}
static void register_pm_notifier_callback ( void )
{
pm_notifier ( usermodehelper_pm_callback , 0 ) ;
}
# else /* CONFIG_PM */
# define usermodehelper_disabled 0
static inline void helper_lock ( void ) { }
static inline void helper_unlock ( void ) { }
static inline void register_pm_notifier_callback ( void ) { }
# endif /* CONFIG_PM */
2005-04-17 02:20:36 +04:00
/**
2007-07-18 05:37:02 +04:00
* call_usermodehelper_setup - prepare to call a usermode helper
2007-07-26 21:40:56 +04:00
* @ path : path to usermode executable
* @ argv : arg vector for process
* @ envp : environment for process
2007-07-18 05:37:02 +04:00
*
2007-07-26 21:40:56 +04:00
* Returns either % NULL on allocation failure , or a subprocess_info
2007-07-18 05:37:02 +04:00
* structure . This should be passed to call_usermodehelper_exec to
* exec the process and free the structure .
*/
struct subprocess_info * call_usermodehelper_setup ( char * path ,
char * * argv , char * * envp )
{
struct subprocess_info * sub_info ;
sub_info = kzalloc ( sizeof ( struct subprocess_info ) , GFP_ATOMIC ) ;
if ( ! sub_info )
goto out ;
INIT_WORK ( & sub_info - > work , __call_usermodehelper ) ;
sub_info - > path = path ;
sub_info - > argv = argv ;
sub_info - > envp = envp ;
out :
return sub_info ;
}
EXPORT_SYMBOL ( call_usermodehelper_setup ) ;
/**
* call_usermodehelper_setkeys - set the session keys for usermode helper
* @ info : a subprocess_info returned by call_usermodehelper_setup
* @ session_keyring : the session keyring for the process
*/
void call_usermodehelper_setkeys ( struct subprocess_info * info ,
struct key * session_keyring )
{
info - > ring = session_keyring ;
}
EXPORT_SYMBOL ( call_usermodehelper_setkeys ) ;
/**
* call_usermodehelper_setcleanup - set a cleanup function
* @ info : a subprocess_info returned by call_usermodehelper_setup
* @ cleanup : a cleanup function
*
* The cleanup function is just befor ethe subprocess_info is about to
* be freed . This can be used for freeing the argv and envp . The
* Function must be runnable in either a process context or the
* context in which call_usermodehelper_exec is called .
*/
void call_usermodehelper_setcleanup ( struct subprocess_info * info ,
void ( * cleanup ) ( char * * argv , char * * envp ) )
{
info - > cleanup = cleanup ;
}
EXPORT_SYMBOL ( call_usermodehelper_setcleanup ) ;
/**
* call_usermodehelper_stdinpipe - set up a pipe to be used for stdin
* @ sub_info : a subprocess_info returned by call_usermodehelper_setup
* @ filp : set to the write - end of a pipe
*
* This constructs a pipe , and sets the read end to be the stdin of the
* subprocess , and returns the write - end in * @ filp .
*/
int call_usermodehelper_stdinpipe ( struct subprocess_info * sub_info ,
struct file * * filp )
{
struct file * f ;
f = create_write_pipe ( ) ;
if ( IS_ERR ( f ) )
return PTR_ERR ( f ) ;
* filp = f ;
f = create_read_pipe ( f ) ;
if ( IS_ERR ( f ) ) {
free_write_pipe ( * filp ) ;
return PTR_ERR ( f ) ;
}
sub_info - > stdin = f ;
return 0 ;
}
EXPORT_SYMBOL ( call_usermodehelper_stdinpipe ) ;
/**
* call_usermodehelper_exec - start a usermode application
* @ sub_info : information about the subprocessa
2005-04-17 02:20:36 +04:00
* @ wait : wait for the application to finish and return status .
2007-02-13 15:26:23 +03:00
* when - 1 don ' t wait at all , but you get no useful error back when
* the program couldn ' t be exec ' ed . This makes it safe to call
* from interrupt context .
2005-04-17 02:20:36 +04:00
*
* Runs a user - space application . The application is started
* asynchronously if wait is not set , and runs as a child of keventd .
* ( ie . it runs with full root capabilities ) .
*/
2007-07-18 05:37:02 +04:00
int call_usermodehelper_exec ( struct subprocess_info * sub_info ,
2007-07-18 05:37:03 +04:00
enum umh_wait wait )
2005-04-17 02:20:36 +04:00
{
2006-07-03 11:25:26 +04:00
DECLARE_COMPLETION_ONSTACK ( done ) ;
2008-01-18 02:21:21 +03:00
int retval = 0 ;
2005-04-17 02:20:36 +04:00
2007-07-19 12:47:37 +04:00
helper_lock ( ) ;
2008-01-18 02:21:21 +03:00
if ( sub_info - > path [ 0 ] = = ' \0 ' )
2007-07-18 05:37:02 +04:00
goto out ;
2005-04-17 02:20:36 +04:00
2007-07-19 12:47:36 +04:00
if ( ! khelper_wq | | usermodehelper_disabled ) {
2007-07-18 05:37:02 +04:00
retval = - EBUSY ;
goto out ;
}
2007-02-13 15:26:23 +03:00
sub_info - > complete = & done ;
sub_info - > wait = wait ;
queue_work ( khelper_wq , & sub_info - > work ) ;
2008-01-18 02:21:21 +03:00
if ( wait = = UMH_NO_WAIT ) /* task has freed sub_info */
goto unlock ;
2005-04-17 02:20:36 +04:00
wait_for_completion ( & done ) ;
2007-02-13 15:26:23 +03:00
retval = sub_info - > retval ;
2007-07-18 05:37:02 +04:00
2008-01-18 02:21:21 +03:00
out :
2007-07-18 05:37:02 +04:00
call_usermodehelper_freeinfo ( sub_info ) ;
2008-01-18 02:21:21 +03:00
unlock :
2007-07-19 12:47:37 +04:00
helper_unlock ( ) ;
2007-02-13 15:26:23 +03:00
return retval ;
2005-04-17 02:20:36 +04:00
}
2007-07-18 05:37:02 +04:00
EXPORT_SYMBOL ( call_usermodehelper_exec ) ;
2005-04-17 02:20:36 +04:00
2007-07-18 05:37:02 +04:00
/**
* call_usermodehelper_pipe - call a usermode helper process with a pipe stdin
* @ path : path to usermode executable
* @ argv : arg vector for process
* @ envp : environment for process
* @ filp : set to the write - end of a pipe
*
* This is a simple wrapper which executes a usermode - helper function
* with a pipe as stdin . It is implemented entirely in terms of
* lower - level call_usermodehelper_ * functions .
*/
2006-10-01 10:29:27 +04:00
int call_usermodehelper_pipe ( char * path , char * * argv , char * * envp ,
struct file * * filp )
{
2007-07-18 05:37:02 +04:00
struct subprocess_info * sub_info ;
int ret ;
2006-10-01 10:29:27 +04:00
2007-07-18 05:37:02 +04:00
sub_info = call_usermodehelper_setup ( path , argv , envp ) ;
if ( sub_info = = NULL )
return - ENOMEM ;
2006-10-01 10:29:27 +04:00
2007-07-18 05:37:02 +04:00
ret = call_usermodehelper_stdinpipe ( sub_info , filp ) ;
if ( ret < 0 )
goto out ;
2006-10-01 10:29:27 +04:00
2007-09-12 02:23:51 +04:00
return call_usermodehelper_exec ( sub_info , UMH_WAIT_EXEC ) ;
2006-10-01 10:29:27 +04:00
2007-07-18 05:37:02 +04:00
out :
call_usermodehelper_freeinfo ( sub_info ) ;
return ret ;
2006-10-01 10:29:27 +04:00
}
EXPORT_SYMBOL ( call_usermodehelper_pipe ) ;
2005-04-17 02:20:36 +04:00
void __init usermodehelper_init ( void )
{
khelper_wq = create_singlethread_workqueue ( " khelper " ) ;
BUG_ON ( ! khelper_wq ) ;
2007-07-19 12:47:37 +04:00
register_pm_notifier_callback ( ) ;
2005-04-17 02:20:36 +04:00
}