diff options
Diffstat (limited to 'kernel/fork.c')
-rw-r--r-- | kernel/fork.c | 20 |
1 files changed, 17 insertions, 3 deletions
diff --git a/kernel/fork.c b/kernel/fork.c index 33fcf0733ca6..c08cf05dd59b 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
@@ -1607,13 +1607,14 @@ asmlinkage long sys_unshare(unsigned long unshare_flags) | |||
1607 | struct files_struct *fd, *new_fd = NULL; | 1607 | struct files_struct *fd, *new_fd = NULL; |
1608 | struct sem_undo_list *new_ulist = NULL; | 1608 | struct sem_undo_list *new_ulist = NULL; |
1609 | struct nsproxy *new_nsproxy, *old_nsproxy; | 1609 | struct nsproxy *new_nsproxy, *old_nsproxy; |
1610 | struct uts_namespace *uts, *new_uts = NULL; | ||
1610 | 1611 | ||
1611 | check_unshare_flags(&unshare_flags); | 1612 | check_unshare_flags(&unshare_flags); |
1612 | 1613 | ||
1613 | /* Return -EINVAL for all unsupported flags */ | 1614 | /* Return -EINVAL for all unsupported flags */ |
1614 | err = -EINVAL; | 1615 | err = -EINVAL; |
1615 | if (unshare_flags & ~(CLONE_THREAD|CLONE_FS|CLONE_NEWNS|CLONE_SIGHAND| | 1616 | if (unshare_flags & ~(CLONE_THREAD|CLONE_FS|CLONE_NEWNS|CLONE_SIGHAND| |
1616 | CLONE_VM|CLONE_FILES|CLONE_SYSVSEM)) | 1617 | CLONE_VM|CLONE_FILES|CLONE_SYSVSEM|CLONE_NEWUTS)) |
1617 | goto bad_unshare_out; | 1618 | goto bad_unshare_out; |
1618 | 1619 | ||
1619 | if ((err = unshare_thread(unshare_flags))) | 1620 | if ((err = unshare_thread(unshare_flags))) |
@@ -1630,14 +1631,17 @@ asmlinkage long sys_unshare(unsigned long unshare_flags) | |||
1630 | goto bad_unshare_cleanup_vm; | 1631 | goto bad_unshare_cleanup_vm; |
1631 | if ((err = unshare_semundo(unshare_flags, &new_ulist))) | 1632 | if ((err = unshare_semundo(unshare_flags, &new_ulist))) |
1632 | goto bad_unshare_cleanup_fd; | 1633 | goto bad_unshare_cleanup_fd; |
1634 | if ((err = unshare_utsname(unshare_flags, &new_uts))) | ||
1635 | goto bad_unshare_cleanup_semundo; | ||
1633 | 1636 | ||
1634 | if (new_fs || new_ns || new_sigh || new_mm || new_fd || new_ulist) { | 1637 | if (new_fs || new_ns || new_sigh || new_mm || new_fd || new_ulist || |
1638 | new_uts) { | ||
1635 | 1639 | ||
1636 | old_nsproxy = current->nsproxy; | 1640 | old_nsproxy = current->nsproxy; |
1637 | new_nsproxy = dup_namespaces(old_nsproxy); | 1641 | new_nsproxy = dup_namespaces(old_nsproxy); |
1638 | if (!new_nsproxy) { | 1642 | if (!new_nsproxy) { |
1639 | err = -ENOMEM; | 1643 | err = -ENOMEM; |
1640 | goto bad_unshare_cleanup_semundo; | 1644 | goto bad_unshare_cleanup_uts; |
1641 | } | 1645 | } |
1642 | 1646 | ||
1643 | task_lock(current); | 1647 | task_lock(current); |
@@ -1676,10 +1680,20 @@ asmlinkage long sys_unshare(unsigned long unshare_flags) | |||
1676 | new_fd = fd; | 1680 | new_fd = fd; |
1677 | } | 1681 | } |
1678 | 1682 | ||
1683 | if (new_uts) { | ||
1684 | uts = current->nsproxy->uts_ns; | ||
1685 | current->nsproxy->uts_ns = new_uts; | ||
1686 | new_uts = uts; | ||
1687 | } | ||
1688 | |||
1679 | task_unlock(current); | 1689 | task_unlock(current); |
1680 | put_nsproxy(old_nsproxy); | 1690 | put_nsproxy(old_nsproxy); |
1681 | } | 1691 | } |
1682 | 1692 | ||
1693 | bad_unshare_cleanup_uts: | ||
1694 | if (new_uts) | ||
1695 | put_uts_ns(new_uts); | ||
1696 | |||
1683 | bad_unshare_cleanup_semundo: | 1697 | bad_unshare_cleanup_semundo: |
1684 | bad_unshare_cleanup_fd: | 1698 | bad_unshare_cleanup_fd: |
1685 | if (new_fd) | 1699 | if (new_fd) |