/* * This is the task which runs the usermode application */ static int ____call_usermodehelper(void *data) { struct subprocess_info *sub_info = data; struct key *new_session, *old_session; int retval; /* Unblock all signals and set the session keyring. */ new_session = key_get(sub_info->ring); flush_signals(current); spin_lock_irq(¤t->sighand->siglock); old_session = __install_session_keyring(current, new_session); flush_signal_handlers(current, 1); sigemptyset(¤t->blocked); recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); key_put(old_session); /* We can run anywhere, unlike our parent keventd(). */ set_cpus_allowed(current, CPU_MASK_ALL); retval = -EPERM; if (current->fs->root) retval = execve(sub_info->path, sub_info->argv,sub_info->envp); /* Exec failed? */ sub_info->retval = retval; do_exit(0); }
/* * This is the task which runs the usermode application */ static int ____call_usermodehelper(void *data) { struct subprocess_info *sub_info = data; int retval; spin_lock_irq(¤t->sighand->siglock); flush_signal_handlers(current, 1); spin_unlock_irq(¤t->sighand->siglock); /* We can run anywhere, unlike our parent keventd(). */ set_cpus_allowed_ptr(current, cpu_all_mask); /* * Our parent is keventd, which runs with elevated scheduling priority. * Avoid propagating that into the userspace child. */ set_user_nice(current, 0); if (sub_info->init) { retval = sub_info->init(sub_info); if (retval) goto fail; } retval = kernel_execve(sub_info->path, sub_info->argv, sub_info->envp); /* Exec failed? */ fail: sub_info->retval = retval; do_exit(0); }
/* * This is the task which runs the usermode application */ static int ____call_usermodehelper(void *data) { struct subprocess_info *sub_info = data; int retval; //TODO:RAWLINSON struct cpumask cpu_padrao = cpumask_of_cpu(CPUID_PADRAO); spin_lock_irq(¤t->sighand->siglock); flush_signal_handlers(current, 1); spin_unlock_irq(¤t->sighand->siglock); /* We can run anywhere, unlike our parent keventd(). */ //TODO:RAWLINSON //set_cpus_allowed_ptr(current, cpu_all_mask); //TODO:RAWLINSON - CODIGO ORIGINAL... current->cpus_allowed = cpu_padrao; set_cpus_allowed_ptr(current, &cpu_padrao); /* * Our parent is keventd, which runs with elevated scheduling priority. * Avoid propagating that into the userspace child. */ set_user_nice(current, 0); if (sub_info->init) { retval = sub_info->init(sub_info); if (retval) goto fail; } retval = kernel_execve(sub_info->path, (const char *const *)sub_info->argv, (const char *const *)sub_info->envp); /* Exec failed? */ fail: sub_info->retval = retval; do_exit(0); }
/* * This is the task which runs the usermode application */ int __exec_usermodehelper(char *path, char **argv, char **envp, struct key *ring) { struct key *new_session, *old_session; int retval; /* Unblock all signals and set the session keyring. */ new_session = key_get(ring); flush_signals(current); spin_lock_irq(¤t->sighand->siglock); old_session = __install_session_keyring(current, new_session); flush_signal_handlers(current, 1); sigemptyset(¤t->blocked); recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); key_put(old_session); retval = -EPERM; if (current->fs->root) retval = execve(path, argv, envp); return retval; }
/* * This is the task which runs the usermode application */ static int ____call_usermodehelper(void *data) { struct subprocess_info *sub_info = data; int retval; BUG_ON(atomic_read(&sub_info->cred->usage) != 1); /* Unblock all signals */ spin_lock_irq(¤t->sighand->siglock); flush_signal_handlers(current, 1); sigemptyset(¤t->blocked); recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); /* Install the credentials */ commit_creds(sub_info->cred); sub_info->cred = NULL; /* 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); /* and disallow core files too */ current->signal->rlim[RLIMIT_CORE] = (struct rlimit){0, 0}; } /* We can run anywhere, unlike our parent keventd(). */ set_cpus_allowed_ptr(current, cpu_all_mask); /* * Our parent is keventd, which runs with elevated scheduling priority. * Avoid propagating that into the userspace child. */ set_user_nice(current, 0); if (sub_info->init) { retval = sub_info->init(sub_info); if (retval) goto fail; } retval = kernel_execve(sub_info->path, sub_info->argv, sub_info->envp); /* Exec failed? */ fail: sub_info->retval = retval; return 0; } void call_usermodehelper_freeinfo(struct subprocess_info *info) { if (info->cleanup) (*info->cleanup)(info); if (info->cred) put_cred(info->cred); kfree(info); } EXPORT_SYMBOL(call_usermodehelper_freeinfo); static void umh_complete(struct subprocess_info *sub_info) { struct completion *comp = xchg(&sub_info->complete, NULL); /* * See call_usermodehelper_exec(). If xchg() returns NULL * we own sub_info, the UMH_KILLABLE caller has gone away. */ if (comp) complete(comp); else call_usermodehelper_freeinfo(sub_info); } /* 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 { int ret; /* * 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. */ 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; } if (sub_info->wait == UMH_NO_WAIT) call_usermodehelper_freeinfo(sub_info); else umh_complete(sub_info); return 0; } /* This is run by khelper thread */ static void __call_usermodehelper(struct work_struct *work) { struct subprocess_info *sub_info = container_of(work, struct subprocess_info, work); int wait = sub_info->wait & ~UMH_KILLABLE; pid_t pid; BUG_ON(atomic_read(&sub_info->cred->usage) != 1); /* CLONE_VFORK: wait until the usermode helper has execve'd * successfully We need the data structures to stay around * until that is done. */ if (wait == UMH_WAIT_PROC || wait == UMH_NO_WAIT) pid = kernel_thread(wait_for_helper, sub_info, CLONE_FS | CLONE_FILES | SIGCHLD); else pid = kernel_thread(____call_usermodehelper, sub_info, CLONE_VFORK | SIGCHLD); switch (wait) { case UMH_NO_WAIT: break; case UMH_WAIT_PROC: if (pid > 0) break; sub_info->retval = pid; /* FALLTHROUGH */ case UMH_WAIT_EXEC: umh_complete(sub_info); } } #ifdef CONFIG_PM_SLEEP /* * 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). * Should always be manipulated under umhelper_sem acquired for write. */ 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) void read_lock_usermodehelper(void) { down_read(&umhelper_sem); }