[PATCH rdma-next 1/3] RDMA/cma: Use correct address when leaving multicast group

From: Leon Romanovsky
Date: Tue Jan 18 2022 - 02:35:23 EST


From: Maor Gottlieb <maorg@xxxxxxxxxx>

In RoCE we should use cma_iboe_set_mgid and not cma_set_mgid to generate
the mgid, otherwise we will try to remove incorrect address.

Fixes: b5de0c60cc30 ("RDMA/cma: Fix use after free race in roce multicast join")
Signed-off-by: Maor Gottlieb <maorg@xxxxxxxxxx>
Signed-off-by: Leon Romanovsky <leonro@xxxxxxxxxx>
---
drivers/infiniband/core/cma.c | 61 +++++++++++++++++------------------
1 file changed, 30 insertions(+), 31 deletions(-)

diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
index 27a00ce2e101..69c9a12dd14e 100644
--- a/drivers/infiniband/core/cma.c
+++ b/drivers/infiniband/core/cma.c
@@ -1830,6 +1830,31 @@ static void cma_release_port(struct rdma_id_private *id_priv)
mutex_unlock(&lock);
}

+static void cma_iboe_set_mgid(struct sockaddr *addr, union ib_gid *mgid,
+ enum ib_gid_type gid_type)
+{
+ struct sockaddr_in *sin = (struct sockaddr_in *)addr;
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr;
+
+ if (!cma_any_addr(addr) && addr->sa_family == AF_INET6) {
+ memcpy(mgid, &sin6->sin6_addr, sizeof(*mgid));
+ return;
+ }
+
+ memset(mgid, 0, sizeof(*mgid));
+ if (cma_any_addr(addr))
+ return;
+
+ /* AF_INET4 */
+ if (gid_type != IB_GID_TYPE_ROCE_UDP_ENCAP) {
+ mgid->raw[0] = 0xff;
+ mgid->raw[1] = 0x0e;
+ }
+ mgid->raw[10] = 0xff;
+ mgid->raw[11] = 0xff;
+ *(__be32 *)(&mgid->raw[12]) = sin->sin_addr.s_addr;
+}
+
static void destroy_mc(struct rdma_id_private *id_priv,
struct cma_multicast *mc)
{
@@ -1847,10 +1872,13 @@ static void destroy_mc(struct rdma_id_private *id_priv,
ndev = dev_get_by_index(dev_addr->net,
dev_addr->bound_dev_if);
if (ndev) {
+ enum ib_gid_type gid_type;
union ib_gid mgid;

- cma_set_mgid(id_priv, (struct sockaddr *)&mc->addr,
- &mgid);
+ gid_type = cma_get_default_gid_type(
+ id_priv->cma_dev, id_priv->id.port_num);
+ cma_iboe_set_mgid((struct sockaddr *)&mc->addr, &mgid,
+ gid_type);

if (!send_only)
cma_igmp_send(ndev, &mgid, false);
@@ -4702,35 +4730,6 @@ static int cma_join_ib_multicast(struct rdma_id_private *id_priv,
return PTR_ERR_OR_ZERO(mc->sa_mc);
}

-static void cma_iboe_set_mgid(struct sockaddr *addr, union ib_gid *mgid,
- enum ib_gid_type gid_type)
-{
- struct sockaddr_in *sin = (struct sockaddr_in *)addr;
- struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr;
-
- if (cma_any_addr(addr)) {
- memset(mgid, 0, sizeof *mgid);
- } else if (addr->sa_family == AF_INET6) {
- memcpy(mgid, &sin6->sin6_addr, sizeof *mgid);
- } else {
- mgid->raw[0] =
- (gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP) ? 0 : 0xff;
- mgid->raw[1] =
- (gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP) ? 0 : 0x0e;
- mgid->raw[2] = 0;
- mgid->raw[3] = 0;
- mgid->raw[4] = 0;
- mgid->raw[5] = 0;
- mgid->raw[6] = 0;
- mgid->raw[7] = 0;
- mgid->raw[8] = 0;
- mgid->raw[9] = 0;
- mgid->raw[10] = 0xff;
- mgid->raw[11] = 0xff;
- *(__be32 *)(&mgid->raw[12]) = sin->sin_addr.s_addr;
- }
-}
-
static int cma_iboe_join_multicast(struct rdma_id_private *id_priv,
struct cma_multicast *mc)
{
--
2.34.1