diff options
| -rw-r--r-- | net/kcm/kcmsock.c | 71 |
1 files changed, 27 insertions, 44 deletions
diff --git a/net/kcm/kcmsock.c b/net/kcm/kcmsock.c index 0b750a22c4b9..c5fa634e63ca 100644 --- a/net/kcm/kcmsock.c +++ b/net/kcm/kcmsock.c | |||
| @@ -1625,60 +1625,35 @@ static struct proto kcm_proto = { | |||
| 1625 | }; | 1625 | }; |
| 1626 | 1626 | ||
| 1627 | /* Clone a kcm socket. */ | 1627 | /* Clone a kcm socket. */ |
| 1628 | static int kcm_clone(struct socket *osock, struct kcm_clone *info, | 1628 | static struct file *kcm_clone(struct socket *osock) |
| 1629 | struct socket **newsockp) | ||
| 1630 | { | 1629 | { |
| 1631 | struct socket *newsock; | 1630 | struct socket *newsock; |
| 1632 | struct sock *newsk; | 1631 | struct sock *newsk; |
| 1633 | struct file *newfile; | 1632 | struct file *file; |
| 1634 | int err, newfd; | ||
| 1635 | 1633 | ||
| 1636 | err = -ENFILE; | ||
| 1637 | newsock = sock_alloc(); | 1634 | newsock = sock_alloc(); |
| 1638 | if (!newsock) | 1635 | if (!newsock) |
| 1639 | goto out; | 1636 | return ERR_PTR(-ENFILE); |
| 1640 | 1637 | ||
| 1641 | newsock->type = osock->type; | 1638 | newsock->type = osock->type; |
| 1642 | newsock->ops = osock->ops; | 1639 | newsock->ops = osock->ops; |
| 1643 | 1640 | ||
| 1644 | __module_get(newsock->ops->owner); | 1641 | __module_get(newsock->ops->owner); |
| 1645 | 1642 | ||
| 1646 | newfd = get_unused_fd_flags(0); | ||
| 1647 | if (unlikely(newfd < 0)) { | ||
| 1648 | err = newfd; | ||
| 1649 | goto out_fd_fail; | ||
| 1650 | } | ||
| 1651 | |||
| 1652 | newfile = sock_alloc_file(newsock, 0, osock->sk->sk_prot_creator->name); | ||
| 1653 | if (IS_ERR(newfile)) { | ||
| 1654 | err = PTR_ERR(newfile); | ||
| 1655 | goto out_sock_alloc_fail; | ||
| 1656 | } | ||
| 1657 | |||
| 1658 | newsk = sk_alloc(sock_net(osock->sk), PF_KCM, GFP_KERNEL, | 1643 | newsk = sk_alloc(sock_net(osock->sk), PF_KCM, GFP_KERNEL, |
| 1659 | &kcm_proto, true); | 1644 | &kcm_proto, true); |
| 1660 | if (!newsk) { | 1645 | if (!newsk) { |
| 1661 | err = -ENOMEM; | 1646 | sock_release(newsock); |
| 1662 | goto out_sk_alloc_fail; | 1647 | return ERR_PTR(-ENOMEM); |
| 1663 | } | 1648 | } |
| 1664 | |||
| 1665 | sock_init_data(newsock, newsk); | 1649 | sock_init_data(newsock, newsk); |
| 1666 | init_kcm_sock(kcm_sk(newsk), kcm_sk(osock->sk)->mux); | 1650 | init_kcm_sock(kcm_sk(newsk), kcm_sk(osock->sk)->mux); |
| 1667 | 1651 | ||
| 1668 | fd_install(newfd, newfile); | 1652 | file = sock_alloc_file(newsock, 0, osock->sk->sk_prot_creator->name); |
| 1669 | *newsockp = newsock; | 1653 | if (IS_ERR(file)) |
| 1670 | info->fd = newfd; | 1654 | sock_release(newsock); |
| 1671 | |||
| 1672 | return 0; | ||
| 1673 | 1655 | ||
| 1674 | out_sk_alloc_fail: | 1656 | return file; |
| 1675 | fput(newfile); | ||
| 1676 | out_sock_alloc_fail: | ||
| 1677 | put_unused_fd(newfd); | ||
| 1678 | out_fd_fail: | ||
| 1679 | sock_release(newsock); | ||
| 1680 | out: | ||
| 1681 | return err; | ||
| 1682 | } | 1657 | } |
| 1683 | 1658 | ||
| 1684 | static int kcm_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | 1659 | static int kcm_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) |
| @@ -1708,17 +1683,25 @@ static int kcm_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | |||
| 1708 | } | 1683 | } |
| 1709 | case SIOCKCMCLONE: { | 1684 | case SIOCKCMCLONE: { |
| 1710 | struct kcm_clone info; | 1685 | struct kcm_clone info; |
| 1711 | struct socket *newsock = NULL; | 1686 | struct file *file; |
| 1712 | 1687 | ||
| 1713 | err = kcm_clone(sock, &info, &newsock); | 1688 | info.fd = get_unused_fd_flags(0); |
| 1714 | if (!err) { | 1689 | if (unlikely(info.fd < 0)) |
| 1715 | if (copy_to_user((void __user *)arg, &info, | 1690 | return info.fd; |
| 1716 | sizeof(info))) { | ||
| 1717 | err = -EFAULT; | ||
| 1718 | sys_close(info.fd); | ||
| 1719 | } | ||
| 1720 | } | ||
| 1721 | 1691 | ||
| 1692 | file = kcm_clone(sock); | ||
| 1693 | if (IS_ERR(file)) { | ||
| 1694 | put_unused_fd(info.fd); | ||
| 1695 | return PTR_ERR(file); | ||
| 1696 | } | ||
| 1697 | if (copy_to_user((void __user *)arg, &info, | ||
| 1698 | sizeof(info))) { | ||
| 1699 | put_unused_fd(info.fd); | ||
| 1700 | fput(file); | ||
| 1701 | return -EFAULT; | ||
| 1702 | } | ||
| 1703 | fd_install(info.fd, file); | ||
| 1704 | err = 0; | ||
| 1722 | break; | 1705 | break; |
| 1723 | } | 1706 | } |
| 1724 | default: | 1707 | default: |
