Slight change to daemonless kernel/kmod.c: please test

Adam J. Richter (adam@yggdrasil.com)
Tue, 28 Apr 1998 09:54:18 -0700


If you are running the daemonless kmod, especially if you
have had problems with init's output vanishing, please try the
following version of kernel/kmod.c.

I include the complete kernel/kmod.c file below rather than
a patch, because I am not sure exactly what I would be patching
against. However, you must have applied my daemonless kmod patch
to get the necessary changes in other files or you must be
the test pre-2.1.99-1 kernel.

The only change here is that I have backed out the
modification that I received earlier that had kmod share init's file
table. Now, it just closes all of its file descriptors. However, it
still uses init's root and current working directories, so we do not
have to maintain another copy of modules in the anonymous FTP area. I
am running this version now, and it works for me so far, although I
was not having the problems caused by kmod's sharing init's file
table. So, please give this version a try, especially if you were
having these problems.

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."
linux/kernel/kmod.c:
----------------------------CUT HERE------------------------------------
/*
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__

#include <linux/sched.h>
#include <linux/types.h>
#include <linux/unistd.h>
#include <asm/smp_lock.h>
#include <asm/uaccess.h>

/*
modprobe_path is set via /proc/sys.
*/
char modprobe_path[256] = "/sbin/modprobe";
static char * envp[] = { "HOME=/", "TERM=linux", "PATH=/usr/bin:/bin", NULL };

/*
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++;

unlock_kernel();
}

static int exec_modprobe(void * module_name)
{
char *argv[] = { modprobe_path, "-s", "-k", (char*)module_name, NULL};
int i;

use_init_file_context();

/* 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);

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 = 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.
*/
int request_module(const char * module_name)
{
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;
}

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu