Patch: init's cwd is changed by modprobe!

Chip Salzenberg (chip@valinux.com)
Fri, 5 Nov 1999 12:26:01 -0800


Unlike most people (apparently) I have /var on a separate filesystem.
Recently I noticed that /var was still busy at shutdown. I tracked
this problem down to the modprobe's filesystem context actually being
*shared* with init... and with a few kernel threads, too. My modprobe
calls chdir("/var/log/ksymoops"), and when it does, init and the
kernel threads follow along.

If you have a modprobe that doesn't call chdir(), or if the chdir() is
to a directory on the root filesystem, you won't have noticed this
behavior. If you're curious, just run "lsof" and look for the cwd of
init. On my system, it was "/var/log/ksymoops".

The below patch fixes this bug by making modprobe's filesystem context
a *copy* of init's. The patch is against 2.2.13, but I wouldn't be
surprised if 2.3 needs a similar fix.

Index: kernel/kmod.c
@@ -23,22 +23,24 @@
char modprobe_path[256] = "/sbin/modprobe";

static inline void
-use_init_file_context(void)
+use_init_fs_context(void)
{
struct fs_struct * fs;

- lock_kernel();
-
/*
- * Don't use the user's root, use init's root instead.
+ * Don't use the user's fs context, use init's instead.
* Note that we can use "init_task" (which is not actually
* the same as the user-level "init" process) because we
* started "init" with a CLONE_FS
*/
- exit_fs(current); /* current->fs->count--; */
- fs = init_task.fs;
- current->fs = fs;
- atomic_inc(&fs->count);
+
+ lock_kernel();
+
+ fs = current->fs;
+ dput(fs->root);
+ dput(fs->pwd);
+ fs->root = dget(init_task.fs->root);
+ fs->pwd = dget(init_task.fs->pwd);

unlock_kernel();
}
@@ -49,8 +51,6 @@ static int exec_modprobe(void * module_n
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
@@ -62,6 +62,10 @@ static int exec_modprobe(void * module_n
flush_signal_handlers(current);
spin_unlock_irq(&current->sigmask_lock);

+ /* Copy root dir and cwd from init */
+ use_init_fs_context();
+
+ /* Close our copies of user's open files */
for (i = 0; i < current->files->max_fds; i++ ) {
if (current->files->fd[i]) close(i);
}
@@ -104,7 +108,7 @@ int request_module(const char * module_n
return -EPERM;
}

- pid = kernel_thread(exec_modprobe, (void*) module_name, CLONE_FS);
+ pid = kernel_thread(exec_modprobe, (void*) module_name, 0);
if (pid < 0) {
printk(KERN_ERR "request_module[%s]: fork failed, errno %d\n", module_name, -pid);
return pid;

-- 
Chip Salzenberg             - a.k.a. -              <chip@valinux.com>
           "I am the Lemon Zester of Destruction!"  //MST3K

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/