summaryrefslogtreecommitdiffstats
path: root/kernel/kmod.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/kmod.c')
-rw-r--r--kernel/kmod.c49
1 files changed, 33 insertions, 16 deletions
diff --git a/kernel/kmod.c b/kernel/kmod.c
index 8b19e2415..36d754380 100644
--- a/kernel/kmod.c
+++ b/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 @@ static int exec_modprobe(void * module_name)
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 @@ int request_module(const char * module_name)
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 @@ int request_module(const char * module_name)
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;
}