The purpose of this security change is to impede attacks using
the chroot'ed anonymous FTP area, so that if an intruder were able to
create the file "~ftp/sbin/modprobe", it still will not be executed,
because the FTP daemon would be running as another user. Even if
the intruder were able to move a file owned by root into that location,
it would have to be a file that could only be written to by root.
It would probably be a good idea to have modprobe extend this
policy to the kernel .o files at some point.
Anyhow, please test this. If I don't hear of any problems by
tomorrow afternoon, I will check to make sure that I've got the nods
of the other kmod developers and then I will ask Linus to put it into
the main kernel distribution.
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.95/Documentation/kmod.txt Tue Mar 10 14:43:13 1998
+++ linux/Documentation/kmod.txt Mon Apr 13 10:25:55 1998
@@ -12,11 +12,12 @@
echo "/sbin/modprobe" > /proc/sys/kernel/modprobe
-To tell kmod when to unload unused modules, do something like:
+To periodically unload unused modules, do 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.95/Documentation/sysctl/kernel.txt Thu Mar 19 15:04:30 1998
+++ linux/Documentation/sysctl/kernel.txt Mon Apr 13 10:23:54 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.95/include/linux/sysctl.h Wed Apr 1 16:19:57 1998
+++ linux/include/linux/sysctl.h Mon Apr 13 10:18:48 1998
@@ -72,7 +72,6 @@
KERN_STATINODE,
KERN_DENTRY, /* dentry statistics */
KERN_MODPROBE,
- KERN_KMOD_UNLOAD_DELAY
};
--- /tmp/linux-2.1.95/init/main.c Wed Apr 8 18:10:01 1998
+++ linux/init/main.c Mon Apr 13 11:54:55 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.95/kernel/kmod.c Tue Apr 7 08:05:05 1998
+++ linux/kernel/kmod.c Tue Apr 14 15:53:34 1998
@@ -1,6 +1,9 @@
/*
kmod, the new module loader (replaces kerneld)
Kirk Petersen
+
+ Reorganized not to be a daemon by Adam Richter, with guidance
+ from Greg Zornetzer.
*/
#define __KERNEL_SYSCALLS__
@@ -8,142 +11,82 @@
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/unistd.h>
+#include <linux/stat.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;
-
-/*
- 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;
-}
-
-/*
- 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)
-{
- int pid;
-
- /*
- Initialize basic thread information
+static void
+security_paranoia(void) {
+ int fd;
+
+ /* 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.
*/
- current->session = 1;
- current->pgrp = 1;
- sprintf(current->comm, "kmod");
+ spin_lock_irq(¤t->sigmask_lock);
sigfillset(¤t->blocked);
+ spin_unlock_irq(¤t->sigmask_lock);
- /*
- 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);
- }
- }
+ /* Prevent open file descriptors from being passed to privileged
+ modprobe program. With the stock modprobe, the only problem
+ is the potential annoyance of an error message being inserted
+ into a program's stderr. However, we want to be safe for
+ customized modprobe replacements as well. -adam@yggdrasil.com */
+ for (fd = 0; fd < current->files->max_fds; fd++ ) {
+ close(fd);
}
-
- 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)
+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);
-}
-
-int kmod_init(void)
-{
- printk("Starting kmod\n");
-
- kernel_thread(kmod_thread, NULL, 0);
-
- 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);
-
+ char *argv[] = { modprobe_path, "-s", "-k", (char*)module_name, NULL};
+ struct stat statbuf;
+ int stat_result;
+ asmlinkage int sys_newstat(char * filename, struct stat * statbuf);
+
+ security_paranoia();
+ set_fs(KERNEL_DS); /* Allow execve args to be in kernel space. */
+ if ((stat_result = sys_newstat(modprobe_path, &statbuf)) < 0) {
+ return stat_result;
+ }
+ if (statbuf.st_uid != 0 || (statbuf.st_mode & (S_IWGRP|S_IWOTH))) {
+ return -EPERM;
+ }
+ 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, 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.95/kernel/sysctl.c Wed Apr 1 16:26:35 1998
+++ linux/kernel/sysctl.c Mon Apr 13 10:17:42 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