diff options
author | Oleg Nesterov <oleg@redhat.com> | 2011-03-22 19:34:09 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-22 20:44:11 -0400 |
commit | 9bfb23fc4a481650e60d22dbe84c0fd5a9d49bba (patch) | |
tree | a88488a871e6b765dede72ff28db00c71848201d /kernel/fork.c | |
parent | 4d51985e484dd11d9047dfcd1278ec9ccfb435d5 (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.c | 123 |
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 | */ |
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 | 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(¤t->mm->mm_users) > 1) |
1546 | 1538 | return -EINVAL; | |
1547 | /* | 1539 | } |
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 | 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 | */ | ||
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 | * Unshare file descriptor table if it is being shared | 1566 | * Unshare file descriptor table if it is being shared |
1609 | */ | 1567 | */ |
1610 | static int unshare_fd(unsigned long unshare_flags, struct files_struct **new_fdp) | 1568 | static 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 | */ |
1633 | SYSCALL_DEFINE1(unshare, unsigned long, unshare_flags) | 1591 | SYSCALL_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 | ||
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 | bad_unshare_cleanup_fs: | 1665 | bad_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 | ||
1741 | bad_unshare_cleanup_thread: | ||
1742 | bad_unshare_out: | 1669 | bad_unshare_out: |
1743 | return err; | 1670 | return err; |
1744 | } | 1671 | } |