Commit 730c8912 authored by Mark Zhang's avatar Mark Zhang Committed by Jason Gunthorpe

RDMA/cma: Protect bind_list and listen_list while finding matching cm id

The bind_list and listen_list must be accessed under a lock, add the
missing locking around the access in cm_ib_id_from_event()

In addition add lockdep asserts to make it clearer what the locking
semantic is here.

  general protection fault: 0000 [#1] SMP NOPTI
  CPU: 226 PID: 126135 Comm: kworker/226:1 Tainted: G OE 4.12.14-150.47-default #1 SLE15
  Hardware name: Cray Inc. Windom/Windom, BIOS 0.8.7 01-10-2020
  Workqueue: ib_cm cm_work_handler [ib_cm]
  task: ffff9c5a60a1d2c0 task.stack: ffffc1d91f554000
  RIP: 0010:cma_ib_req_handler+0x3f1/0x11b0 [rdma_cm]
  RSP: 0018:ffffc1d91f557b40 EFLAGS: 00010286
  RAX: deacffffffffff30 RBX: 0000000000000001 RCX: ffff9c2af5bb6000
  RDX: 00000000000000a9 RSI: ffff9c5aa4ed2f10 RDI: ffffc1d91f557b08
  RBP: ffffc1d91f557d90 R08: ffff9c340cc80000 R09: ffff9c2c0f901900
  R10: 0000000000000000 R11: 0000000000000001 R12: deacffffffffff30
  R13: ffff9c5a48aeec00 R14: ffffc1d91f557c30 R15: ffff9c5c2eea3688
  FS: 0000000000000000(0000) GS:ffff9c5c2fa80000(0000) knlGS:0000000000000000
  CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
  CR2: 00002b5cc03fa320 CR3: 0000003f8500a000 CR4: 00000000003406e0
  Call Trace:
  ? rdma_addr_cancel+0xa0/0xa0 [ib_core]
  ? cm_process_work+0x28/0x140 [ib_cm]
  cm_process_work+0x28/0x140 [ib_cm]
  ? cm_get_bth_pkey.isra.44+0x34/0xa0 [ib_cm]
  cm_work_handler+0xa06/0x1a6f [ib_cm]
  ? __switch_to_asm+0x34/0x70
  ? __switch_to_asm+0x34/0x70
  ? __switch_to_asm+0x40/0x70
  ? __switch_to_asm+0x34/0x70
  ? __switch_to_asm+0x40/0x70
  ? __switch_to_asm+0x34/0x70
  ? __switch_to_asm+0x40/0x70
  ? __switch_to+0x7c/0x4b0
  ? __switch_to_asm+0x40/0x70
  ? __switch_to_asm+0x34/0x70
  process_one_work+0x1da/0x400
  worker_thread+0x2b/0x3f0
  ? process_one_work+0x400/0x400
  kthread+0x118/0x140
  ? kthread_create_on_node+0x40/0x40
  ret_from_fork+0x22/0x40
  Code: 00 66 83 f8 02 0f 84 ca 05 00 00 49 8b 84 24 d0 01 00 00 48 85 c0 0f 84 68 07 00 00 48 2d d0 01
  00 00 49 89 c4 0f 84 59 07 00 00 <41> 0f b7 44 24 20 49 8b 77 50 66 83 f8 0a 75 9e 49 8b 7c 24 28

Fixes: 4c21b5bc ("IB/cma: Add net_dev and private data checks to RDMA CM")
Link: https://lore.kernel.org/r/20200616104304.2426081-1-leon@kernel.orgSigned-off-by: default avatarMark Zhang <markz@mellanox.com>
Reviewed-by: default avatarMaor Gottlieb <maorg@mellanox.com>
Signed-off-by: default avatarLeon Romanovsky <leonro@mellanox.com>
Signed-off-by: default avatarJason Gunthorpe <jgg@mellanox.com>
parent 0dfbd5ec
...@@ -1624,6 +1624,8 @@ static struct rdma_id_private *cma_find_listener( ...@@ -1624,6 +1624,8 @@ static struct rdma_id_private *cma_find_listener(
{ {
struct rdma_id_private *id_priv, *id_priv_dev; struct rdma_id_private *id_priv, *id_priv_dev;
lockdep_assert_held(&lock);
if (!bind_list) if (!bind_list)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
...@@ -1670,6 +1672,7 @@ cma_ib_id_from_event(struct ib_cm_id *cm_id, ...@@ -1670,6 +1672,7 @@ cma_ib_id_from_event(struct ib_cm_id *cm_id,
} }
} }
mutex_lock(&lock);
/* /*
* Net namespace might be getting deleted while route lookup, * Net namespace might be getting deleted while route lookup,
* cm_id lookup is in progress. Therefore, perform netdevice * cm_id lookup is in progress. Therefore, perform netdevice
...@@ -1711,6 +1714,7 @@ cma_ib_id_from_event(struct ib_cm_id *cm_id, ...@@ -1711,6 +1714,7 @@ cma_ib_id_from_event(struct ib_cm_id *cm_id,
id_priv = cma_find_listener(bind_list, cm_id, ib_event, req, *net_dev); id_priv = cma_find_listener(bind_list, cm_id, ib_event, req, *net_dev);
err: err:
rcu_read_unlock(); rcu_read_unlock();
mutex_unlock(&lock);
if (IS_ERR(id_priv) && *net_dev) { if (IS_ERR(id_priv) && *net_dev) {
dev_put(*net_dev); dev_put(*net_dev);
*net_dev = NULL; *net_dev = NULL;
...@@ -2492,6 +2496,8 @@ static void cma_listen_on_dev(struct rdma_id_private *id_priv, ...@@ -2492,6 +2496,8 @@ static void cma_listen_on_dev(struct rdma_id_private *id_priv,
struct net *net = id_priv->id.route.addr.dev_addr.net; struct net *net = id_priv->id.route.addr.dev_addr.net;
int ret; int ret;
lockdep_assert_held(&lock);
if (cma_family(id_priv) == AF_IB && !rdma_cap_ib_cm(cma_dev->device, 1)) if (cma_family(id_priv) == AF_IB && !rdma_cap_ib_cm(cma_dev->device, 1))
return; return;
...@@ -3342,6 +3348,8 @@ static void cma_bind_port(struct rdma_bind_list *bind_list, ...@@ -3342,6 +3348,8 @@ static void cma_bind_port(struct rdma_bind_list *bind_list,
u64 sid, mask; u64 sid, mask;
__be16 port; __be16 port;
lockdep_assert_held(&lock);
addr = cma_src_addr(id_priv); addr = cma_src_addr(id_priv);
port = htons(bind_list->port); port = htons(bind_list->port);
...@@ -3370,6 +3378,8 @@ static int cma_alloc_port(enum rdma_ucm_port_space ps, ...@@ -3370,6 +3378,8 @@ static int cma_alloc_port(enum rdma_ucm_port_space ps,
struct rdma_bind_list *bind_list; struct rdma_bind_list *bind_list;
int ret; int ret;
lockdep_assert_held(&lock);
bind_list = kzalloc(sizeof *bind_list, GFP_KERNEL); bind_list = kzalloc(sizeof *bind_list, GFP_KERNEL);
if (!bind_list) if (!bind_list)
return -ENOMEM; return -ENOMEM;
...@@ -3396,6 +3406,8 @@ static int cma_port_is_unique(struct rdma_bind_list *bind_list, ...@@ -3396,6 +3406,8 @@ static int cma_port_is_unique(struct rdma_bind_list *bind_list,
struct sockaddr *saddr = cma_src_addr(id_priv); struct sockaddr *saddr = cma_src_addr(id_priv);
__be16 dport = cma_port(daddr); __be16 dport = cma_port(daddr);
lockdep_assert_held(&lock);
hlist_for_each_entry(cur_id, &bind_list->owners, node) { hlist_for_each_entry(cur_id, &bind_list->owners, node) {
struct sockaddr *cur_daddr = cma_dst_addr(cur_id); struct sockaddr *cur_daddr = cma_dst_addr(cur_id);
struct sockaddr *cur_saddr = cma_src_addr(cur_id); struct sockaddr *cur_saddr = cma_src_addr(cur_id);
...@@ -3435,6 +3447,8 @@ static int cma_alloc_any_port(enum rdma_ucm_port_space ps, ...@@ -3435,6 +3447,8 @@ static int cma_alloc_any_port(enum rdma_ucm_port_space ps,
unsigned int rover; unsigned int rover;
struct net *net = id_priv->id.route.addr.dev_addr.net; struct net *net = id_priv->id.route.addr.dev_addr.net;
lockdep_assert_held(&lock);
inet_get_local_port_range(net, &low, &high); inet_get_local_port_range(net, &low, &high);
remaining = (high - low) + 1; remaining = (high - low) + 1;
rover = prandom_u32() % remaining + low; rover = prandom_u32() % remaining + low;
...@@ -3482,6 +3496,8 @@ static int cma_check_port(struct rdma_bind_list *bind_list, ...@@ -3482,6 +3496,8 @@ static int cma_check_port(struct rdma_bind_list *bind_list,
struct rdma_id_private *cur_id; struct rdma_id_private *cur_id;
struct sockaddr *addr, *cur_addr; struct sockaddr *addr, *cur_addr;
lockdep_assert_held(&lock);
addr = cma_src_addr(id_priv); addr = cma_src_addr(id_priv);
hlist_for_each_entry(cur_id, &bind_list->owners, node) { hlist_for_each_entry(cur_id, &bind_list->owners, node) {
if (id_priv == cur_id) if (id_priv == cur_id)
...@@ -3512,6 +3528,8 @@ static int cma_use_port(enum rdma_ucm_port_space ps, ...@@ -3512,6 +3528,8 @@ static int cma_use_port(enum rdma_ucm_port_space ps,
unsigned short snum; unsigned short snum;
int ret; int ret;
lockdep_assert_held(&lock);
snum = ntohs(cma_port(cma_src_addr(id_priv))); snum = ntohs(cma_port(cma_src_addr(id_priv)));
if (snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE)) if (snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE))
return -EACCES; return -EACCES;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment