mirror of
https://github.com/torvalds/linux.git
synced 2026-11-06 21:58:01 +01:00
net/rds: restrict the rdma_cm ids to IB devices
RDS only has an IB transport, but it never tells the rdma_cm so. The listener created in rds_rdma_listen_init() is therefore installed on every RDMA device in the system, including iWARP RNICs, and the id an outgoing connection resolves through in rds_ib_conn_path_connect() may be bound to whichever device the address resolution picks: rds_ib_laddr_check() only vouched for the local address being served by one of RDS's IB devices, while cma_acquire_dev_by_src_ip() walks every RDMA device for the same address, so a software iWARP device attached to the same netdev can win. The event handler then runs the IB transport's callbacks against a device that is not one. The rdma_cm has an API for exactly this since commita760e80e90("RDMA/core: introduce rdma_restrict_node_type()"). Restrict all three ids RDS creates - the listener, the per-connection id and the probe id in rds_ib_laddr_check_cm() - to RDMA_NODE_IB_CA before they are bound, so that the listener is only installed on IB devices, an outgoing connection can only bind one, and the address check's bind fails outright on anything else - which makes its explicit node_type test dead, so it goes; the check that the bind produced a device at all stays. With that, no rdma_cm event reaches RDS's handler from a device it has no transport for. The handler itself still assumes IB: it assigns its transport pointer only for RDMA_NODE_IB_CA and dereferences it regardless, which is the crash that first surfaced this. The fix for that is a separate net patch, Aohan Mei's "net: rds: fix uninitialized trans dereference in CM event handler", and is what stable kernels without rdma_restrict_node_type() - which arrived in commita760e80e90("RDMA/core: introduce rdma_restrict_node_type()") - have to take: this patch depends on that API, so stable trees need that separate, minimal fix rather than a backport of this one. The two patches are independent and apply in either order. The listener has been on every RDMA device since the iWARP transport was removed and left the ids unrestricted, hence the Fixes tag. Signed-off-by: Allison Henderson <achender@kernel.org> Reviewed-by: Simon Horman <horms@kernel.org> Link: https://patch.msgid.link/20260927063058.170273-2-achender@kernel.org Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
58328b5b58
commit
c7fca8aae6
14
net/rds/ib.c
14
net/rds/ib.c
|
|
@ -414,13 +414,14 @@ static int rds_ib_laddr_check_cm(struct net *net, const struct in6_addr *addr,
|
|||
bool isv4;
|
||||
|
||||
isv4 = ipv6_addr_v4mapped(addr);
|
||||
/* Create a CMA ID and try to bind it. This catches both
|
||||
* IB and iWARP capable NICs.
|
||||
*/
|
||||
/* Create a CMA ID restricted to IB devices and try to bind it. */
|
||||
cm_id = rdma_create_id(&init_net, rds_rdma_cm_event_handler,
|
||||
NULL, RDMA_PS_TCP, IB_QPT_RC);
|
||||
if (IS_ERR(cm_id))
|
||||
return PTR_ERR(cm_id);
|
||||
ret = rdma_restrict_node_type(cm_id, RDMA_NODE_IB_CA);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
if (isv4) {
|
||||
memset(&sin, 0, sizeof(sin));
|
||||
|
|
@ -473,12 +474,9 @@ static int rds_ib_laddr_check_cm(struct net *net, const struct in6_addr *addr,
|
|||
#endif
|
||||
}
|
||||
|
||||
/* rdma_bind_addr will only succeed for IB & iWARP devices */
|
||||
/* the restriction above means this only succeeds for IB devices */
|
||||
ret = rdma_bind_addr(cm_id, sa);
|
||||
/* due to this, we will claim to support iWARP devices unless we
|
||||
check node_type. */
|
||||
if (ret || !cm_id->device ||
|
||||
cm_id->device->node_type != RDMA_NODE_IB_CA)
|
||||
if (ret || !cm_id->device)
|
||||
ret = -EADDRNOTAVAIL;
|
||||
|
||||
rdsdebug("addr %pI6c%%%u ret %d node type %d\n",
|
||||
|
|
|
|||
|
|
@ -999,6 +999,18 @@ int rds_ib_conn_path_connect(struct rds_conn_path *cp)
|
|||
goto out;
|
||||
}
|
||||
|
||||
/* rds_ib_laddr_check() only vouched for the local address being
|
||||
* on an IB device; the address resolution below picks the device
|
||||
* on its own, so restrict it to the same kind.
|
||||
*/
|
||||
ret = rdma_restrict_node_type(ic->i_cm_id, RDMA_NODE_IB_CA);
|
||||
if (ret) {
|
||||
rdsdebug("rdma_restrict_node_type() failed: %d\n", ret);
|
||||
rdma_destroy_id(ic->i_cm_id);
|
||||
ic->i_cm_id = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rdsdebug("created cm id %p for conn %p\n", ic->i_cm_id, conn);
|
||||
|
||||
if (ipv6_addr_v4mapped(&conn->c_faddr)) {
|
||||
|
|
|
|||
|
|
@ -210,6 +210,14 @@ static int rds_rdma_listen_init_common(rdma_cm_event_handler handler,
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* Only the IB transport is left, so only listen on IB devices */
|
||||
ret = rdma_restrict_node_type(cm_id, RDMA_NODE_IB_CA);
|
||||
if (ret) {
|
||||
pr_err("RDS/RDMA: failed to setup listener, rdma_restrict_node_type() returned %d\n",
|
||||
ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX I bet this binds the cm_id to a device. If we want to support
|
||||
* fail-over we'll have to take this into consideration.
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user