diff options
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/Makefile | 3 | ||||
| -rw-r--r-- | kernel/compat.c | 2 | ||||
| -rw-r--r-- | kernel/exit.c | 11 | ||||
| -rw-r--r-- | kernel/fork.c | 81 | ||||
| -rw-r--r-- | kernel/futex.c | 2 | ||||
| -rw-r--r-- | kernel/kallsyms.c | 1 | ||||
| -rw-r--r-- | kernel/kmod.c | 5 | ||||
| -rw-r--r-- | kernel/kprobes.c | 53 | ||||
| -rw-r--r-- | kernel/lockdep.c | 6 | ||||
| -rw-r--r-- | kernel/module.c | 37 | ||||
| -rw-r--r-- | kernel/nsproxy.c | 139 | ||||
| -rw-r--r-- | kernel/pid.c | 111 | ||||
| -rw-r--r-- | kernel/power/snapshot.c | 10 | ||||
| -rw-r--r-- | kernel/sched.c | 3 | ||||
| -rw-r--r-- | kernel/signal.c | 65 | ||||
| -rw-r--r-- | kernel/sys.c | 22 | ||||
| -rw-r--r-- | kernel/sysctl.c | 350 | ||||
| -rw-r--r-- | kernel/utsname.c | 95 |
18 files changed, 818 insertions, 178 deletions
diff --git a/kernel/Makefile b/kernel/Makefile index aacaafb28b9d..d948ca12acf0 100644 --- a/kernel/Makefile +++ b/kernel/Makefile | |||
| @@ -8,7 +8,7 @@ obj-y = sched.o fork.o exec_domain.o panic.o printk.o profile.o \ | |||
| 8 | signal.o sys.o kmod.o workqueue.o pid.o \ | 8 | signal.o sys.o kmod.o workqueue.o pid.o \ |
| 9 | rcupdate.o extable.o params.o posix-timers.o \ | 9 | rcupdate.o extable.o params.o posix-timers.o \ |
| 10 | kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \ | 10 | kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \ |
| 11 | hrtimer.o rwsem.o latency.o | 11 | hrtimer.o rwsem.o latency.o nsproxy.o |
| 12 | 12 | ||
| 13 | obj-$(CONFIG_STACKTRACE) += stacktrace.o | 13 | obj-$(CONFIG_STACKTRACE) += stacktrace.o |
| 14 | obj-y += time/ | 14 | obj-y += time/ |
| @@ -48,6 +48,7 @@ obj-$(CONFIG_GENERIC_HARDIRQS) += irq/ | |||
| 48 | obj-$(CONFIG_SECCOMP) += seccomp.o | 48 | obj-$(CONFIG_SECCOMP) += seccomp.o |
| 49 | obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o | 49 | obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o |
| 50 | obj-$(CONFIG_RELAY) += relay.o | 50 | obj-$(CONFIG_RELAY) += relay.o |
| 51 | obj-$(CONFIG_UTS_NS) += utsname.o | ||
| 51 | obj-$(CONFIG_TASK_DELAY_ACCT) += delayacct.o | 52 | obj-$(CONFIG_TASK_DELAY_ACCT) += delayacct.o |
| 52 | obj-$(CONFIG_TASKSTATS) += taskstats.o tsacct.o | 53 | obj-$(CONFIG_TASKSTATS) += taskstats.o tsacct.o |
| 53 | 54 | ||
diff --git a/kernel/compat.c b/kernel/compat.c index b4fbd838cd77..75573e5d27b0 100644 --- a/kernel/compat.c +++ b/kernel/compat.c | |||
| @@ -26,8 +26,6 @@ | |||
| 26 | 26 | ||
| 27 | #include <asm/uaccess.h> | 27 | #include <asm/uaccess.h> |
| 28 | 28 | ||
| 29 | extern void sigset_from_compat(sigset_t *set, compat_sigset_t *compat); | ||
| 30 | |||
| 31 | int get_compat_timespec(struct timespec *ts, const struct compat_timespec __user *cts) | 29 | int get_compat_timespec(struct timespec *ts, const struct compat_timespec __user *cts) |
| 32 | { | 30 | { |
| 33 | return (!access_ok(VERIFY_READ, cts, sizeof(*cts)) || | 31 | return (!access_ok(VERIFY_READ, cts, sizeof(*cts)) || |
diff --git a/kernel/exit.c b/kernel/exit.c index 3b47f26985f2..f250a5e3e281 100644 --- a/kernel/exit.c +++ b/kernel/exit.c | |||
| @@ -21,6 +21,7 @@ | |||
| 21 | #include <linux/tsacct_kern.h> | 21 | #include <linux/tsacct_kern.h> |
| 22 | #include <linux/file.h> | 22 | #include <linux/file.h> |
| 23 | #include <linux/binfmts.h> | 23 | #include <linux/binfmts.h> |
| 24 | #include <linux/nsproxy.h> | ||
| 24 | #include <linux/ptrace.h> | 25 | #include <linux/ptrace.h> |
| 25 | #include <linux/profile.h> | 26 | #include <linux/profile.h> |
| 26 | #include <linux/mount.h> | 27 | #include <linux/mount.h> |
| @@ -397,9 +398,11 @@ void daemonize(const char *name, ...) | |||
| 397 | fs = init_task.fs; | 398 | fs = init_task.fs; |
| 398 | current->fs = fs; | 399 | current->fs = fs; |
| 399 | atomic_inc(&fs->count); | 400 | atomic_inc(&fs->count); |
| 400 | exit_namespace(current); | 401 | |
| 401 | current->namespace = init_task.namespace; | 402 | exit_task_namespaces(current); |
| 402 | get_namespace(current->namespace); | 403 | current->nsproxy = init_task.nsproxy; |
| 404 | get_task_namespaces(current); | ||
| 405 | |||
| 403 | exit_files(current); | 406 | exit_files(current); |
| 404 | current->files = init_task.files; | 407 | current->files = init_task.files; |
| 405 | atomic_inc(¤t->files->count); | 408 | atomic_inc(¤t->files->count); |
| @@ -917,7 +920,6 @@ fastcall NORET_TYPE void do_exit(long code) | |||
| 917 | exit_sem(tsk); | 920 | exit_sem(tsk); |
| 918 | __exit_files(tsk); | 921 | __exit_files(tsk); |
| 919 | __exit_fs(tsk); | 922 | __exit_fs(tsk); |
| 920 | exit_namespace(tsk); | ||
| 921 | exit_thread(); | 923 | exit_thread(); |
| 922 | cpuset_exit(tsk); | 924 | cpuset_exit(tsk); |
| 923 | exit_keys(tsk); | 925 | exit_keys(tsk); |
| @@ -932,6 +934,7 @@ fastcall NORET_TYPE void do_exit(long code) | |||
| 932 | tsk->exit_code = code; | 934 | tsk->exit_code = code; |
| 933 | proc_exit_connector(tsk); | 935 | proc_exit_connector(tsk); |
| 934 | exit_notify(tsk); | 936 | exit_notify(tsk); |
| 937 | exit_task_namespaces(tsk); | ||
| 935 | #ifdef CONFIG_NUMA | 938 | #ifdef CONFIG_NUMA |
| 936 | mpol_free(tsk->mempolicy); | 939 | mpol_free(tsk->mempolicy); |
| 937 | tsk->mempolicy = NULL; | 940 | tsk->mempolicy = NULL; |
diff --git a/kernel/fork.c b/kernel/fork.c index 89f666491d1f..7dc6140baac6 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
| @@ -27,6 +27,7 @@ | |||
| 27 | #include <linux/binfmts.h> | 27 | #include <linux/binfmts.h> |
| 28 | #include <linux/mman.h> | 28 | #include <linux/mman.h> |
| 29 | #include <linux/fs.h> | 29 | #include <linux/fs.h> |
| 30 | #include <linux/nsproxy.h> | ||
| 30 | #include <linux/capability.h> | 31 | #include <linux/capability.h> |
| 31 | #include <linux/cpu.h> | 32 | #include <linux/cpu.h> |
| 32 | #include <linux/cpuset.h> | 33 | #include <linux/cpuset.h> |
| @@ -1116,11 +1117,11 @@ static struct task_struct *copy_process(unsigned long clone_flags, | |||
| 1116 | goto bad_fork_cleanup_signal; | 1117 | goto bad_fork_cleanup_signal; |
| 1117 | if ((retval = copy_keys(clone_flags, p))) | 1118 | if ((retval = copy_keys(clone_flags, p))) |
| 1118 | goto bad_fork_cleanup_mm; | 1119 | goto bad_fork_cleanup_mm; |
| 1119 | if ((retval = copy_namespace(clone_flags, p))) | 1120 | if ((retval = copy_namespaces(clone_flags, p))) |
| 1120 | goto bad_fork_cleanup_keys; | 1121 | goto bad_fork_cleanup_keys; |
| 1121 | retval = copy_thread(0, clone_flags, stack_start, stack_size, p, regs); | 1122 | retval = copy_thread(0, clone_flags, stack_start, stack_size, p, regs); |
| 1122 | if (retval) | 1123 | if (retval) |
| 1123 | goto bad_fork_cleanup_namespace; | 1124 | goto bad_fork_cleanup_namespaces; |
| 1124 | 1125 | ||
| 1125 | p->set_child_tid = (clone_flags & CLONE_CHILD_SETTID) ? child_tidptr : NULL; | 1126 | p->set_child_tid = (clone_flags & CLONE_CHILD_SETTID) ? child_tidptr : NULL; |
| 1126 | /* | 1127 | /* |
| @@ -1212,7 +1213,7 @@ static struct task_struct *copy_process(unsigned long clone_flags, | |||
| 1212 | spin_unlock(¤t->sighand->siglock); | 1213 | spin_unlock(¤t->sighand->siglock); |
| 1213 | write_unlock_irq(&tasklist_lock); | 1214 | write_unlock_irq(&tasklist_lock); |
| 1214 | retval = -ERESTARTNOINTR; | 1215 | retval = -ERESTARTNOINTR; |
| 1215 | goto bad_fork_cleanup_namespace; | 1216 | goto bad_fork_cleanup_namespaces; |
| 1216 | } | 1217 | } |
| 1217 | 1218 | ||
| 1218 | if (clone_flags & CLONE_THREAD) { | 1219 | if (clone_flags & CLONE_THREAD) { |
| @@ -1260,8 +1261,8 @@ static struct task_struct *copy_process(unsigned long clone_flags, | |||
| 1260 | proc_fork_connector(p); | 1261 | proc_fork_connector(p); |
| 1261 | return p; | 1262 | return p; |
| 1262 | 1263 | ||
| 1263 | bad_fork_cleanup_namespace: | 1264 | bad_fork_cleanup_namespaces: |
| 1264 | exit_namespace(p); | 1265 | exit_task_namespaces(p); |
| 1265 | bad_fork_cleanup_keys: | 1266 | bad_fork_cleanup_keys: |
| 1266 | exit_keys(p); | 1267 | exit_keys(p); |
| 1267 | bad_fork_cleanup_mm: | 1268 | bad_fork_cleanup_mm: |
| @@ -1514,10 +1515,9 @@ static int unshare_fs(unsigned long unshare_flags, struct fs_struct **new_fsp) | |||
| 1514 | */ | 1515 | */ |
| 1515 | static int unshare_namespace(unsigned long unshare_flags, struct namespace **new_nsp, struct fs_struct *new_fs) | 1516 | static int unshare_namespace(unsigned long unshare_flags, struct namespace **new_nsp, struct fs_struct *new_fs) |
| 1516 | { | 1517 | { |
| 1517 | struct namespace *ns = current->namespace; | 1518 | struct namespace *ns = current->nsproxy->namespace; |
| 1518 | 1519 | ||
| 1519 | if ((unshare_flags & CLONE_NEWNS) && | 1520 | if ((unshare_flags & CLONE_NEWNS) && ns) { |
| 1520 | (ns && atomic_read(&ns->count) > 1)) { | ||
| 1521 | if (!capable(CAP_SYS_ADMIN)) | 1521 | if (!capable(CAP_SYS_ADMIN)) |
| 1522 | return -EPERM; | 1522 | return -EPERM; |
| 1523 | 1523 | ||
| @@ -1589,6 +1589,16 @@ static int unshare_semundo(unsigned long unshare_flags, struct sem_undo_list **n | |||
| 1589 | return 0; | 1589 | return 0; |
| 1590 | } | 1590 | } |
| 1591 | 1591 | ||
| 1592 | #ifndef CONFIG_IPC_NS | ||
| 1593 | static inline int unshare_ipcs(unsigned long flags, struct ipc_namespace **ns) | ||
| 1594 | { | ||
| 1595 | if (flags & CLONE_NEWIPC) | ||
| 1596 | return -EINVAL; | ||
| 1597 | |||
| 1598 | return 0; | ||
| 1599 | } | ||
| 1600 | #endif | ||
| 1601 | |||
| 1592 | /* | 1602 | /* |
| 1593 | * unshare allows a process to 'unshare' part of the process | 1603 | * unshare allows a process to 'unshare' part of the process |
| 1594 | * context which was originally shared using clone. copy_* | 1604 | * context which was originally shared using clone. copy_* |
| @@ -1606,13 +1616,17 @@ asmlinkage long sys_unshare(unsigned long unshare_flags) | |||
| 1606 | struct mm_struct *mm, *new_mm = NULL, *active_mm = NULL; | 1616 | struct mm_struct *mm, *new_mm = NULL, *active_mm = NULL; |
| 1607 | struct files_struct *fd, *new_fd = NULL; | 1617 | struct files_struct *fd, *new_fd = NULL; |
| 1608 | struct sem_undo_list *new_ulist = NULL; | 1618 | struct sem_undo_list *new_ulist = NULL; |
| 1619 | struct nsproxy *new_nsproxy = NULL, *old_nsproxy = NULL; | ||
| 1620 | struct uts_namespace *uts, *new_uts = NULL; | ||
| 1621 | struct ipc_namespace *ipc, *new_ipc = NULL; | ||
| 1609 | 1622 | ||
| 1610 | check_unshare_flags(&unshare_flags); | 1623 | check_unshare_flags(&unshare_flags); |
| 1611 | 1624 | ||
| 1612 | /* Return -EINVAL for all unsupported flags */ | 1625 | /* Return -EINVAL for all unsupported flags */ |
| 1613 | err = -EINVAL; | 1626 | err = -EINVAL; |
| 1614 | if (unshare_flags & ~(CLONE_THREAD|CLONE_FS|CLONE_NEWNS|CLONE_SIGHAND| | 1627 | if (unshare_flags & ~(CLONE_THREAD|CLONE_FS|CLONE_NEWNS|CLONE_SIGHAND| |
| 1615 | CLONE_VM|CLONE_FILES|CLONE_SYSVSEM)) | 1628 | CLONE_VM|CLONE_FILES|CLONE_SYSVSEM| |
| 1629 | CLONE_NEWUTS|CLONE_NEWIPC)) | ||
| 1616 | goto bad_unshare_out; | 1630 | goto bad_unshare_out; |
| 1617 | 1631 | ||
| 1618 | if ((err = unshare_thread(unshare_flags))) | 1632 | if ((err = unshare_thread(unshare_flags))) |
| @@ -1629,11 +1643,30 @@ asmlinkage long sys_unshare(unsigned long unshare_flags) | |||
| 1629 | goto bad_unshare_cleanup_vm; | 1643 | goto bad_unshare_cleanup_vm; |
| 1630 | if ((err = unshare_semundo(unshare_flags, &new_ulist))) | 1644 | if ((err = unshare_semundo(unshare_flags, &new_ulist))) |
| 1631 | goto bad_unshare_cleanup_fd; | 1645 | goto bad_unshare_cleanup_fd; |
| 1646 | if ((err = unshare_utsname(unshare_flags, &new_uts))) | ||
| 1647 | goto bad_unshare_cleanup_semundo; | ||
| 1648 | if ((err = unshare_ipcs(unshare_flags, &new_ipc))) | ||
| 1649 | goto bad_unshare_cleanup_uts; | ||
| 1650 | |||
| 1651 | if (new_ns || new_uts || new_ipc) { | ||
| 1652 | old_nsproxy = current->nsproxy; | ||
| 1653 | new_nsproxy = dup_namespaces(old_nsproxy); | ||
| 1654 | if (!new_nsproxy) { | ||
| 1655 | err = -ENOMEM; | ||
| 1656 | goto bad_unshare_cleanup_ipc; | ||
| 1657 | } | ||
| 1658 | } | ||
| 1632 | 1659 | ||
| 1633 | if (new_fs || new_ns || new_sigh || new_mm || new_fd || new_ulist) { | 1660 | if (new_fs || new_ns || new_sigh || new_mm || new_fd || new_ulist || |
| 1661 | new_uts || new_ipc) { | ||
| 1634 | 1662 | ||
| 1635 | task_lock(current); | 1663 | task_lock(current); |
| 1636 | 1664 | ||
| 1665 | if (new_nsproxy) { | ||
| 1666 | current->nsproxy = new_nsproxy; | ||
| 1667 | new_nsproxy = old_nsproxy; | ||
| 1668 | } | ||
| 1669 | |||
| 1637 | if (new_fs) { | 1670 | if (new_fs) { |
| 1638 | fs = current->fs; | 1671 | fs = current->fs; |
| 1639 | current->fs = new_fs; | 1672 | current->fs = new_fs; |
| @@ -1641,8 +1674,8 @@ asmlinkage long sys_unshare(unsigned long unshare_flags) | |||
| 1641 | } | 1674 | } |
| 1642 | 1675 | ||
| 1643 | if (new_ns) { | 1676 | if (new_ns) { |
| 1644 | ns = current->namespace; | 1677 | ns = current->nsproxy->namespace; |
| 1645 | current->namespace = new_ns; | 1678 | current->nsproxy->namespace = new_ns; |
| 1646 | new_ns = ns; | 1679 | new_ns = ns; |
| 1647 | } | 1680 | } |
| 1648 | 1681 | ||
| @@ -1667,9 +1700,33 @@ asmlinkage long sys_unshare(unsigned long unshare_flags) | |||
| 1667 | new_fd = fd; | 1700 | new_fd = fd; |
| 1668 | } | 1701 | } |
| 1669 | 1702 | ||
| 1703 | if (new_uts) { | ||
| 1704 | uts = current->nsproxy->uts_ns; | ||
| 1705 | current->nsproxy->uts_ns = new_uts; | ||
| 1706 | new_uts = uts; | ||
| 1707 | } | ||
| 1708 | |||
| 1709 | if (new_ipc) { | ||
| 1710 | ipc = current->nsproxy->ipc_ns; | ||
| 1711 | current->nsproxy->ipc_ns = new_ipc; | ||
| 1712 | new_ipc = ipc; | ||
| 1713 | } | ||
| 1714 | |||
| 1670 | task_unlock(current); | 1715 | task_unlock(current); |
| 1671 | } | 1716 | } |
| 1672 | 1717 | ||
| 1718 | if (new_nsproxy) | ||
| 1719 | put_nsproxy(new_nsproxy); | ||
| 1720 | |||
| 1721 | bad_unshare_cleanup_ipc: | ||
| 1722 | if (new_ipc) | ||
| 1723 | put_ipc_ns(new_ipc); | ||
| 1724 | |||
| 1725 | bad_unshare_cleanup_uts: | ||
| 1726 | if (new_uts) | ||
| 1727 | put_uts_ns(new_uts); | ||
| 1728 | |||
| 1729 | bad_unshare_cleanup_semundo: | ||
| 1673 | bad_unshare_cleanup_fd: | 1730 | bad_unshare_cleanup_fd: |
| 1674 | if (new_fd) | 1731 | if (new_fd) |
| 1675 | put_files_struct(new_fd); | 1732 | put_files_struct(new_fd); |
diff --git a/kernel/futex.c b/kernel/futex.c index 4b6770e9806d..4aaf91951a43 100644 --- a/kernel/futex.c +++ b/kernel/futex.c | |||
| @@ -1527,7 +1527,7 @@ static int futex_fd(u32 __user *uaddr, int signal) | |||
| 1527 | filp->f_mapping = filp->f_dentry->d_inode->i_mapping; | 1527 | filp->f_mapping = filp->f_dentry->d_inode->i_mapping; |
| 1528 | 1528 | ||
| 1529 | if (signal) { | 1529 | if (signal) { |
| 1530 | err = f_setown(filp, current->pid, 1); | 1530 | err = __f_setown(filp, task_pid(current), PIDTYPE_PID, 1); |
| 1531 | if (err < 0) { | 1531 | if (err < 0) { |
| 1532 | goto error; | 1532 | goto error; |
| 1533 | } | 1533 | } |
diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c index ab16a5a4cfe9..342bca62c496 100644 --- a/kernel/kallsyms.c +++ b/kernel/kallsyms.c | |||
| @@ -154,7 +154,6 @@ unsigned long kallsyms_lookup_name(const char *name) | |||
| 154 | } | 154 | } |
| 155 | return module_kallsyms_lookup_name(name); | 155 | return module_kallsyms_lookup_name(name); |
| 156 | } | 156 | } |
| 157 | EXPORT_SYMBOL_GPL(kallsyms_lookup_name); | ||
| 158 | 157 | ||
| 159 | /* | 158 | /* |
| 160 | * Lookup an address | 159 | * Lookup an address |
diff --git a/kernel/kmod.c b/kernel/kmod.c index f8121b95183f..bb4e29d924e4 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c | |||
| @@ -18,8 +18,6 @@ | |||
| 18 | call_usermodehelper wait flag, and remove exec_usermodehelper. | 18 | call_usermodehelper wait flag, and remove exec_usermodehelper. |
| 19 | Rusty Russell <rusty@rustcorp.com.au> Jan 2003 | 19 | Rusty Russell <rusty@rustcorp.com.au> Jan 2003 |
| 20 | */ | 20 | */ |
| 21 | #define __KERNEL_SYSCALLS__ | ||
| 22 | |||
| 23 | #include <linux/module.h> | 21 | #include <linux/module.h> |
| 24 | #include <linux/sched.h> | 22 | #include <linux/sched.h> |
| 25 | #include <linux/syscalls.h> | 23 | #include <linux/syscalls.h> |
| @@ -169,7 +167,8 @@ static int ____call_usermodehelper(void *data) | |||
| 169 | 167 | ||
| 170 | retval = -EPERM; | 168 | retval = -EPERM; |
| 171 | if (current->fs->root) | 169 | if (current->fs->root) |
| 172 | retval = execve(sub_info->path, sub_info->argv, sub_info->envp); | 170 | retval = kernel_execve(sub_info->path, |
| 171 | sub_info->argv, sub_info->envp); | ||
| 173 | 172 | ||
| 174 | /* Exec failed? */ | 173 | /* Exec failed? */ |
| 175 | sub_info->retval = retval; | 174 | sub_info->retval = retval; |
diff --git a/kernel/kprobes.c b/kernel/kprobes.c index 3f57dfdc8f92..610c837ad9e0 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c | |||
| @@ -37,6 +37,7 @@ | |||
| 37 | #include <linux/slab.h> | 37 | #include <linux/slab.h> |
| 38 | #include <linux/module.h> | 38 | #include <linux/module.h> |
| 39 | #include <linux/moduleloader.h> | 39 | #include <linux/moduleloader.h> |
| 40 | #include <linux/kallsyms.h> | ||
| 40 | #include <asm-generic/sections.h> | 41 | #include <asm-generic/sections.h> |
| 41 | #include <asm/cacheflush.h> | 42 | #include <asm/cacheflush.h> |
| 42 | #include <asm/errno.h> | 43 | #include <asm/errno.h> |
| @@ -45,6 +46,16 @@ | |||
| 45 | #define KPROBE_HASH_BITS 6 | 46 | #define KPROBE_HASH_BITS 6 |
| 46 | #define KPROBE_TABLE_SIZE (1 << KPROBE_HASH_BITS) | 47 | #define KPROBE_TABLE_SIZE (1 << KPROBE_HASH_BITS) |
| 47 | 48 | ||
| 49 | |||
| 50 | /* | ||
| 51 | * Some oddball architectures like 64bit powerpc have function descriptors | ||
| 52 | * so this must be overridable. | ||
| 53 | */ | ||
| 54 | #ifndef kprobe_lookup_name | ||
| 55 | #define kprobe_lookup_name(name, addr) \ | ||
| 56 | addr = ((kprobe_opcode_t *)(kallsyms_lookup_name(name))) | ||
| 57 | #endif | ||
| 58 | |||
| 48 | static struct hlist_head kprobe_table[KPROBE_TABLE_SIZE]; | 59 | static struct hlist_head kprobe_table[KPROBE_TABLE_SIZE]; |
| 49 | static struct hlist_head kretprobe_inst_table[KPROBE_TABLE_SIZE]; | 60 | static struct hlist_head kretprobe_inst_table[KPROBE_TABLE_SIZE]; |
| 50 | static atomic_t kprobe_count; | 61 | static atomic_t kprobe_count; |
| @@ -308,7 +319,8 @@ void __kprobes add_rp_inst(struct kretprobe_instance *ri) | |||
| 308 | } | 319 | } |
| 309 | 320 | ||
| 310 | /* Called with kretprobe_lock held */ | 321 | /* Called with kretprobe_lock held */ |
| 311 | void __kprobes recycle_rp_inst(struct kretprobe_instance *ri) | 322 | void __kprobes recycle_rp_inst(struct kretprobe_instance *ri, |
| 323 | struct hlist_head *head) | ||
| 312 | { | 324 | { |
| 313 | /* remove rp inst off the rprobe_inst_table */ | 325 | /* remove rp inst off the rprobe_inst_table */ |
| 314 | hlist_del(&ri->hlist); | 326 | hlist_del(&ri->hlist); |
| @@ -320,7 +332,7 @@ void __kprobes recycle_rp_inst(struct kretprobe_instance *ri) | |||
| 320 | hlist_add_head(&ri->uflist, &ri->rp->free_instances); | 332 | hlist_add_head(&ri->uflist, &ri->rp->free_instances); |
| 321 | } else | 333 | } else |
| 322 | /* Unregistering */ | 334 | /* Unregistering */ |
| 323 | kfree(ri); | 335 | hlist_add_head(&ri->hlist, head); |
| 324 | } | 336 | } |
| 325 | 337 | ||
| 326 | struct hlist_head __kprobes *kretprobe_inst_table_head(struct task_struct *tsk) | 338 | struct hlist_head __kprobes *kretprobe_inst_table_head(struct task_struct *tsk) |
| @@ -336,18 +348,24 @@ struct hlist_head __kprobes *kretprobe_inst_table_head(struct task_struct *tsk) | |||
| 336 | */ | 348 | */ |
| 337 | void __kprobes kprobe_flush_task(struct task_struct *tk) | 349 | void __kprobes kprobe_flush_task(struct task_struct *tk) |
| 338 | { | 350 | { |
| 339 | struct kretprobe_instance *ri; | 351 | struct kretprobe_instance *ri; |
| 340 | struct hlist_head *head; | 352 | struct hlist_head *head, empty_rp; |
| 341 | struct hlist_node *node, *tmp; | 353 | struct hlist_node *node, *tmp; |
| 342 | unsigned long flags = 0; | 354 | unsigned long flags = 0; |
| 343 | 355 | ||
| 356 | INIT_HLIST_HEAD(&empty_rp); | ||
| 344 | spin_lock_irqsave(&kretprobe_lock, flags); | 357 | spin_lock_irqsave(&kretprobe_lock, flags); |
| 345 | head = kretprobe_inst_table_head(tk); | 358 | head = kretprobe_inst_table_head(tk); |
| 346 | hlist_for_each_entry_safe(ri, node, tmp, head, hlist) { | 359 | hlist_for_each_entry_safe(ri, node, tmp, head, hlist) { |
| 347 | if (ri->task == tk) | 360 | if (ri->task == tk) |
| 348 | recycle_rp_inst(ri); | 361 | recycle_rp_inst(ri, &empty_rp); |
| 349 | } | 362 | } |
| 350 | spin_unlock_irqrestore(&kretprobe_lock, flags); | 363 | spin_unlock_irqrestore(&kretprobe_lock, flags); |
| 364 | |||
| 365 | hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist) { | ||
| 366 | hlist_del(&ri->hlist); | ||
| 367 | kfree(ri); | ||
| 368 | } | ||
| 351 | } | 369 | } |
| 352 | 370 | ||
| 353 | static inline void free_rp_inst(struct kretprobe *rp) | 371 | static inline void free_rp_inst(struct kretprobe *rp) |
| @@ -447,6 +465,21 @@ static int __kprobes __register_kprobe(struct kprobe *p, | |||
| 447 | struct kprobe *old_p; | 465 | struct kprobe *old_p; |
| 448 | struct module *probed_mod; | 466 | struct module *probed_mod; |
| 449 | 467 | ||
| 468 | /* | ||
| 469 | * If we have a symbol_name argument look it up, | ||
| 470 | * and add it to the address. That way the addr | ||
| 471 | * field can either be global or relative to a symbol. | ||
| 472 | */ | ||
| 473 | if (p->symbol_name) { | ||
| 474 | if (p->addr) | ||
| 475 | return -EINVAL; | ||
| 476 | kprobe_lookup_name(p->symbol_name, p->addr); | ||
| 477 | } | ||
| 478 | |||
| 479 | if (!p->addr) | ||
| 480 | return -EINVAL; | ||
| 481 | p->addr = (kprobe_opcode_t *)(((char *)p->addr)+ p->offset); | ||
| 482 | |||
| 450 | if ((!kernel_text_address((unsigned long) p->addr)) || | 483 | if ((!kernel_text_address((unsigned long) p->addr)) || |
| 451 | in_kprobes_functions((unsigned long) p->addr)) | 484 | in_kprobes_functions((unsigned long) p->addr)) |
| 452 | return -EINVAL; | 485 | return -EINVAL; |
| @@ -488,7 +521,7 @@ static int __kprobes __register_kprobe(struct kprobe *p, | |||
| 488 | (ARCH_INACTIVE_KPROBE_COUNT + 1)) | 521 | (ARCH_INACTIVE_KPROBE_COUNT + 1)) |
| 489 | register_page_fault_notifier(&kprobe_page_fault_nb); | 522 | register_page_fault_notifier(&kprobe_page_fault_nb); |
| 490 | 523 | ||
| 491 | arch_arm_kprobe(p); | 524 | arch_arm_kprobe(p); |
| 492 | 525 | ||
| 493 | out: | 526 | out: |
| 494 | mutex_unlock(&kprobe_mutex); | 527 | mutex_unlock(&kprobe_mutex); |
diff --git a/kernel/lockdep.c b/kernel/lockdep.c index e596525669ed..4c0553461000 100644 --- a/kernel/lockdep.c +++ b/kernel/lockdep.c | |||
| @@ -518,9 +518,9 @@ print_circular_bug_entry(struct lock_list *target, unsigned int depth) | |||
| 518 | 518 | ||
| 519 | static void print_kernel_version(void) | 519 | static void print_kernel_version(void) |
| 520 | { | 520 | { |
| 521 | printk("%s %.*s\n", system_utsname.release, | 521 | printk("%s %.*s\n", init_utsname()->release, |
| 522 | (int)strcspn(system_utsname.version, " "), | 522 | (int)strcspn(init_utsname()->version, " "), |
| 523 | system_utsname.version); | 523 | init_utsname()->version); |
| 524 | } | 524 | } |
| 525 | 525 | ||
| 526 | /* | 526 | /* |
diff --git a/kernel/module.c b/kernel/module.c index 05625d5dc758..7c77a0a9275c 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
| @@ -851,6 +851,7 @@ static int check_version(Elf_Shdr *sechdrs, | |||
| 851 | printk("%s: no version for \"%s\" found: kernel tainted.\n", | 851 | printk("%s: no version for \"%s\" found: kernel tainted.\n", |
| 852 | mod->name, symname); | 852 | mod->name, symname); |
| 853 | add_taint(TAINT_FORCED_MODULE); | 853 | add_taint(TAINT_FORCED_MODULE); |
| 854 | mod->taints |= TAINT_FORCED_MODULE; | ||
| 854 | } | 855 | } |
| 855 | return 1; | 856 | return 1; |
| 856 | } | 857 | } |
| @@ -1339,6 +1340,7 @@ static void set_license(struct module *mod, const char *license) | |||
| 1339 | printk(KERN_WARNING "%s: module license '%s' taints kernel.\n", | 1340 | printk(KERN_WARNING "%s: module license '%s' taints kernel.\n", |
| 1340 | mod->name, license); | 1341 | mod->name, license); |
| 1341 | add_taint(TAINT_PROPRIETARY_MODULE); | 1342 | add_taint(TAINT_PROPRIETARY_MODULE); |
| 1343 | mod->taints |= TAINT_PROPRIETARY_MODULE; | ||
| 1342 | } | 1344 | } |
| 1343 | } | 1345 | } |
| 1344 | 1346 | ||
| @@ -1618,6 +1620,7 @@ static struct module *load_module(void __user *umod, | |||
| 1618 | /* This is allowed: modprobe --force will invalidate it. */ | 1620 | /* This is allowed: modprobe --force will invalidate it. */ |
| 1619 | if (!modmagic) { | 1621 | if (!modmagic) { |
| 1620 | add_taint(TAINT_FORCED_MODULE); | 1622 | add_taint(TAINT_FORCED_MODULE); |
| 1623 | mod->taints |= TAINT_FORCED_MODULE; | ||
| 1621 | printk(KERN_WARNING "%s: no version magic, tainting kernel.\n", | 1624 | printk(KERN_WARNING "%s: no version magic, tainting kernel.\n", |
| 1622 | mod->name); | 1625 | mod->name); |
| 1623 | } else if (!same_magic(modmagic, vermagic)) { | 1626 | } else if (!same_magic(modmagic, vermagic)) { |
| @@ -1711,10 +1714,14 @@ static struct module *load_module(void __user *umod, | |||
| 1711 | /* Set up license info based on the info section */ | 1714 | /* Set up license info based on the info section */ |
| 1712 | set_license(mod, get_modinfo(sechdrs, infoindex, "license")); | 1715 | set_license(mod, get_modinfo(sechdrs, infoindex, "license")); |
| 1713 | 1716 | ||
| 1714 | if (strcmp(mod->name, "ndiswrapper") == 0) | 1717 | if (strcmp(mod->name, "ndiswrapper") == 0) { |
| 1715 | add_taint(TAINT_PROPRIETARY_MODULE); | 1718 | add_taint(TAINT_PROPRIETARY_MODULE); |
| 1716 | if (strcmp(mod->name, "driverloader") == 0) | 1719 | mod->taints |= TAINT_PROPRIETARY_MODULE; |
| 1720 | } | ||
| 1721 | if (strcmp(mod->name, "driverloader") == 0) { | ||
| 1717 | add_taint(TAINT_PROPRIETARY_MODULE); | 1722 | add_taint(TAINT_PROPRIETARY_MODULE); |
| 1723 | mod->taints |= TAINT_PROPRIETARY_MODULE; | ||
| 1724 | } | ||
| 1718 | 1725 | ||
| 1719 | /* Set up MODINFO_ATTR fields */ | 1726 | /* Set up MODINFO_ATTR fields */ |
| 1720 | setup_modinfo(mod, sechdrs, infoindex); | 1727 | setup_modinfo(mod, sechdrs, infoindex); |
| @@ -1760,6 +1767,7 @@ static struct module *load_module(void __user *umod, | |||
| 1760 | printk(KERN_WARNING "%s: No versions for exported symbols." | 1767 | printk(KERN_WARNING "%s: No versions for exported symbols." |
| 1761 | " Tainting kernel.\n", mod->name); | 1768 | " Tainting kernel.\n", mod->name); |
| 1762 | add_taint(TAINT_FORCED_MODULE); | 1769 | add_taint(TAINT_FORCED_MODULE); |
| 1770 | mod->taints |= TAINT_FORCED_MODULE; | ||
| 1763 | } | 1771 | } |
| 1764 | #endif | 1772 | #endif |
| 1765 | 1773 | ||
| @@ -2226,14 +2234,37 @@ struct module *module_text_address(unsigned long addr) | |||
| 2226 | return mod; | 2234 | return mod; |
| 2227 | } | 2235 | } |
| 2228 | 2236 | ||
| 2237 | static char *taint_flags(unsigned int taints, char *buf) | ||
| 2238 | { | ||
| 2239 | *buf = '\0'; | ||
| 2240 | if (taints) { | ||
| 2241 | int bx; | ||
| 2242 | |||
| 2243 | buf[0] = '('; | ||
| 2244 | bx = 1; | ||
| 2245 | if (taints & TAINT_PROPRIETARY_MODULE) | ||
| 2246 | buf[bx++] = 'P'; | ||
| 2247 | if (taints & TAINT_FORCED_MODULE) | ||
| 2248 | buf[bx++] = 'F'; | ||
| 2249 | /* | ||
| 2250 | * TAINT_FORCED_RMMOD: could be added. | ||
| 2251 | * TAINT_UNSAFE_SMP, TAINT_MACHINE_CHECK, TAINT_BAD_PAGE don't | ||
| 2252 | * apply to modules. | ||
| 2253 | */ | ||
| 2254 | buf[bx] = ')'; | ||
| 2255 | } | ||
| 2256 | return buf; | ||
| 2257 | } | ||
| 2258 | |||
| 2229 | /* Don't grab lock, we're oopsing. */ | 2259 | /* Don't grab lock, we're oopsing. */ |
| 2230 | void print_modules(void) | 2260 | void print_modules(void) |
| 2231 | { | 2261 | { |
| 2232 | struct module *mod; | 2262 | struct module *mod; |
| 2263 | char buf[8]; | ||
| 2233 | 2264 | ||
| 2234 | printk("Modules linked in:"); | 2265 | printk("Modules linked in:"); |
| 2235 | list_for_each_entry(mod, &modules, list) | 2266 | list_for_each_entry(mod, &modules, list) |
| 2236 | printk(" %s", mod->name); | 2267 | printk(" %s%s", mod->name, taint_flags(mod->taints, buf)); |
| 2237 | printk("\n"); | 2268 | printk("\n"); |
| 2238 | } | 2269 | } |
| 2239 | 2270 | ||
diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c new file mode 100644 index 000000000000..6ebdb82a0ce4 --- /dev/null +++ b/kernel/nsproxy.c | |||
| @@ -0,0 +1,139 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2006 IBM Corporation | ||
| 3 | * | ||
| 4 | * Author: Serge Hallyn <serue@us.ibm.com> | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public License as | ||
| 8 | * published by the Free Software Foundation, version 2 of the | ||
| 9 | * License. | ||
| 10 | * | ||
| 11 | * Jun 2006 - namespaces support | ||
| 12 | * OpenVZ, SWsoft Inc. | ||
| 13 | * Pavel Emelianov <xemul@openvz.org> | ||
| 14 | */ | ||
| 15 | |||
| 16 | #include <linux/module.h> | ||
| 17 | #include <linux/version.h> | ||
| 18 | #include <linux/nsproxy.h> | ||
| 19 | #include <linux/init_task.h> | ||
| 20 | #include <linux/namespace.h> | ||
| 21 | #include <linux/utsname.h> | ||
| 22 | |||
| 23 | struct nsproxy init_nsproxy = INIT_NSPROXY(init_nsproxy); | ||
| 24 | |||
| 25 | static inline void get_nsproxy(struct nsproxy *ns) | ||
| 26 | { | ||
| 27 | atomic_inc(&ns->count); | ||
| 28 | } | ||
| 29 | |||
| 30 | void get_task_namespaces(struct task_struct *tsk) | ||
| 31 | { | ||
| 32 | struct nsproxy *ns = tsk->nsproxy; | ||
| 33 | if (ns) { | ||
| 34 | get_nsproxy(ns); | ||
| 35 | } | ||
| 36 | } | ||
| 37 | |||
| 38 | /* | ||
| 39 | * creates a copy of "orig" with refcount 1. | ||
| 40 | * This does not grab references to the contained namespaces, | ||
| 41 | * so that needs to be done by dup_namespaces. | ||
| 42 | */ | ||
| 43 | static inline struct nsproxy *clone_namespaces(struct nsproxy *orig) | ||
| 44 | { | ||
| 45 | struct nsproxy *ns; | ||
| 46 | |||
| 47 | ns = kmalloc(sizeof(struct nsproxy), GFP_KERNEL); | ||
| 48 | if (ns) { | ||
| 49 | memcpy(ns, orig, sizeof(struct nsproxy)); | ||
| 50 | atomic_set(&ns->count, 1); | ||
| 51 | } | ||
| 52 | return ns; | ||
| 53 | } | ||
| 54 | |||
| 55 | /* | ||
| 56 | * copies the nsproxy, setting refcount to 1, and grabbing a | ||
| 57 | * reference to all contained namespaces. Called from | ||
| 58 | * sys_unshare() | ||
| 59 | */ | ||
| 60 | struct nsproxy *dup_namespaces(struct nsproxy *orig) | ||
| 61 | { | ||
| 62 | struct nsproxy *ns = clone_namespaces(orig); | ||
| 63 | |||
| 64 | if (ns) { | ||
| 65 | if (ns->namespace) | ||
| 66 | get_namespace(ns->namespace); | ||
| 67 | if (ns->uts_ns) | ||
| 68 | get_uts_ns(ns->uts_ns); | ||
| 69 | if (ns->ipc_ns) | ||
| 70 | get_ipc_ns(ns->ipc_ns); | ||
| 71 | } | ||
| 72 | |||
| 73 | return ns; | ||
| 74 | } | ||
| 75 | |||
| 76 | /* | ||
| 77 | * called from clone. This now handles copy for nsproxy and all | ||
| 78 | * namespaces therein. | ||
| 79 | */ | ||
| 80 | int copy_namespaces(int flags, struct task_struct *tsk) | ||
| 81 | { | ||
| 82 | struct nsproxy *old_ns = tsk->nsproxy; | ||
| 83 | struct nsproxy *new_ns; | ||
| 84 | int err = 0; | ||
| 85 | |||
| 86 | if (!old_ns) | ||
| 87 | return 0; | ||
| 88 | |||
| 89 | get_nsproxy(old_ns); | ||
| 90 | |||
| 91 | if (!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC))) | ||
| 92 | return 0; | ||
| 93 | |||
| 94 | new_ns = clone_namespaces(old_ns); | ||
| 95 | if (!new_ns) { | ||
| 96 | err = -ENOMEM; | ||
| 97 | goto out; | ||
| 98 | } | ||
| 99 | |||
| 100 | tsk->nsproxy = new_ns; | ||
| 101 | |||
| 102 | err = copy_namespace(flags, tsk); | ||
| 103 | if (err) | ||
| 104 | goto out_ns; | ||
| 105 | |||
| 106 | err = copy_utsname(flags, tsk); | ||
| 107 | if (err) | ||
| 108 | goto out_uts; | ||
| 109 | |||
| 110 | err = copy_ipcs(flags, tsk); | ||
| 111 | if (err) | ||
| 112 | goto out_ipc; | ||
| 113 | |||
| 114 | out: | ||
| 115 | put_nsproxy(old_ns); | ||
| 116 | return err; | ||
| 117 | |||
| 118 | out_ipc: | ||
| 119 | if (new_ns->uts_ns) | ||
| 120 | put_uts_ns(new_ns->uts_ns); | ||
| 121 | out_uts: | ||
| 122 | if (new_ns->namespace) | ||
| 123 | put_namespace(new_ns->namespace); | ||
| 124 | out_ns: | ||
| 125 | tsk->nsproxy = old_ns; | ||
| 126 | kfree(new_ns); | ||
| 127 | goto out; | ||
| 128 | } | ||
| 129 | |||
| 130 | void free_nsproxy(struct nsproxy *ns) | ||
| 131 | { | ||
| 132 | if (ns->namespace) | ||
| 133 | put_namespace(ns->namespace); | ||
| 134 | if (ns->uts_ns) | ||
| 135 | put_uts_ns(ns->uts_ns); | ||
| 136 | if (ns->ipc_ns) | ||
| 137 | put_ipc_ns(ns->ipc_ns); | ||
| 138 | kfree(ns); | ||
| 139 | } | ||
diff --git a/kernel/pid.c b/kernel/pid.c index 8387e8c68193..b914392085f9 100644 --- a/kernel/pid.c +++ b/kernel/pid.c | |||
| @@ -26,6 +26,7 @@ | |||
| 26 | #include <linux/init.h> | 26 | #include <linux/init.h> |
| 27 | #include <linux/bootmem.h> | 27 | #include <linux/bootmem.h> |
| 28 | #include <linux/hash.h> | 28 | #include <linux/hash.h> |
| 29 | #include <linux/pspace.h> | ||
| 29 | 30 | ||
| 30 | #define pid_hashfn(nr) hash_long((unsigned long)nr, pidhash_shift) | 31 | #define pid_hashfn(nr) hash_long((unsigned long)nr, pidhash_shift) |
| 31 | static struct hlist_head *pid_hash; | 32 | static struct hlist_head *pid_hash; |
| @@ -33,17 +34,20 @@ static int pidhash_shift; | |||
| 33 | static kmem_cache_t *pid_cachep; | 34 | static kmem_cache_t *pid_cachep; |
| 34 | 35 | ||
| 35 | int pid_max = PID_MAX_DEFAULT; | 36 | int pid_max = PID_MAX_DEFAULT; |
| 36 | int last_pid; | ||
| 37 | 37 | ||
| 38 | #define RESERVED_PIDS 300 | 38 | #define RESERVED_PIDS 300 |
| 39 | 39 | ||
| 40 | int pid_max_min = RESERVED_PIDS + 1; | 40 | int pid_max_min = RESERVED_PIDS + 1; |
| 41 | int pid_max_max = PID_MAX_LIMIT; | 41 | int pid_max_max = PID_MAX_LIMIT; |
| 42 | 42 | ||
| 43 | #define PIDMAP_ENTRIES ((PID_MAX_LIMIT + 8*PAGE_SIZE - 1)/PAGE_SIZE/8) | ||
| 44 | #define BITS_PER_PAGE (PAGE_SIZE*8) | 43 | #define BITS_PER_PAGE (PAGE_SIZE*8) |
| 45 | #define BITS_PER_PAGE_MASK (BITS_PER_PAGE-1) | 44 | #define BITS_PER_PAGE_MASK (BITS_PER_PAGE-1) |
| 46 | #define mk_pid(map, off) (((map) - pidmap_array)*BITS_PER_PAGE + (off)) | 45 | |
| 46 | static inline int mk_pid(struct pspace *pspace, struct pidmap *map, int off) | ||
| 47 | { | ||
| 48 | return (map - pspace->pidmap)*BITS_PER_PAGE + off; | ||
| 49 | } | ||
| 50 | |||
| 47 | #define find_next_offset(map, off) \ | 51 | #define find_next_offset(map, off) \ |
| 48 | find_next_zero_bit((map)->page, BITS_PER_PAGE, off) | 52 | find_next_zero_bit((map)->page, BITS_PER_PAGE, off) |
| 49 | 53 | ||
| @@ -53,13 +57,12 @@ int pid_max_max = PID_MAX_LIMIT; | |||
| 53 | * value does not cause lots of bitmaps to be allocated, but | 57 | * value does not cause lots of bitmaps to be allocated, but |
| 54 | * the scheme scales to up to 4 million PIDs, runtime. | 58 | * the scheme scales to up to 4 million PIDs, runtime. |
| 55 | */ | 59 | */ |
| 56 | typedef struct pidmap { | 60 | struct pspace init_pspace = { |
| 57 | atomic_t nr_free; | 61 | .pidmap = { |
| 58 | void *page; | 62 | [ 0 ... PIDMAP_ENTRIES-1] = { ATOMIC_INIT(BITS_PER_PAGE), NULL } |
| 59 | } pidmap_t; | 63 | }, |
| 60 | 64 | .last_pid = 0 | |
| 61 | static pidmap_t pidmap_array[PIDMAP_ENTRIES] = | 65 | }; |
| 62 | { [ 0 ... PIDMAP_ENTRIES-1 ] = { ATOMIC_INIT(BITS_PER_PAGE), NULL } }; | ||
| 63 | 66 | ||
| 64 | /* | 67 | /* |
| 65 | * Note: disable interrupts while the pidmap_lock is held as an | 68 | * Note: disable interrupts while the pidmap_lock is held as an |
| @@ -74,40 +77,41 @@ static pidmap_t pidmap_array[PIDMAP_ENTRIES] = | |||
| 74 | * irq handlers that take it we can leave the interrupts enabled. | 77 | * irq handlers that take it we can leave the interrupts enabled. |
| 75 | * For now it is easier to be safe than to prove it can't happen. | 78 | * For now it is easier to be safe than to prove it can't happen. |
| 76 | */ | 79 | */ |
| 80 | |||
| 77 | static __cacheline_aligned_in_smp DEFINE_SPINLOCK(pidmap_lock); | 81 | static __cacheline_aligned_in_smp DEFINE_SPINLOCK(pidmap_lock); |
| 78 | 82 | ||
| 79 | static fastcall void free_pidmap(int pid) | 83 | static fastcall void free_pidmap(struct pspace *pspace, int pid) |
| 80 | { | 84 | { |
| 81 | pidmap_t *map = pidmap_array + pid / BITS_PER_PAGE; | 85 | struct pidmap *map = pspace->pidmap + pid / BITS_PER_PAGE; |
| 82 | int offset = pid & BITS_PER_PAGE_MASK; | 86 | int offset = pid & BITS_PER_PAGE_MASK; |
| 83 | 87 | ||
| 84 | clear_bit(offset, map->page); | 88 | clear_bit(offset, map->page); |
| 85 | atomic_inc(&map->nr_free); | 89 | atomic_inc(&map->nr_free); |
| 86 | } | 90 | } |
| 87 | 91 | ||
| 88 | static int alloc_pidmap(void) | 92 | static int alloc_pidmap(struct pspace *pspace) |
| 89 | { | 93 | { |
| 90 | int i, offset, max_scan, pid, last = last_pid; | 94 | int i, offset, max_scan, pid, last = pspace->last_pid; |
| 91 | pidmap_t *map; | 95 | struct pidmap *map; |
| 92 | 96 | ||
| 93 | pid = last + 1; | 97 | pid = last + 1; |
| 94 | if (pid >= pid_max) | 98 | if (pid >= pid_max) |
| 95 | pid = RESERVED_PIDS; | 99 | pid = RESERVED_PIDS; |
| 96 | offset = pid & BITS_PER_PAGE_MASK; | 100 | offset = pid & BITS_PER_PAGE_MASK; |
| 97 | map = &pidmap_array[pid/BITS_PER_PAGE]; | 101 | map = &pspace->pidmap[pid/BITS_PER_PAGE]; |
| 98 | max_scan = (pid_max + BITS_PER_PAGE - 1)/BITS_PER_PAGE - !offset; | 102 | max_scan = (pid_max + BITS_PER_PAGE - 1)/BITS_PER_PAGE - !offset; |
| 99 | for (i = 0; i <= max_scan; ++i) { | 103 | for (i = 0; i <= max_scan; ++i) { |
| 100 | if (unlikely(!map->page)) { | 104 | if (unlikely(!map->page)) { |
| 101 | unsigned long page = get_zeroed_page(GFP_KERNEL); | 105 | void *page = kzalloc(PAGE_SIZE, GFP_KERNEL); |
| 102 | /* | 106 | /* |
| 103 | * Free the page if someone raced with us | 107 | * Free the page if someone raced with us |
| 104 | * installing it: | 108 | * installing it: |
| 105 | */ | 109 | */ |
| 106 | spin_lock_irq(&pidmap_lock); | 110 | spin_lock_irq(&pidmap_lock); |
| 107 | if (map->page) | 111 | if (map->page) |
| 108 | free_page(page); | 112 | kfree(page); |
| 109 | else | 113 | else |
| 110 | map->page = (void *)page; | 114 | map->page = page; |
| 111 | spin_unlock_irq(&pidmap_lock); | 115 | spin_unlock_irq(&pidmap_lock); |
| 112 | if (unlikely(!map->page)) | 116 | if (unlikely(!map->page)) |
| 113 | break; | 117 | break; |
| @@ -116,11 +120,11 @@ static int alloc_pidmap(void) | |||
| 116 | do { | 120 | do { |
| 117 | if (!test_and_set_bit(offset, map->page)) { | 121 | if (!test_and_set_bit(offset, map->page)) { |
| 118 | atomic_dec(&map->nr_free); | 122 | atomic_dec(&map->nr_free); |
| 119 | last_pid = pid; | 123 | pspace->last_pid = pid; |
| 120 | return pid; | 124 | return pid; |
| 121 | } | 125 | } |
| 122 | offset = find_next_offset(map, offset); | 126 | offset = find_next_offset(map, offset); |
| 123 | pid = mk_pid(map, offset); | 127 | pid = mk_pid(pspace, map, offset); |
| 124 | /* | 128 | /* |
| 125 | * find_next_offset() found a bit, the pid from it | 129 | * find_next_offset() found a bit, the pid from it |
| 126 | * is in-bounds, and if we fell back to the last | 130 | * is in-bounds, and if we fell back to the last |
| @@ -131,16 +135,34 @@ static int alloc_pidmap(void) | |||
| 131 | (i != max_scan || pid < last || | 135 | (i != max_scan || pid < last || |
| 132 | !((last+1) & BITS_PER_PAGE_MASK))); | 136 | !((last+1) & BITS_PER_PAGE_MASK))); |
| 133 | } | 137 | } |
| 134 | if (map < &pidmap_array[(pid_max-1)/BITS_PER_PAGE]) { | 138 | if (map < &pspace->pidmap[(pid_max-1)/BITS_PER_PAGE]) { |
| 135 | ++map; | 139 | ++map; |
| 136 | offset = 0; | 140 | offset = 0; |
| 137 | } else { | 141 | } else { |
| 138 | map = &pidmap_array[0]; | 142 | map = &pspace->pidmap[0]; |
| 139 | offset = RESERVED_PIDS; | 143 | offset = RESERVED_PIDS; |
| 140 | if (unlikely(last == offset)) | 144 | if (unlikely(last == offset)) |
| 141 | break; | 145 | break; |
| 142 | } | 146 | } |
| 143 | pid = mk_pid(map, offset); | 147 | pid = mk_pid(pspace, map, offset); |
| 148 | } | ||
| 149 | return -1; | ||
| 150 | } | ||
| 151 | |||
| 152 | static int next_pidmap(struct pspace *pspace, int last) | ||
| 153 | { | ||
| 154 | int offset; | ||
| 155 | struct pidmap *map, *end; | ||
| 156 | |||
| 157 | offset = (last + 1) & BITS_PER_PAGE_MASK; | ||
| 158 | map = &pspace->pidmap[(last + 1)/BITS_PER_PAGE]; | ||
| 159 | end = &pspace->pidmap[PIDMAP_ENTRIES]; | ||
| 160 | for (; map < end; map++, offset = 0) { | ||
| 161 | if (unlikely(!map->page)) | ||
| 162 | continue; | ||
| 163 | offset = find_next_bit((map)->page, BITS_PER_PAGE, offset); | ||
| 164 | if (offset < BITS_PER_PAGE) | ||
| 165 | return mk_pid(pspace, map, offset); | ||
| 144 | } | 166 | } |
| 145 | return -1; | 167 | return -1; |
| 146 | } | 168 | } |
| @@ -153,6 +175,7 @@ fastcall void put_pid(struct pid *pid) | |||
| 153 | atomic_dec_and_test(&pid->count)) | 175 | atomic_dec_and_test(&pid->count)) |
| 154 | kmem_cache_free(pid_cachep, pid); | 176 | kmem_cache_free(pid_cachep, pid); |
| 155 | } | 177 | } |
| 178 | EXPORT_SYMBOL_GPL(put_pid); | ||
| 156 | 179 | ||
| 157 | static void delayed_put_pid(struct rcu_head *rhp) | 180 | static void delayed_put_pid(struct rcu_head *rhp) |
| 158 | { | 181 | { |
| @@ -169,7 +192,7 @@ fastcall void free_pid(struct pid *pid) | |||
| 169 | hlist_del_rcu(&pid->pid_chain); | 192 | hlist_del_rcu(&pid->pid_chain); |
| 170 | spin_unlock_irqrestore(&pidmap_lock, flags); | 193 | spin_unlock_irqrestore(&pidmap_lock, flags); |
| 171 | 194 | ||
| 172 | free_pidmap(pid->nr); | 195 | free_pidmap(&init_pspace, pid->nr); |
| 173 | call_rcu(&pid->rcu, delayed_put_pid); | 196 | call_rcu(&pid->rcu, delayed_put_pid); |
| 174 | } | 197 | } |
| 175 | 198 | ||
| @@ -183,7 +206,7 @@ struct pid *alloc_pid(void) | |||
| 183 | if (!pid) | 206 | if (!pid) |
| 184 | goto out; | 207 | goto out; |
| 185 | 208 | ||
| 186 | nr = alloc_pidmap(); | 209 | nr = alloc_pidmap(&init_pspace); |
| 187 | if (nr < 0) | 210 | if (nr < 0) |
| 188 | goto out_free; | 211 | goto out_free; |
| 189 | 212 | ||
| @@ -217,6 +240,7 @@ struct pid * fastcall find_pid(int nr) | |||
| 217 | } | 240 | } |
| 218 | return NULL; | 241 | return NULL; |
| 219 | } | 242 | } |
| 243 | EXPORT_SYMBOL_GPL(find_pid); | ||
| 220 | 244 | ||
| 221 | int fastcall attach_pid(struct task_struct *task, enum pid_type type, int nr) | 245 | int fastcall attach_pid(struct task_struct *task, enum pid_type type, int nr) |
| 222 | { | 246 | { |
| @@ -280,6 +304,15 @@ struct task_struct *find_task_by_pid_type(int type, int nr) | |||
| 280 | 304 | ||
| 281 | EXPORT_SYMBOL(find_task_by_pid_type); | 305 | EXPORT_SYMBOL(find_task_by_pid_type); |
| 282 | 306 | ||
| 307 | struct pid *get_task_pid(struct task_struct *task, enum pid_type type) | ||
| 308 | { | ||
| 309 | struct pid *pid; | ||
| 310 | rcu_read_lock(); | ||
| 311 | pid = get_pid(task->pids[type].pid); | ||
| 312 | rcu_read_unlock(); | ||
| 313 | return pid; | ||
| 314 | } | ||
| 315 | |||
| 283 | struct task_struct *fastcall get_pid_task(struct pid *pid, enum pid_type type) | 316 | struct task_struct *fastcall get_pid_task(struct pid *pid, enum pid_type type) |
| 284 | { | 317 | { |
| 285 | struct task_struct *result; | 318 | struct task_struct *result; |
| @@ -303,6 +336,26 @@ struct pid *find_get_pid(pid_t nr) | |||
| 303 | } | 336 | } |
| 304 | 337 | ||
| 305 | /* | 338 | /* |
| 339 | * Used by proc to find the first pid that is greater then or equal to nr. | ||
| 340 | * | ||
| 341 | * If there is a pid at nr this function is exactly the same as find_pid. | ||
| 342 | */ | ||
| 343 | struct pid *find_ge_pid(int nr) | ||
| 344 | { | ||
| 345 | struct pid *pid; | ||
| 346 | |||
| 347 | do { | ||
| 348 | pid = find_pid(nr); | ||
| 349 | if (pid) | ||
| 350 | break; | ||
| 351 | nr = next_pidmap(&init_pspace, nr); | ||
| 352 | } while (nr > 0); | ||
| 353 | |||
| 354 | return pid; | ||
| 355 | } | ||
| 356 | EXPORT_SYMBOL_GPL(find_get_pid); | ||
| 357 | |||
| 358 | /* | ||
| 306 | * The pid hash table is scaled according to the amount of memory in the | 359 | * The pid hash table is scaled according to the amount of memory in the |
| 307 | * machine. From a minimum of 16 slots up to 4096 slots at one gigabyte or | 360 | * machine. From a minimum of 16 slots up to 4096 slots at one gigabyte or |
| 308 | * more. | 361 | * more. |
| @@ -329,10 +382,10 @@ void __init pidhash_init(void) | |||
| 329 | 382 | ||
| 330 | void __init pidmap_init(void) | 383 | void __init pidmap_init(void) |
| 331 | { | 384 | { |
| 332 | pidmap_array->page = (void *)get_zeroed_page(GFP_KERNEL); | 385 | init_pspace.pidmap[0].page = kzalloc(PAGE_SIZE, GFP_KERNEL); |
| 333 | /* Reserve PID 0. We never call free_pidmap(0) */ | 386 | /* Reserve PID 0. We never call free_pidmap(0) */ |
| 334 | set_bit(0, pidmap_array->page); | 387 | set_bit(0, init_pspace.pidmap[0].page); |
| 335 | atomic_dec(&pidmap_array->nr_free); | 388 | atomic_dec(&init_pspace.pidmap[0].nr_free); |
| 336 | 389 | ||
| 337 | pid_cachep = kmem_cache_create("pid", sizeof(struct pid), | 390 | pid_cachep = kmem_cache_create("pid", sizeof(struct pid), |
| 338 | __alignof__(struct pid), | 391 | __alignof__(struct pid), |
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index 1b84313cbab5..99f9b7d177d6 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c | |||
| @@ -906,7 +906,7 @@ static void init_header(struct swsusp_info *info) | |||
| 906 | memset(info, 0, sizeof(struct swsusp_info)); | 906 | memset(info, 0, sizeof(struct swsusp_info)); |
| 907 | info->version_code = LINUX_VERSION_CODE; | 907 | info->version_code = LINUX_VERSION_CODE; |
| 908 | info->num_physpages = num_physpages; | 908 | info->num_physpages = num_physpages; |
| 909 | memcpy(&info->uts, &system_utsname, sizeof(system_utsname)); | 909 | memcpy(&info->uts, init_utsname(), sizeof(struct new_utsname)); |
| 910 | info->cpus = num_online_cpus(); | 910 | info->cpus = num_online_cpus(); |
| 911 | info->image_pages = nr_copy_pages; | 911 | info->image_pages = nr_copy_pages; |
| 912 | info->pages = nr_copy_pages + nr_meta_pages + 1; | 912 | info->pages = nr_copy_pages + nr_meta_pages + 1; |
| @@ -1050,13 +1050,13 @@ static inline int check_header(struct swsusp_info *info) | |||
| 1050 | reason = "kernel version"; | 1050 | reason = "kernel version"; |
| 1051 | if (info->num_physpages != num_physpages) | 1051 | if (info->num_physpages != num_physpages) |
| 1052 | reason = "memory size"; | 1052 | reason = "memory size"; |
| 1053 | if (strcmp(info->uts.sysname,system_utsname.sysname)) | 1053 | if (strcmp(info->uts.sysname,init_utsname()->sysname)) |
| 1054 | reason = "system type"; | 1054 | reason = "system type"; |
| 1055 | if (strcmp(info->uts.release,system_utsname.release)) | 1055 | if (strcmp(info->uts.release,init_utsname()->release)) |
| 1056 | reason = "kernel release"; | 1056 | reason = "kernel release"; |
| 1057 | if (strcmp(info->uts.version,system_utsname.version)) | 1057 | if (strcmp(info->uts.version,init_utsname()->version)) |
| 1058 | reason = "version"; | 1058 | reason = "version"; |
| 1059 | if (strcmp(info->uts.machine,system_utsname.machine)) | 1059 | if (strcmp(info->uts.machine,init_utsname()->machine)) |
| 1060 | reason = "machine"; | 1060 | reason = "machine"; |
| 1061 | if (reason) { | 1061 | if (reason) { |
| 1062 | printk(KERN_ERR "swsusp: Resume mismatch: %s\n", reason); | 1062 | printk(KERN_ERR "swsusp: Resume mismatch: %s\n", reason); |
diff --git a/kernel/sched.c b/kernel/sched.c index 2bbd948f0169..e4e54e86f4a2 100644 --- a/kernel/sched.c +++ b/kernel/sched.c | |||
| @@ -4384,7 +4384,10 @@ EXPORT_SYMBOL(cpu_present_map); | |||
| 4384 | 4384 | ||
| 4385 | #ifndef CONFIG_SMP | 4385 | #ifndef CONFIG_SMP |
| 4386 | cpumask_t cpu_online_map __read_mostly = CPU_MASK_ALL; | 4386 | cpumask_t cpu_online_map __read_mostly = CPU_MASK_ALL; |
| 4387 | EXPORT_SYMBOL(cpu_online_map); | ||
| 4388 | |||
| 4387 | cpumask_t cpu_possible_map __read_mostly = CPU_MASK_ALL; | 4389 | cpumask_t cpu_possible_map __read_mostly = CPU_MASK_ALL; |
| 4390 | EXPORT_SYMBOL(cpu_possible_map); | ||
| 4388 | #endif | 4391 | #endif |
| 4389 | 4392 | ||
| 4390 | long sched_getaffinity(pid_t pid, cpumask_t *mask) | 4393 | long sched_getaffinity(pid_t pid, cpumask_t *mask) |
diff --git a/kernel/signal.c b/kernel/signal.c index fb5da6d19f14..7ed8d5304bec 100644 --- a/kernel/signal.c +++ b/kernel/signal.c | |||
| @@ -1055,28 +1055,44 @@ int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p) | |||
| 1055 | } | 1055 | } |
| 1056 | 1056 | ||
| 1057 | /* | 1057 | /* |
| 1058 | * kill_pg_info() sends a signal to a process group: this is what the tty | 1058 | * kill_pgrp_info() sends a signal to a process group: this is what the tty |
| 1059 | * control characters do (^C, ^Z etc) | 1059 | * control characters do (^C, ^Z etc) |
| 1060 | */ | 1060 | */ |
| 1061 | 1061 | ||
| 1062 | int __kill_pg_info(int sig, struct siginfo *info, pid_t pgrp) | 1062 | int __kill_pgrp_info(int sig, struct siginfo *info, struct pid *pgrp) |
| 1063 | { | 1063 | { |
| 1064 | struct task_struct *p = NULL; | 1064 | struct task_struct *p = NULL; |
| 1065 | int retval, success; | 1065 | int retval, success; |
| 1066 | 1066 | ||
| 1067 | if (pgrp <= 0) | ||
| 1068 | return -EINVAL; | ||
| 1069 | |||
| 1070 | success = 0; | 1067 | success = 0; |
| 1071 | retval = -ESRCH; | 1068 | retval = -ESRCH; |
| 1072 | do_each_task_pid(pgrp, PIDTYPE_PGID, p) { | 1069 | do_each_pid_task(pgrp, PIDTYPE_PGID, p) { |
| 1073 | int err = group_send_sig_info(sig, info, p); | 1070 | int err = group_send_sig_info(sig, info, p); |
| 1074 | success |= !err; | 1071 | success |= !err; |
| 1075 | retval = err; | 1072 | retval = err; |
| 1076 | } while_each_task_pid(pgrp, PIDTYPE_PGID, p); | 1073 | } while_each_pid_task(pgrp, PIDTYPE_PGID, p); |
| 1077 | return success ? 0 : retval; | 1074 | return success ? 0 : retval; |
| 1078 | } | 1075 | } |
| 1079 | 1076 | ||
| 1077 | int kill_pgrp_info(int sig, struct siginfo *info, struct pid *pgrp) | ||
| 1078 | { | ||
| 1079 | int retval; | ||
| 1080 | |||
| 1081 | read_lock(&tasklist_lock); | ||
| 1082 | retval = __kill_pgrp_info(sig, info, pgrp); | ||
| 1083 | read_unlock(&tasklist_lock); | ||
| 1084 | |||
| 1085 | return retval; | ||
| 1086 | } | ||
| 1087 | |||
| 1088 | int __kill_pg_info(int sig, struct siginfo *info, pid_t pgrp) | ||
| 1089 | { | ||
| 1090 | if (pgrp <= 0) | ||
| 1091 | return -EINVAL; | ||
| 1092 | |||
| 1093 | return __kill_pgrp_info(sig, info, find_pid(pgrp)); | ||
| 1094 | } | ||
| 1095 | |||
| 1080 | int | 1096 | int |
| 1081 | kill_pg_info(int sig, struct siginfo *info, pid_t pgrp) | 1097 | kill_pg_info(int sig, struct siginfo *info, pid_t pgrp) |
| 1082 | { | 1098 | { |
| @@ -1089,8 +1105,7 @@ kill_pg_info(int sig, struct siginfo *info, pid_t pgrp) | |||
| 1089 | return retval; | 1105 | return retval; |
| 1090 | } | 1106 | } |
| 1091 | 1107 | ||
| 1092 | int | 1108 | int kill_pid_info(int sig, struct siginfo *info, struct pid *pid) |
| 1093 | kill_proc_info(int sig, struct siginfo *info, pid_t pid) | ||
| 1094 | { | 1109 | { |
| 1095 | int error; | 1110 | int error; |
| 1096 | int acquired_tasklist_lock = 0; | 1111 | int acquired_tasklist_lock = 0; |
| @@ -1101,7 +1116,7 @@ kill_proc_info(int sig, struct siginfo *info, pid_t pid) | |||
| 1101 | read_lock(&tasklist_lock); | 1116 | read_lock(&tasklist_lock); |
| 1102 | acquired_tasklist_lock = 1; | 1117 | acquired_tasklist_lock = 1; |
| 1103 | } | 1118 | } |
| 1104 | p = find_task_by_pid(pid); | 1119 | p = pid_task(pid, PIDTYPE_PID); |
| 1105 | error = -ESRCH; | 1120 | error = -ESRCH; |
| 1106 | if (p) | 1121 | if (p) |
| 1107 | error = group_send_sig_info(sig, info, p); | 1122 | error = group_send_sig_info(sig, info, p); |
| @@ -1111,8 +1126,18 @@ kill_proc_info(int sig, struct siginfo *info, pid_t pid) | |||
| 1111 | return error; | 1126 | return error; |
| 1112 | } | 1127 | } |
| 1113 | 1128 | ||
| 1114 | /* like kill_proc_info(), but doesn't use uid/euid of "current" */ | 1129 | int |
| 1115 | int kill_proc_info_as_uid(int sig, struct siginfo *info, pid_t pid, | 1130 | kill_proc_info(int sig, struct siginfo *info, pid_t pid) |
| 1131 | { | ||
| 1132 | int error; | ||
| 1133 | rcu_read_lock(); | ||
| 1134 | error = kill_pid_info(sig, info, find_pid(pid)); | ||
| 1135 | rcu_read_unlock(); | ||
| 1136 | return error; | ||
| 1137 | } | ||
| 1138 | |||
| 1139 | /* like kill_pid_info(), but doesn't use uid/euid of "current" */ | ||
| 1140 | int kill_pid_info_as_uid(int sig, struct siginfo *info, struct pid *pid, | ||
| 1116 | uid_t uid, uid_t euid, u32 secid) | 1141 | uid_t uid, uid_t euid, u32 secid) |
| 1117 | { | 1142 | { |
| 1118 | int ret = -EINVAL; | 1143 | int ret = -EINVAL; |
| @@ -1122,7 +1147,7 @@ int kill_proc_info_as_uid(int sig, struct siginfo *info, pid_t pid, | |||
| 1122 | return ret; | 1147 | return ret; |
| 1123 | 1148 | ||
| 1124 | read_lock(&tasklist_lock); | 1149 | read_lock(&tasklist_lock); |
| 1125 | p = find_task_by_pid(pid); | 1150 | p = pid_task(pid, PIDTYPE_PID); |
| 1126 | if (!p) { | 1151 | if (!p) { |
| 1127 | ret = -ESRCH; | 1152 | ret = -ESRCH; |
| 1128 | goto out_unlock; | 1153 | goto out_unlock; |
| @@ -1146,7 +1171,7 @@ out_unlock: | |||
| 1146 | read_unlock(&tasklist_lock); | 1171 | read_unlock(&tasklist_lock); |
| 1147 | return ret; | 1172 | return ret; |
| 1148 | } | 1173 | } |
| 1149 | EXPORT_SYMBOL_GPL(kill_proc_info_as_uid); | 1174 | EXPORT_SYMBOL_GPL(kill_pid_info_as_uid); |
| 1150 | 1175 | ||
| 1151 | /* | 1176 | /* |
| 1152 | * kill_something_info() interprets pid in interesting ways just like kill(2). | 1177 | * kill_something_info() interprets pid in interesting ways just like kill(2). |
| @@ -1264,6 +1289,18 @@ force_sigsegv(int sig, struct task_struct *p) | |||
| 1264 | return 0; | 1289 | return 0; |
| 1265 | } | 1290 | } |
| 1266 | 1291 | ||
| 1292 | int kill_pgrp(struct pid *pid, int sig, int priv) | ||
| 1293 | { | ||
| 1294 | return kill_pgrp_info(sig, __si_special(priv), pid); | ||
| 1295 | } | ||
| 1296 | EXPORT_SYMBOL(kill_pgrp); | ||
| 1297 | |||
| 1298 | int kill_pid(struct pid *pid, int sig, int priv) | ||
| 1299 | { | ||
| 1300 | return kill_pid_info(sig, __si_special(priv), pid); | ||
| 1301 | } | ||
| 1302 | EXPORT_SYMBOL(kill_pid); | ||
| 1303 | |||
| 1267 | int | 1304 | int |
| 1268 | kill_pg(pid_t pgrp, int sig, int priv) | 1305 | kill_pg(pid_t pgrp, int sig, int priv) |
| 1269 | { | 1306 | { |
diff --git a/kernel/sys.c b/kernel/sys.c index 2460581c928c..2314867ae34f 100644 --- a/kernel/sys.c +++ b/kernel/sys.c | |||
| @@ -92,7 +92,8 @@ EXPORT_SYMBOL(fs_overflowgid); | |||
| 92 | */ | 92 | */ |
| 93 | 93 | ||
| 94 | int C_A_D = 1; | 94 | int C_A_D = 1; |
| 95 | int cad_pid = 1; | 95 | struct pid *cad_pid; |
| 96 | EXPORT_SYMBOL(cad_pid); | ||
| 96 | 97 | ||
| 97 | /* | 98 | /* |
| 98 | * Notifier list for kernel code which wants to be called | 99 | * Notifier list for kernel code which wants to be called |
| @@ -221,7 +222,7 @@ EXPORT_SYMBOL_GPL(atomic_notifier_chain_unregister); | |||
| 221 | * of the last notifier function called. | 222 | * of the last notifier function called. |
| 222 | */ | 223 | */ |
| 223 | 224 | ||
| 224 | int atomic_notifier_call_chain(struct atomic_notifier_head *nh, | 225 | int __kprobes atomic_notifier_call_chain(struct atomic_notifier_head *nh, |
| 225 | unsigned long val, void *v) | 226 | unsigned long val, void *v) |
| 226 | { | 227 | { |
| 227 | int ret; | 228 | int ret; |
| @@ -773,10 +774,9 @@ void ctrl_alt_del(void) | |||
| 773 | if (C_A_D) | 774 | if (C_A_D) |
| 774 | schedule_work(&cad_work); | 775 | schedule_work(&cad_work); |
| 775 | else | 776 | else |
| 776 | kill_proc(cad_pid, SIGINT, 1); | 777 | kill_cad_pid(SIGINT, 1); |
| 777 | } | 778 | } |
| 778 | 779 | ||
| 779 | |||
| 780 | /* | 780 | /* |
| 781 | * Unprivileged users may change the real gid to the effective gid | 781 | * Unprivileged users may change the real gid to the effective gid |
| 782 | * or vice versa. (BSD-style) | 782 | * or vice versa. (BSD-style) |
| @@ -1655,7 +1655,7 @@ asmlinkage long sys_newuname(struct new_utsname __user * name) | |||
| 1655 | int errno = 0; | 1655 | int errno = 0; |
| 1656 | 1656 | ||
| 1657 | down_read(&uts_sem); | 1657 | down_read(&uts_sem); |
| 1658 | if (copy_to_user(name,&system_utsname,sizeof *name)) | 1658 | if (copy_to_user(name, utsname(), sizeof *name)) |
| 1659 | errno = -EFAULT; | 1659 | errno = -EFAULT; |
| 1660 | up_read(&uts_sem); | 1660 | up_read(&uts_sem); |
| 1661 | return errno; | 1661 | return errno; |
| @@ -1673,8 +1673,8 @@ asmlinkage long sys_sethostname(char __user *name, int len) | |||
| 1673 | down_write(&uts_sem); | 1673 | down_write(&uts_sem); |
| 1674 | errno = -EFAULT; | 1674 | errno = -EFAULT; |
| 1675 | if (!copy_from_user(tmp, name, len)) { | 1675 | if (!copy_from_user(tmp, name, len)) { |
| 1676 | memcpy(system_utsname.nodename, tmp, len); | 1676 | memcpy(utsname()->nodename, tmp, len); |
| 1677 | system_utsname.nodename[len] = 0; | 1677 | utsname()->nodename[len] = 0; |
| 1678 | errno = 0; | 1678 | errno = 0; |
| 1679 | } | 1679 | } |
| 1680 | up_write(&uts_sem); | 1680 | up_write(&uts_sem); |
| @@ -1690,11 +1690,11 @@ asmlinkage long sys_gethostname(char __user *name, int len) | |||
| 1690 | if (len < 0) | 1690 | if (len < 0) |
| 1691 | return -EINVAL; | 1691 | return -EINVAL; |
| 1692 | down_read(&uts_sem); | 1692 | down_read(&uts_sem); |
| 1693 | i = 1 + strlen(system_utsname.nodename); | 1693 | i = 1 + strlen(utsname()->nodename); |
| 1694 | if (i > len) | 1694 | if (i > len) |
| 1695 | i = len; | 1695 | i = len; |
| 1696 | errno = 0; | 1696 | errno = 0; |
| 1697 | if (copy_to_user(name, system_utsname.nodename, i)) | 1697 | if (copy_to_user(name, utsname()->nodename, i)) |
| 1698 | errno = -EFAULT; | 1698 | errno = -EFAULT; |
| 1699 | up_read(&uts_sem); | 1699 | up_read(&uts_sem); |
| 1700 | return errno; | 1700 | return errno; |
| @@ -1719,8 +1719,8 @@ asmlinkage long sys_setdomainname(char __user *name, int len) | |||
| 1719 | down_write(&uts_sem); | 1719 | down_write(&uts_sem); |
| 1720 | errno = -EFAULT; | 1720 | errno = -EFAULT; |
| 1721 | if (!copy_from_user(tmp, name, len)) { | 1721 | if (!copy_from_user(tmp, name, len)) { |
| 1722 | memcpy(system_utsname.domainname, tmp, len); | 1722 | memcpy(utsname()->domainname, tmp, len); |
| 1723 | system_utsname.domainname[len] = 0; | 1723 | utsname()->domainname[len] = 0; |
| 1724 | errno = 0; | 1724 | errno = 0; |
| 1725 | } | 1725 | } |
| 1726 | up_write(&uts_sem); | 1726 | up_write(&uts_sem); |
diff --git a/kernel/sysctl.c b/kernel/sysctl.c index ba42694f0453..8020fb273c4f 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c | |||
| @@ -68,7 +68,6 @@ extern int sysrq_enabled; | |||
| 68 | extern int core_uses_pid; | 68 | extern int core_uses_pid; |
| 69 | extern int suid_dumpable; | 69 | extern int suid_dumpable; |
| 70 | extern char core_pattern[]; | 70 | extern char core_pattern[]; |
| 71 | extern int cad_pid; | ||
| 72 | extern int pid_max; | 71 | extern int pid_max; |
| 73 | extern int min_free_kbytes; | 72 | extern int min_free_kbytes; |
| 74 | extern int printk_ratelimit_jiffies; | 73 | extern int printk_ratelimit_jiffies; |
| @@ -92,13 +91,8 @@ extern char modprobe_path[]; | |||
| 92 | extern int sg_big_buff; | 91 | extern int sg_big_buff; |
| 93 | #endif | 92 | #endif |
| 94 | #ifdef CONFIG_SYSVIPC | 93 | #ifdef CONFIG_SYSVIPC |
| 95 | extern size_t shm_ctlmax; | 94 | static int proc_do_ipc_string(ctl_table *table, int write, struct file *filp, |
| 96 | extern size_t shm_ctlall; | 95 | void __user *buffer, size_t *lenp, loff_t *ppos); |
| 97 | extern int shm_ctlmni; | ||
| 98 | extern int msg_ctlmax; | ||
| 99 | extern int msg_ctlmnb; | ||
| 100 | extern int msg_ctlmni; | ||
| 101 | extern int sem_ctls[]; | ||
| 102 | #endif | 96 | #endif |
| 103 | 97 | ||
| 104 | #ifdef __sparc__ | 98 | #ifdef __sparc__ |
| @@ -139,7 +133,10 @@ static int parse_table(int __user *, int, void __user *, size_t __user *, | |||
| 139 | void __user *, size_t, ctl_table *, void **); | 133 | void __user *, size_t, ctl_table *, void **); |
| 140 | #endif | 134 | #endif |
| 141 | 135 | ||
| 142 | static int proc_doutsstring(ctl_table *table, int write, struct file *filp, | 136 | static int proc_do_uts_string(ctl_table *table, int write, struct file *filp, |
| 137 | void __user *buffer, size_t *lenp, loff_t *ppos); | ||
| 138 | |||
| 139 | static int proc_do_cad_pid(ctl_table *table, int write, struct file *filp, | ||
| 143 | void __user *buffer, size_t *lenp, loff_t *ppos); | 140 | void __user *buffer, size_t *lenp, loff_t *ppos); |
| 144 | 141 | ||
| 145 | static ctl_table root_table[]; | 142 | static ctl_table root_table[]; |
| @@ -229,51 +226,100 @@ static ctl_table root_table[] = { | |||
| 229 | }; | 226 | }; |
| 230 | 227 | ||
| 231 | static ctl_table kern_table[] = { | 228 | static ctl_table kern_table[] = { |
| 229 | #ifndef CONFIG_UTS_NS | ||
| 230 | { | ||
| 231 | .ctl_name = KERN_OSTYPE, | ||
| 232 | .procname = "ostype", | ||
| 233 | .data = init_uts_ns.name.sysname, | ||
| 234 | .maxlen = sizeof(init_uts_ns.name.sysname), | ||
| 235 | .mode = 0444, | ||
| 236 | .proc_handler = &proc_do_uts_string, | ||
| 237 | .strategy = &sysctl_string, | ||
| 238 | }, | ||
| 239 | { | ||
| 240 | .ctl_name = KERN_OSRELEASE, | ||
| 241 | .procname = "osrelease", | ||
| 242 | .data = init_uts_ns.name.release, | ||
| 243 | .maxlen = sizeof(init_uts_ns.name.release), | ||
| 244 | .mode = 0444, | ||
| 245 | .proc_handler = &proc_do_uts_string, | ||
| 246 | .strategy = &sysctl_string, | ||
| 247 | }, | ||
| 248 | { | ||
| 249 | .ctl_name = KERN_VERSION, | ||
| 250 | .procname = "version", | ||
| 251 | .data = init_uts_ns.name.version, | ||
| 252 | .maxlen = sizeof(init_uts_ns.name.version), | ||
| 253 | .mode = 0444, | ||
| 254 | .proc_handler = &proc_do_uts_string, | ||
| 255 | .strategy = &sysctl_string, | ||
| 256 | }, | ||
| 257 | { | ||
| 258 | .ctl_name = KERN_NODENAME, | ||
| 259 | .procname = "hostname", | ||
| 260 | .data = init_uts_ns.name.nodename, | ||
| 261 | .maxlen = sizeof(init_uts_ns.name.nodename), | ||
| 262 | .mode = 0644, | ||
| 263 | .proc_handler = &proc_do_uts_string, | ||
| 264 | .strategy = &sysctl_string, | ||
| 265 | }, | ||
| 266 | { | ||
| 267 | .ctl_name = KERN_DOMAINNAME, | ||
| 268 | .procname = "domainname", | ||
| 269 | .data = init_uts_ns.name.domainname, | ||
| 270 | .maxlen = sizeof(init_uts_ns.name.domainname), | ||
| 271 | .mode = 0644, | ||
| 272 | .proc_handler = &proc_do_uts_string, | ||
| 273 | .strategy = &sysctl_string, | ||
| 274 | }, | ||
| 275 | #else /* !CONFIG_UTS_NS */ | ||
| 232 | { | 276 | { |
| 233 | .ctl_name = KERN_OSTYPE, | 277 | .ctl_name = KERN_OSTYPE, |
| 234 | .procname = "ostype", | 278 | .procname = "ostype", |
| 235 | .data = system_utsname.sysname, | 279 | .data = NULL, |
| 236 | .maxlen = sizeof(system_utsname.sysname), | 280 | /* could maybe use __NEW_UTS_LEN here? */ |
| 281 | .maxlen = FIELD_SIZEOF(struct new_utsname, sysname), | ||
| 237 | .mode = 0444, | 282 | .mode = 0444, |
| 238 | .proc_handler = &proc_doutsstring, | 283 | .proc_handler = &proc_do_uts_string, |
| 239 | .strategy = &sysctl_string, | 284 | .strategy = &sysctl_string, |
| 240 | }, | 285 | }, |
| 241 | { | 286 | { |
| 242 | .ctl_name = KERN_OSRELEASE, | 287 | .ctl_name = KERN_OSRELEASE, |
| 243 | .procname = "osrelease", | 288 | .procname = "osrelease", |
| 244 | .data = system_utsname.release, | 289 | .data = NULL, |
| 245 | .maxlen = sizeof(system_utsname.release), | 290 | .maxlen = FIELD_SIZEOF(struct new_utsname, release), |
| 246 | .mode = 0444, | 291 | .mode = 0444, |
| 247 | .proc_handler = &proc_doutsstring, | 292 | .proc_handler = &proc_do_uts_string, |
| 248 | .strategy = &sysctl_string, | 293 | .strategy = &sysctl_string, |
| 249 | }, | 294 | }, |
| 250 | { | 295 | { |
| 251 | .ctl_name = KERN_VERSION, | 296 | .ctl_name = KERN_VERSION, |
| 252 | .procname = "version", | 297 | .procname = "version", |
| 253 | .data = system_utsname.version, | 298 | .data = NULL, |
| 254 | .maxlen = sizeof(system_utsname.version), | 299 | .maxlen = FIELD_SIZEOF(struct new_utsname, version), |
| 255 | .mode = 0444, | 300 | .mode = 0444, |
| 256 | .proc_handler = &proc_doutsstring, | 301 | .proc_handler = &proc_do_uts_string, |
| 257 | .strategy = &sysctl_string, | 302 | .strategy = &sysctl_string, |
| 258 | }, | 303 | }, |
| 259 | { | 304 | { |
| 260 | .ctl_name = KERN_NODENAME, | 305 | .ctl_name = KERN_NODENAME, |
| 261 | .procname = "hostname", | 306 | .procname = "hostname", |
| 262 | .data = system_utsname.nodename, | 307 | .data = NULL, |
| 263 | .maxlen = sizeof(system_utsname.nodename), | 308 | .maxlen = FIELD_SIZEOF(struct new_utsname, nodename), |
| 264 | .mode = 0644, | 309 | .mode = 0644, |
| 265 | .proc_handler = &proc_doutsstring, | 310 | .proc_handler = &proc_do_uts_string, |
| 266 | .strategy = &sysctl_string, | 311 | .strategy = &sysctl_string, |
| 267 | }, | 312 | }, |
| 268 | { | 313 | { |
| 269 | .ctl_name = KERN_DOMAINNAME, | 314 | .ctl_name = KERN_DOMAINNAME, |
| 270 | .procname = "domainname", | 315 | .procname = "domainname", |
| 271 | .data = system_utsname.domainname, | 316 | .data = NULL, |
| 272 | .maxlen = sizeof(system_utsname.domainname), | 317 | .maxlen = FIELD_SIZEOF(struct new_utsname, domainname), |
| 273 | .mode = 0644, | 318 | .mode = 0644, |
| 274 | .proc_handler = &proc_doutsstring, | 319 | .proc_handler = &proc_do_uts_string, |
| 275 | .strategy = &sysctl_string, | 320 | .strategy = &sysctl_string, |
| 276 | }, | 321 | }, |
| 322 | #endif /* !CONFIG_UTS_NS */ | ||
| 277 | { | 323 | { |
| 278 | .ctl_name = KERN_PANIC, | 324 | .ctl_name = KERN_PANIC, |
| 279 | .procname = "panic", | 325 | .procname = "panic", |
| @@ -432,58 +478,58 @@ static ctl_table kern_table[] = { | |||
| 432 | { | 478 | { |
| 433 | .ctl_name = KERN_SHMMAX, | 479 | .ctl_name = KERN_SHMMAX, |
| 434 | .procname = "shmmax", | 480 | .procname = "shmmax", |
| 435 | .data = &shm_ctlmax, | 481 | .data = NULL, |
| 436 | .maxlen = sizeof (size_t), | 482 | .maxlen = sizeof (size_t), |
| 437 | .mode = 0644, | 483 | .mode = 0644, |
| 438 | .proc_handler = &proc_doulongvec_minmax, | 484 | .proc_handler = &proc_do_ipc_string, |
| 439 | }, | 485 | }, |
| 440 | { | 486 | { |
| 441 | .ctl_name = KERN_SHMALL, | 487 | .ctl_name = KERN_SHMALL, |
| 442 | .procname = "shmall", | 488 | .procname = "shmall", |
| 443 | .data = &shm_ctlall, | 489 | .data = NULL, |
| 444 | .maxlen = sizeof (size_t), | 490 | .maxlen = sizeof (size_t), |
| 445 | .mode = 0644, | 491 | .mode = 0644, |
| 446 | .proc_handler = &proc_doulongvec_minmax, | 492 | .proc_handler = &proc_do_ipc_string, |
| 447 | }, | 493 | }, |
| 448 | { | 494 | { |
| 449 | .ctl_name = KERN_SHMMNI, | 495 | .ctl_name = KERN_SHMMNI, |
| 450 | .procname = "shmmni", | 496 | .procname = "shmmni", |
| 451 | .data = &shm_ctlmni, | 497 | .data = NULL, |
| 452 | .maxlen = sizeof (int), | 498 | .maxlen = sizeof (int), |
| 453 | .mode = 0644, | 499 | .mode = 0644, |
| 454 | .proc_handler = &proc_dointvec, | 500 | .proc_handler = &proc_do_ipc_string, |
| 455 | }, | 501 | }, |
| 456 | { | 502 | { |
| 457 | .ctl_name = KERN_MSGMAX, | 503 | .ctl_name = KERN_MSGMAX, |
| 458 | .procname = "msgmax", | 504 | .procname = "msgmax", |
| 459 | .data = &msg_ctlmax, | 505 | .data = NULL, |
| 460 | .maxlen = sizeof (int), | 506 | .maxlen = sizeof (int), |
| 461 | .mode = 0644, | 507 | .mode = 0644, |
| 462 | .proc_handler = &proc_dointvec, | 508 | .proc_handler = &proc_do_ipc_string, |
| 463 | }, | 509 | }, |
| 464 | { | 510 | { |
| 465 | .ctl_name = KERN_MSGMNI, | 511 | .ctl_name = KERN_MSGMNI, |
| 466 | .procname = "msgmni", | 512 | .procname = "msgmni", |
| 467 | .data = &msg_ctlmni, | 513 | .data = NULL, |
| 468 | .maxlen = sizeof (int), | 514 | .maxlen = sizeof (int), |
| 469 | .mode = 0644, | 515 | .mode = 0644, |
| 470 | .proc_handler = &proc_dointvec, | 516 | .proc_handler = &proc_do_ipc_string, |
| 471 | }, | 517 | }, |
| 472 | { | 518 | { |
| 473 | .ctl_name = KERN_MSGMNB, | 519 | .ctl_name = KERN_MSGMNB, |
| 474 | .procname = "msgmnb", | 520 | .procname = "msgmnb", |
| 475 | .data = &msg_ctlmnb, | 521 | .data = NULL, |
| 476 | .maxlen = sizeof (int), | 522 | .maxlen = sizeof (int), |
| 477 | .mode = 0644, | 523 | .mode = 0644, |
| 478 | .proc_handler = &proc_dointvec, | 524 | .proc_handler = &proc_do_ipc_string, |
| 479 | }, | 525 | }, |
| 480 | { | 526 | { |
| 481 | .ctl_name = KERN_SEM, | 527 | .ctl_name = KERN_SEM, |
| 482 | .procname = "sem", | 528 | .procname = "sem", |
| 483 | .data = &sem_ctls, | 529 | .data = NULL, |
| 484 | .maxlen = 4*sizeof (int), | 530 | .maxlen = 4*sizeof (int), |
| 485 | .mode = 0644, | 531 | .mode = 0644, |
| 486 | .proc_handler = &proc_dointvec, | 532 | .proc_handler = &proc_do_ipc_string, |
| 487 | }, | 533 | }, |
| 488 | #endif | 534 | #endif |
| 489 | #ifdef CONFIG_MAGIC_SYSRQ | 535 | #ifdef CONFIG_MAGIC_SYSRQ |
| @@ -499,10 +545,10 @@ static ctl_table kern_table[] = { | |||
| 499 | { | 545 | { |
| 500 | .ctl_name = KERN_CADPID, | 546 | .ctl_name = KERN_CADPID, |
| 501 | .procname = "cad_pid", | 547 | .procname = "cad_pid", |
| 502 | .data = &cad_pid, | 548 | .data = NULL, |
| 503 | .maxlen = sizeof (int), | 549 | .maxlen = sizeof (int), |
| 504 | .mode = 0600, | 550 | .mode = 0600, |
| 505 | .proc_handler = &proc_dointvec, | 551 | .proc_handler = &proc_do_cad_pid, |
| 506 | }, | 552 | }, |
| 507 | { | 553 | { |
| 508 | .ctl_name = KERN_MAX_THREADS, | 554 | .ctl_name = KERN_MAX_THREADS, |
| @@ -1624,32 +1670,15 @@ static ssize_t proc_writesys(struct file * file, const char __user * buf, | |||
| 1624 | return do_rw_proc(1, file, (char __user *) buf, count, ppos); | 1670 | return do_rw_proc(1, file, (char __user *) buf, count, ppos); |
| 1625 | } | 1671 | } |
| 1626 | 1672 | ||
| 1627 | /** | 1673 | static int _proc_do_string(void* data, int maxlen, int write, |
| 1628 | * proc_dostring - read a string sysctl | 1674 | struct file *filp, void __user *buffer, |
| 1629 | * @table: the sysctl table | 1675 | size_t *lenp, loff_t *ppos) |
| 1630 | * @write: %TRUE if this is a write to the sysctl file | ||
| 1631 | * @filp: the file structure | ||
| 1632 | * @buffer: the user buffer | ||
| 1633 | * @lenp: the size of the user buffer | ||
| 1634 | * @ppos: file position | ||
| 1635 | * | ||
| 1636 | * Reads/writes a string from/to the user buffer. If the kernel | ||
| 1637 | * buffer provided is not large enough to hold the string, the | ||
| 1638 | * string is truncated. The copied string is %NULL-terminated. | ||
| 1639 | * If the string is being read by the user process, it is copied | ||
| 1640 | * and a newline '\n' is added. It is truncated if the buffer is | ||
| 1641 | * not large enough. | ||
| 1642 | * | ||
| 1643 | * Returns 0 on success. | ||
| 1644 | */ | ||
| 1645 | int proc_dostring(ctl_table *table, int write, struct file *filp, | ||
| 1646 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
| 1647 | { | 1676 | { |
| 1648 | size_t len; | 1677 | size_t len; |
| 1649 | char __user *p; | 1678 | char __user *p; |
| 1650 | char c; | 1679 | char c; |
| 1651 | 1680 | ||
| 1652 | if (!table->data || !table->maxlen || !*lenp || | 1681 | if (!data || !maxlen || !*lenp || |
| 1653 | (*ppos && !write)) { | 1682 | (*ppos && !write)) { |
| 1654 | *lenp = 0; | 1683 | *lenp = 0; |
| 1655 | return 0; | 1684 | return 0; |
| @@ -1665,20 +1694,20 @@ int proc_dostring(ctl_table *table, int write, struct file *filp, | |||
| 1665 | break; | 1694 | break; |
| 1666 | len++; | 1695 | len++; |
| 1667 | } | 1696 | } |
| 1668 | if (len >= table->maxlen) | 1697 | if (len >= maxlen) |
| 1669 | len = table->maxlen-1; | 1698 | len = maxlen-1; |
| 1670 | if(copy_from_user(table->data, buffer, len)) | 1699 | if(copy_from_user(data, buffer, len)) |
| 1671 | return -EFAULT; | 1700 | return -EFAULT; |
| 1672 | ((char *) table->data)[len] = 0; | 1701 | ((char *) data)[len] = 0; |
| 1673 | *ppos += *lenp; | 1702 | *ppos += *lenp; |
| 1674 | } else { | 1703 | } else { |
| 1675 | len = strlen(table->data); | 1704 | len = strlen(data); |
| 1676 | if (len > table->maxlen) | 1705 | if (len > maxlen) |
| 1677 | len = table->maxlen; | 1706 | len = maxlen; |
| 1678 | if (len > *lenp) | 1707 | if (len > *lenp) |
| 1679 | len = *lenp; | 1708 | len = *lenp; |
| 1680 | if (len) | 1709 | if (len) |
| 1681 | if(copy_to_user(buffer, table->data, len)) | 1710 | if(copy_to_user(buffer, data, len)) |
| 1682 | return -EFAULT; | 1711 | return -EFAULT; |
| 1683 | if (len < *lenp) { | 1712 | if (len < *lenp) { |
| 1684 | if(put_user('\n', ((char __user *) buffer) + len)) | 1713 | if(put_user('\n', ((char __user *) buffer) + len)) |
| @@ -1691,12 +1720,38 @@ int proc_dostring(ctl_table *table, int write, struct file *filp, | |||
| 1691 | return 0; | 1720 | return 0; |
| 1692 | } | 1721 | } |
| 1693 | 1722 | ||
| 1723 | /** | ||
| 1724 | * proc_dostring - read a string sysctl | ||
| 1725 | * @table: the sysctl table | ||
| 1726 | * @write: %TRUE if this is a write to the sysctl file | ||
| 1727 | * @filp: the file structure | ||
| 1728 | * @buffer: the user buffer | ||
| 1729 | * @lenp: the size of the user buffer | ||
| 1730 | * @ppos: file position | ||
| 1731 | * | ||
| 1732 | * Reads/writes a string from/to the user buffer. If the kernel | ||
| 1733 | * buffer provided is not large enough to hold the string, the | ||
| 1734 | * string is truncated. The copied string is %NULL-terminated. | ||
| 1735 | * If the string is being read by the user process, it is copied | ||
| 1736 | * and a newline '\n' is added. It is truncated if the buffer is | ||
| 1737 | * not large enough. | ||
| 1738 | * | ||
| 1739 | * Returns 0 on success. | ||
| 1740 | */ | ||
| 1741 | int proc_dostring(ctl_table *table, int write, struct file *filp, | ||
| 1742 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
| 1743 | { | ||
| 1744 | return _proc_do_string(table->data, table->maxlen, write, filp, | ||
| 1745 | buffer, lenp, ppos); | ||
| 1746 | } | ||
| 1747 | |||
| 1694 | /* | 1748 | /* |
| 1695 | * Special case of dostring for the UTS structure. This has locks | 1749 | * Special case of dostring for the UTS structure. This has locks |
| 1696 | * to observe. Should this be in kernel/sys.c ???? | 1750 | * to observe. Should this be in kernel/sys.c ???? |
| 1697 | */ | 1751 | */ |
| 1698 | 1752 | ||
| 1699 | static int proc_doutsstring(ctl_table *table, int write, struct file *filp, | 1753 | #ifndef CONFIG_UTS_NS |
| 1754 | static int proc_do_uts_string(ctl_table *table, int write, struct file *filp, | ||
| 1700 | void __user *buffer, size_t *lenp, loff_t *ppos) | 1755 | void __user *buffer, size_t *lenp, loff_t *ppos) |
| 1701 | { | 1756 | { |
| 1702 | int r; | 1757 | int r; |
| @@ -1712,6 +1767,48 @@ static int proc_doutsstring(ctl_table *table, int write, struct file *filp, | |||
| 1712 | } | 1767 | } |
| 1713 | return r; | 1768 | return r; |
| 1714 | } | 1769 | } |
| 1770 | #else /* !CONFIG_UTS_NS */ | ||
| 1771 | static int proc_do_uts_string(ctl_table *table, int write, struct file *filp, | ||
| 1772 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
| 1773 | { | ||
| 1774 | int r; | ||
| 1775 | struct uts_namespace* uts_ns = current->nsproxy->uts_ns; | ||
| 1776 | char* which; | ||
| 1777 | |||
| 1778 | switch (table->ctl_name) { | ||
| 1779 | case KERN_OSTYPE: | ||
| 1780 | which = uts_ns->name.sysname; | ||
| 1781 | break; | ||
| 1782 | case KERN_NODENAME: | ||
| 1783 | which = uts_ns->name.nodename; | ||
| 1784 | break; | ||
| 1785 | case KERN_OSRELEASE: | ||
| 1786 | which = uts_ns->name.release; | ||
| 1787 | break; | ||
| 1788 | case KERN_VERSION: | ||
| 1789 | which = uts_ns->name.version; | ||
| 1790 | break; | ||
| 1791 | case KERN_DOMAINNAME: | ||
| 1792 | which = uts_ns->name.domainname; | ||
| 1793 | break; | ||
| 1794 | default: | ||
| 1795 | r = -EINVAL; | ||
| 1796 | goto out; | ||
| 1797 | } | ||
| 1798 | |||
| 1799 | if (!write) { | ||
| 1800 | down_read(&uts_sem); | ||
| 1801 | r=_proc_do_string(which,table->maxlen,0,filp,buffer,lenp, ppos); | ||
| 1802 | up_read(&uts_sem); | ||
| 1803 | } else { | ||
| 1804 | down_write(&uts_sem); | ||
| 1805 | r=_proc_do_string(which,table->maxlen,1,filp,buffer,lenp, ppos); | ||
| 1806 | up_write(&uts_sem); | ||
| 1807 | } | ||
| 1808 | out: | ||
| 1809 | return r; | ||
| 1810 | } | ||
| 1811 | #endif /* !CONFIG_UTS_NS */ | ||
| 1715 | 1812 | ||
| 1716 | static int do_proc_dointvec_conv(int *negp, unsigned long *lvalp, | 1813 | static int do_proc_dointvec_conv(int *negp, unsigned long *lvalp, |
| 1717 | int *valp, | 1814 | int *valp, |
| @@ -1732,8 +1829,9 @@ static int do_proc_dointvec_conv(int *negp, unsigned long *lvalp, | |||
| 1732 | return 0; | 1829 | return 0; |
| 1733 | } | 1830 | } |
| 1734 | 1831 | ||
| 1735 | static int do_proc_dointvec(ctl_table *table, int write, struct file *filp, | 1832 | static int __do_proc_dointvec(void *tbl_data, ctl_table *table, |
| 1736 | void __user *buffer, size_t *lenp, loff_t *ppos, | 1833 | int write, struct file *filp, void __user *buffer, |
| 1834 | size_t *lenp, loff_t *ppos, | ||
| 1737 | int (*conv)(int *negp, unsigned long *lvalp, int *valp, | 1835 | int (*conv)(int *negp, unsigned long *lvalp, int *valp, |
| 1738 | int write, void *data), | 1836 | int write, void *data), |
| 1739 | void *data) | 1837 | void *data) |
| @@ -1746,13 +1844,13 @@ static int do_proc_dointvec(ctl_table *table, int write, struct file *filp, | |||
| 1746 | char buf[TMPBUFLEN], *p; | 1844 | char buf[TMPBUFLEN], *p; |
| 1747 | char __user *s = buffer; | 1845 | char __user *s = buffer; |
| 1748 | 1846 | ||
| 1749 | if (!table->data || !table->maxlen || !*lenp || | 1847 | if (!tbl_data || !table->maxlen || !*lenp || |
| 1750 | (*ppos && !write)) { | 1848 | (*ppos && !write)) { |
| 1751 | *lenp = 0; | 1849 | *lenp = 0; |
| 1752 | return 0; | 1850 | return 0; |
| 1753 | } | 1851 | } |
| 1754 | 1852 | ||
| 1755 | i = (int *) table->data; | 1853 | i = (int *) tbl_data; |
| 1756 | vleft = table->maxlen / sizeof(*i); | 1854 | vleft = table->maxlen / sizeof(*i); |
| 1757 | left = *lenp; | 1855 | left = *lenp; |
| 1758 | 1856 | ||
| @@ -1841,6 +1939,16 @@ static int do_proc_dointvec(ctl_table *table, int write, struct file *filp, | |||
| 1841 | #undef TMPBUFLEN | 1939 | #undef TMPBUFLEN |
| 1842 | } | 1940 | } |
| 1843 | 1941 | ||
| 1942 | static int do_proc_dointvec(ctl_table *table, int write, struct file *filp, | ||
| 1943 | void __user *buffer, size_t *lenp, loff_t *ppos, | ||
| 1944 | int (*conv)(int *negp, unsigned long *lvalp, int *valp, | ||
| 1945 | int write, void *data), | ||
| 1946 | void *data) | ||
| 1947 | { | ||
| 1948 | return __do_proc_dointvec(table->data, table, write, filp, | ||
| 1949 | buffer, lenp, ppos, conv, data); | ||
| 1950 | } | ||
| 1951 | |||
| 1844 | /** | 1952 | /** |
| 1845 | * proc_dointvec - read a vector of integers | 1953 | * proc_dointvec - read a vector of integers |
| 1846 | * @table: the sysctl table | 1954 | * @table: the sysctl table |
| @@ -1974,7 +2082,7 @@ int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp, | |||
| 1974 | do_proc_dointvec_minmax_conv, ¶m); | 2082 | do_proc_dointvec_minmax_conv, ¶m); |
| 1975 | } | 2083 | } |
| 1976 | 2084 | ||
| 1977 | static int do_proc_doulongvec_minmax(ctl_table *table, int write, | 2085 | static int __do_proc_doulongvec_minmax(void *data, ctl_table *table, int write, |
| 1978 | struct file *filp, | 2086 | struct file *filp, |
| 1979 | void __user *buffer, | 2087 | void __user *buffer, |
| 1980 | size_t *lenp, loff_t *ppos, | 2088 | size_t *lenp, loff_t *ppos, |
| @@ -1988,13 +2096,13 @@ static int do_proc_doulongvec_minmax(ctl_table *table, int write, | |||
| 1988 | char buf[TMPBUFLEN], *p; | 2096 | char buf[TMPBUFLEN], *p; |
| 1989 | char __user *s = buffer; | 2097 | char __user *s = buffer; |
| 1990 | 2098 | ||
| 1991 | if (!table->data || !table->maxlen || !*lenp || | 2099 | if (!data || !table->maxlen || !*lenp || |
| 1992 | (*ppos && !write)) { | 2100 | (*ppos && !write)) { |
| 1993 | *lenp = 0; | 2101 | *lenp = 0; |
| 1994 | return 0; | 2102 | return 0; |
| 1995 | } | 2103 | } |
| 1996 | 2104 | ||
| 1997 | i = (unsigned long *) table->data; | 2105 | i = (unsigned long *) data; |
| 1998 | min = (unsigned long *) table->extra1; | 2106 | min = (unsigned long *) table->extra1; |
| 1999 | max = (unsigned long *) table->extra2; | 2107 | max = (unsigned long *) table->extra2; |
| 2000 | vleft = table->maxlen / sizeof(unsigned long); | 2108 | vleft = table->maxlen / sizeof(unsigned long); |
| @@ -2079,6 +2187,17 @@ static int do_proc_doulongvec_minmax(ctl_table *table, int write, | |||
| 2079 | #undef TMPBUFLEN | 2187 | #undef TMPBUFLEN |
| 2080 | } | 2188 | } |
| 2081 | 2189 | ||
| 2190 | static int do_proc_doulongvec_minmax(ctl_table *table, int write, | ||
| 2191 | struct file *filp, | ||
| 2192 | void __user *buffer, | ||
| 2193 | size_t *lenp, loff_t *ppos, | ||
| 2194 | unsigned long convmul, | ||
| 2195 | unsigned long convdiv) | ||
| 2196 | { | ||
| 2197 | return __do_proc_doulongvec_minmax(table->data, table, write, | ||
| 2198 | filp, buffer, lenp, ppos, convmul, convdiv); | ||
| 2199 | } | ||
| 2200 | |||
| 2082 | /** | 2201 | /** |
| 2083 | * proc_doulongvec_minmax - read a vector of long integers with min/max values | 2202 | * proc_doulongvec_minmax - read a vector of long integers with min/max values |
| 2084 | * @table: the sysctl table | 2203 | * @table: the sysctl table |
| @@ -2267,6 +2386,71 @@ int proc_dointvec_ms_jiffies(ctl_table *table, int write, struct file *filp, | |||
| 2267 | do_proc_dointvec_ms_jiffies_conv, NULL); | 2386 | do_proc_dointvec_ms_jiffies_conv, NULL); |
| 2268 | } | 2387 | } |
| 2269 | 2388 | ||
| 2389 | #ifdef CONFIG_SYSVIPC | ||
| 2390 | static int proc_do_ipc_string(ctl_table *table, int write, struct file *filp, | ||
| 2391 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
| 2392 | { | ||
| 2393 | void *data; | ||
| 2394 | struct ipc_namespace *ns; | ||
| 2395 | |||
| 2396 | ns = current->nsproxy->ipc_ns; | ||
| 2397 | |||
| 2398 | switch (table->ctl_name) { | ||
| 2399 | case KERN_SHMMAX: | ||
| 2400 | data = &ns->shm_ctlmax; | ||
| 2401 | goto proc_minmax; | ||
| 2402 | case KERN_SHMALL: | ||
| 2403 | data = &ns->shm_ctlall; | ||
| 2404 | goto proc_minmax; | ||
| 2405 | case KERN_SHMMNI: | ||
| 2406 | data = &ns->shm_ctlmni; | ||
| 2407 | break; | ||
| 2408 | case KERN_MSGMAX: | ||
| 2409 | data = &ns->msg_ctlmax; | ||
| 2410 | break; | ||
| 2411 | case KERN_MSGMNI: | ||
| 2412 | data = &ns->msg_ctlmni; | ||
| 2413 | break; | ||
| 2414 | case KERN_MSGMNB: | ||
| 2415 | data = &ns->msg_ctlmnb; | ||
| 2416 | break; | ||
| 2417 | case KERN_SEM: | ||
| 2418 | data = &ns->sem_ctls; | ||
| 2419 | break; | ||
| 2420 | default: | ||
| 2421 | return -EINVAL; | ||
| 2422 | } | ||
| 2423 | |||
| 2424 | return __do_proc_dointvec(data, table, write, filp, buffer, | ||
| 2425 | lenp, ppos, NULL, NULL); | ||
| 2426 | proc_minmax: | ||
| 2427 | return __do_proc_doulongvec_minmax(data, table, write, filp, buffer, | ||
| 2428 | lenp, ppos, 1l, 1l); | ||
| 2429 | } | ||
| 2430 | #endif | ||
| 2431 | |||
| 2432 | static int proc_do_cad_pid(ctl_table *table, int write, struct file *filp, | ||
| 2433 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
| 2434 | { | ||
| 2435 | struct pid *new_pid; | ||
| 2436 | pid_t tmp; | ||
| 2437 | int r; | ||
| 2438 | |||
| 2439 | tmp = pid_nr(cad_pid); | ||
| 2440 | |||
| 2441 | r = __do_proc_dointvec(&tmp, table, write, filp, buffer, | ||
| 2442 | lenp, ppos, NULL, NULL); | ||
| 2443 | if (r || !write) | ||
| 2444 | return r; | ||
| 2445 | |||
| 2446 | new_pid = find_get_pid(tmp); | ||
| 2447 | if (!new_pid) | ||
| 2448 | return -ESRCH; | ||
| 2449 | |||
| 2450 | put_pid(xchg(&cad_pid, new_pid)); | ||
| 2451 | return 0; | ||
| 2452 | } | ||
| 2453 | |||
| 2270 | #else /* CONFIG_PROC_FS */ | 2454 | #else /* CONFIG_PROC_FS */ |
| 2271 | 2455 | ||
| 2272 | int proc_dostring(ctl_table *table, int write, struct file *filp, | 2456 | int proc_dostring(ctl_table *table, int write, struct file *filp, |
| @@ -2275,12 +2459,20 @@ int proc_dostring(ctl_table *table, int write, struct file *filp, | |||
| 2275 | return -ENOSYS; | 2459 | return -ENOSYS; |
| 2276 | } | 2460 | } |
| 2277 | 2461 | ||
| 2278 | static int proc_doutsstring(ctl_table *table, int write, struct file *filp, | 2462 | static int proc_do_uts_string(ctl_table *table, int write, struct file *filp, |
| 2279 | void __user *buffer, size_t *lenp, loff_t *ppos) | 2463 | void __user *buffer, size_t *lenp, loff_t *ppos) |
| 2280 | { | 2464 | { |
| 2281 | return -ENOSYS; | 2465 | return -ENOSYS; |
| 2282 | } | 2466 | } |
| 2283 | 2467 | ||
| 2468 | #ifdef CONFIG_SYSVIPC | ||
| 2469 | static int proc_do_ipc_string(ctl_table *table, int write, struct file *filp, | ||
| 2470 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
| 2471 | { | ||
| 2472 | return -ENOSYS; | ||
| 2473 | } | ||
| 2474 | #endif | ||
| 2475 | |||
| 2284 | int proc_dointvec(ctl_table *table, int write, struct file *filp, | 2476 | int proc_dointvec(ctl_table *table, int write, struct file *filp, |
| 2285 | void __user *buffer, size_t *lenp, loff_t *ppos) | 2477 | void __user *buffer, size_t *lenp, loff_t *ppos) |
| 2286 | { | 2478 | { |
diff --git a/kernel/utsname.c b/kernel/utsname.c new file mode 100644 index 000000000000..c859164a6993 --- /dev/null +++ b/kernel/utsname.c | |||
| @@ -0,0 +1,95 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2004 IBM Corporation | ||
| 3 | * | ||
| 4 | * Author: Serge Hallyn <serue@us.ibm.com> | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public License as | ||
| 8 | * published by the Free Software Foundation, version 2 of the | ||
| 9 | * License. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/module.h> | ||
| 13 | #include <linux/uts.h> | ||
| 14 | #include <linux/utsname.h> | ||
| 15 | #include <linux/version.h> | ||
| 16 | |||
| 17 | /* | ||
| 18 | * Clone a new ns copying an original utsname, setting refcount to 1 | ||
| 19 | * @old_ns: namespace to clone | ||
| 20 | * Return NULL on error (failure to kmalloc), new ns otherwise | ||
| 21 | */ | ||
| 22 | static struct uts_namespace *clone_uts_ns(struct uts_namespace *old_ns) | ||
| 23 | { | ||
| 24 | struct uts_namespace *ns; | ||
| 25 | |||
| 26 | ns = kmalloc(sizeof(struct uts_namespace), GFP_KERNEL); | ||
| 27 | if (ns) { | ||
| 28 | memcpy(&ns->name, &old_ns->name, sizeof(ns->name)); | ||
| 29 | kref_init(&ns->kref); | ||
| 30 | } | ||
| 31 | return ns; | ||
| 32 | } | ||
| 33 | |||
| 34 | /* | ||
| 35 | * unshare the current process' utsname namespace. | ||
| 36 | * called only in sys_unshare() | ||
| 37 | */ | ||
| 38 | int unshare_utsname(unsigned long unshare_flags, struct uts_namespace **new_uts) | ||
| 39 | { | ||
| 40 | if (unshare_flags & CLONE_NEWUTS) { | ||
| 41 | if (!capable(CAP_SYS_ADMIN)) | ||
| 42 | return -EPERM; | ||
| 43 | |||
| 44 | *new_uts = clone_uts_ns(current->nsproxy->uts_ns); | ||
| 45 | if (!*new_uts) | ||
| 46 | return -ENOMEM; | ||
| 47 | } | ||
| 48 | |||
| 49 | return 0; | ||
| 50 | } | ||
| 51 | |||
| 52 | /* | ||
| 53 | * Copy task tsk's utsname namespace, or clone it if flags | ||
| 54 | * specifies CLONE_NEWUTS. In latter case, changes to the | ||
| 55 | * utsname of this process won't be seen by parent, and vice | ||
| 56 | * versa. | ||
| 57 | */ | ||
| 58 | int copy_utsname(int flags, struct task_struct *tsk) | ||
| 59 | { | ||
| 60 | struct uts_namespace *old_ns = tsk->nsproxy->uts_ns; | ||
| 61 | struct uts_namespace *new_ns; | ||
| 62 | int err = 0; | ||
| 63 | |||
| 64 | if (!old_ns) | ||
| 65 | return 0; | ||
| 66 | |||
| 67 | get_uts_ns(old_ns); | ||
| 68 | |||
| 69 | if (!(flags & CLONE_NEWUTS)) | ||
| 70 | return 0; | ||
| 71 | |||
| 72 | if (!capable(CAP_SYS_ADMIN)) { | ||
| 73 | err = -EPERM; | ||
| 74 | goto out; | ||
| 75 | } | ||
| 76 | |||
| 77 | new_ns = clone_uts_ns(old_ns); | ||
| 78 | if (!new_ns) { | ||
| 79 | err = -ENOMEM; | ||
| 80 | goto out; | ||
| 81 | } | ||
| 82 | tsk->nsproxy->uts_ns = new_ns; | ||
| 83 | |||
| 84 | out: | ||
| 85 | put_uts_ns(old_ns); | ||
| 86 | return err; | ||
| 87 | } | ||
| 88 | |||
| 89 | void free_uts_ns(struct kref *kref) | ||
| 90 | { | ||
| 91 | struct uts_namespace *ns; | ||
| 92 | |||
| 93 | ns = container_of(kref, struct uts_namespace, kref); | ||
| 94 | kfree(ns); | ||
| 95 | } | ||
