Instead of going through the ioctl handler from kernel space, use symbol_get to access the ip_tunnel_ioctl directly.
Signed-off-by: Christoph Hellwig <h...@lst.de> --- net/ipv4/ipmr.c | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 6bf2a88abe86e..3780ab694c574 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -438,10 +438,9 @@ static bool ipmr_init_vif_indev(const struct net_device *dev) static struct net_device *ipmr_new_tunnel(struct net *net, struct vifctl *v) { - mm_segment_t oldfs = get_fs(); + int (*tunnel_ctl)(struct net_device *, struct ip_tunnel_parm *, int); struct net_device *tunnel_dev, *new_dev; struct ip_tunnel_parm p = { }; - struct ifreq ifr; int err; tunnel_dev = __dev_get_by_name(net, "tunl0"); @@ -454,21 +453,17 @@ static struct net_device *ipmr_new_tunnel(struct net *net, struct vifctl *v) p.iph.ihl = 5; p.iph.protocol = IPPROTO_IPIP; sprintf(p.name, "dvmrp%d", v->vifc_vifi); - ifr.ifr_ifru.ifru_data = (__force void __user *)&p; - if (!tunnel_dev->netdev_ops->ndo_do_ioctl) - goto out; + tunnel_ctl = symbol_get(ip_tunnel_ioctl); + if (!tunnel_ctl) + return ERR_PTR(-ENOBUFS); - set_fs(KERNEL_DS); - err = tunnel_dev->netdev_ops->ndo_do_ioctl(tunnel_dev, &ifr, - SIOCADDTUNNEL); - set_fs(oldfs); - if (err) - goto out; + if (tunnel_ctl(tunnel_dev, &p, SIOCADDTUNNEL)) + goto out_symbol_put; new_dev = __dev_get_by_name(net, p.name); if (!new_dev) - goto out; + goto out_symbol_put; new_dev->flags |= IFF_MULTICAST; if (!ipmr_init_vif_indev(new_dev)) @@ -479,17 +474,18 @@ static struct net_device *ipmr_new_tunnel(struct net *net, struct vifctl *v) err = dev_set_allmulti(new_dev, 1); if (err) { dev_close(new_dev); - set_fs(KERNEL_DS); - tunnel_dev->netdev_ops->ndo_do_ioctl(tunnel_dev, &ifr, - SIOCDELTUNNEL); - set_fs(oldfs); + tunnel_ctl(tunnel_dev, &p, SIOCDELTUNNEL); dev_put(new_dev); new_dev = ERR_PTR(err); } + + symbol_put(ip_tunnel_ioctl); return new_dev; out_unregister: unregister_netdevice(new_dev); +out_symbol_put: + symbol_put(ipmr_new_tunnel); out: return ERR_PTR(-ENOBUFS); } -- 2.26.2