diff options
Diffstat (limited to 'kernel/fork.c')
-rw-r--r-- | kernel/fork.c | 22 |
1 files changed, 18 insertions, 4 deletions
diff --git a/kernel/fork.c b/kernel/fork.c index 208dd99f13bc..d6cc56558507 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
@@ -1608,13 +1608,15 @@ asmlinkage long sys_unshare(unsigned long unshare_flags) | |||
1608 | struct sem_undo_list *new_ulist = NULL; | 1608 | struct sem_undo_list *new_ulist = NULL; |
1609 | struct nsproxy *new_nsproxy = NULL, *old_nsproxy = NULL; | 1609 | struct nsproxy *new_nsproxy = NULL, *old_nsproxy = NULL; |
1610 | struct uts_namespace *uts, *new_uts = NULL; | 1610 | struct uts_namespace *uts, *new_uts = NULL; |
1611 | struct ipc_namespace *ipc, *new_ipc = NULL; | ||
1611 | 1612 | ||
1612 | check_unshare_flags(&unshare_flags); | 1613 | check_unshare_flags(&unshare_flags); |
1613 | 1614 | ||
1614 | /* Return -EINVAL for all unsupported flags */ | 1615 | /* Return -EINVAL for all unsupported flags */ |
1615 | err = -EINVAL; | 1616 | err = -EINVAL; |
1616 | if (unshare_flags & ~(CLONE_THREAD|CLONE_FS|CLONE_NEWNS|CLONE_SIGHAND| | 1617 | if (unshare_flags & ~(CLONE_THREAD|CLONE_FS|CLONE_NEWNS|CLONE_SIGHAND| |
1617 | CLONE_VM|CLONE_FILES|CLONE_SYSVSEM|CLONE_NEWUTS)) | 1618 | CLONE_VM|CLONE_FILES|CLONE_SYSVSEM| |
1619 | CLONE_NEWUTS|CLONE_NEWIPC)) | ||
1618 | goto bad_unshare_out; | 1620 | goto bad_unshare_out; |
1619 | 1621 | ||
1620 | if ((err = unshare_thread(unshare_flags))) | 1622 | if ((err = unshare_thread(unshare_flags))) |
@@ -1633,18 +1635,20 @@ asmlinkage long sys_unshare(unsigned long unshare_flags) | |||
1633 | goto bad_unshare_cleanup_fd; | 1635 | goto bad_unshare_cleanup_fd; |
1634 | if ((err = unshare_utsname(unshare_flags, &new_uts))) | 1636 | if ((err = unshare_utsname(unshare_flags, &new_uts))) |
1635 | goto bad_unshare_cleanup_semundo; | 1637 | goto bad_unshare_cleanup_semundo; |
1638 | if ((err = unshare_ipcs(unshare_flags, &new_ipc))) | ||
1639 | goto bad_unshare_cleanup_uts; | ||
1636 | 1640 | ||
1637 | if (new_ns || new_uts) { | 1641 | if (new_ns || new_uts || new_ipc) { |
1638 | old_nsproxy = current->nsproxy; | 1642 | old_nsproxy = current->nsproxy; |
1639 | new_nsproxy = dup_namespaces(old_nsproxy); | 1643 | new_nsproxy = dup_namespaces(old_nsproxy); |
1640 | if (!new_nsproxy) { | 1644 | if (!new_nsproxy) { |
1641 | err = -ENOMEM; | 1645 | err = -ENOMEM; |
1642 | goto bad_unshare_cleanup_uts; | 1646 | goto bad_unshare_cleanup_ipc; |
1643 | } | 1647 | } |
1644 | } | 1648 | } |
1645 | 1649 | ||
1646 | if (new_fs || new_ns || new_sigh || new_mm || new_fd || new_ulist || | 1650 | if (new_fs || new_ns || new_sigh || new_mm || new_fd || new_ulist || |
1647 | new_uts) { | 1651 | new_uts || new_ipc) { |
1648 | 1652 | ||
1649 | task_lock(current); | 1653 | task_lock(current); |
1650 | 1654 | ||
@@ -1692,12 +1696,22 @@ asmlinkage long sys_unshare(unsigned long unshare_flags) | |||
1692 | new_uts = uts; | 1696 | new_uts = uts; |
1693 | } | 1697 | } |
1694 | 1698 | ||
1699 | if (new_ipc) { | ||
1700 | ipc = current->nsproxy->ipc_ns; | ||
1701 | current->nsproxy->ipc_ns = new_ipc; | ||
1702 | new_ipc = ipc; | ||
1703 | } | ||
1704 | |||
1695 | task_unlock(current); | 1705 | task_unlock(current); |
1696 | } | 1706 | } |
1697 | 1707 | ||
1698 | if (new_nsproxy) | 1708 | if (new_nsproxy) |
1699 | put_nsproxy(new_nsproxy); | 1709 | put_nsproxy(new_nsproxy); |
1700 | 1710 | ||
1711 | bad_unshare_cleanup_ipc: | ||
1712 | if (new_ipc) | ||
1713 | put_ipc_ns(new_ipc); | ||
1714 | |||
1701 | bad_unshare_cleanup_uts: | 1715 | bad_unshare_cleanup_uts: |
1702 | if (new_uts) | 1716 | if (new_uts) |
1703 | put_uts_ns(new_uts); | 1717 | put_uts_ns(new_uts); |