In kernel-programming we should avoid doing call_usermodehelper() which allows to execute a command from kernel-space. And sometimes we even want to call this function within a systemcall. Normally, we really don’t wanna do this. But, desperate times require extraordinary methods.
When I first tried to execute call_usermodehelper() within a systemcall() I got a kernel failure. So I googled and what I found was:
Are you calling call_usermodehelper() from within an interrupt handler ?
I believe call_usermodehelper() must be called from a context that can
wait.
Seems like I need a context that can wait. So I created a worker_queue and inside the systemcall I just schedule a worker:
struct work_cont {
struct work_struct real_work;
char cmd[MAX_STRING_LEN];
};
struct work_cont *execwq;
void cmdexec_worker(struct work_struct *work)
{
struct work_cont *c_ptr = container_of(work, struct work_cont, real_work);
set_current_state(TASK_INTERRUPTIBLE);
char *argv[] = { "/bin/sh", "-c", c_ptr->cmd, NULL };
static char *envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/bin:/usr/sbin:/usr/bin", NULL };
call_usermodehelper( argv[0], argv, envp, UMH_WAIT_PROC);
return;
}
DEFINE_MUTEX(cmd_mutex);
/*
Please note that this code is just an incomplete example to give
an idea how to call call_usermodehelper from a systemcall. You have
to include/implement my_own_systemcall() by yourself
*/
asmlinkage long my_own_systemcall(const char __user *filename, const char__ user *const __user *argv, const char__ user *const __user *envp)
{
mutex_lock(cmd_mutex);
strncpy(execwq->cmd,argv[1],MAX_STRING_LEN);
mutex_unlock(cmd_mutex);
schedule_work(&execwq->real_work);
}
int __init loadlkm(void)
{
execwq = kmalloc(sizeof(*execwq),GFP_KERNEL);
INIT_WORK(&execwq->real_work, cmdexec_worker);
return 0;
}
void __exit clean_up(void)
{
flush_work(&execwq->real_work);
kfree(execwq);
}