diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1998-05-07 02:55:41 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1998-05-07 02:55:41 +0000 |
commit | dcec8a13bf565e47942a1751a9cec21bec5648fe (patch) | |
tree | 548b69625b18cc2e88c3e68d0923be546c9ebb03 /kernel | |
parent | 2e0f55e79c49509b7ff70ff1a10e1e9e90a3dfd4 (diff) |
o Merge with Linux 2.1.99.
o Fix ancient bug in the ELF loader making ldd crash.
o Fix ancient bug in the keyboard code for SGI, SNI and Jazz.
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/exit.c | 21 | ||||
-rw-r--r-- | kernel/fork.c | 9 | ||||
-rw-r--r-- | kernel/kmod.c | 178 | ||||
-rw-r--r-- | kernel/ksyms.c | 21 | ||||
-rw-r--r-- | kernel/printk.c | 23 | ||||
-rw-r--r-- | kernel/sched.c | 2 | ||||
-rw-r--r-- | kernel/signal.c | 1 | ||||
-rw-r--r-- | kernel/sys.c | 3 | ||||
-rw-r--r-- | kernel/sysctl.c | 43 |
9 files changed, 118 insertions, 183 deletions
diff --git a/kernel/exit.c b/kernel/exit.c index 2d5835ac8..ae2a34f44 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -299,7 +299,10 @@ static void exit_notify(void) * as a result of our exiting, and if they have any stopped * jobs, send them a SIGHUP and then a SIGCONT. (POSIX 3.2.2.2) */ - while ((p = current->p_cptr) != NULL) { + + write_lock_irq(&tasklist_lock); + while (current->p_cptr != NULL) { + p = current->p_cptr; current->p_cptr = p->p_osptr; p->p_ysptr = NULL; p->flags &= ~(PF_PTRACED|PF_TRACESYS); @@ -318,13 +321,19 @@ static void exit_notify(void) * outside, so the child pgrp is now orphaned. */ if ((p->pgrp != current->pgrp) && - (p->session == current->session) && - is_orphaned_pgrp(p->pgrp) && - has_stopped_jobs(p->pgrp)) { - kill_pg(p->pgrp,SIGHUP,1); - kill_pg(p->pgrp,SIGCONT,1); + (p->session == current->session)) { + int pgrp = p->pgrp; + + write_unlock_irq(&tasklist_lock); + if (is_orphaned_pgrp(pgrp) && has_stopped_jobs(pgrp)) { + kill_pg(pgrp,SIGHUP,1); + kill_pg(pgrp,SIGCONT,1); + } + write_lock_irq(&tasklist_lock); } } + write_unlock_irq(&tasklist_lock); + if (current->leader) disassociate_ctty(1); } diff --git a/kernel/fork.c b/kernel/fork.c index a08aa2c64..88199cae1 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -208,6 +208,7 @@ static inline int dup_mmap(struct mm_struct * mm) int retval; flush_cache_mm(current->mm); + down(¤t->mm->mmap_sem); pprev = &mm->mmap; for (mpnt = current->mm->mmap ; mpnt ; mpnt = mpnt->vm_next) { struct file *file; @@ -257,6 +258,7 @@ static inline int dup_mmap(struct mm_struct * mm) fail_nomem: flush_tlb_mm(current->mm); + up(¤t->mm->mmap_sem); return retval; } @@ -298,13 +300,14 @@ struct mm_struct * mm_alloc(void) void mmput(struct mm_struct *mm) { if (!--mm->count) { + release_segments(mm); exit_mmap(mm); free_page_tables(mm); kmem_cache_free(mm_cachep, mm); } } -static inline int copy_mm(unsigned long clone_flags, struct task_struct * tsk) +static inline int copy_mm(int nr, unsigned long clone_flags, struct task_struct * tsk) { struct mm_struct * mm; int retval; @@ -324,6 +327,7 @@ static inline int copy_mm(unsigned long clone_flags, struct task_struct * tsk) tsk->min_flt = tsk->maj_flt = 0; tsk->cmin_flt = tsk->cmaj_flt = 0; tsk->nswap = tsk->cnswap = 0; + copy_segments(nr, tsk, mm); retval = new_page_tables(tsk); if (retval) goto free_mm; @@ -514,6 +518,7 @@ int do_fork(unsigned long clone_flags, unsigned long usp, struct pt_regs *regs) /* ?? should we just memset this ?? */ for(i = 0; i < smp_num_cpus; i++) p->per_cpu_utime[i] = p->per_cpu_stime[i] = 0; + spin_lock_init(&p->sigmask_lock); } #endif p->lock_depth = 0; @@ -539,7 +544,7 @@ int do_fork(unsigned long clone_flags, unsigned long usp, struct pt_regs *regs) goto bad_fork_cleanup_files; if (copy_sighand(clone_flags, p)) goto bad_fork_cleanup_fs; - if (copy_mm(clone_flags, p)) + if (copy_mm(nr, clone_flags, p)) goto bad_fork_cleanup_sighand; error = copy_thread(nr, clone_flags, usp, p, regs); if (error) diff --git a/kernel/kmod.c b/kernel/kmod.c index 379c27695..7468e4382 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c @@ -1,6 +1,12 @@ /* 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__ @@ -8,140 +14,88 @@ #include <linux/sched.h> #include <linux/types.h> #include <linux/unistd.h> +#include <asm/smp_lock.h> +#include <asm/uaccess.h> /* - kmod_unload_delay and modprobe_path are set via /proc/sys. + modprobe_path is set via /proc/sys. */ -int kmod_unload_delay = 60; char modprobe_path[256] = "/sbin/modprobe"; -static char module_name[64] = ""; -static char * argv[] = { "modprobe", "-k", module_name, NULL, }; -static char * envp[] = { "HOME=/", "TERM=linux", NULL, }; - -/* - kmod_queue synchronizes the kmod thread and the rest of the system - kmod_unload_timer is what we use to unload modules - after kmod_unload_delay seconds -*/ -static struct wait_queue * kmod_queue = NULL; -static struct timer_list kmod_unload_timer; +static char * envp[] = { "HOME=/", "TERM=linux", "PATH=/usr/bin:/bin", NULL }; /* - kmod_thread is the thread that does most of the work. kmod_unload and - request_module tell it to wake up and do work. + exec_modprobe is spawned from a kernel-mode user process, + then changes its state to behave _as_if_ it was spawned + from the kernel's init process + (ppid and {e,}gid are not adjusted, but that shouldn't + be a problem since we trust modprobe) */ -int kmod_thread(void * data) -{ - int pid; +#define task_init task[smp_num_cpus] - /* - Initialize basic thread information - */ - current->session = 1; - current->pgrp = 1; - sprintf(current->comm, "kmod"); - sigfillset(¤t->blocked); - - /* - This is the main kmod_thread loop. It first sleeps, then - handles requests from request_module or kmod_unload. - */ +static inline void +use_init_file_context(void) { + lock_kernel(); - while (1) { - interruptible_sleep_on(&kmod_queue); - - /* - If request_module woke us up, we should try to - load module_name. If not, kmod_unload woke us up, - do call delete_module. - (if somehow both want us to do something, ignore the - delete_module request) - */ - if (module_name[0] == '\0') { - delete_module(NULL); - } else { - pid = fork(); - if (pid > 0) { - waitpid(pid, NULL, 0); - module_name[0] = '\0'; - wake_up(&kmod_queue); - } else - if (pid == 0) { - - /* - Call modprobe with module_name. If execve returns, - print out an error. - */ - execve(modprobe_path, argv, envp); - - printk("kmod: failed to load module %s\n", module_name); - _exit(0); - } else { - printk("error, fork failed in kmod\n"); - } - } - } + /* 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++; - return 0; /* Never reached. */ + unlock_kernel(); } -/* - kmod_unload is the function that the kernel calls when - the kmod_unload_timer expires -*/ -void kmod_unload(unsigned long x) +static int exec_modprobe(void * module_name) { - /* - wake up the kmod thread, which does the work - (we can't call delete_module, as it locks the kernel and - we are in the bottom half of the kernel (right?)) - once it is awake, reset the timer - */ - wake_up(&kmod_queue); - kmod_unload_timer.expires = jiffies + (kmod_unload_delay * HZ); - add_timer(&kmod_unload_timer); -} + char *argv[] = { modprobe_path, "-s", "-k", (char*)module_name, NULL}; + int i; -int kmod_init(void) -{ - printk ("Starting kmod\n"); + use_init_file_context(); - kernel_thread(kmod_thread, NULL, 0); + /* 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); - kmod_unload_timer.next = NULL; - kmod_unload_timer.prev = NULL; - kmod_unload_timer.expires = jiffies + (5 * 60 * HZ); - kmod_unload_timer.data = 0L; - kmod_unload_timer.function = kmod_unload; - add_timer(&kmod_unload_timer); + for (i = 0; i < current->files->max_fds; i++ ) { + if (current->files->fd[i]) close(i); + } + set_fs(KERNEL_DS); /* Allow execve args to be in kernel space. */ + current->uid = current->euid = current->fsuid = 0; + 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 to be loaded + request_module: the function that everyone calls when they need + a module. */ -int request_module(const char * name) +int request_module(const char * module_name) { - /* first, copy the name of the module into module_name */ - /* then wake_up() the kmod daemon */ - /* wait for the kmod daemon to finish (it will wake us up) */ - - /* - kmod_thread is sleeping, so start by copying the name of - the module into module_name. Once that is done, wake up - kmod_thread. - */ - strncpy(module_name, name, sizeof(module_name)); - module_name[sizeof(module_name)-1] = '\0'; - wake_up(&kmod_queue); - - /* - Now that we have told kmod_thread what to do, we want to - go to sleep and let it do its work. It will wake us up, - at which point we will be done (the module will be loaded). - */ - interruptible_sleep_on(&kmod_queue); + int pid; + int waitpid_result; + + pid = kernel_thread(exec_modprobe, (void*) module_name, + CLONE_FS | SIGCHLD); + if (pid < 0) { + printk(KERN_ERR "kmod: fork failed, errno %d\n", -pid); + return pid; + } + waitpid_result = waitpid(pid, NULL, 0); + if (waitpid_result != pid) { + printk (KERN_ERR "kmod: waitpid(%d,NULL,0) failed, returning %d.\n", + pid, waitpid_result); + } return 0; } diff --git a/kernel/ksyms.c b/kernel/ksyms.c index 7ff40d7bd..61201da16 100644 --- a/kernel/ksyms.c +++ b/kernel/ksyms.c @@ -54,10 +54,6 @@ extern unsigned char aux_device_present, kbd_read_mask; -#ifdef CONFIG_PCI -#include <linux/bios32.h> -#include <linux/pci.h> -#endif #if defined(CONFIG_PROC_FS) #include <linux/proc_fs.h> #endif @@ -100,19 +96,6 @@ EXPORT_SYMBOL(get_module_symbol); #endif EXPORT_SYMBOL(get_options); -#ifdef CONFIG_PCI -EXPORT_SYMBOL(pcibios_present); -EXPORT_SYMBOL(pcibios_find_class); -EXPORT_SYMBOL(pcibios_find_device); -EXPORT_SYMBOL(pcibios_read_config_byte); -EXPORT_SYMBOL(pcibios_read_config_word); -EXPORT_SYMBOL(pcibios_read_config_dword); -EXPORT_SYMBOL(pcibios_write_config_byte); -EXPORT_SYMBOL(pcibios_write_config_word); -EXPORT_SYMBOL(pcibios_write_config_dword); -EXPORT_SYMBOL(pcibios_strerror); -#endif - /* process memory management */ EXPORT_SYMBOL(do_mmap); EXPORT_SYMBOL(do_munmap); @@ -265,6 +248,7 @@ EXPORT_SYMBOL(register_binfmt); EXPORT_SYMBOL(unregister_binfmt); EXPORT_SYMBOL(search_binary_handler); EXPORT_SYMBOL(prepare_binprm); +EXPORT_SYMBOL(compute_creds); EXPORT_SYMBOL(remove_arg_zero); /* execution environment registration */ @@ -295,6 +279,7 @@ EXPORT_SYMBOL(bh_mask_count); EXPORT_SYMBOL(bh_base); EXPORT_SYMBOL(add_timer); EXPORT_SYMBOL(del_timer); +EXPORT_SYMBOL(mod_timer); EXPORT_SYMBOL(tq_timer); EXPORT_SYMBOL(tq_immediate); EXPORT_SYMBOL(tq_scheduler); @@ -353,6 +338,7 @@ EXPORT_SYMBOL(unregister_reboot_notifier); EXPORT_SYMBOL(_ctype); EXPORT_SYMBOL(secure_tcp_sequence_number); EXPORT_SYMBOL(get_random_bytes); +EXPORT_SYMBOL(securebits); /* Program loader interfaces */ EXPORT_SYMBOL(setup_arg_pages); @@ -388,7 +374,6 @@ EXPORT_SYMBOL(is_bad_inode); EXPORT_SYMBOL(event); EXPORT_SYMBOL(__down); EXPORT_SYMBOL(__up); -EXPORT_SYMBOL(securelevel); /* all busmice */ EXPORT_SYMBOL(add_mouse_randomness); diff --git a/kernel/printk.c b/kernel/printk.c index afc178c5e..48922d779 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -54,7 +54,7 @@ static char log_buf[LOG_BUF_LEN]; static unsigned long log_start = 0; static unsigned long logged_chars = 0; struct console_cmdline console_cmdline[MAX_CMDLINECONSOLES]; -static int selected_console = 0; +static int preferred_console = -1; /* * Setup a list of consoles. Called from init/main.c @@ -95,11 +95,13 @@ __initfunc(void console_setup(char *str, int *ints)) */ for(i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++) if (strcmp(console_cmdline[i].name, name) == 0 && - console_cmdline[i].index == idx) + console_cmdline[i].index == idx) { + preferred_console = i; return; + } if (i == MAX_CMDLINECONSOLES) return; - selected_console = 1; + preferred_console = i; c = &console_cmdline[i]; memcpy(c->name, name, sizeof(c->name)); c->options = options; @@ -336,13 +338,13 @@ void register_console(struct console * console) * didn't select a console we take the first one * that registers here. */ - if (selected_console == 0) { + if (preferred_console < 0) { if (console->index < 0) console->index = 0; if (console->setup == NULL || console->setup(console, NULL) == 0) { - console->flags |= CON_ENABLED | CON_FIRST; - selected_console = 1; + console->flags |= CON_ENABLED | CON_CONSDEV; + preferred_console = 0; } } @@ -356,14 +358,15 @@ void register_console(struct console * console) if (console->index >= 0 && console->index != console_cmdline[i].index) continue; - if (console->index < 0) console->index = 0; + if (console->index < 0) + console->index = console_cmdline[i].index; if (console->setup && console->setup(console, console_cmdline[i].options) != 0) break; console->flags |= CON_ENABLED; console->index = console_cmdline[i].index; - if (i == 0) - console->flags |= CON_FIRST; + if (i == preferred_console) + console->flags |= CON_CONSDEV; break; } @@ -374,7 +377,7 @@ void register_console(struct console * console) * Put this console in the list - keep the * preferred driver at the head of the list. */ - if ((console->flags & CON_FIRST) || console_drivers == NULL) { + if ((console->flags & CON_CONSDEV) || console_drivers == NULL) { console->next = console_drivers; console_drivers = console; } else { diff --git a/kernel/sched.c b/kernel/sched.c index 8d8576808..f9246e785 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -47,7 +47,7 @@ * kernel variables */ -int securelevel = 0; /* system security level */ +unsigned securebits = SECUREBITS_DEFAULT; /* systemwide security settings */ long tick = (1000000 + HZ/2) / HZ; /* timer interrupt period */ diff --git a/kernel/signal.c b/kernel/signal.c index c313b0a11..f9145783e 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -788,6 +788,7 @@ do_sigaction(int sig, const struct k_sigaction *act, struct k_sigaction *oact) if (act) { *k = *act; + sigdelsetmask(&k->sa.sa_mask, sigmask(SIGKILL) | sigmask(SIGSTOP)); /* * POSIX 3.3.1.3: diff --git a/kernel/sys.c b/kernel/sys.c index e86d18c09..aadb3ab5f 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -177,7 +177,8 @@ asmlinkage int sys_reboot(int magic1, int magic2, int cmd, void * arg) /* For safety, we require "magic" arguments. */ if (magic1 != LINUX_REBOOT_MAGIC1 || - (magic2 != LINUX_REBOOT_MAGIC2 && magic2 != LINUX_REBOOT_MAGIC2A)) + (magic2 != LINUX_REBOOT_MAGIC2 && magic2 != LINUX_REBOOT_MAGIC2A && + magic2 != LINUX_REBOOT_MAGIC2B)) return -EINVAL; lock_kernel(); diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 47bb36171..27616bfee 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -33,7 +33,7 @@ #include <linux/nfs_fs.h> #endif -#ifdef CONFIG_SYSCTL +#if defined(CONFIG_SYSCTL) && defined(CONFIG_PROC_FS) /* External variables not in a header file. */ extern int panic_timeout; @@ -43,7 +43,9 @@ extern char binfmt_java_interpreter[], binfmt_java_appletviewer[]; extern int sysctl_overcommit_memory; #ifdef CONFIG_KMOD extern char modprobe_path[]; -extern int kmod_unload_delay; +#endif +#ifdef CONFIG_CHR_DEV_SG +extern int sg_big_buff; #endif #ifdef __sparc__ @@ -52,8 +54,6 @@ extern char reboot_command []; static int parse_table(int *, int, void *, size_t *, void *, size_t, ctl_table *, void **); -static int do_securelevel_strategy (ctl_table *, int *, int, void *, size_t *, - void *, size_t, void **); static ctl_table root_table[]; @@ -156,8 +156,6 @@ static ctl_table kern_table[] = { 0644, NULL, &proc_dointvec}, {KERN_DENTRY, "dentry-state", &dentry_stat, 6*sizeof(int), 0444, NULL, &proc_dointvec}, - {KERN_SECURELVL, "securelevel", &securelevel, sizeof(int), - 0444, NULL, &proc_dointvec, (ctl_handler *)&do_securelevel_strategy}, {KERN_PANIC, "panic", &panic_timeout, sizeof(int), 0644, NULL, &proc_dointvec}, #ifdef CONFIG_BLK_DEV_INITRD @@ -181,8 +179,10 @@ static ctl_table kern_table[] = { #ifdef CONFIG_KMOD {KERN_MODPROBE, "modprobe", &modprobe_path, 256, 0644, NULL, &proc_dostring, &sysctl_string }, - {KERN_KMOD_UNLOAD_DELAY, "kmod_unload_delay", &kmod_unload_delay, - sizeof(int), 0644, NULL, &proc_dointvec}, +#endif +#ifdef CONFIG_CHR_DEV_SG + {KERN_NRFILE, "sg-big-buff", &sg_big_buff, sizeof (int), + 0444, NULL, &proc_dointvec}, #endif {0} }; @@ -408,29 +408,6 @@ int do_sysctl_strategy (ctl_table *table, return 0; } -/* - * This function only checks permission for changing the security level - * If the tests are successful, the actual change is done by - * do_sysctl_strategy - */ -static int do_securelevel_strategy (ctl_table *table, - int *name, int nlen, - void *oldval, size_t *oldlenp, - void *newval, size_t newlen, void **context) -{ - int level; - - if (newval && newlen) { - if (newlen != sizeof (int)) - return -EINVAL; - if(copy_from_user (&level, newval, newlen)) - return -EFAULT; - if (level < securelevel && current->pid != 1) - return -EPERM; - } - return 0; -} - struct ctl_table_header *register_sysctl_table(ctl_table * table, int insert_at_head) { @@ -1031,7 +1008,7 @@ int do_struct ( } -#else /* CONFIG_SYSCTL */ +#else /* CONFIG_PROC_FS && CONFIG_SYSCTL */ extern asmlinkage int sys_sysctl(struct __sysctl_args *args) @@ -1087,7 +1064,7 @@ void unregister_sysctl_table(struct ctl_table_header * table) { } -#endif /* CONFIG_SYSCTL */ +#endif /* CONFIG_PROC_FS && CONFIG_SYSCTL */ |