aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/fork.c
diff options
context:
space:
mode:
authorOleg Nesterov <oleg@redhat.com>2011-03-22 19:34:09 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-03-22 20:44:11 -0400
commit9bfb23fc4a481650e60d22dbe84c0fd5a9d49bba (patch)
treea88488a871e6b765dede72ff28db00c71848201d /kernel/fork.c
parent4d51985e484dd11d9047dfcd1278ec9ccfb435d5 (diff)
sys_unshare: remove the dead CLONE_THREAD/SIGHAND/VM code
Cleanup: kill the dead code which does nothing but complicates the code and confuses the reader. sys_unshare(CLONE_THREAD/SIGHAND/VM) is not really implemented, and I doubt very much it will ever work. At least, nobody even tried since the original 99d1419d96d7df9cfa56 ("unshare system call -v5: system call handler function") was applied more than 4 years ago. And the code is not consistent. unshare_thread() always fails unconditionally, while unshare_sighand() and unshare_vm() pretend to work if there is nothing to unshare. Remove unshare_thread(), unshare_sighand(), unshare_vm() helpers and related variables and add a simple CLONE_THREAD | CLONE_SIGHAND| CLONE_VM check into check_unshare_flags(). Also, move the "CLONE_NEWNS needs CLONE_FS" check from check_unshare_flags() to sys_unshare(). This looks more consistent and matches the similar do_sysvsem check in sys_unshare(). Note: with or without this patch "atomic_read(mm->mm_users) > 1" can give a false positive due to get_task_mm(). Signed-off-by: Oleg Nesterov <oleg@redhat.com> Acked-by: Roland McGrath <roland@redhat.com> Cc: Janak Desai <janak@us.ibm.com> Cc: Daniel Lezcano <daniel.lezcano@free.fr> Cc: "Eric W. Biederman" <ebiederm@xmission.com> Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> Cc: Alexey Dobriyan <adobriyan@gmail.com> Acked-by: Serge Hallyn <serge.hallyn@canonical.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel/fork.c')
-rw-r--r--kernel/fork.c123
1 files changed, 25 insertions, 98 deletions
diff --git a/kernel/fork.c b/kernel/fork.c
index a8f64f8ec7e1..f2b494d7c557 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1519,38 +1519,24 @@ void __init proc_caches_init(void)
1519} 1519}
1520 1520
1521/* 1521/*
1522 * Check constraints on flags passed to the unshare system call and 1522 * Check constraints on flags passed to the unshare system call.
1523 * force unsharing of additional process context as appropriate.
1524 */ 1523 */
1525static void check_unshare_flags(unsigned long *flags_ptr) 1524static int check_unshare_flags(unsigned long unshare_flags)
1526{ 1525{
1526 if (unshare_flags & ~(CLONE_THREAD|CLONE_FS|CLONE_NEWNS|CLONE_SIGHAND|
1527 CLONE_VM|CLONE_FILES|CLONE_SYSVSEM|
1528 CLONE_NEWUTS|CLONE_NEWIPC|CLONE_NEWNET))
1529 return -EINVAL;
1527 /* 1530 /*
1528 * If unsharing a thread from a thread group, must also 1531 * Not implemented, but pretend it works if there is nothing to
1529 * unshare vm. 1532 * unshare. Note that unsharing CLONE_THREAD or CLONE_SIGHAND
1530 */ 1533 * needs to unshare vm.
1531 if (*flags_ptr & CLONE_THREAD)
1532 *flags_ptr |= CLONE_VM;
1533
1534 /*
1535 * If unsharing vm, must also unshare signal handlers.
1536 */
1537 if (*flags_ptr & CLONE_VM)
1538 *flags_ptr |= CLONE_SIGHAND;
1539
1540 /*
1541 * If unsharing namespace, must also unshare filesystem information.
1542 */ 1534 */
1543 if (*flags_ptr & CLONE_NEWNS) 1535 if (unshare_flags & (CLONE_THREAD | CLONE_SIGHAND | CLONE_VM)) {
1544 *flags_ptr |= CLONE_FS; 1536 /* FIXME: get_task_mm() increments ->mm_users */
1545} 1537 if (atomic_read(&current->mm->mm_users) > 1)
1546 1538 return -EINVAL;
1547/* 1539 }
1548 * Unsharing of tasks created with CLONE_THREAD is not supported yet
1549 */
1550static int unshare_thread(unsigned long unshare_flags)
1551{
1552 if (unshare_flags & CLONE_THREAD)
1553 return -EINVAL;
1554 1540
1555 return 0; 1541 return 0;
1556} 1542}
@@ -1577,34 +1563,6 @@ static int unshare_fs(unsigned long unshare_flags, struct fs_struct **new_fsp)
1577} 1563}
1578 1564
1579/* 1565/*
1580 * Unsharing of sighand is not supported yet
1581 */
1582static int unshare_sighand(unsigned long unshare_flags, struct sighand_struct **new_sighp)
1583{
1584 struct sighand_struct *sigh = current->sighand;
1585
1586 if ((unshare_flags & CLONE_SIGHAND) && atomic_read(&sigh->count) > 1)
1587 return -EINVAL;
1588 else
1589 return 0;
1590}
1591
1592/*
1593 * Unshare vm if it is being shared
1594 */
1595static int unshare_vm(unsigned long unshare_flags, struct mm_struct **new_mmp)
1596{
1597 struct mm_struct *mm = current->mm;
1598
1599 if ((unshare_flags & CLONE_VM) &&
1600 (mm && atomic_read(&mm->mm_users) > 1)) {
1601 return -EINVAL;
1602 }
1603
1604 return 0;
1605}
1606
1607/*
1608 * Unshare file descriptor table if it is being shared 1566 * Unshare file descriptor table if it is being shared
1609 */ 1567 */
1610static int unshare_fd(unsigned long unshare_flags, struct files_struct **new_fdp) 1568static int unshare_fd(unsigned long unshare_flags, struct files_struct **new_fdp)
@@ -1632,45 +1590,37 @@ static int unshare_fd(unsigned long unshare_flags, struct files_struct **new_fdp
1632 */ 1590 */
1633SYSCALL_DEFINE1(unshare, unsigned long, unshare_flags) 1591SYSCALL_DEFINE1(unshare, unsigned long, unshare_flags)
1634{ 1592{
1635 int err = 0;
1636 struct fs_struct *fs, *new_fs = NULL; 1593 struct fs_struct *fs, *new_fs = NULL;
1637 struct sighand_struct *new_sigh = NULL;
1638 struct mm_struct *mm, *new_mm = NULL, *active_mm = NULL;
1639 struct files_struct *fd, *new_fd = NULL; 1594 struct files_struct *fd, *new_fd = NULL;
1640 struct nsproxy *new_nsproxy = NULL; 1595 struct nsproxy *new_nsproxy = NULL;
1641 int do_sysvsem = 0; 1596 int do_sysvsem = 0;
1597 int err;
1642 1598
1643 check_unshare_flags(&unshare_flags); 1599 err = check_unshare_flags(unshare_flags);
1644 1600 if (err)
1645 /* Return -EINVAL for all unsupported flags */
1646 err = -EINVAL;
1647 if (unshare_flags & ~(CLONE_THREAD|CLONE_FS|CLONE_NEWNS|CLONE_SIGHAND|
1648 CLONE_VM|CLONE_FILES|CLONE_SYSVSEM|
1649 CLONE_NEWUTS|CLONE_NEWIPC|CLONE_NEWNET))
1650 goto bad_unshare_out; 1601 goto bad_unshare_out;
1651 1602
1652 /* 1603 /*
1604 * If unsharing namespace, must also unshare filesystem information.
1605 */
1606 if (unshare_flags & CLONE_NEWNS)
1607 unshare_flags |= CLONE_FS;
1608 /*
1653 * CLONE_NEWIPC must also detach from the undolist: after switching 1609 * CLONE_NEWIPC must also detach from the undolist: after switching
1654 * to a new ipc namespace, the semaphore arrays from the old 1610 * to a new ipc namespace, the semaphore arrays from the old
1655 * namespace are unreachable. 1611 * namespace are unreachable.
1656 */ 1612 */
1657 if (unshare_flags & (CLONE_NEWIPC|CLONE_SYSVSEM)) 1613 if (unshare_flags & (CLONE_NEWIPC|CLONE_SYSVSEM))
1658 do_sysvsem = 1; 1614 do_sysvsem = 1;
1659 if ((err = unshare_thread(unshare_flags)))
1660 goto bad_unshare_out;
1661 if ((err = unshare_fs(unshare_flags, &new_fs))) 1615 if ((err = unshare_fs(unshare_flags, &new_fs)))
1662 goto bad_unshare_cleanup_thread; 1616 goto bad_unshare_out;
1663 if ((err = unshare_sighand(unshare_flags, &new_sigh)))
1664 goto bad_unshare_cleanup_fs;
1665 if ((err = unshare_vm(unshare_flags, &new_mm)))
1666 goto bad_unshare_cleanup_sigh;
1667 if ((err = unshare_fd(unshare_flags, &new_fd))) 1617 if ((err = unshare_fd(unshare_flags, &new_fd)))
1668 goto bad_unshare_cleanup_vm; 1618 goto bad_unshare_cleanup_fs;
1669 if ((err = unshare_nsproxy_namespaces(unshare_flags, &new_nsproxy, 1619 if ((err = unshare_nsproxy_namespaces(unshare_flags, &new_nsproxy,
1670 new_fs))) 1620 new_fs)))
1671 goto bad_unshare_cleanup_fd; 1621 goto bad_unshare_cleanup_fd;
1672 1622
1673 if (new_fs || new_mm || new_fd || do_sysvsem || new_nsproxy) { 1623 if (new_fs || new_fd || do_sysvsem || new_nsproxy) {
1674 if (do_sysvsem) { 1624 if (do_sysvsem) {
1675 /* 1625 /*
1676 * CLONE_SYSVSEM is equivalent to sys_exit(). 1626 * CLONE_SYSVSEM is equivalent to sys_exit().
@@ -1696,19 +1646,6 @@ SYSCALL_DEFINE1(unshare, unsigned long, unshare_flags)
1696 spin_unlock(&fs->lock); 1646 spin_unlock(&fs->lock);
1697 } 1647 }
1698 1648
1699 if (new_mm) {
1700 mm = current->mm;
1701 active_mm = current->active_mm;
1702 current->mm = new_mm;
1703 current->active_mm = new_mm;
1704 if (current->signal->oom_score_adj == OOM_SCORE_ADJ_MIN) {
1705 atomic_dec(&mm->oom_disable_count);
1706 atomic_inc(&new_mm->oom_disable_count);
1707 }
1708 activate_mm(active_mm, new_mm);
1709 new_mm = mm;
1710 }
1711
1712 if (new_fd) { 1649 if (new_fd) {
1713 fd = current->files; 1650 fd = current->files;
1714 current->files = new_fd; 1651 current->files = new_fd;
@@ -1725,20 +1662,10 @@ bad_unshare_cleanup_fd:
1725 if (new_fd) 1662 if (new_fd)
1726 put_files_struct(new_fd); 1663 put_files_struct(new_fd);
1727 1664
1728bad_unshare_cleanup_vm:
1729 if (new_mm)
1730 mmput(new_mm);
1731
1732bad_unshare_cleanup_sigh:
1733 if (new_sigh)
1734 if (atomic_dec_and_test(&new_sigh->count))
1735 kmem_cache_free(sighand_cachep, new_sigh);
1736
1737bad_unshare_cleanup_fs: 1665bad_unshare_cleanup_fs:
1738 if (new_fs) 1666 if (new_fs)
1739 free_fs_struct(new_fs); 1667 free_fs_struct(new_fs);
1740 1668
1741bad_unshare_cleanup_thread:
1742bad_unshare_out: 1669bad_unshare_out:
1743 return err; 1670 return err;
1744} 1671}