summaryrefslogtreecommitdiffstats
path: root/kernel/kmod.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1998-05-07 02:55:41 +0000
committerRalf Baechle <ralf@linux-mips.org>1998-05-07 02:55:41 +0000
commitdcec8a13bf565e47942a1751a9cec21bec5648fe (patch)
tree548b69625b18cc2e88c3e68d0923be546c9ebb03 /kernel/kmod.c
parent2e0f55e79c49509b7ff70ff1a10e1e9e90a3dfd4 (diff)
o Merge with Linux 2.1.99.
o Fix ancient bug in the ELF loader making ldd crash. o Fix ancient bug in the keyboard code for SGI, SNI and Jazz.
Diffstat (limited to 'kernel/kmod.c')
-rw-r--r--kernel/kmod.c178
1 files changed, 66 insertions, 112 deletions
diff --git a/kernel/kmod.c b/kernel/kmod.c
index 379c27695..7468e4382 100644
--- a/kernel/kmod.c
+++ b/kernel/kmod.c
@@ -1,6 +1,12 @@
/*
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
*/
#define __KERNEL_SYSCALLS__
@@ -8,140 +14,88 @@
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/unistd.h>
+#include <asm/smp_lock.h>
+#include <asm/uaccess.h>
/*
- kmod_unload_delay and modprobe_path are set via /proc/sys.
+ modprobe_path is set via /proc/sys.
*/
-int kmod_unload_delay = 60;
char modprobe_path[256] = "/sbin/modprobe";
-static char module_name[64] = "";
-static char * argv[] = { "modprobe", "-k", module_name, NULL, };
-static char * envp[] = { "HOME=/", "TERM=linux", NULL, };
-
-/*
- kmod_queue synchronizes the kmod thread and the rest of the system
- kmod_unload_timer is what we use to unload modules
- after kmod_unload_delay seconds
-*/
-static struct wait_queue * kmod_queue = NULL;
-static struct timer_list kmod_unload_timer;
+static char * envp[] = { "HOME=/", "TERM=linux", "PATH=/usr/bin:/bin", NULL };
/*
- kmod_thread is the thread that does most of the work. kmod_unload and
- request_module tell it to wake up and do work.
+ exec_modprobe is spawned from a kernel-mode user process,
+ then changes its state to behave _as_if_ it was spawned
+ from the kernel's init process
+ (ppid and {e,}gid are not adjusted, but that shouldn't
+ be a problem since we trust modprobe)
*/
-int kmod_thread(void * data)
-{
- int pid;
+#define task_init task[smp_num_cpus]
- /*
- Initialize basic thread information
- */
- current->session = 1;
- current->pgrp = 1;
- sprintf(current->comm, "kmod");
- sigfillset(&current->blocked);
-
- /*
- This is the main kmod_thread loop. It first sleeps, then
- handles requests from request_module or kmod_unload.
- */
+static inline void
+use_init_file_context(void) {
+ lock_kernel();
- while (1) {
- interruptible_sleep_on(&kmod_queue);
-
- /*
- If request_module woke us up, we should try to
- load module_name. If not, kmod_unload woke us up,
- do call delete_module.
- (if somehow both want us to do something, ignore the
- delete_module request)
- */
- if (module_name[0] == '\0') {
- delete_module(NULL);
- } else {
- pid = fork();
- if (pid > 0) {
- waitpid(pid, NULL, 0);
- module_name[0] = '\0';
- wake_up(&kmod_queue);
- } else
- if (pid == 0) {
-
- /*
- Call modprobe with module_name. If execve returns,
- print out an error.
- */
- execve(modprobe_path, argv, envp);
-
- printk("kmod: failed to load module %s\n", module_name);
- _exit(0);
- } else {
- printk("error, fork failed in kmod\n");
- }
- }
- }
+ /* don't use the user's root, use init's root instead */
+ exit_fs(current); /* current->fs->count--; */
+ current->fs = task_init->fs;
+ current->fs->count++;
- return 0; /* Never reached. */
+ unlock_kernel();
}
-/*
- kmod_unload is the function that the kernel calls when
- the kmod_unload_timer expires
-*/
-void kmod_unload(unsigned long x)
+static int exec_modprobe(void * module_name)
{
- /*
- wake up the kmod thread, which does the work
- (we can't call delete_module, as it locks the kernel and
- we are in the bottom half of the kernel (right?))
- once it is awake, reset the timer
- */
- wake_up(&kmod_queue);
- kmod_unload_timer.expires = jiffies + (kmod_unload_delay * HZ);
- add_timer(&kmod_unload_timer);
-}
+ char *argv[] = { modprobe_path, "-s", "-k", (char*)module_name, NULL};
+ int i;
-int kmod_init(void)
-{
- printk ("Starting kmod\n");
+ use_init_file_context();
- kernel_thread(kmod_thread, NULL, 0);
+ /* Prevent parent user process from sending signals to child.
+ Otherwise, if the modprobe program does not exist, it might
+ be possible to get a user defined signal handler to execute
+ as the super user right after the execve fails if you time
+ the signal just right.
+ */
+ spin_lock_irq(&current->sigmask_lock);
+ flush_signals(current);
+ flush_signal_handlers(current);
+ spin_unlock_irq(&current->sigmask_lock);
- kmod_unload_timer.next = NULL;
- kmod_unload_timer.prev = NULL;
- kmod_unload_timer.expires = jiffies + (5 * 60 * HZ);
- kmod_unload_timer.data = 0L;
- kmod_unload_timer.function = kmod_unload;
- add_timer(&kmod_unload_timer);
+ for (i = 0; i < current->files->max_fds; i++ ) {
+ if (current->files->fd[i]) close(i);
+ }
+ set_fs(KERNEL_DS); /* Allow execve args to be in kernel space. */
+ current->uid = current->euid = current->fsuid = 0;
+ if (execve(modprobe_path, argv, envp) < 0) {
+ printk(KERN_ERR
+ "kmod: failed to exec %s -s -k %s, errno = %d\n",
+ modprobe_path, (char*) module_name, errno);
+ return -errno;
+ }
return 0;
}
/*
- request_module, the function that everyone calls when they need a
- module to be loaded
+ request_module: the function that everyone calls when they need
+ a module.
*/
-int request_module(const char * name)
+int request_module(const char * module_name)
{
- /* first, copy the name of the module into module_name */
- /* then wake_up() the kmod daemon */
- /* wait for the kmod daemon to finish (it will wake us up) */
-
- /*
- kmod_thread is sleeping, so start by copying the name of
- the module into module_name. Once that is done, wake up
- kmod_thread.
- */
- strncpy(module_name, name, sizeof(module_name));
- module_name[sizeof(module_name)-1] = '\0';
- wake_up(&kmod_queue);
-
- /*
- Now that we have told kmod_thread what to do, we want to
- go to sleep and let it do its work. It will wake us up,
- at which point we will be done (the module will be loaded).
- */
- interruptible_sleep_on(&kmod_queue);
+ int pid;
+ int waitpid_result;
+
+ pid = kernel_thread(exec_modprobe, (void*) module_name,
+ CLONE_FS | SIGCHLD);
+ if (pid < 0) {
+ printk(KERN_ERR "kmod: fork failed, errno %d\n", -pid);
+ return pid;
+ }
+ waitpid_result = waitpid(pid, NULL, 0);
+ if (waitpid_result != pid) {
+ printk (KERN_ERR "kmod: waitpid(%d,NULL,0) failed, returning %d.\n",
+ pid, waitpid_result);
+ }
return 0;
}