patch-2.3.27 linux/kernel/kmod.c

Next file: linux/kernel/ksyms.c
Previous file: linux/kernel/fork.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.26/linux/kernel/kmod.c linux/kernel/kmod.c
@@ -23,22 +23,36 @@
 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();
+	struct fs_struct *our_fs, *init_fs;
 
 	/*
-	 * Don't use the user's root, use init's root 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
+	 * Make modprobe's fs context be a copy of init's.
+	 *
+	 * We cannot use the user's fs context, because it
+	 * may have a different root than init.
+	 * Since init was created with CLONE_FS, we can grab
+	 * its fs context from "init_task".
+	 *
+	 * The fs context has to be a copy. If it is shared
+	 * with init, then any chdir() call in modprobe will
+	 * also affect init and the other threads sharing
+	 * init_task's fs context.
+	 *
+	 * We created the exec_modprobe thread without CLONE_FS,
+	 * so we can update the fields in our fs context freely.
 	 */
-	exit_fs(current);	/* current->fs->count--; */
-	fs = init_task.fs;
-	current->fs = fs;
-	atomic_inc(&fs->count);
+	lock_kernel();
+
+	our_fs = current->fs;
+	dput(our_fs->root);
+	dput(our_fs->pwd);
+
+	init_fs = init_task.fs;
+	our_fs->umask = init_fs->umask;
+	our_fs->root = dget(init_fs->root);
+	our_fs->pwd = dget(init_fs->pwd);
 
 	unlock_kernel();
 }
@@ -49,7 +63,10 @@
 	char *argv[] = { modprobe_path, "-s", "-k", (char*)module_name, NULL };
 	int i;
 
-	use_init_file_context();
+	current->session = 1;
+	current->pgrp = 1;
+
+	use_init_fs_context();
 
 	/* Prevent parent user process from sending signals to child.
 	   Otherwise, if the modprobe program does not exist, it might
@@ -104,7 +121,7 @@
 		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;
@@ -126,8 +143,8 @@
 	spin_unlock_irq(&current->sigmask_lock);
 
 	if (waitpid_result != pid) {
-		printk (KERN_ERR "kmod: waitpid(%d,NULL,0) failed, returning %d.\n",
-			pid, waitpid_result);
+		printk(KERN_ERR "request_module[%s]: waitpid(%d,...) failed, errno %d\n",
+		       module_name, pid, -waitpid_result);
 	}
 	return 0;
 }

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)