Skip to content

Commit

Permalink
RDMA/siw: Remove direct link to net_device
Browse files Browse the repository at this point in the history
Do not manage a per device direct link to net_device. Rely
on associated ib_devices net_device management, not doubling
the effort locally. A badly managed local link to net_device
was causing a 'KASAN: slab-use-after-free' exception during
siw_query_port() call.

Fixes: bdcf26b ("rdma/siw: network and RDMA core interface")
Reported-by: syzbot+4b87489410b4efd181bf@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=4b87489410b4efd181bf
Signed-off-by: Bernard Metzler <bmt@zurich.ibm.com>
Link: https://patch.msgid.link/20241212151848.564872-1-bmt@zurich.ibm.com
Reviewed-by: Zhu Yanjun <yanjun.zhu@linux.dev>
Signed-off-by: Leon Romanovsky <leon@kernel.org>
  • Loading branch information
Bernard Metzler authored and Leon Romanovsky committed Dec 19, 2024
1 parent 13a6691 commit 16b8703
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 35 deletions.
7 changes: 3 additions & 4 deletions drivers/infiniband/sw/siw/siw.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@
*/
#define SIW_IRQ_MAXBURST_SQ_ACTIVE 4

/* There is always only a port 1 per siw device */
#define SIW_PORT 1

struct siw_dev_cap {
int max_qp;
int max_qp_wr;
Expand All @@ -69,16 +72,12 @@ struct siw_pd {

struct siw_device {
struct ib_device base_dev;
struct net_device *netdev;
struct siw_dev_cap attrs;

u32 vendor_part_id;
int numa_node;
char raw_gid[ETH_ALEN];

/* physical port state (only one port per device) */
enum ib_port_state state;

spinlock_t lock;

struct xarray qp_xa;
Expand Down
27 changes: 21 additions & 6 deletions drivers/infiniband/sw/siw/siw_cm.c
Original file line number Diff line number Diff line change
Expand Up @@ -1759,6 +1759,7 @@ int siw_create_listen(struct iw_cm_id *id, int backlog)
{
struct socket *s;
struct siw_cep *cep = NULL;
struct net_device *ndev = NULL;
struct siw_device *sdev = to_siw_dev(id->device);
int addr_family = id->local_addr.ss_family;
int rv = 0;
Expand All @@ -1779,9 +1780,15 @@ int siw_create_listen(struct iw_cm_id *id, int backlog)
struct sockaddr_in *laddr = &to_sockaddr_in(id->local_addr);

/* For wildcard addr, limit binding to current device only */
if (ipv4_is_zeronet(laddr->sin_addr.s_addr))
s->sk->sk_bound_dev_if = sdev->netdev->ifindex;

if (ipv4_is_zeronet(laddr->sin_addr.s_addr)) {
ndev = ib_device_get_netdev(id->device, SIW_PORT);
if (ndev) {
s->sk->sk_bound_dev_if = ndev->ifindex;
} else {
rv = -ENODEV;
goto error;
}
}
rv = s->ops->bind(s, (struct sockaddr *)laddr,
sizeof(struct sockaddr_in));
} else {
Expand All @@ -1797,9 +1804,15 @@ int siw_create_listen(struct iw_cm_id *id, int backlog)
}

/* For wildcard addr, limit binding to current device only */
if (ipv6_addr_any(&laddr->sin6_addr))
s->sk->sk_bound_dev_if = sdev->netdev->ifindex;

if (ipv6_addr_any(&laddr->sin6_addr)) {
ndev = ib_device_get_netdev(id->device, SIW_PORT);
if (ndev) {
s->sk->sk_bound_dev_if = ndev->ifindex;
} else {
rv = -ENODEV;
goto error;
}
}
rv = s->ops->bind(s, (struct sockaddr *)laddr,
sizeof(struct sockaddr_in6));
}
Expand Down Expand Up @@ -1860,6 +1873,7 @@ int siw_create_listen(struct iw_cm_id *id, int backlog)
}
list_add_tail(&cep->listenq, (struct list_head *)id->provider_data);
cep->state = SIW_EPSTATE_LISTENING;
dev_put(ndev);

siw_dbg(id->device, "Listen at laddr %pISp\n", &id->local_addr);

Expand All @@ -1879,6 +1893,7 @@ int siw_create_listen(struct iw_cm_id *id, int backlog)
siw_cep_set_free_and_put(cep);
}
sock_release(s);
dev_put(ndev);

return rv;
}
Expand Down
15 changes: 1 addition & 14 deletions drivers/infiniband/sw/siw/siw_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,6 @@ static struct siw_device *siw_device_create(struct net_device *netdev)
return NULL;

base_dev = &sdev->base_dev;
sdev->netdev = netdev;

if (netdev->addr_len) {
memcpy(sdev->raw_gid, netdev->dev_addr,
Expand Down Expand Up @@ -381,12 +380,10 @@ static int siw_netdev_event(struct notifier_block *nb, unsigned long event,

switch (event) {
case NETDEV_UP:
sdev->state = IB_PORT_ACTIVE;
siw_port_event(sdev, 1, IB_EVENT_PORT_ACTIVE);
break;

case NETDEV_DOWN:
sdev->state = IB_PORT_DOWN;
siw_port_event(sdev, 1, IB_EVENT_PORT_ERR);
break;

Expand All @@ -407,12 +404,8 @@ static int siw_netdev_event(struct notifier_block *nb, unsigned long event,
siw_port_event(sdev, 1, IB_EVENT_LID_CHANGE);
break;
/*
* Todo: Below netdev events are currently not handled.
* All other events are not handled
*/
case NETDEV_CHANGEMTU:
case NETDEV_CHANGE:
break;

default:
break;
}
Expand Down Expand Up @@ -442,12 +435,6 @@ static int siw_newlink(const char *basedev_name, struct net_device *netdev)
sdev = siw_device_create(netdev);
if (sdev) {
dev_dbg(&netdev->dev, "siw: new device\n");

if (netif_running(netdev) && netif_carrier_ok(netdev))
sdev->state = IB_PORT_ACTIVE;
else
sdev->state = IB_PORT_DOWN;

ib_mark_name_assigned_by_user(&sdev->base_dev);
rv = siw_device_register(sdev, basedev_name);
if (rv)
Expand Down
35 changes: 24 additions & 11 deletions drivers/infiniband/sw/siw/siw_verbs.c
Original file line number Diff line number Diff line change
Expand Up @@ -171,21 +171,29 @@ int siw_query_device(struct ib_device *base_dev, struct ib_device_attr *attr,
int siw_query_port(struct ib_device *base_dev, u32 port,
struct ib_port_attr *attr)
{
struct siw_device *sdev = to_siw_dev(base_dev);
struct net_device *ndev;
int rv;

memset(attr, 0, sizeof(*attr));

rv = ib_get_eth_speed(base_dev, port, &attr->active_speed,
&attr->active_width);
if (rv)
return rv;

ndev = ib_device_get_netdev(base_dev, SIW_PORT);
if (!ndev)
return -ENODEV;

attr->gid_tbl_len = 1;
attr->max_msg_sz = -1;
attr->max_mtu = ib_mtu_int_to_enum(sdev->netdev->mtu);
attr->active_mtu = ib_mtu_int_to_enum(sdev->netdev->mtu);
attr->phys_state = sdev->state == IB_PORT_ACTIVE ?
attr->max_mtu = ib_mtu_int_to_enum(ndev->max_mtu);
attr->active_mtu = ib_mtu_int_to_enum(READ_ONCE(ndev->mtu));
attr->phys_state = (netif_running(ndev) && netif_carrier_ok(ndev)) ?
IB_PORT_PHYS_STATE_LINK_UP : IB_PORT_PHYS_STATE_DISABLED;
attr->state = attr->phys_state == IB_PORT_PHYS_STATE_LINK_UP ?
IB_PORT_ACTIVE : IB_PORT_DOWN;
attr->port_cap_flags = IB_PORT_CM_SUP | IB_PORT_DEVICE_MGMT_SUP;
attr->state = sdev->state;
/*
* All zero
*
Expand All @@ -199,6 +207,7 @@ int siw_query_port(struct ib_device *base_dev, u32 port,
* attr->subnet_timeout = 0;
* attr->init_type_repy = 0;
*/
dev_put(ndev);
return rv;
}

Expand Down Expand Up @@ -505,21 +514,24 @@ int siw_query_qp(struct ib_qp *base_qp, struct ib_qp_attr *qp_attr,
int qp_attr_mask, struct ib_qp_init_attr *qp_init_attr)
{
struct siw_qp *qp;
struct siw_device *sdev;
struct net_device *ndev;

if (base_qp && qp_attr && qp_init_attr) {
if (base_qp && qp_attr && qp_init_attr)
qp = to_siw_qp(base_qp);
sdev = to_siw_dev(base_qp->device);
} else {
else
return -EINVAL;
}

ndev = ib_device_get_netdev(base_qp->device, SIW_PORT);
if (!ndev)
return -ENODEV;

qp_attr->qp_state = siw_qp_state_to_ib_qp_state[qp->attrs.state];
qp_attr->cap.max_inline_data = SIW_MAX_INLINE;
qp_attr->cap.max_send_wr = qp->attrs.sq_size;
qp_attr->cap.max_send_sge = qp->attrs.sq_max_sges;
qp_attr->cap.max_recv_wr = qp->attrs.rq_size;
qp_attr->cap.max_recv_sge = qp->attrs.rq_max_sges;
qp_attr->path_mtu = ib_mtu_int_to_enum(sdev->netdev->mtu);
qp_attr->path_mtu = ib_mtu_int_to_enum(READ_ONCE(ndev->mtu));
qp_attr->max_rd_atomic = qp->attrs.irq_size;
qp_attr->max_dest_rd_atomic = qp->attrs.orq_size;

Expand All @@ -534,6 +546,7 @@ int siw_query_qp(struct ib_qp *base_qp, struct ib_qp_attr *qp_attr,

qp_init_attr->cap = qp_attr->cap;

dev_put(ndev);
return 0;
}

Expand Down

0 comments on commit 16b8703

Please sign in to comment.