Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dledford/rdma

Pull infiniband fixes from Doug Ledford:
"It's late in the game, I know, but these fixes seemed important enough
to warrant a late pull request. They all involve oopses or use after
frees or corruptions.

Six serious fixes:

- Hold the mutex around the find and corresponding update of our gid

- The ifa list is rcu protected, copy its contents under rcu to avoid
using a freed structure

- On error, netdev might be null, so check it before trying to
release it

- On init, if workqueue alloc fails, fail init

- The new demux patches exposed a bug in mlx5 and ipath drivers, we
need to use the payload P_Key to determine the P_Key the packet
arrived on because the hardware doesn't tell us the truth

- Due to a couple convoluted error flows, it is possible for the CM
to trigger a use_after_free and a double_free of rb nodes. Add two
checks to prevent that. This code has worked for 10+ years. It is
likely that some of the recent changes have caused this issue to
surface. The current patch will protect us from nasty events for
now while we track down why this is just now showing up"

* tag 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dledford/rdma:
IB/cm: Fix rb-tree duplicate free and use-after-free
IB/cma: Use inner P_Key to determine netdev
IB/ucma: check workqueue allocation before usage
IB/cma: Potential NULL dereference in cma_id_from_event
IB/core: Fix use after free of ifa
IB/core: Fix memory corruption in ib_cache_gid_set_default_gid

+46 -14
+1 -1
drivers/infiniband/core/cache.c
··· 508 508 memset(&gid_attr, 0, sizeof(gid_attr)); 509 509 gid_attr.ndev = ndev; 510 510 511 + mutex_lock(&table->lock); 511 512 ix = find_gid(table, NULL, NULL, true, GID_ATTR_FIND_MASK_DEFAULT); 512 513 513 514 /* Coudn't find default GID location */ 514 515 WARN_ON(ix < 0); 515 516 516 - mutex_lock(&table->lock); 517 517 if (!__ib_cache_gid_get(ib_dev, port, ix, 518 518 &current_gid, &current_gid_attr) && 519 519 mode == IB_CACHE_GID_DEFAULT_MODE_SET &&
+9 -1
drivers/infiniband/core/cm.c
··· 835 835 case IB_CM_SIDR_REQ_RCVD: 836 836 spin_unlock_irq(&cm_id_priv->lock); 837 837 cm_reject_sidr_req(cm_id_priv, IB_SIDR_REJECT); 838 + spin_lock_irq(&cm.lock); 839 + if (!RB_EMPTY_NODE(&cm_id_priv->sidr_id_node)) 840 + rb_erase(&cm_id_priv->sidr_id_node, 841 + &cm.remote_sidr_table); 842 + spin_unlock_irq(&cm.lock); 838 843 break; 839 844 case IB_CM_REQ_SENT: 840 845 case IB_CM_MRA_REQ_RCVD: ··· 3177 3172 spin_unlock_irqrestore(&cm_id_priv->lock, flags); 3178 3173 3179 3174 spin_lock_irqsave(&cm.lock, flags); 3180 - rb_erase(&cm_id_priv->sidr_id_node, &cm.remote_sidr_table); 3175 + if (!RB_EMPTY_NODE(&cm_id_priv->sidr_id_node)) { 3176 + rb_erase(&cm_id_priv->sidr_id_node, &cm.remote_sidr_table); 3177 + RB_CLEAR_NODE(&cm_id_priv->sidr_id_node); 3178 + } 3181 3179 spin_unlock_irqrestore(&cm.lock, flags); 3182 3180 return 0; 3183 3181
+3 -3
drivers/infiniband/core/cma.c
··· 1067 1067 sizeof(req->local_gid)); 1068 1068 req->has_gid = true; 1069 1069 req->service_id = req_param->primary_path->service_id; 1070 - req->pkey = req_param->bth_pkey; 1070 + req->pkey = be16_to_cpu(req_param->primary_path->pkey); 1071 1071 break; 1072 1072 case IB_CM_SIDR_REQ_RECEIVED: 1073 1073 req->device = sidr_param->listen_id->device; 1074 1074 req->port = sidr_param->port; 1075 1075 req->has_gid = false; 1076 1076 req->service_id = sidr_param->service_id; 1077 - req->pkey = sidr_param->bth_pkey; 1077 + req->pkey = sidr_param->pkey; 1078 1078 break; 1079 1079 default: 1080 1080 return -EINVAL; ··· 1324 1324 bind_list = cma_ps_find(rdma_ps_from_service_id(req.service_id), 1325 1325 cma_port_from_service_id(req.service_id)); 1326 1326 id_priv = cma_find_listener(bind_list, cm_id, ib_event, &req, *net_dev); 1327 - if (IS_ERR(id_priv)) { 1327 + if (IS_ERR(id_priv) && *net_dev) { 1328 1328 dev_put(*net_dev); 1329 1329 *net_dev = NULL; 1330 1330 }
+27 -8
drivers/infiniband/core/roce_gid_mgmt.c
··· 250 250 u8 port, struct net_device *ndev) 251 251 { 252 252 struct in_device *in_dev; 253 + struct sin_list { 254 + struct list_head list; 255 + struct sockaddr_in ip; 256 + }; 257 + struct sin_list *sin_iter; 258 + struct sin_list *sin_temp; 253 259 260 + LIST_HEAD(sin_list); 254 261 if (ndev->reg_state >= NETREG_UNREGISTERING) 255 262 return; 256 263 257 - in_dev = in_dev_get(ndev); 258 - if (!in_dev) 264 + rcu_read_lock(); 265 + in_dev = __in_dev_get_rcu(ndev); 266 + if (!in_dev) { 267 + rcu_read_unlock(); 259 268 return; 269 + } 260 270 261 271 for_ifa(in_dev) { 262 - struct sockaddr_in ip; 272 + struct sin_list *entry = kzalloc(sizeof(*entry), GFP_ATOMIC); 263 273 264 - ip.sin_family = AF_INET; 265 - ip.sin_addr.s_addr = ifa->ifa_address; 266 - update_gid_ip(GID_ADD, ib_dev, port, ndev, 267 - (struct sockaddr *)&ip); 274 + if (!entry) { 275 + pr_warn("roce_gid_mgmt: couldn't allocate entry for IPv4 update\n"); 276 + continue; 277 + } 278 + entry->ip.sin_family = AF_INET; 279 + entry->ip.sin_addr.s_addr = ifa->ifa_address; 280 + list_add_tail(&entry->list, &sin_list); 268 281 } 269 282 endfor_ifa(in_dev); 283 + rcu_read_unlock(); 270 284 271 - in_dev_put(in_dev); 285 + list_for_each_entry_safe(sin_iter, sin_temp, &sin_list, list) { 286 + update_gid_ip(GID_ADD, ib_dev, port, ndev, 287 + (struct sockaddr *)&sin_iter->ip); 288 + list_del(&sin_iter->list); 289 + kfree(sin_iter); 290 + } 272 291 } 273 292 274 293 static void enum_netdev_ipv6_ips(struct ib_device *ib_dev,
+6 -1
drivers/infiniband/core/ucma.c
··· 1624 1624 if (!file) 1625 1625 return -ENOMEM; 1626 1626 1627 + file->close_wq = create_singlethread_workqueue("ucma_close_id"); 1628 + if (!file->close_wq) { 1629 + kfree(file); 1630 + return -ENOMEM; 1631 + } 1632 + 1627 1633 INIT_LIST_HEAD(&file->event_list); 1628 1634 INIT_LIST_HEAD(&file->ctx_list); 1629 1635 init_waitqueue_head(&file->poll_wait); 1630 1636 mutex_init(&file->mut); 1631 - file->close_wq = create_singlethread_workqueue("ucma_close_id"); 1632 1637 1633 1638 filp->private_data = file; 1634 1639 file->filp = filp;