Commit 9bfb23fc4a481650e60d22dbe84c0fd5a9d49bba
Committed by
Linus Torvalds
1 parent
4d51985e48
Exists in
master
and in
7 other branches
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>
Showing 1 changed file with 25 additions and 98 deletions Side-by-side Diff
kernel/fork.c
... | ... | @@ -1519,39 +1519,25 @@ |
1519 | 1519 | } |
1520 | 1520 | |
1521 | 1521 | /* |
1522 | - * Check constraints on flags passed to the unshare system call and | |
1523 | - * force unsharing of additional process context as appropriate. | |
1522 | + * Check constraints on flags passed to the unshare system call. | |
1524 | 1523 | */ |
1525 | -static void check_unshare_flags(unsigned long *flags_ptr) | |
1524 | +static 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 | |
1529 | - * unshare vm. | |
1531 | + * Not implemented, but pretend it works if there is nothing to | |
1532 | + * unshare. Note that unsharing CLONE_THREAD or CLONE_SIGHAND | |
1533 | + * needs to unshare vm. | |
1530 | 1534 | */ |
1531 | - if (*flags_ptr & CLONE_THREAD) | |
1532 | - *flags_ptr |= CLONE_VM; | |
1535 | + if (unshare_flags & (CLONE_THREAD | CLONE_SIGHAND | CLONE_VM)) { | |
1536 | + /* FIXME: get_task_mm() increments ->mm_users */ | |
1537 | + if (atomic_read(¤t->mm->mm_users) > 1) | |
1538 | + return -EINVAL; | |
1539 | + } | |
1533 | 1540 | |
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 | - */ | |
1543 | - if (*flags_ptr & CLONE_NEWNS) | |
1544 | - *flags_ptr |= CLONE_FS; | |
1545 | -} | |
1546 | - | |
1547 | -/* | |
1548 | - * Unsharing of tasks created with CLONE_THREAD is not supported yet | |
1549 | - */ | |
1550 | -static int unshare_thread(unsigned long unshare_flags) | |
1551 | -{ | |
1552 | - if (unshare_flags & CLONE_THREAD) | |
1553 | - return -EINVAL; | |
1554 | - | |
1555 | 1541 | return 0; |
1556 | 1542 | } |
1557 | 1543 | |
... | ... | @@ -1577,34 +1563,6 @@ |
1577 | 1563 | } |
1578 | 1564 | |
1579 | 1565 | /* |
1580 | - * Unsharing of sighand is not supported yet | |
1581 | - */ | |
1582 | -static 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 | - */ | |
1595 | -static 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 | 1566 | * Unshare file descriptor table if it is being shared |
1609 | 1567 | */ |
1610 | 1568 | static int unshare_fd(unsigned long unshare_flags, struct files_struct **new_fdp) |
1611 | 1569 | |
1612 | 1570 | |
1613 | 1571 | |
1614 | 1572 | |
1615 | 1573 | |
1616 | 1574 | |
1617 | 1575 | |
1618 | 1576 | |
... | ... | @@ -1632,45 +1590,37 @@ |
1632 | 1590 | */ |
1633 | 1591 | SYSCALL_DEFINE1(unshare, unsigned long, unshare_flags) |
1634 | 1592 | { |
1635 | - int err = 0; | |
1636 | 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 | 1594 | struct files_struct *fd, *new_fd = NULL; |
1640 | 1595 | struct nsproxy *new_nsproxy = NULL; |
1641 | 1596 | int do_sysvsem = 0; |
1597 | + int err; | |
1642 | 1598 | |
1643 | - check_unshare_flags(&unshare_flags); | |
1644 | - | |
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)) | |
1599 | + err = check_unshare_flags(unshare_flags); | |
1600 | + if (err) | |
1650 | 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 | 1609 | * CLONE_NEWIPC must also detach from the undolist: after switching |
1654 | 1610 | * to a new ipc namespace, the semaphore arrays from the old |
1655 | 1611 | * namespace are unreachable. |
1656 | 1612 | */ |
1657 | 1613 | if (unshare_flags & (CLONE_NEWIPC|CLONE_SYSVSEM)) |
1658 | 1614 | do_sysvsem = 1; |
1659 | - if ((err = unshare_thread(unshare_flags))) | |
1660 | - goto bad_unshare_out; | |
1661 | 1615 | if ((err = unshare_fs(unshare_flags, &new_fs))) |
1662 | - goto bad_unshare_cleanup_thread; | |
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; | |
1616 | + goto bad_unshare_out; | |
1667 | 1617 | if ((err = unshare_fd(unshare_flags, &new_fd))) |
1668 | - goto bad_unshare_cleanup_vm; | |
1618 | + goto bad_unshare_cleanup_fs; | |
1669 | 1619 | if ((err = unshare_nsproxy_namespaces(unshare_flags, &new_nsproxy, |
1670 | 1620 | new_fs))) |
1671 | 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 | 1624 | if (do_sysvsem) { |
1675 | 1625 | /* |
1676 | 1626 | * CLONE_SYSVSEM is equivalent to sys_exit(). |
... | ... | @@ -1696,19 +1646,6 @@ |
1696 | 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 | 1649 | if (new_fd) { |
1713 | 1650 | fd = current->files; |
1714 | 1651 | current->files = new_fd; |
1715 | 1652 | |
... | ... | @@ -1725,20 +1662,10 @@ |
1725 | 1662 | if (new_fd) |
1726 | 1663 | put_files_struct(new_fd); |
1727 | 1664 | |
1728 | -bad_unshare_cleanup_vm: | |
1729 | - if (new_mm) | |
1730 | - mmput(new_mm); | |
1731 | - | |
1732 | -bad_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 | - | |
1737 | 1665 | bad_unshare_cleanup_fs: |
1738 | 1666 | if (new_fs) |
1739 | 1667 | free_fs_struct(new_fs); |
1740 | 1668 | |
1741 | -bad_unshare_cleanup_thread: | |
1742 | 1669 | bad_unshare_out: |
1743 | 1670 | return err; |
1744 | 1671 | } |