diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-04-17 09:04:38 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-04-17 09:04:38 -0400 |
| commit | 54e514b91b95d6441c12a7955addfb9f9d2afc65 (patch) | |
| tree | 8b73d901bd2a6ec5a31f34a8954e5ea92216dd6c /kernel | |
| parent | 4fc8adcfec3da639da76e8314c9ccefe5bf9a045 (diff) | |
| parent | 6c8c90319c0bb1c9e0b68e721359b89ae4f28465 (diff) | |
Merge branch 'akpm' (patches from Andrew)
Merge third patchbomb from Andrew Morton:
- various misc things
- a couple of lib/ optimisations
- provide DIV_ROUND_CLOSEST_ULL()
- checkpatch updates
- rtc tree
- befs, nilfs2, hfs, hfsplus, fatfs, adfs, affs, bfs
- ptrace fixes
- fork() fixes
- seccomp cleanups
- more mmap_sem hold time reductions from Davidlohr
* emailed patches from Andrew Morton <akpm@linux-foundation.org>: (138 commits)
proc: show locks in /proc/pid/fdinfo/X
docs: add missing and new /proc/PID/status file entries, fix typos
drivers/rtc/rtc-at91rm9200.c: make IO endian agnostic
Documentation/spi/spidev_test.c: fix warning
drivers/rtc/rtc-s5m.c: allow usage on device type different than main MFD type
.gitignore: ignore *.tar
MAINTAINERS: add Mediatek SoC mailing list
tomoyo: reduce mmap_sem hold for mm->exe_file
powerpc/oprofile: reduce mmap_sem hold for exe_file
oprofile: reduce mmap_sem hold for mm->exe_file
mips: ip32: add platform data hooks to use DS1685 driver
lib/Kconfig: fix up HAVE_ARCH_BITREVERSE help text
x86: switch to using asm-generic for seccomp.h
sparc: switch to using asm-generic for seccomp.h
powerpc: switch to using asm-generic for seccomp.h
parisc: switch to using asm-generic for seccomp.h
mips: switch to using asm-generic for seccomp.h
microblaze: use asm-generic for seccomp.h
arm: use asm-generic for seccomp.h
seccomp: allow COMPAT sigreturn overrides
...
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/fork.c | 141 | ||||
| -rw-r--r-- | kernel/gcov/base.c | 5 | ||||
| -rw-r--r-- | kernel/pid.c | 15 | ||||
| -rw-r--r-- | kernel/ptrace.c | 39 | ||||
| -rw-r--r-- | kernel/signal.c | 14 | ||||
| -rw-r--r-- | kernel/sys.c | 47 | ||||
| -rw-r--r-- | kernel/sysctl.c | 16 |
7 files changed, 192 insertions, 85 deletions
diff --git a/kernel/fork.c b/kernel/fork.c index f2c1e7352298..03c1eaaa6ef5 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
| @@ -74,6 +74,7 @@ | |||
| 74 | #include <linux/uprobes.h> | 74 | #include <linux/uprobes.h> |
| 75 | #include <linux/aio.h> | 75 | #include <linux/aio.h> |
| 76 | #include <linux/compiler.h> | 76 | #include <linux/compiler.h> |
| 77 | #include <linux/sysctl.h> | ||
| 77 | 78 | ||
| 78 | #include <asm/pgtable.h> | 79 | #include <asm/pgtable.h> |
| 79 | #include <asm/pgalloc.h> | 80 | #include <asm/pgalloc.h> |
| @@ -88,6 +89,16 @@ | |||
| 88 | #include <trace/events/task.h> | 89 | #include <trace/events/task.h> |
| 89 | 90 | ||
| 90 | /* | 91 | /* |
| 92 | * Minimum number of threads to boot the kernel | ||
| 93 | */ | ||
| 94 | #define MIN_THREADS 20 | ||
| 95 | |||
| 96 | /* | ||
| 97 | * Maximum number of threads | ||
| 98 | */ | ||
| 99 | #define MAX_THREADS FUTEX_TID_MASK | ||
| 100 | |||
| 101 | /* | ||
| 91 | * Protected counters by write_lock_irq(&tasklist_lock) | 102 | * Protected counters by write_lock_irq(&tasklist_lock) |
| 92 | */ | 103 | */ |
| 93 | unsigned long total_forks; /* Handle normal Linux uptimes. */ | 104 | unsigned long total_forks; /* Handle normal Linux uptimes. */ |
| @@ -253,7 +264,30 @@ EXPORT_SYMBOL_GPL(__put_task_struct); | |||
| 253 | 264 | ||
| 254 | void __init __weak arch_task_cache_init(void) { } | 265 | void __init __weak arch_task_cache_init(void) { } |
| 255 | 266 | ||
| 256 | void __init fork_init(unsigned long mempages) | 267 | /* |
| 268 | * set_max_threads | ||
| 269 | */ | ||
| 270 | static void set_max_threads(unsigned int max_threads_suggested) | ||
| 271 | { | ||
| 272 | u64 threads; | ||
| 273 | |||
| 274 | /* | ||
| 275 | * The number of threads shall be limited such that the thread | ||
| 276 | * structures may only consume a small part of the available memory. | ||
| 277 | */ | ||
| 278 | if (fls64(totalram_pages) + fls64(PAGE_SIZE) > 64) | ||
| 279 | threads = MAX_THREADS; | ||
| 280 | else | ||
| 281 | threads = div64_u64((u64) totalram_pages * (u64) PAGE_SIZE, | ||
| 282 | (u64) THREAD_SIZE * 8UL); | ||
| 283 | |||
| 284 | if (threads > max_threads_suggested) | ||
| 285 | threads = max_threads_suggested; | ||
| 286 | |||
| 287 | max_threads = clamp_t(u64, threads, MIN_THREADS, MAX_THREADS); | ||
| 288 | } | ||
| 289 | |||
| 290 | void __init fork_init(void) | ||
| 257 | { | 291 | { |
| 258 | #ifndef CONFIG_ARCH_TASK_STRUCT_ALLOCATOR | 292 | #ifndef CONFIG_ARCH_TASK_STRUCT_ALLOCATOR |
| 259 | #ifndef ARCH_MIN_TASKALIGN | 293 | #ifndef ARCH_MIN_TASKALIGN |
| @@ -268,18 +302,7 @@ void __init fork_init(unsigned long mempages) | |||
| 268 | /* do the arch specific task caches init */ | 302 | /* do the arch specific task caches init */ |
| 269 | arch_task_cache_init(); | 303 | arch_task_cache_init(); |
| 270 | 304 | ||
| 271 | /* | 305 | set_max_threads(MAX_THREADS); |
| 272 | * The default maximum number of threads is set to a safe | ||
| 273 | * value: the thread structures can take up at most half | ||
| 274 | * of memory. | ||
| 275 | */ | ||
| 276 | max_threads = mempages / (8 * THREAD_SIZE / PAGE_SIZE); | ||
| 277 | |||
| 278 | /* | ||
| 279 | * we need to allow at least 20 threads to boot a system | ||
| 280 | */ | ||
| 281 | if (max_threads < 20) | ||
| 282 | max_threads = 20; | ||
| 283 | 306 | ||
| 284 | init_task.signal->rlim[RLIMIT_NPROC].rlim_cur = max_threads/2; | 307 | init_task.signal->rlim[RLIMIT_NPROC].rlim_cur = max_threads/2; |
| 285 | init_task.signal->rlim[RLIMIT_NPROC].rlim_max = max_threads/2; | 308 | init_task.signal->rlim[RLIMIT_NPROC].rlim_max = max_threads/2; |
| @@ -380,6 +403,9 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm) | |||
| 380 | */ | 403 | */ |
| 381 | down_write_nested(&mm->mmap_sem, SINGLE_DEPTH_NESTING); | 404 | down_write_nested(&mm->mmap_sem, SINGLE_DEPTH_NESTING); |
| 382 | 405 | ||
| 406 | /* No ordering required: file already has been exposed. */ | ||
| 407 | RCU_INIT_POINTER(mm->exe_file, get_mm_exe_file(oldmm)); | ||
| 408 | |||
| 383 | mm->total_vm = oldmm->total_vm; | 409 | mm->total_vm = oldmm->total_vm; |
| 384 | mm->shared_vm = oldmm->shared_vm; | 410 | mm->shared_vm = oldmm->shared_vm; |
| 385 | mm->exec_vm = oldmm->exec_vm; | 411 | mm->exec_vm = oldmm->exec_vm; |
| @@ -505,7 +531,13 @@ static inline void mm_free_pgd(struct mm_struct *mm) | |||
| 505 | pgd_free(mm, mm->pgd); | 531 | pgd_free(mm, mm->pgd); |
| 506 | } | 532 | } |
| 507 | #else | 533 | #else |
| 508 | #define dup_mmap(mm, oldmm) (0) | 534 | static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm) |
| 535 | { | ||
| 536 | down_write(&oldmm->mmap_sem); | ||
| 537 | RCU_INIT_POINTER(mm->exe_file, get_mm_exe_file(oldmm)); | ||
| 538 | up_write(&oldmm->mmap_sem); | ||
| 539 | return 0; | ||
| 540 | } | ||
| 509 | #define mm_alloc_pgd(mm) (0) | 541 | #define mm_alloc_pgd(mm) (0) |
| 510 | #define mm_free_pgd(mm) | 542 | #define mm_free_pgd(mm) |
| 511 | #endif /* CONFIG_MMU */ | 543 | #endif /* CONFIG_MMU */ |
| @@ -674,34 +706,53 @@ void mmput(struct mm_struct *mm) | |||
| 674 | } | 706 | } |
| 675 | EXPORT_SYMBOL_GPL(mmput); | 707 | EXPORT_SYMBOL_GPL(mmput); |
| 676 | 708 | ||
| 709 | /** | ||
| 710 | * set_mm_exe_file - change a reference to the mm's executable file | ||
| 711 | * | ||
| 712 | * This changes mm's executable file (shown as symlink /proc/[pid]/exe). | ||
| 713 | * | ||
| 714 | * Main users are mmput() and sys_execve(). Callers prevent concurrent | ||
| 715 | * invocations: in mmput() nobody alive left, in execve task is single | ||
| 716 | * threaded. sys_prctl(PR_SET_MM_MAP/EXE_FILE) also needs to set the | ||
| 717 | * mm->exe_file, but does so without using set_mm_exe_file() in order | ||
| 718 | * to do avoid the need for any locks. | ||
| 719 | */ | ||
| 677 | void set_mm_exe_file(struct mm_struct *mm, struct file *new_exe_file) | 720 | void set_mm_exe_file(struct mm_struct *mm, struct file *new_exe_file) |
| 678 | { | 721 | { |
| 722 | struct file *old_exe_file; | ||
| 723 | |||
| 724 | /* | ||
| 725 | * It is safe to dereference the exe_file without RCU as | ||
| 726 | * this function is only called if nobody else can access | ||
| 727 | * this mm -- see comment above for justification. | ||
| 728 | */ | ||
| 729 | old_exe_file = rcu_dereference_raw(mm->exe_file); | ||
| 730 | |||
| 679 | if (new_exe_file) | 731 | if (new_exe_file) |
| 680 | get_file(new_exe_file); | 732 | get_file(new_exe_file); |
| 681 | if (mm->exe_file) | 733 | rcu_assign_pointer(mm->exe_file, new_exe_file); |
| 682 | fput(mm->exe_file); | 734 | if (old_exe_file) |
| 683 | mm->exe_file = new_exe_file; | 735 | fput(old_exe_file); |
| 684 | } | 736 | } |
| 685 | 737 | ||
| 738 | /** | ||
| 739 | * get_mm_exe_file - acquire a reference to the mm's executable file | ||
| 740 | * | ||
| 741 | * Returns %NULL if mm has no associated executable file. | ||
| 742 | * User must release file via fput(). | ||
| 743 | */ | ||
| 686 | struct file *get_mm_exe_file(struct mm_struct *mm) | 744 | struct file *get_mm_exe_file(struct mm_struct *mm) |
| 687 | { | 745 | { |
| 688 | struct file *exe_file; | 746 | struct file *exe_file; |
| 689 | 747 | ||
| 690 | /* We need mmap_sem to protect against races with removal of exe_file */ | 748 | rcu_read_lock(); |
| 691 | down_read(&mm->mmap_sem); | 749 | exe_file = rcu_dereference(mm->exe_file); |
| 692 | exe_file = mm->exe_file; | 750 | if (exe_file && !get_file_rcu(exe_file)) |
| 693 | if (exe_file) | 751 | exe_file = NULL; |
| 694 | get_file(exe_file); | 752 | rcu_read_unlock(); |
| 695 | up_read(&mm->mmap_sem); | ||
| 696 | return exe_file; | 753 | return exe_file; |
| 697 | } | 754 | } |
| 698 | 755 | EXPORT_SYMBOL(get_mm_exe_file); | |
| 699 | static void dup_mm_exe_file(struct mm_struct *oldmm, struct mm_struct *newmm) | ||
| 700 | { | ||
| 701 | /* It's safe to write the exe_file pointer without exe_file_lock because | ||
| 702 | * this is called during fork when the task is not yet in /proc */ | ||
| 703 | newmm->exe_file = get_mm_exe_file(oldmm); | ||
| 704 | } | ||
| 705 | 756 | ||
| 706 | /** | 757 | /** |
| 707 | * get_task_mm - acquire a reference to the task's mm | 758 | * get_task_mm - acquire a reference to the task's mm |
| @@ -864,8 +915,6 @@ static struct mm_struct *dup_mm(struct task_struct *tsk) | |||
| 864 | if (!mm_init(mm, tsk)) | 915 | if (!mm_init(mm, tsk)) |
| 865 | goto fail_nomem; | 916 | goto fail_nomem; |
| 866 | 917 | ||
| 867 | dup_mm_exe_file(oldmm, mm); | ||
| 868 | |||
| 869 | err = dup_mmap(mm, oldmm); | 918 | err = dup_mmap(mm, oldmm); |
| 870 | if (err) | 919 | if (err) |
| 871 | goto free_pt; | 920 | goto free_pt; |
| @@ -1403,10 +1452,11 @@ static struct task_struct *copy_process(unsigned long clone_flags, | |||
| 1403 | goto bad_fork_cleanup_io; | 1452 | goto bad_fork_cleanup_io; |
| 1404 | 1453 | ||
| 1405 | if (pid != &init_struct_pid) { | 1454 | if (pid != &init_struct_pid) { |
| 1406 | retval = -ENOMEM; | ||
| 1407 | pid = alloc_pid(p->nsproxy->pid_ns_for_children); | 1455 | pid = alloc_pid(p->nsproxy->pid_ns_for_children); |
| 1408 | if (!pid) | 1456 | if (IS_ERR(pid)) { |
| 1457 | retval = PTR_ERR(pid); | ||
| 1409 | goto bad_fork_cleanup_io; | 1458 | goto bad_fork_cleanup_io; |
| 1459 | } | ||
| 1410 | } | 1460 | } |
| 1411 | 1461 | ||
| 1412 | p->set_child_tid = (clone_flags & CLONE_CHILD_SETTID) ? child_tidptr : NULL; | 1462 | p->set_child_tid = (clone_flags & CLONE_CHILD_SETTID) ? child_tidptr : NULL; |
| @@ -2000,3 +2050,26 @@ int unshare_files(struct files_struct **displaced) | |||
| 2000 | task_unlock(task); | 2050 | task_unlock(task); |
| 2001 | return 0; | 2051 | return 0; |
| 2002 | } | 2052 | } |
| 2053 | |||
| 2054 | int sysctl_max_threads(struct ctl_table *table, int write, | ||
| 2055 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
| 2056 | { | ||
| 2057 | struct ctl_table t; | ||
| 2058 | int ret; | ||
| 2059 | int threads = max_threads; | ||
| 2060 | int min = MIN_THREADS; | ||
| 2061 | int max = MAX_THREADS; | ||
| 2062 | |||
| 2063 | t = *table; | ||
| 2064 | t.data = &threads; | ||
| 2065 | t.extra1 = &min; | ||
| 2066 | t.extra2 = &max; | ||
| 2067 | |||
| 2068 | ret = proc_dointvec_minmax(&t, write, buffer, lenp, ppos); | ||
| 2069 | if (ret || !write) | ||
| 2070 | return ret; | ||
| 2071 | |||
| 2072 | set_max_threads(threads); | ||
| 2073 | |||
| 2074 | return 0; | ||
| 2075 | } | ||
diff --git a/kernel/gcov/base.c b/kernel/gcov/base.c index b358a802fd18..a744098e4eb7 100644 --- a/kernel/gcov/base.c +++ b/kernel/gcov/base.c | |||
| @@ -18,6 +18,7 @@ | |||
| 18 | #include <linux/init.h> | 18 | #include <linux/init.h> |
| 19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
| 20 | #include <linux/mutex.h> | 20 | #include <linux/mutex.h> |
| 21 | #include <linux/sched.h> | ||
| 21 | #include "gcov.h" | 22 | #include "gcov.h" |
| 22 | 23 | ||
| 23 | static int gcov_events_enabled; | 24 | static int gcov_events_enabled; |
| @@ -107,8 +108,10 @@ void gcov_enable_events(void) | |||
| 107 | gcov_events_enabled = 1; | 108 | gcov_events_enabled = 1; |
| 108 | 109 | ||
| 109 | /* Perform event callback for previously registered entries. */ | 110 | /* Perform event callback for previously registered entries. */ |
| 110 | while ((info = gcov_info_next(info))) | 111 | while ((info = gcov_info_next(info))) { |
| 111 | gcov_event(GCOV_ADD, info); | 112 | gcov_event(GCOV_ADD, info); |
| 113 | cond_resched(); | ||
| 114 | } | ||
| 112 | 115 | ||
| 113 | mutex_unlock(&gcov_lock); | 116 | mutex_unlock(&gcov_lock); |
| 114 | } | 117 | } |
diff --git a/kernel/pid.c b/kernel/pid.c index cd36a5e0d173..4fd07d5b7baf 100644 --- a/kernel/pid.c +++ b/kernel/pid.c | |||
| @@ -182,7 +182,7 @@ static int alloc_pidmap(struct pid_namespace *pid_ns) | |||
| 182 | spin_unlock_irq(&pidmap_lock); | 182 | spin_unlock_irq(&pidmap_lock); |
| 183 | kfree(page); | 183 | kfree(page); |
| 184 | if (unlikely(!map->page)) | 184 | if (unlikely(!map->page)) |
| 185 | break; | 185 | return -ENOMEM; |
| 186 | } | 186 | } |
| 187 | if (likely(atomic_read(&map->nr_free))) { | 187 | if (likely(atomic_read(&map->nr_free))) { |
| 188 | for ( ; ; ) { | 188 | for ( ; ; ) { |
| @@ -210,7 +210,7 @@ static int alloc_pidmap(struct pid_namespace *pid_ns) | |||
| 210 | } | 210 | } |
| 211 | pid = mk_pid(pid_ns, map, offset); | 211 | pid = mk_pid(pid_ns, map, offset); |
| 212 | } | 212 | } |
| 213 | return -1; | 213 | return -EAGAIN; |
| 214 | } | 214 | } |
| 215 | 215 | ||
| 216 | int next_pidmap(struct pid_namespace *pid_ns, unsigned int last) | 216 | int next_pidmap(struct pid_namespace *pid_ns, unsigned int last) |
| @@ -301,17 +301,20 @@ struct pid *alloc_pid(struct pid_namespace *ns) | |||
| 301 | int i, nr; | 301 | int i, nr; |
| 302 | struct pid_namespace *tmp; | 302 | struct pid_namespace *tmp; |
| 303 | struct upid *upid; | 303 | struct upid *upid; |
| 304 | int retval = -ENOMEM; | ||
| 304 | 305 | ||
| 305 | pid = kmem_cache_alloc(ns->pid_cachep, GFP_KERNEL); | 306 | pid = kmem_cache_alloc(ns->pid_cachep, GFP_KERNEL); |
| 306 | if (!pid) | 307 | if (!pid) |
| 307 | goto out; | 308 | return ERR_PTR(retval); |
| 308 | 309 | ||
| 309 | tmp = ns; | 310 | tmp = ns; |
| 310 | pid->level = ns->level; | 311 | pid->level = ns->level; |
| 311 | for (i = ns->level; i >= 0; i--) { | 312 | for (i = ns->level; i >= 0; i--) { |
| 312 | nr = alloc_pidmap(tmp); | 313 | nr = alloc_pidmap(tmp); |
| 313 | if (nr < 0) | 314 | if (IS_ERR_VALUE(nr)) { |
| 315 | retval = nr; | ||
| 314 | goto out_free; | 316 | goto out_free; |
| 317 | } | ||
| 315 | 318 | ||
| 316 | pid->numbers[i].nr = nr; | 319 | pid->numbers[i].nr = nr; |
| 317 | pid->numbers[i].ns = tmp; | 320 | pid->numbers[i].ns = tmp; |
| @@ -339,7 +342,6 @@ struct pid *alloc_pid(struct pid_namespace *ns) | |||
| 339 | } | 342 | } |
| 340 | spin_unlock_irq(&pidmap_lock); | 343 | spin_unlock_irq(&pidmap_lock); |
| 341 | 344 | ||
| 342 | out: | ||
| 343 | return pid; | 345 | return pid; |
| 344 | 346 | ||
| 345 | out_unlock: | 347 | out_unlock: |
| @@ -351,8 +353,7 @@ out_free: | |||
| 351 | free_pidmap(pid->numbers + i); | 353 | free_pidmap(pid->numbers + i); |
| 352 | 354 | ||
| 353 | kmem_cache_free(ns->pid_cachep, pid); | 355 | kmem_cache_free(ns->pid_cachep, pid); |
| 354 | pid = NULL; | 356 | return ERR_PTR(retval); |
| 355 | goto out; | ||
| 356 | } | 357 | } |
| 357 | 358 | ||
| 358 | void disable_pid_allocation(struct pid_namespace *ns) | 359 | void disable_pid_allocation(struct pid_namespace *ns) |
diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 227fec36b12a..c8e0e050a36a 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c | |||
| @@ -456,8 +456,6 @@ static bool __ptrace_detach(struct task_struct *tracer, struct task_struct *p) | |||
| 456 | 456 | ||
| 457 | static int ptrace_detach(struct task_struct *child, unsigned int data) | 457 | static int ptrace_detach(struct task_struct *child, unsigned int data) |
| 458 | { | 458 | { |
| 459 | bool dead = false; | ||
| 460 | |||
| 461 | if (!valid_signal(data)) | 459 | if (!valid_signal(data)) |
| 462 | return -EIO; | 460 | return -EIO; |
| 463 | 461 | ||
| @@ -467,18 +465,19 @@ static int ptrace_detach(struct task_struct *child, unsigned int data) | |||
| 467 | 465 | ||
| 468 | write_lock_irq(&tasklist_lock); | 466 | write_lock_irq(&tasklist_lock); |
| 469 | /* | 467 | /* |
| 470 | * This child can be already killed. Make sure de_thread() or | 468 | * We rely on ptrace_freeze_traced(). It can't be killed and |
| 471 | * our sub-thread doing do_wait() didn't do release_task() yet. | 469 | * untraced by another thread, it can't be a zombie. |
| 472 | */ | 470 | */ |
| 473 | if (child->ptrace) { | 471 | WARN_ON(!child->ptrace || child->exit_state); |
| 474 | child->exit_code = data; | 472 | /* |
| 475 | dead = __ptrace_detach(current, child); | 473 | * tasklist_lock avoids the race with wait_task_stopped(), see |
| 476 | } | 474 | * the comment in ptrace_resume(). |
| 475 | */ | ||
| 476 | child->exit_code = data; | ||
| 477 | __ptrace_detach(current, child); | ||
| 477 | write_unlock_irq(&tasklist_lock); | 478 | write_unlock_irq(&tasklist_lock); |
| 478 | 479 | ||
| 479 | proc_ptrace_connector(child, PTRACE_DETACH); | 480 | proc_ptrace_connector(child, PTRACE_DETACH); |
| 480 | if (unlikely(dead)) | ||
| 481 | release_task(child); | ||
| 482 | 481 | ||
| 483 | return 0; | 482 | return 0; |
| 484 | } | 483 | } |
| @@ -697,6 +696,8 @@ static int ptrace_peek_siginfo(struct task_struct *child, | |||
| 697 | static int ptrace_resume(struct task_struct *child, long request, | 696 | static int ptrace_resume(struct task_struct *child, long request, |
| 698 | unsigned long data) | 697 | unsigned long data) |
| 699 | { | 698 | { |
| 699 | bool need_siglock; | ||
| 700 | |||
| 700 | if (!valid_signal(data)) | 701 | if (!valid_signal(data)) |
| 701 | return -EIO; | 702 | return -EIO; |
| 702 | 703 | ||
| @@ -724,8 +725,26 @@ static int ptrace_resume(struct task_struct *child, long request, | |||
| 724 | user_disable_single_step(child); | 725 | user_disable_single_step(child); |
| 725 | } | 726 | } |
| 726 | 727 | ||
| 728 | /* | ||
| 729 | * Change ->exit_code and ->state under siglock to avoid the race | ||
| 730 | * with wait_task_stopped() in between; a non-zero ->exit_code will | ||
| 731 | * wrongly look like another report from tracee. | ||
| 732 | * | ||
| 733 | * Note that we need siglock even if ->exit_code == data and/or this | ||
| 734 | * status was not reported yet, the new status must not be cleared by | ||
| 735 | * wait_task_stopped() after resume. | ||
| 736 | * | ||
| 737 | * If data == 0 we do not care if wait_task_stopped() reports the old | ||
| 738 | * status and clears the code too; this can't race with the tracee, it | ||
| 739 | * takes siglock after resume. | ||
| 740 | */ | ||
| 741 | need_siglock = data && !thread_group_empty(current); | ||
| 742 | if (need_siglock) | ||
| 743 | spin_lock_irq(&child->sighand->siglock); | ||
| 727 | child->exit_code = data; | 744 | child->exit_code = data; |
| 728 | wake_up_state(child, __TASK_TRACED); | 745 | wake_up_state(child, __TASK_TRACED); |
| 746 | if (need_siglock) | ||
| 747 | spin_unlock_irq(&child->sighand->siglock); | ||
| 729 | 748 | ||
| 730 | return 0; | 749 | return 0; |
| 731 | } | 750 | } |
diff --git a/kernel/signal.c b/kernel/signal.c index a390499943e4..d51c5ddd855c 100644 --- a/kernel/signal.c +++ b/kernel/signal.c | |||
| @@ -2992,11 +2992,9 @@ static int do_rt_sigqueueinfo(pid_t pid, int sig, siginfo_t *info) | |||
| 2992 | * Nor can they impersonate a kill()/tgkill(), which adds source info. | 2992 | * Nor can they impersonate a kill()/tgkill(), which adds source info. |
| 2993 | */ | 2993 | */ |
| 2994 | if ((info->si_code >= 0 || info->si_code == SI_TKILL) && | 2994 | if ((info->si_code >= 0 || info->si_code == SI_TKILL) && |
| 2995 | (task_pid_vnr(current) != pid)) { | 2995 | (task_pid_vnr(current) != pid)) |
| 2996 | /* We used to allow any < 0 si_code */ | ||
| 2997 | WARN_ON_ONCE(info->si_code < 0); | ||
| 2998 | return -EPERM; | 2996 | return -EPERM; |
| 2999 | } | 2997 | |
| 3000 | info->si_signo = sig; | 2998 | info->si_signo = sig; |
| 3001 | 2999 | ||
| 3002 | /* POSIX.1b doesn't mention process groups. */ | 3000 | /* POSIX.1b doesn't mention process groups. */ |
| @@ -3041,12 +3039,10 @@ static int do_rt_tgsigqueueinfo(pid_t tgid, pid_t pid, int sig, siginfo_t *info) | |||
| 3041 | /* Not even root can pretend to send signals from the kernel. | 3039 | /* Not even root can pretend to send signals from the kernel. |
| 3042 | * Nor can they impersonate a kill()/tgkill(), which adds source info. | 3040 | * Nor can they impersonate a kill()/tgkill(), which adds source info. |
| 3043 | */ | 3041 | */ |
| 3044 | if (((info->si_code >= 0 || info->si_code == SI_TKILL)) && | 3042 | if ((info->si_code >= 0 || info->si_code == SI_TKILL) && |
| 3045 | (task_pid_vnr(current) != pid)) { | 3043 | (task_pid_vnr(current) != pid)) |
| 3046 | /* We used to allow any < 0 si_code */ | ||
| 3047 | WARN_ON_ONCE(info->si_code < 0); | ||
| 3048 | return -EPERM; | 3044 | return -EPERM; |
| 3049 | } | 3045 | |
| 3050 | info->si_signo = sig; | 3046 | info->si_signo = sig; |
| 3051 | 3047 | ||
| 3052 | return do_send_specific(tgid, pid, sig, info); | 3048 | return do_send_specific(tgid, pid, sig, info); |
diff --git a/kernel/sys.c b/kernel/sys.c index 3be344902316..a4e372b798a5 100644 --- a/kernel/sys.c +++ b/kernel/sys.c | |||
| @@ -1649,14 +1649,13 @@ SYSCALL_DEFINE1(umask, int, mask) | |||
| 1649 | return mask; | 1649 | return mask; |
| 1650 | } | 1650 | } |
| 1651 | 1651 | ||
| 1652 | static int prctl_set_mm_exe_file_locked(struct mm_struct *mm, unsigned int fd) | 1652 | static int prctl_set_mm_exe_file(struct mm_struct *mm, unsigned int fd) |
| 1653 | { | 1653 | { |
| 1654 | struct fd exe; | 1654 | struct fd exe; |
| 1655 | struct file *old_exe, *exe_file; | ||
| 1655 | struct inode *inode; | 1656 | struct inode *inode; |
| 1656 | int err; | 1657 | int err; |
| 1657 | 1658 | ||
| 1658 | VM_BUG_ON_MM(!rwsem_is_locked(&mm->mmap_sem), mm); | ||
| 1659 | |||
| 1660 | exe = fdget(fd); | 1659 | exe = fdget(fd); |
| 1661 | if (!exe.file) | 1660 | if (!exe.file) |
| 1662 | return -EBADF; | 1661 | return -EBADF; |
| @@ -1680,15 +1679,22 @@ static int prctl_set_mm_exe_file_locked(struct mm_struct *mm, unsigned int fd) | |||
| 1680 | /* | 1679 | /* |
| 1681 | * Forbid mm->exe_file change if old file still mapped. | 1680 | * Forbid mm->exe_file change if old file still mapped. |
| 1682 | */ | 1681 | */ |
| 1682 | exe_file = get_mm_exe_file(mm); | ||
| 1683 | err = -EBUSY; | 1683 | err = -EBUSY; |
| 1684 | if (mm->exe_file) { | 1684 | if (exe_file) { |
| 1685 | struct vm_area_struct *vma; | 1685 | struct vm_area_struct *vma; |
| 1686 | 1686 | ||
| 1687 | for (vma = mm->mmap; vma; vma = vma->vm_next) | 1687 | down_read(&mm->mmap_sem); |
| 1688 | if (vma->vm_file && | 1688 | for (vma = mm->mmap; vma; vma = vma->vm_next) { |
| 1689 | path_equal(&vma->vm_file->f_path, | 1689 | if (!vma->vm_file) |
| 1690 | &mm->exe_file->f_path)) | 1690 | continue; |
| 1691 | goto exit; | 1691 | if (path_equal(&vma->vm_file->f_path, |
| 1692 | &exe_file->f_path)) | ||
| 1693 | goto exit_err; | ||
| 1694 | } | ||
| 1695 | |||
| 1696 | up_read(&mm->mmap_sem); | ||
| 1697 | fput(exe_file); | ||
| 1692 | } | 1698 | } |
| 1693 | 1699 | ||
| 1694 | /* | 1700 | /* |
| @@ -1702,10 +1708,18 @@ static int prctl_set_mm_exe_file_locked(struct mm_struct *mm, unsigned int fd) | |||
| 1702 | goto exit; | 1708 | goto exit; |
| 1703 | 1709 | ||
| 1704 | err = 0; | 1710 | err = 0; |
| 1705 | set_mm_exe_file(mm, exe.file); /* this grabs a reference to exe.file */ | 1711 | /* set the new file, lockless */ |
| 1712 | get_file(exe.file); | ||
| 1713 | old_exe = xchg(&mm->exe_file, exe.file); | ||
| 1714 | if (old_exe) | ||
| 1715 | fput(old_exe); | ||
| 1706 | exit: | 1716 | exit: |
| 1707 | fdput(exe); | 1717 | fdput(exe); |
| 1708 | return err; | 1718 | return err; |
| 1719 | exit_err: | ||
| 1720 | up_read(&mm->mmap_sem); | ||
| 1721 | fput(exe_file); | ||
| 1722 | goto exit; | ||
| 1709 | } | 1723 | } |
| 1710 | 1724 | ||
| 1711 | #ifdef CONFIG_CHECKPOINT_RESTORE | 1725 | #ifdef CONFIG_CHECKPOINT_RESTORE |
| @@ -1840,10 +1854,9 @@ static int prctl_set_mm_map(int opt, const void __user *addr, unsigned long data | |||
| 1840 | user_auxv[AT_VECTOR_SIZE - 1] = AT_NULL; | 1854 | user_auxv[AT_VECTOR_SIZE - 1] = AT_NULL; |
| 1841 | } | 1855 | } |
| 1842 | 1856 | ||
| 1843 | down_write(&mm->mmap_sem); | ||
| 1844 | if (prctl_map.exe_fd != (u32)-1) | 1857 | if (prctl_map.exe_fd != (u32)-1) |
| 1845 | error = prctl_set_mm_exe_file_locked(mm, prctl_map.exe_fd); | 1858 | error = prctl_set_mm_exe_file(mm, prctl_map.exe_fd); |
| 1846 | downgrade_write(&mm->mmap_sem); | 1859 | down_read(&mm->mmap_sem); |
| 1847 | if (error) | 1860 | if (error) |
| 1848 | goto out; | 1861 | goto out; |
| 1849 | 1862 | ||
| @@ -1909,12 +1922,8 @@ static int prctl_set_mm(int opt, unsigned long addr, | |||
| 1909 | if (!capable(CAP_SYS_RESOURCE)) | 1922 | if (!capable(CAP_SYS_RESOURCE)) |
| 1910 | return -EPERM; | 1923 | return -EPERM; |
| 1911 | 1924 | ||
| 1912 | if (opt == PR_SET_MM_EXE_FILE) { | 1925 | if (opt == PR_SET_MM_EXE_FILE) |
| 1913 | down_write(&mm->mmap_sem); | 1926 | return prctl_set_mm_exe_file(mm, (unsigned int)addr); |
| 1914 | error = prctl_set_mm_exe_file_locked(mm, (unsigned int)addr); | ||
| 1915 | up_write(&mm->mmap_sem); | ||
| 1916 | return error; | ||
| 1917 | } | ||
| 1918 | 1927 | ||
| 1919 | if (addr >= TASK_SIZE || addr < mmap_min_addr) | 1928 | if (addr >= TASK_SIZE || addr < mmap_min_addr) |
| 1920 | return -EINVAL; | 1929 | return -EINVAL; |
diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 42b7fc2860c1..2082b1a88fb9 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c | |||
| @@ -93,11 +93,9 @@ | |||
| 93 | #include <linux/nmi.h> | 93 | #include <linux/nmi.h> |
| 94 | #endif | 94 | #endif |
| 95 | 95 | ||
| 96 | |||
| 97 | #if defined(CONFIG_SYSCTL) | 96 | #if defined(CONFIG_SYSCTL) |
| 98 | 97 | ||
| 99 | /* External variables not in a header file. */ | 98 | /* External variables not in a header file. */ |
| 100 | extern int max_threads; | ||
| 101 | extern int suid_dumpable; | 99 | extern int suid_dumpable; |
| 102 | #ifdef CONFIG_COREDUMP | 100 | #ifdef CONFIG_COREDUMP |
| 103 | extern int core_uses_pid; | 101 | extern int core_uses_pid; |
| @@ -710,10 +708,10 @@ static struct ctl_table kern_table[] = { | |||
| 710 | #endif | 708 | #endif |
| 711 | { | 709 | { |
| 712 | .procname = "threads-max", | 710 | .procname = "threads-max", |
| 713 | .data = &max_threads, | 711 | .data = NULL, |
| 714 | .maxlen = sizeof(int), | 712 | .maxlen = sizeof(int), |
| 715 | .mode = 0644, | 713 | .mode = 0644, |
| 716 | .proc_handler = proc_dointvec, | 714 | .proc_handler = sysctl_max_threads, |
| 717 | }, | 715 | }, |
| 718 | { | 716 | { |
| 719 | .procname = "random", | 717 | .procname = "random", |
| @@ -1983,7 +1981,15 @@ static int do_proc_dointvec_conv(bool *negp, unsigned long *lvalp, | |||
| 1983 | int write, void *data) | 1981 | int write, void *data) |
| 1984 | { | 1982 | { |
| 1985 | if (write) { | 1983 | if (write) { |
| 1986 | *valp = *negp ? -*lvalp : *lvalp; | 1984 | if (*negp) { |
| 1985 | if (*lvalp > (unsigned long) INT_MAX + 1) | ||
| 1986 | return -EINVAL; | ||
| 1987 | *valp = -*lvalp; | ||
| 1988 | } else { | ||
| 1989 | if (*lvalp > (unsigned long) INT_MAX) | ||
| 1990 | return -EINVAL; | ||
| 1991 | *valp = *lvalp; | ||
| 1992 | } | ||
| 1987 | } else { | 1993 | } else { |
| 1988 | int val = *valp; | 1994 | int val = *valp; |
| 1989 | if (val < 0) { | 1995 | if (val < 0) { |
