Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | /* kmod, the new module loader (replaces kerneld) Kirk Petersen Reorganized not to be a daemon by Adam Richter, with guidance from Greg Zornetzer. Modified to avoid chroot and file sharing problems. Mikael Pettersson */ #define __KERNEL_SYSCALLS__ #include <linux/sched.h> #include <linux/unistd.h> #include <linux/smp_lock.h> #include <asm/uaccess.h> /* modprobe_path is set via /proc/sys. */ char modprobe_path[256] = "/sbin/modprobe"; static inline void use_init_file_context(void) { struct fs_struct * fs; lock_kernel(); /* * 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 */ exit_fs(current); /* current->fs->count--; */ fs = init_task.fs; current->fs = fs; atomic_inc(&fs->count); unlock_kernel(); } static int exec_modprobe(void * module_name) { 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(); /* 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 as the super user right after the execve fails if you time the signal just right. */ spin_lock_irq(¤t->sigmask_lock); flush_signals(current); flush_signal_handlers(current); spin_unlock_irq(¤t->sigmask_lock); for (i = 0; i < current->files->max_fds; i++ ) { if (current->files->fd[i]) close(i); } /* Drop the "current user" thing */ free_uid(current); /* Give kmod all privileges.. */ current->uid = current->euid = current->fsuid = 0; cap_set_full(current->cap_inheritable); cap_set_full(current->cap_effective); /* Allow execve args to be in kernel space. */ set_fs(KERNEL_DS); /* Go, go, go... */ if (execve(modprobe_path, argv, envp) < 0) { printk(KERN_ERR "kmod: failed to exec %s -s -k %s, errno = %d\n", modprobe_path, (char*) module_name, errno); return -errno; } return 0; } /* request_module: the function that everyone calls when they need a module. */ int request_module(const char * module_name) { int pid; int waitpid_result; sigset_t tmpsig; /* Don't allow request_module() before the root fs is mounted! */ if ( ! current->fs->root ) { printk(KERN_ERR "request_module[%s]: Root fs not mounted\n", module_name); return -EPERM; } pid = kernel_thread(exec_modprobe, (void*) module_name, CLONE_FS); if (pid < 0) { printk(KERN_ERR "request_module[%s]: fork failed, errno %d\n", module_name, -pid); return pid; } /* Block everything but SIGKILL/SIGSTOP */ spin_lock_irq(¤t->sigmask_lock); tmpsig = current->blocked; siginitsetinv(¤t->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP)); recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); waitpid_result = waitpid(pid, NULL, __WCLONE); /* Allow signals again.. */ spin_lock_irq(¤t->sigmask_lock); current->blocked = tmpsig; recalc_sigpending(current); 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); } return 0; } |