aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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}