Skip to content

Commit 2918c1a

Browse files
paravmellanoxdledford
authored andcommitted
RDMA/cma: Fix use after destroy access to net namespace for IPoIB
There are few issues with validation of netdevice and listen id lookup for IB (IPoIB) while processing incoming CM request as below. 1. While performing lookup of bind_list in cma_ps_find(), net namespace of the netdevice can get deleted in cma_exit_net(), resulting in use after free access of idr and/or net namespace structures. This lookup occurs from the workqueue context (and not userspace context where net namespace is always valid). CPU0 CPU1 ==== ==== bind_list = cma_ps_find(); move netdevice to new namespace delete net namespace cma_exit_net() idr_destroy(idr); [..] cma_find_listener(bind_list, ..); 2. While netdevice is validated for IP address in given net namespace, netdevice's net namespace and/or ifindex can change in cma_get_net_dev() and cma_match_net_dev(). Above issues are overcome by using rcu lock along with netdevice UP/DOWN state as described below. When a net namespace is getting deleted, netdevice is closed and shutdown before moving it back to init_net namespace. change_net_namespace() synchronizes with any existing use of netdevice before changing the netdev properties such as net or ifindex. Once netdevice IFF_UP flags is cleared, such fields are not guaranteed to be valid. Therefore, rcu lock along with netdevice state check ensures that, while route lookup and cm_id lookup is in progress, netdevice of interest won't migrate to any other net namespace. This ensures that associated net namespace of netdevice won't get deleted while rcu lock is held for netdevice which is in IFF_UP state. Fixes: fa20105 ("IB/cma: Add support for network namespaces") Fixes: 4be74b4 ("IB/cma: Separate port allocation to network namespaces") Fixes: f887f2a ("IB/cma: Validate routing of incoming requests") Signed-off-by: Parav Pandit <[email protected]> Signed-off-by: Leon Romanovsky <[email protected]> Signed-off-by: Doug Ledford <[email protected]>
1 parent f604db6 commit 2918c1a

File tree

1 file changed

+43
-10
lines changed
  • drivers/infiniband/core

1 file changed

+43
-10
lines changed

drivers/infiniband/core/cma.c

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,8 @@ struct cma_hdr {
382382
#define CMA_VERSION 0x00
383383

384384
struct cma_req_info {
385+
struct sockaddr_storage listen_addr_storage;
386+
struct sockaddr_storage src_addr_storage;
385387
struct ib_device *device;
386388
int port;
387389
union ib_gid local_gid;
@@ -1340,11 +1342,11 @@ static bool validate_net_dev(struct net_device *net_dev,
13401342
}
13411343

13421344
static struct net_device *cma_get_net_dev(struct ib_cm_event *ib_event,
1343-
const struct cma_req_info *req)
1345+
struct cma_req_info *req)
13441346
{
1345-
struct sockaddr_storage listen_addr_storage, src_addr_storage;
1346-
struct sockaddr *listen_addr = (struct sockaddr *)&listen_addr_storage,
1347-
*src_addr = (struct sockaddr *)&src_addr_storage;
1347+
struct sockaddr *listen_addr =
1348+
(struct sockaddr *)&req->listen_addr_storage;
1349+
struct sockaddr *src_addr = (struct sockaddr *)&req->src_addr_storage;
13481350
struct net_device *net_dev;
13491351
const union ib_gid *gid = req->has_gid ? &req->local_gid : NULL;
13501352
int err;
@@ -1359,11 +1361,6 @@ static struct net_device *cma_get_net_dev(struct ib_cm_event *ib_event,
13591361
if (!net_dev)
13601362
return ERR_PTR(-ENODEV);
13611363

1362-
if (!validate_net_dev(net_dev, listen_addr, src_addr)) {
1363-
dev_put(net_dev);
1364-
return ERR_PTR(-EHOSTUNREACH);
1365-
}
1366-
13671364
return net_dev;
13681365
}
13691366

@@ -1490,15 +1487,51 @@ static struct rdma_id_private *cma_id_from_event(struct ib_cm_id *cm_id,
14901487
}
14911488
}
14921489

1490+
/*
1491+
* Net namespace might be getting deleted while route lookup,
1492+
* cm_id lookup is in progress. Therefore, perform netdevice
1493+
* validation, cm_id lookup under rcu lock.
1494+
* RCU lock along with netdevice state check, synchronizes with
1495+
* netdevice migrating to different net namespace and also avoids
1496+
* case where net namespace doesn't get deleted while lookup is in
1497+
* progress.
1498+
* If the device state is not IFF_UP, its properties such as ifindex
1499+
* and nd_net cannot be trusted to remain valid without rcu lock.
1500+
* net/core/dev.c change_net_namespace() ensures to synchronize with
1501+
* ongoing operations on net device after device is closed using
1502+
* synchronize_net().
1503+
*/
1504+
rcu_read_lock();
1505+
if (*net_dev) {
1506+
/*
1507+
* If netdevice is down, it is likely that it is administratively
1508+
* down or it might be migrating to different namespace.
1509+
* In that case avoid further processing, as the net namespace
1510+
* or ifindex may change.
1511+
*/
1512+
if (((*net_dev)->flags & IFF_UP) == 0) {
1513+
id_priv = ERR_PTR(-EHOSTUNREACH);
1514+
goto err;
1515+
}
1516+
1517+
if (!validate_net_dev(*net_dev,
1518+
(struct sockaddr *)&req.listen_addr_storage,
1519+
(struct sockaddr *)&req.src_addr_storage)) {
1520+
id_priv = ERR_PTR(-EHOSTUNREACH);
1521+
goto err;
1522+
}
1523+
}
1524+
14931525
bind_list = cma_ps_find(*net_dev ? dev_net(*net_dev) : &init_net,
14941526
rdma_ps_from_service_id(req.service_id),
14951527
cma_port_from_service_id(req.service_id));
14961528
id_priv = cma_find_listener(bind_list, cm_id, ib_event, &req, *net_dev);
1529+
err:
1530+
rcu_read_unlock();
14971531
if (IS_ERR(id_priv) && *net_dev) {
14981532
dev_put(*net_dev);
14991533
*net_dev = NULL;
15001534
}
1501-
15021535
return id_priv;
15031536
}
15041537

0 commit comments

Comments
 (0)