diff options
Diffstat (limited to 'kernel/kmod.c')
-rw-r--r-- | kernel/kmod.c | 49 |
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(¤t->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; } |