Messages in this thread Patch in this message | | | From | "Adam J. Richter" <> | Date | Fri, 24 Apr 1998 03:46:11 -0700 | Subject | Linux 2.1.98 daemonless kmod patch |
| |
Since 2.1.98 is out and includes a tiny change to its kmod.c, here is the patch for the daemonless kmod with everybody's tweaks against pristine 2.1.98. There is are no changes here. I am just posting this diff from 2.1.98 for everyone's convenience.
Adam J. Richter __ ______________ 4880 Stevens Creek Blvd, Suite 205 adam@yggdrasil.com \ / San Jose, California 95129-1034 +1 408 261-6630 | g g d r a s i l United States of America fax +1 408 261-6631 "Free Software For The Rest Of Us." -----------------------CUT HERE------------------------------------ --- /tmp/linux-2.1.98/Documentation/kmod.txt Tue Mar 10 14:43:13 1998 +++ linux/Documentation/kmod.txt Fri Apr 24 01:16:07 1998 @@ -4,19 +4,19 @@ Kmod is a simple replacement for kerneld. It consists of a request_module() replacement and a kernel thread called kmod. When the kernel requests a module, the kmod wakes up and execve()s modprobe, -passing it the name that was requested. After a configurable period of -time, kmod will have delete_module() remove any unused modules. +passing it the name that was requested. -Kmod is configurable through two entries in /proc/sys/kernel. You can -set the path of modprobe (where the kernel looks for it) by doing: +If you have the /proc filesystem mounted, you can set the path of +modprobe (where the kernel looks for it) by doing: echo "/sbin/modprobe" > /proc/sys/kernel/modprobe -To tell kmod when to unload unused modules, do something like: +To periodically unload unused modules, put something like the following +in root's crontab entry: - echo "120" > /proc/sys/kernel/kmod_unload_delay + 0-59/5 * * * * /sbin/rmmod -a -Kmod only loads and unloads modules. Kerneld could do more (although +Kmod only loads modules. Kerneld could do more (although nothing in the standard kernel used its other features). If you require features such as request_route, we suggest that you take a similar approach. A simple request_route function could be called, --- /tmp/linux-2.1.98/Documentation/sysctl/kernel.txt Fri Apr 17 22:06:22 1998 +++ linux/Documentation/sysctl/kernel.txt Fri Apr 24 01:16:11 1998 @@ -25,7 +25,6 @@ - inode-max - inode-nr - inode-state -- kmod_unload_delay ==> Documentation/kmod.txt - modprobe ==> Documentation/kmod.txt - osrelease - ostype --- /tmp/linux-2.1.98/include/linux/sysctl.h Sat Apr 11 17:18:15 1998 +++ linux/include/linux/sysctl.h Fri Apr 24 01:19:08 1998 @@ -72,7 +72,6 @@ KERN_STATINODE, KERN_DENTRY, /* dentry statistics */ KERN_MODPROBE, - KERN_KMOD_UNLOAD_DELAY }; --- /tmp/linux-2.1.98/init/main.c Mon Apr 13 18:11:17 1998 +++ linux/init/main.c Fri Apr 24 01:19:12 1998 @@ -1162,13 +1162,6 @@ smp_begin(); #endif -#ifdef CONFIG_KMOD - { - extern int kmod_init(void); - kmod_init(); - } -#endif - #ifdef CONFIG_UMSDOS_FS { /* --- /tmp/linux-2.1.98/kernel/kmod.c Sat Apr 18 19:41:17 1998 +++ linux/kernel/kmod.c Fri Apr 24 01:19:13 1998 @@ -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++; + + /* don't use the user's files, use init's files instead */ + exit_files(current); /* current->files->count--; */ + current->files = task_init->files; + current->files->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); - - /* - 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); - } - } - } + char *argv[] = { modprobe_path, "-s", "-k", (char*)module_name, NULL}; - return 0; /* Never reached. */ -} + use_init_file_context(); -/* - 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"); - - /* - * 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); - + spin_lock_irq(¤t->sigmask_lock); + flush_signals(current); + flush_signal_handlers(current); + spin_unlock_irq(¤t->sigmask_lock); + + set_fs(KERNEL_DS); /* Allow execve args to be in kernel space. */ + current->uid = current->euid = 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 | CLONE_FILES | 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; } --- /tmp/linux-2.1.98/kernel/sysctl.c Wed Apr 1 16:26:35 1998 +++ linux/kernel/sysctl.c Fri Apr 24 01:19:13 1998 @@ -43,7 +43,6 @@ extern int sysctl_overcommit_memory; #ifdef CONFIG_KMOD extern char modprobe_path[]; -extern int kmod_unload_delay; #endif #ifdef CONFIG_CHR_DEV_SG extern int sg_big_buff; @@ -180,8 +179,6 @@ #ifdef CONFIG_KMOD {KERN_MODPROBE, "modprobe", &modprobe_path, 256, 0644, NULL, &proc_dostring, &sysctl_string }, - {KERN_KMOD_UNLOAD_DELAY, "kmod_unload_delay", &kmod_unload_delay, - sizeof(int), 0644, NULL, &proc_dointvec}, #endif #ifdef CONFIG_CHR_DEV_SG {KERN_NRFILE, "sg-big-buff", &sg_big_buff, sizeof (int), - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu
| |