]> git.baikalelectronics.ru Git - kernel.git/commitdiff
RDMA/core: Fix use after free and refcnt leak on ndev in_device in iwarp_query_port
authorMichal Kalderon <michal.kalderon@marvell.com>
Wed, 25 Sep 2019 12:33:32 +0000 (15:33 +0300)
committerJason Gunthorpe <jgg@mellanox.com>
Tue, 1 Oct 2019 14:31:27 +0000 (11:31 -0300)
If an iWARP driver is probed and removed while there are no ips set for
the device, it will lead to a reference count leak on the inet device of
the netdevice.

In addition, the netdevice was accessed after already calling netdev_put,
which could lead to using the netdev after already freed.

Fixes: 4929116bdf72 ("RDMA/core: Add common iWARP query port")
Link: https://lore.kernel.org/r/20190925123332.10746-1-michal.kalderon@marvell.com
Signed-off-by: Ariel Elior <ariel.elior@marvell.com>
Signed-off-by: Michal Kalderon <michal.kalderon@marvell.com>
Reviewed-by: Shiraz Saleem <shiraz.saleem@intel.com>
Reviewed-by: Kamal Heib <kamalheib1@gmail.com>
Reviewed-by: Jason Gunthorpe <jgg@mellanox.com>
Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
drivers/infiniband/core/device.c

index 99c4a55545cfba00812824c87ac56c4b0a2acd20..2dd2cfe9b56136f950fd9648120304e2b21a6904 100644 (file)
@@ -1987,8 +1987,6 @@ static int iw_query_port(struct ib_device *device,
        if (!netdev)
                return -ENODEV;
 
-       dev_put(netdev);
-
        port_attr->max_mtu = IB_MTU_4096;
        port_attr->active_mtu = ib_mtu_int_to_enum(netdev->mtu);
 
@@ -1996,19 +1994,22 @@ static int iw_query_port(struct ib_device *device,
                port_attr->state = IB_PORT_DOWN;
                port_attr->phys_state = IB_PORT_PHYS_STATE_DISABLED;
        } else {
-               inetdev = in_dev_get(netdev);
+               rcu_read_lock();
+               inetdev = __in_dev_get_rcu(netdev);
 
                if (inetdev && inetdev->ifa_list) {
                        port_attr->state = IB_PORT_ACTIVE;
                        port_attr->phys_state = IB_PORT_PHYS_STATE_LINK_UP;
-                       in_dev_put(inetdev);
                } else {
                        port_attr->state = IB_PORT_INIT;
                        port_attr->phys_state =
                                IB_PORT_PHYS_STATE_PORT_CONFIGURATION_TRAINING;
                }
+
+               rcu_read_unlock();
        }
 
+       dev_put(netdev);
        err = device->ops.query_port(device, port_num, port_attr);
        if (err)
                return err;