patch-2.1.116 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.1.115/linux/kernel/kmod.c linux/kernel/kmod.c
@@ -15,6 +15,7 @@
 #include <linux/types.h>
 #include <linux/unistd.h>
 #include <linux/smp_lock.h>
+#include <linux/signal.h>
 
 #include <asm/uaccess.h>
 
@@ -22,7 +23,6 @@
 	modprobe_path is set via /proc/sys.
 */
 char modprobe_path[256] = "/sbin/modprobe";
-static char * envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
 
 /*
 	exec_modprobe is spawned from a kernel-mode user process,
@@ -41,14 +41,15 @@
 	/* 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++;
+	atomic_inc(&current->fs->count);
 
 	unlock_kernel();
 }
 
 static int exec_modprobe(void * module_name)
 {
-	char *argv[] = { modprobe_path, "-s", "-k", (char*)module_name, NULL};
+	static char * envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
+	char *argv[] = { modprobe_path, "-s", "-k", (char*)module_name, NULL };
 	int i;
 
 	use_init_file_context();
@@ -68,8 +69,8 @@
 		if (current->files->fd[i]) close(i);
 	}
 
-	/* kernel_thread() -> ... -> charge_uid(current, 1) workaround */
-	charge_uid(current, -1);
+	/* Drop the "current user" thing */
+	free_uid(current);
 
 	/* Give kmod all privileges.. */
 	current->uid = current->euid = current->fsuid = 0;
@@ -97,6 +98,7 @@
 {
 	int pid;
 	int waitpid_result;
+	sigset_t tmpsig;
 
 	/* Don't allow request_module() before the root fs is mounted!  */
 	if ( ! current->fs->root ) {
@@ -107,10 +109,25 @@
 
 	pid = kernel_thread(exec_modprobe, (void*) module_name, CLONE_FS);
 	if (pid < 0) {
-		printk(KERN_ERR "kmod: fork failed, errno %d\n", -pid);
+		printk(KERN_ERR "request_module[%s]: fork failed, errno %d\n", module_name, -pid);
 		return pid;
 	}
+
+	/* Block everything but SIGKILL/SIGSTOP */
+	spin_lock_irq(&current->sigmask_lock);
+	tmpsig = current->blocked;
+	siginitset(&current->blocked, ~(sigmask(SIGKILL)|sigmask(SIGSTOP)));
+	recalc_sigpending(current);
+	spin_unlock_irq(&current->sigmask_lock);
+
 	waitpid_result = waitpid(pid, NULL, __WCLONE);
+
+	/* Allow signals again.. */
+	spin_lock_irq(&current->sigmask_lock);
+	current->blocked = tmpsig;
+	recalc_sigpending(current);
+	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);

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov