aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAl Viro <viro@ZenIV.linux.org.uk>2017-12-05 18:27:57 -0500
committerDavid S. Miller <davem@davemloft.net>2017-12-05 18:39:28 -0500
commita5739435b5a3b8c449f8844ecd71a3b1e89f0a33 (patch)
treeb440fa1710f0e7c3779461cb1d851596d5b11ac5
parent69c64866ce072dea1d1e59a0d61e0f66c0dffb76 (diff)
fix kcm_clone()
1) it's fput() or sock_release(), not both 2) don't do fd_install() until the last failure exit. 3) not a bug per se, but... don't attach socket to struct file until it's set up. Take reserving descriptor into the caller, move fd_install() to the caller, sanitize failure exits and calling conventions. Cc: stable@vger.kernel.org # v4.6+ Acked-by: Tom Herbert <tom@herbertland.com> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/kcm/kcmsock.c71
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. */
1628static int kcm_clone(struct socket *osock, struct kcm_clone *info, 1628static 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
1674out_sk_alloc_fail: 1656 return file;
1675 fput(newfile);
1676out_sock_alloc_fail:
1677 put_unused_fd(newfd);
1678out_fd_fail:
1679 sock_release(newsock);
1680out:
1681 return err;
1682} 1657}
1683 1658
1684static int kcm_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) 1659static 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: