forked from mirrors/linux
		
	Bluetooth: hci_event: Fix using rcu_read_(un)lock while iterating
The usage of rcu_read_(un)lock while inside list_for_each_entry_rcu is
not safe since for the most part entries fetched this way shall be
treated as rcu_dereference:
	Note that the value returned by rcu_dereference() is valid
	only within the enclosing RCU read-side critical section [1]_.
	For example, the following is **not** legal::
		rcu_read_lock();
		p = rcu_dereference(head.next);
		rcu_read_unlock();
		x = p->address;	/* BUG!!! */
		rcu_read_lock();
		y = p->data;	/* BUG!!! */
		rcu_read_unlock();
Fixes: a0bfde167b ("Bluetooth: ISO: Add support for connecting multiple BISes")
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
			
			
This commit is contained in:
		
							parent
							
								
									4d94f05558
								
							
						
					
					
						commit
						581dd2dc16
					
				
					 1 changed files with 11 additions and 22 deletions
				
			
		| 
						 | 
					@ -6870,38 +6870,27 @@ static void hci_le_create_big_complete_evt(struct hci_dev *hdev, void *data,
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	hci_dev_lock(hdev);
 | 
						hci_dev_lock(hdev);
 | 
				
			||||||
	rcu_read_lock();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Connect all BISes that are bound to the BIG */
 | 
						/* Connect all BISes that are bound to the BIG */
 | 
				
			||||||
	list_for_each_entry_rcu(conn, &hdev->conn_hash.list, list) {
 | 
						while ((conn = hci_conn_hash_lookup_big_state(hdev, ev->handle,
 | 
				
			||||||
		if (bacmp(&conn->dst, BDADDR_ANY) ||
 | 
											      BT_BOUND))) {
 | 
				
			||||||
		    conn->type != ISO_LINK ||
 | 
							if (ev->status) {
 | 
				
			||||||
		    conn->iso_qos.bcast.big != ev->handle)
 | 
								hci_connect_cfm(conn, ev->status);
 | 
				
			||||||
 | 
								hci_conn_del(conn);
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (hci_conn_set_handle(conn,
 | 
							if (hci_conn_set_handle(conn,
 | 
				
			||||||
					__le16_to_cpu(ev->bis_handle[i++])))
 | 
										__le16_to_cpu(ev->bis_handle[i++])))
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (!ev->status) {
 | 
					 | 
				
			||||||
		conn->state = BT_CONNECTED;
 | 
							conn->state = BT_CONNECTED;
 | 
				
			||||||
		set_bit(HCI_CONN_BIG_CREATED, &conn->flags);
 | 
							set_bit(HCI_CONN_BIG_CREATED, &conn->flags);
 | 
				
			||||||
			rcu_read_unlock();
 | 
					 | 
				
			||||||
		hci_debugfs_create_conn(conn);
 | 
							hci_debugfs_create_conn(conn);
 | 
				
			||||||
		hci_conn_add_sysfs(conn);
 | 
							hci_conn_add_sysfs(conn);
 | 
				
			||||||
		hci_iso_setup_path(conn);
 | 
							hci_iso_setup_path(conn);
 | 
				
			||||||
			rcu_read_lock();
 | 
					 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		hci_connect_cfm(conn, ev->status);
 | 
					 | 
				
			||||||
		rcu_read_unlock();
 | 
					 | 
				
			||||||
		hci_conn_del(conn);
 | 
					 | 
				
			||||||
		rcu_read_lock();
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	rcu_read_unlock();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!ev->status && !i)
 | 
						if (!ev->status && !i)
 | 
				
			||||||
		/* If no BISes have been connected for the BIG,
 | 
							/* If no BISes have been connected for the BIG,
 | 
				
			||||||
		 * terminate. This is in case all bound connections
 | 
							 * terminate. This is in case all bound connections
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue