patch-2.1.99 linux/kernel/kmod.c
Next file: linux/kernel/sysctl.c
Previous file: linux/init/main.c
Back to the patch index
Back to the overall index
- Lines: 222
- Date:
Wed Apr 29 17:53:00 1998
- Orig file:
v2.1.98/linux/kernel/kmod.c
- Orig date:
Sat Apr 25 18:13:12 1998
diff -u --recursive --new-file v2.1.98/linux/kernel/kmod.c linux/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,147 +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_path, "-s", "-k", module_name, NULL };
static char * envp[] = { "HOME=/", "TERM=linux", "PATH=/usr/bin:/bin", 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;
+ 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)
+*/
+#define task_init task[smp_num_cpus]
+
+static inline void
+use_init_file_context(void) {
+ lock_kernel();
+
+ /* 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++;
-/*
- It is not easy to implement a full fork in kernel-space on some
- systems (Alpha), and it is not necessary for us here. This is
- a new thread that does the exec.
-*/
-static int kmod_exec_modprobe(void * data)
-{
- sigemptyset(¤t->blocked);
- execve(modprobe_path, argv, envp);
- printk(KERN_ERR "kmod: failed to load module %s\n", module_name);
- return 0;
+ unlock_kernel();
}
-/*
- kmod_thread is the thread that does most of the work. kmod_unload and
- request_module tell it to wake up and do work.
-*/
-static int kmod_thread(void * data)
+static int exec_modprobe(void * module_name)
{
- int pid;
-
- /*
- Initialize basic thread information
- */
- current->session = 1;
- current->pgrp = 1;
- sprintf(current->comm, "kmod");
- sigfillset(¤t->blocked);
-
- /*
- This is the main kmod_thread loop. It first sleeps, then
- handles requests from request_module or kmod_unload.
- */
-
- while (1) {
- interruptible_sleep_on(&kmod_queue);
+ char *argv[] = { modprobe_path, "-s", "-k", (char*)module_name, NULL};
+ int i;
- /*
- 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 = kernel_thread(kmod_exec_modprobe, NULL, SIGCHLD);
- if (pid > 0) {
- waitpid(pid, NULL, 0);
- module_name[0] = '\0';
- wake_up(&kmod_queue);
- } else {
- printk(KERN_ERR "kmod: fork failed, errno %d\n", -pid);
- }
- }
- }
+ use_init_file_context();
- return 0; /* Never reached. */
-}
-
-/*
- kmod_unload is the function that the kernel calls when
- the kmod_unload_timer expires
-*/
-void kmod_unload(unsigned long x)
-{
- /*
- 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
+ /* 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.
*/
- wake_up(&kmod_queue);
- kmod_unload_timer.expires = jiffies + (kmod_unload_delay * HZ);
- add_timer(&kmod_unload_timer);
-}
-
-int kmod_init(void)
-{
- printk("Starting kmod\n");
+ spin_lock_irq(¤t->sigmask_lock);
+ flush_signals(current);
+ flush_signal_handlers(current);
+ spin_unlock_irq(¤t->sigmask_lock);
- /*
- * CLONE_FS means that our "cwd" will follow that of init.
- * CLONE_FILES just saves some space (we don't need any
- * new file descriptors). Ditto for CLONE_SIGHAND.
- */
- kernel_thread(kmod_thread, NULL, CLONE_FILES | CLONE_FS | CLONE_SIGHAND);
-
- 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;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov