mirror of
https://github.com/raspberrypi/linux.git
synced 2025-12-06 10:00:17 +00:00
vxlan: fix use-after-free on deletion
[ Upstream commita53cb29b0a] Adding a vxlan interface to a socket isn't symmetrical, while adding is done in vxlan_open() the deletion is done in vxlan_dellink(). This can cause a use-after-free error when we close the vxlan interface before deleting it. We add vxlan_vs_del_dev() to match vxlan_vs_add_dev() and call it from vxlan_stop() to match the call from vxlan_open(). Fixes:56ef9c909b("vxlan: Move socket initialization to within rtnl scope") Acked-by: Jiri Benc <jbenc@redhat.com> Tested-by: Roi Dayan <roid@mellanox.com> Signed-off-by: Mark Bloch <markb@mellanox.com> Acked-by: Roopa Prabhu <roopa@cumulusnetworks.com> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
905ae1b1e6
commit
35e08f6e2b
@@ -59,6 +59,8 @@ static const u8 all_zeros_mac[ETH_ALEN + 2];
|
|||||||
|
|
||||||
static int vxlan_sock_add(struct vxlan_dev *vxlan);
|
static int vxlan_sock_add(struct vxlan_dev *vxlan);
|
||||||
|
|
||||||
|
static void vxlan_vs_del_dev(struct vxlan_dev *vxlan);
|
||||||
|
|
||||||
/* per-network namespace private data for this module */
|
/* per-network namespace private data for this module */
|
||||||
struct vxlan_net {
|
struct vxlan_net {
|
||||||
struct list_head vxlan_list;
|
struct list_head vxlan_list;
|
||||||
@@ -1081,6 +1083,8 @@ static void vxlan_sock_release(struct vxlan_dev *vxlan)
|
|||||||
rcu_assign_pointer(vxlan->vn4_sock, NULL);
|
rcu_assign_pointer(vxlan->vn4_sock, NULL);
|
||||||
synchronize_net();
|
synchronize_net();
|
||||||
|
|
||||||
|
vxlan_vs_del_dev(vxlan);
|
||||||
|
|
||||||
if (__vxlan_sock_release_prep(sock4)) {
|
if (__vxlan_sock_release_prep(sock4)) {
|
||||||
udp_tunnel_sock_release(sock4->sock);
|
udp_tunnel_sock_release(sock4->sock);
|
||||||
kfree(sock4);
|
kfree(sock4);
|
||||||
@@ -2352,6 +2356,15 @@ static void vxlan_cleanup(unsigned long arg)
|
|||||||
mod_timer(&vxlan->age_timer, next_timer);
|
mod_timer(&vxlan->age_timer, next_timer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void vxlan_vs_del_dev(struct vxlan_dev *vxlan)
|
||||||
|
{
|
||||||
|
struct vxlan_net *vn = net_generic(vxlan->net, vxlan_net_id);
|
||||||
|
|
||||||
|
spin_lock(&vn->sock_lock);
|
||||||
|
hlist_del_init_rcu(&vxlan->hlist);
|
||||||
|
spin_unlock(&vn->sock_lock);
|
||||||
|
}
|
||||||
|
|
||||||
static void vxlan_vs_add_dev(struct vxlan_sock *vs, struct vxlan_dev *vxlan)
|
static void vxlan_vs_add_dev(struct vxlan_sock *vs, struct vxlan_dev *vxlan)
|
||||||
{
|
{
|
||||||
struct vxlan_net *vn = net_generic(vxlan->net, vxlan_net_id);
|
struct vxlan_net *vn = net_generic(vxlan->net, vxlan_net_id);
|
||||||
@@ -3289,15 +3302,9 @@ static int vxlan_changelink(struct net_device *dev, struct nlattr *tb[],
|
|||||||
static void vxlan_dellink(struct net_device *dev, struct list_head *head)
|
static void vxlan_dellink(struct net_device *dev, struct list_head *head)
|
||||||
{
|
{
|
||||||
struct vxlan_dev *vxlan = netdev_priv(dev);
|
struct vxlan_dev *vxlan = netdev_priv(dev);
|
||||||
struct vxlan_net *vn = net_generic(vxlan->net, vxlan_net_id);
|
|
||||||
|
|
||||||
vxlan_flush(vxlan, true);
|
vxlan_flush(vxlan, true);
|
||||||
|
|
||||||
spin_lock(&vn->sock_lock);
|
|
||||||
if (!hlist_unhashed(&vxlan->hlist))
|
|
||||||
hlist_del_rcu(&vxlan->hlist);
|
|
||||||
spin_unlock(&vn->sock_lock);
|
|
||||||
|
|
||||||
gro_cells_destroy(&vxlan->gro_cells);
|
gro_cells_destroy(&vxlan->gro_cells);
|
||||||
list_del(&vxlan->next);
|
list_del(&vxlan->next);
|
||||||
unregister_netdevice_queue(dev, head);
|
unregister_netdevice_queue(dev, head);
|
||||||
|
|||||||
Reference in New Issue
Block a user