lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20200514145101.3000612-5-hch@lst.de>
Date:   Thu, 14 May 2020 16:51:01 +0200
From:   Christoph Hellwig <hch@....de>
To:     "David S. Miller" <davem@...emloft.net>,
        Jakub Kicinski <kuba@...nel.org>
Cc:     Alexey Kuznetsov <kuznet@....inr.ac.ru>,
        Hideaki YOSHIFUJI <yoshfuji@...ux-ipv6.org>,
        netdev@...r.kernel.org, linux-kernel@...r.kernel.org
Subject: [PATCH 4/4] ipv6: symbol_get to access a sit symbol

Instead of going through the ioctl handler from kernel space, use
symbol_get to the newly factored out ipip6_set_dstaddr helper, bypassing
addrconf.c entirely.

Signed-off-by: Christoph Hellwig <hch@....de>
---
 include/net/addrconf.h |  1 -
 include/net/ipv6.h     |  2 ++
 net/ipv6/addrconf.c    | 66 ------------------------------------------
 net/ipv6/af_inet6.c    | 20 ++++++++++++-
 net/ipv6/sit.c         | 41 ++++++++++++++++++++++++++
 5 files changed, 62 insertions(+), 68 deletions(-)

diff --git a/include/net/addrconf.h b/include/net/addrconf.h
index fdb07105384ca..569eb03ae2440 100644
--- a/include/net/addrconf.h
+++ b/include/net/addrconf.h
@@ -76,7 +76,6 @@ void addrconf_cleanup(void);
 
 int addrconf_add_ifaddr(struct net *net, void __user *arg);
 int addrconf_del_ifaddr(struct net *net, void __user *arg);
-int addrconf_set_dstaddr(struct net *net, void __user *arg);
 
 int ipv6_chk_addr(struct net *net, const struct in6_addr *addr,
 		  const struct net_device *dev, int strict);
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 955badd1e8ffc..1b983f32c87ce 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -1080,6 +1080,8 @@ struct in6_addr *fl6_update_dst(struct flowi6 *fl6,
 				const struct ipv6_txoptions *opt,
 				struct in6_addr *orig);
 
+int ipip6_set_dstaddr(struct net *net, void __user *arg);
+
 /*
  *	socket options (ipv6_sockglue.c)
  */
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index fd885f06c4ed6..02186f00f91c5 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -2783,72 +2783,6 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao)
 	in6_dev_put(in6_dev);
 }
 
-/*
- *	Set destination address.
- *	Special case for SIT interfaces where we create a new "virtual"
- *	device.
- */
-int addrconf_set_dstaddr(struct net *net, void __user *arg)
-{
-	struct in6_ifreq ireq;
-	struct net_device *dev;
-	int err = -EINVAL;
-
-	rtnl_lock();
-
-	err = -EFAULT;
-	if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq)))
-		goto err_exit;
-
-	dev = __dev_get_by_index(net, ireq.ifr6_ifindex);
-
-	err = -ENODEV;
-	if (!dev)
-		goto err_exit;
-
-#if IS_ENABLED(CONFIG_IPV6_SIT)
-	if (dev->type == ARPHRD_SIT) {
-		const struct net_device_ops *ops = dev->netdev_ops;
-		struct ifreq ifr;
-		struct ip_tunnel_parm p;
-
-		err = -EADDRNOTAVAIL;
-		if (!(ipv6_addr_type(&ireq.ifr6_addr) & IPV6_ADDR_COMPATv4))
-			goto err_exit;
-
-		memset(&p, 0, sizeof(p));
-		p.iph.daddr = ireq.ifr6_addr.s6_addr32[3];
-		p.iph.saddr = 0;
-		p.iph.version = 4;
-		p.iph.ihl = 5;
-		p.iph.protocol = IPPROTO_IPV6;
-		p.iph.ttl = 64;
-		ifr.ifr_ifru.ifru_data = (__force void __user *)&p;
-
-		if (ops->ndo_do_ioctl) {
-			mm_segment_t oldfs = get_fs();
-
-			set_fs(KERNEL_DS);
-			err = ops->ndo_do_ioctl(dev, &ifr, SIOCADDTUNNEL);
-			set_fs(oldfs);
-		} else
-			err = -EOPNOTSUPP;
-
-		if (err == 0) {
-			err = -ENOBUFS;
-			dev = __dev_get_by_name(net, p.name);
-			if (!dev)
-				goto err_exit;
-			err = dev_open(dev, NULL);
-		}
-	}
-#endif
-
-err_exit:
-	rtnl_unlock();
-	return err;
-}
-
 static int ipv6_mc_config(struct sock *sk, bool join,
 			  const struct in6_addr *addr, int ifindex)
 {
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 345baa0a754f4..3ec9734c7bb11 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -538,6 +538,19 @@ int inet6_getname(struct socket *sock, struct sockaddr *uaddr,
 }
 EXPORT_SYMBOL(inet6_getname);
 
+static int inet6_ioctl_set_dstaddr(struct net *net, void __user *arg)
+{
+	int (*set_dstaddr)(struct net *, void __user *);
+	int err;
+
+	set_dstaddr = symbol_get(ipip6_set_dstaddr);
+	if (!set_dstaddr)
+		return -EOPNOTSUPP;
+	err = set_dstaddr(net, arg);
+	symbol_put(ipip6_set_dstaddr);
+	return err;
+}
+
 int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 {
 	struct sock *sk = sock->sk;
@@ -554,7 +567,12 @@ int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 	case SIOCDIFADDR:
 		return addrconf_del_ifaddr(net, (void __user *) arg);
 	case SIOCSIFDSTADDR:
-		return addrconf_set_dstaddr(net, (void __user *) arg);
+		/* Special case for SIT interfaces where we create a new
+		 * "virtual" device.
+		 */
+		if (!IS_ENABLED(CONFIG_IPV6_SIT))
+			return -ENODEV;
+		return inet6_ioctl_set_dstaddr(net, (void __user *) arg);
 	default:
 		if (!sk->sk_prot->ioctl)
 			return -ENOIOCTLCMD;
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index 98954830c40ba..cb2cfa297f72e 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -274,6 +274,47 @@ static struct ip_tunnel *ipip6_tunnel_locate(struct net *net,
 	return NULL;
 }
 
+int ipip6_set_dstaddr(struct net *net, void __user *arg)
+{
+	struct ip_tunnel_parm p = { };
+	struct in6_ifreq ireq;
+	struct net_device *tunnel_dev, *new_dev;
+	int err;
+
+	rtnl_lock();
+	err = -EFAULT;
+	if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq)))
+		goto out_unlock;
+
+	err = -ENODEV;
+	tunnel_dev = __dev_get_by_index(net, ireq.ifr6_ifindex);
+	if (!tunnel_dev || tunnel_dev->type != ARPHRD_SIT)
+		goto out_unlock;
+
+	err = -EADDRNOTAVAIL;
+	if (!(ipv6_addr_type(&ireq.ifr6_addr) & IPV6_ADDR_COMPATv4))
+		goto out_unlock;
+
+	p.iph.daddr = ireq.ifr6_addr.s6_addr32[3];
+	p.iph.version = 4;
+	p.iph.ihl = 5;
+	p.iph.protocol = IPPROTO_IPV6;
+	p.iph.ttl = 64;
+	p.iph.frag_off |= htons(IP_DF);
+
+	err = -ENOBUFS;
+	if (!ipip6_tunnel_locate(dev_net(tunnel_dev), &p, true))
+		goto out_unlock;
+	new_dev = __dev_get_by_name(net, p.name);
+	if (!new_dev)
+		goto out_unlock;
+	err = dev_open(new_dev, NULL);
+out_unlock:
+	rtnl_unlock();
+	return err;
+}
+EXPORT_SYMBOL_GPL(ipip6_set_dstaddr);
+
 #define for_each_prl_rcu(start)			\
 	for (prl = rcu_dereference(start);	\
 	     prl;				\
-- 
2.26.2

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ