lkml.org 
[lkml]   [2014]   [Oct]   [12]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 3.16 32/55] macvtap: Fix race between device delete and open.
    Date
    3.16-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Vlad Yasevich <vyasevich@gmail.com>

    [ Upstream commit 40b8fe45d1f094e3babe7b2dc2b71557ab71401d ]

    In macvtap device delete and open calls can race and
    this causes a list curruption of the vlan queue_list.

    The race intself is triggered by the idr accessors
    that located the vlan device. The device is stored
    into and removed from the idr under both an rtnl and
    a mutex. However, when attempting to locate the device
    in idr, only a mutex is taken. As a result, once cpu
    perfoming a delete may take an rtnl and wait for the mutex,
    while another cput doing an open() will take the idr
    mutex first to fetch the device pointer and later take
    an rtnl to add a queue for the device which may have
    just gotten deleted.

    With this patch, we now hold the rtnl for the duration
    of the macvtap_open() call thus making sure that
    open will not race with delete.

    CC: Michael S. Tsirkin <mst@redhat.com>
    CC: Jason Wang <jasowang@redhat.com>
    Signed-off-by: Vladislav Yasevich <vyasevic@redhat.com>
    Acked-by: Jason Wang <jasowang@redhat.com>
    Acked-by: Michael S. Tsirkin <mst@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    ---
    drivers/net/macvtap.c | 18 ++++++++----------
    1 file changed, 8 insertions(+), 10 deletions(-)

    --- a/drivers/net/macvtap.c
    +++ b/drivers/net/macvtap.c
    @@ -112,17 +112,15 @@ out:
    return err;
    }

    +/* Requires RTNL */
    static int macvtap_set_queue(struct net_device *dev, struct file *file,
    struct macvtap_queue *q)
    {
    struct macvlan_dev *vlan = netdev_priv(dev);
    - int err = -EBUSY;

    - rtnl_lock();
    if (vlan->numqueues == MAX_MACVTAP_QUEUES)
    - goto out;
    + return -EBUSY;

    - err = 0;
    rcu_assign_pointer(q->vlan, vlan);
    rcu_assign_pointer(vlan->taps[vlan->numvtaps], q);
    sock_hold(&q->sk);
    @@ -136,9 +134,7 @@ static int macvtap_set_queue(struct net_
    vlan->numvtaps++;
    vlan->numqueues++;

    -out:
    - rtnl_unlock();
    - return err;
    + return 0;
    }

    static int macvtap_disable_queue(struct macvtap_queue *q)
    @@ -454,11 +450,12 @@ static void macvtap_sock_destruct(struct
    static int macvtap_open(struct inode *inode, struct file *file)
    {
    struct net *net = current->nsproxy->net_ns;
    - struct net_device *dev = dev_get_by_macvtap_minor(iminor(inode));
    + struct net_device *dev;
    struct macvtap_queue *q;
    - int err;
    + int err = -ENODEV;

    - err = -ENODEV;
    + rtnl_lock();
    + dev = dev_get_by_macvtap_minor(iminor(inode));
    if (!dev)
    goto out;

    @@ -498,6 +495,7 @@ out:
    if (dev)
    dev_put(dev);

    + rtnl_unlock();
    return err;
    }




    \
     
     \ /
      Last update: 2014-10-13 05:21    [W:4.623 / U:0.104 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site