diff options
Diffstat (limited to 'kernel/fork.c')
-rw-r--r-- | kernel/fork.c | 51 |
1 files changed, 29 insertions, 22 deletions
diff --git a/kernel/fork.c b/kernel/fork.c index 6067e429f281..933e60ebccae 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/mempolicy.h> | 22 | #include <linux/mempolicy.h> |
23 | #include <linux/sem.h> | 23 | #include <linux/sem.h> |
24 | #include <linux/file.h> | 24 | #include <linux/file.h> |
25 | #include <linux/fdtable.h> | ||
25 | #include <linux/key.h> | 26 | #include <linux/key.h> |
26 | #include <linux/binfmts.h> | 27 | #include <linux/binfmts.h> |
27 | #include <linux/mman.h> | 28 | #include <linux/mman.h> |
@@ -381,14 +382,13 @@ static struct mm_struct * mm_init(struct mm_struct * mm, struct task_struct *p) | |||
381 | mm->ioctx_list = NULL; | 382 | mm->ioctx_list = NULL; |
382 | mm->free_area_cache = TASK_UNMAPPED_BASE; | 383 | mm->free_area_cache = TASK_UNMAPPED_BASE; |
383 | mm->cached_hole_size = ~0UL; | 384 | mm->cached_hole_size = ~0UL; |
384 | mm_init_cgroup(mm, p); | 385 | mm_init_owner(mm, p); |
385 | 386 | ||
386 | if (likely(!mm_alloc_pgd(mm))) { | 387 | if (likely(!mm_alloc_pgd(mm))) { |
387 | mm->def_flags = 0; | 388 | mm->def_flags = 0; |
388 | return mm; | 389 | return mm; |
389 | } | 390 | } |
390 | 391 | ||
391 | mm_free_cgroup(mm); | ||
392 | free_mm(mm); | 392 | free_mm(mm); |
393 | return NULL; | 393 | return NULL; |
394 | } | 394 | } |
@@ -432,13 +432,13 @@ void mmput(struct mm_struct *mm) | |||
432 | if (atomic_dec_and_test(&mm->mm_users)) { | 432 | if (atomic_dec_and_test(&mm->mm_users)) { |
433 | exit_aio(mm); | 433 | exit_aio(mm); |
434 | exit_mmap(mm); | 434 | exit_mmap(mm); |
435 | set_mm_exe_file(mm, NULL); | ||
435 | if (!list_empty(&mm->mmlist)) { | 436 | if (!list_empty(&mm->mmlist)) { |
436 | spin_lock(&mmlist_lock); | 437 | spin_lock(&mmlist_lock); |
437 | list_del(&mm->mmlist); | 438 | list_del(&mm->mmlist); |
438 | spin_unlock(&mmlist_lock); | 439 | spin_unlock(&mmlist_lock); |
439 | } | 440 | } |
440 | put_swap_token(mm); | 441 | put_swap_token(mm); |
441 | mm_free_cgroup(mm); | ||
442 | mmdrop(mm); | 442 | mmdrop(mm); |
443 | } | 443 | } |
444 | } | 444 | } |
@@ -545,6 +545,8 @@ struct mm_struct *dup_mm(struct task_struct *tsk) | |||
545 | if (init_new_context(tsk, mm)) | 545 | if (init_new_context(tsk, mm)) |
546 | goto fail_nocontext; | 546 | goto fail_nocontext; |
547 | 547 | ||
548 | dup_mm_exe_file(oldmm, mm); | ||
549 | |||
548 | err = dup_mmap(mm, oldmm); | 550 | err = dup_mmap(mm, oldmm); |
549 | if (err) | 551 | if (err) |
550 | goto free_pt; | 552 | goto free_pt; |
@@ -891,7 +893,7 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk) | |||
891 | sig->group_exit_code = 0; | 893 | sig->group_exit_code = 0; |
892 | sig->group_exit_task = NULL; | 894 | sig->group_exit_task = NULL; |
893 | sig->group_stop_count = 0; | 895 | sig->group_stop_count = 0; |
894 | sig->curr_target = NULL; | 896 | sig->curr_target = tsk; |
895 | init_sigpending(&sig->shared_pending); | 897 | init_sigpending(&sig->shared_pending); |
896 | INIT_LIST_HEAD(&sig->posix_timers); | 898 | INIT_LIST_HEAD(&sig->posix_timers); |
897 | 899 | ||
@@ -982,6 +984,13 @@ static void rt_mutex_init_task(struct task_struct *p) | |||
982 | #endif | 984 | #endif |
983 | } | 985 | } |
984 | 986 | ||
987 | #ifdef CONFIG_MM_OWNER | ||
988 | void mm_init_owner(struct mm_struct *mm, struct task_struct *p) | ||
989 | { | ||
990 | mm->owner = p; | ||
991 | } | ||
992 | #endif /* CONFIG_MM_OWNER */ | ||
993 | |||
985 | /* | 994 | /* |
986 | * This creates a new process as a copy of the old one, | 995 | * This creates a new process as a copy of the old one, |
987 | * but does not actually start it yet. | 996 | * but does not actually start it yet. |
@@ -1664,18 +1673,6 @@ static int unshare_fd(unsigned long unshare_flags, struct files_struct **new_fdp | |||
1664 | } | 1673 | } |
1665 | 1674 | ||
1666 | /* | 1675 | /* |
1667 | * Unsharing of semundo for tasks created with CLONE_SYSVSEM is not | ||
1668 | * supported yet | ||
1669 | */ | ||
1670 | static int unshare_semundo(unsigned long unshare_flags, struct sem_undo_list **new_ulistp) | ||
1671 | { | ||
1672 | if (unshare_flags & CLONE_SYSVSEM) | ||
1673 | return -EINVAL; | ||
1674 | |||
1675 | return 0; | ||
1676 | } | ||
1677 | |||
1678 | /* | ||
1679 | * unshare allows a process to 'unshare' part of the process | 1676 | * unshare allows a process to 'unshare' part of the process |
1680 | * context which was originally shared using clone. copy_* | 1677 | * context which was originally shared using clone. copy_* |
1681 | * functions used by do_fork() cannot be used here directly | 1678 | * functions used by do_fork() cannot be used here directly |
@@ -1690,8 +1687,8 @@ asmlinkage long sys_unshare(unsigned long unshare_flags) | |||
1690 | struct sighand_struct *new_sigh = NULL; | 1687 | struct sighand_struct *new_sigh = NULL; |
1691 | struct mm_struct *mm, *new_mm = NULL, *active_mm = NULL; | 1688 | struct mm_struct *mm, *new_mm = NULL, *active_mm = NULL; |
1692 | struct files_struct *fd, *new_fd = NULL; | 1689 | struct files_struct *fd, *new_fd = NULL; |
1693 | struct sem_undo_list *new_ulist = NULL; | ||
1694 | struct nsproxy *new_nsproxy = NULL; | 1690 | struct nsproxy *new_nsproxy = NULL; |
1691 | int do_sysvsem = 0; | ||
1695 | 1692 | ||
1696 | check_unshare_flags(&unshare_flags); | 1693 | check_unshare_flags(&unshare_flags); |
1697 | 1694 | ||
@@ -1703,6 +1700,13 @@ asmlinkage long sys_unshare(unsigned long unshare_flags) | |||
1703 | CLONE_NEWNET)) | 1700 | CLONE_NEWNET)) |
1704 | goto bad_unshare_out; | 1701 | goto bad_unshare_out; |
1705 | 1702 | ||
1703 | /* | ||
1704 | * CLONE_NEWIPC must also detach from the undolist: after switching | ||
1705 | * to a new ipc namespace, the semaphore arrays from the old | ||
1706 | * namespace are unreachable. | ||
1707 | */ | ||
1708 | if (unshare_flags & (CLONE_NEWIPC|CLONE_SYSVSEM)) | ||
1709 | do_sysvsem = 1; | ||
1706 | if ((err = unshare_thread(unshare_flags))) | 1710 | if ((err = unshare_thread(unshare_flags))) |
1707 | goto bad_unshare_out; | 1711 | goto bad_unshare_out; |
1708 | if ((err = unshare_fs(unshare_flags, &new_fs))) | 1712 | if ((err = unshare_fs(unshare_flags, &new_fs))) |
@@ -1713,13 +1717,17 @@ asmlinkage long sys_unshare(unsigned long unshare_flags) | |||
1713 | goto bad_unshare_cleanup_sigh; | 1717 | goto bad_unshare_cleanup_sigh; |
1714 | if ((err = unshare_fd(unshare_flags, &new_fd))) | 1718 | if ((err = unshare_fd(unshare_flags, &new_fd))) |
1715 | goto bad_unshare_cleanup_vm; | 1719 | goto bad_unshare_cleanup_vm; |
1716 | if ((err = unshare_semundo(unshare_flags, &new_ulist))) | ||
1717 | goto bad_unshare_cleanup_fd; | ||
1718 | if ((err = unshare_nsproxy_namespaces(unshare_flags, &new_nsproxy, | 1720 | if ((err = unshare_nsproxy_namespaces(unshare_flags, &new_nsproxy, |
1719 | new_fs))) | 1721 | new_fs))) |
1720 | goto bad_unshare_cleanup_semundo; | 1722 | goto bad_unshare_cleanup_fd; |
1721 | 1723 | ||
1722 | if (new_fs || new_mm || new_fd || new_ulist || new_nsproxy) { | 1724 | if (new_fs || new_mm || new_fd || do_sysvsem || new_nsproxy) { |
1725 | if (do_sysvsem) { | ||
1726 | /* | ||
1727 | * CLONE_SYSVSEM is equivalent to sys_exit(). | ||
1728 | */ | ||
1729 | exit_sem(current); | ||
1730 | } | ||
1723 | 1731 | ||
1724 | if (new_nsproxy) { | 1732 | if (new_nsproxy) { |
1725 | switch_task_namespaces(current, new_nsproxy); | 1733 | switch_task_namespaces(current, new_nsproxy); |
@@ -1755,7 +1763,6 @@ asmlinkage long sys_unshare(unsigned long unshare_flags) | |||
1755 | if (new_nsproxy) | 1763 | if (new_nsproxy) |
1756 | put_nsproxy(new_nsproxy); | 1764 | put_nsproxy(new_nsproxy); |
1757 | 1765 | ||
1758 | bad_unshare_cleanup_semundo: | ||
1759 | bad_unshare_cleanup_fd: | 1766 | bad_unshare_cleanup_fd: |
1760 | if (new_fd) | 1767 | if (new_fd) |
1761 | put_files_struct(new_fd); | 1768 | put_files_struct(new_fd); |