mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	bluez5: free rfcomm when device is freed
Avoids use-after-free if device gets freed before the corresponding rfcomm.
This commit is contained in:
		
							parent
							
								
									0beb6bfc6c
								
							
						
					
					
						commit
						87aa18edb1
					
				
					 3 changed files with 33 additions and 11 deletions
				
			
		| 
						 | 
					@ -88,6 +88,7 @@ struct rfcomm {
 | 
				
			||||||
	struct spa_source source;
 | 
						struct spa_source source;
 | 
				
			||||||
	struct impl *backend;
 | 
						struct impl *backend;
 | 
				
			||||||
	struct spa_bt_device *device;
 | 
						struct spa_bt_device *device;
 | 
				
			||||||
 | 
						struct spa_hook device_listener;
 | 
				
			||||||
	struct spa_bt_transport *transport;
 | 
						struct spa_bt_transport *transport;
 | 
				
			||||||
	struct spa_hook transport_listener;
 | 
						struct spa_hook transport_listener;
 | 
				
			||||||
	enum spa_bt_profile profile;
 | 
						enum spa_bt_profile profile;
 | 
				
			||||||
| 
						 | 
					@ -174,8 +175,18 @@ static void rfcomm_free(struct rfcomm *rfcomm)
 | 
				
			||||||
		spa_hook_remove(&rfcomm->transport_listener);
 | 
							spa_hook_remove(&rfcomm->transport_listener);
 | 
				
			||||||
		spa_bt_transport_free(rfcomm->transport);
 | 
							spa_bt_transport_free(rfcomm->transport);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (rfcomm->device)
 | 
						if (rfcomm->device) {
 | 
				
			||||||
		spa_bt_device_report_battery_level(rfcomm->device, SPA_BT_NO_BATTERY);
 | 
							spa_bt_device_report_battery_level(rfcomm->device, SPA_BT_NO_BATTERY);
 | 
				
			||||||
 | 
							spa_hook_remove(&rfcomm->device_listener);
 | 
				
			||||||
 | 
							rfcomm->device = NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (rfcomm->source.fd >= 0) {
 | 
				
			||||||
 | 
							if (rfcomm->source.loop)
 | 
				
			||||||
 | 
								spa_loop_remove_source(rfcomm->source.loop, &rfcomm->source);
 | 
				
			||||||
 | 
							shutdown(rfcomm->source.fd, SHUT_RDWR);
 | 
				
			||||||
 | 
							close (rfcomm->source.fd);
 | 
				
			||||||
 | 
							rfcomm->source.fd = -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	free(rfcomm);
 | 
						free(rfcomm);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -664,8 +675,6 @@ static void rfcomm_event(struct spa_source *source)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (source->rmask & (SPA_IO_HUP | SPA_IO_ERR)) {
 | 
						if (source->rmask & (SPA_IO_HUP | SPA_IO_ERR)) {
 | 
				
			||||||
		spa_log_info(backend->log, NAME": lost RFCOMM connection.");
 | 
							spa_log_info(backend->log, NAME": lost RFCOMM connection.");
 | 
				
			||||||
		if (source->loop)
 | 
					 | 
				
			||||||
			spa_loop_remove_source(source->loop, source);
 | 
					 | 
				
			||||||
		rfcomm_free(rfcomm);
 | 
							rfcomm_free(rfcomm);
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -1157,6 +1166,17 @@ static int backend_native_ensure_codec(void *data, struct spa_bt_device *device,
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void device_destroy(void *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct rfcomm *rfcomm = data;
 | 
				
			||||||
 | 
						rfcomm_free(rfcomm);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct spa_bt_device_events device_events = {
 | 
				
			||||||
 | 
						SPA_VERSION_BT_DEVICE_EVENTS,
 | 
				
			||||||
 | 
						.destroy = device_destroy,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static DBusHandlerResult profile_new_connection(DBusConnection *conn, DBusMessage *m, void *userdata)
 | 
					static DBusHandlerResult profile_new_connection(DBusConnection *conn, DBusMessage *m, void *userdata)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct impl *backend = userdata;
 | 
						struct impl *backend = userdata;
 | 
				
			||||||
| 
						 | 
					@ -1221,6 +1241,10 @@ static DBusHandlerResult profile_new_connection(DBusConnection *conn, DBusMessag
 | 
				
			||||||
	rfcomm->source.mask = SPA_IO_IN;
 | 
						rfcomm->source.mask = SPA_IO_IN;
 | 
				
			||||||
	rfcomm->source.rmask = 0;
 | 
						rfcomm->source.rmask = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spa_bt_device_add_listener(d, &rfcomm->device_listener, &device_events, rfcomm);
 | 
				
			||||||
 | 
						spa_loop_add_source(backend->main_loop, &rfcomm->source);
 | 
				
			||||||
 | 
						spa_list_append(&backend->rfcomm_list, &rfcomm->link);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (d->settings && (str = spa_dict_lookup(d->settings, "bluez5.msbc-support")))
 | 
						if (d->settings && (str = spa_dict_lookup(d->settings, "bluez5.msbc-support")))
 | 
				
			||||||
		rfcomm->msbc_support_enabled_in_config = strcmp(str, "true") == 0 || atoi(str) == 1;
 | 
							rfcomm->msbc_support_enabled_in_config = strcmp(str, "true") == 0 || atoi(str) == 1;
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
| 
						 | 
					@ -1270,9 +1294,6 @@ static DBusHandlerResult profile_new_connection(DBusConnection *conn, DBusMessag
 | 
				
			||||||
		goto fail_need_memory;
 | 
							goto fail_need_memory;
 | 
				
			||||||
	dbus_message_unref(r);
 | 
						dbus_message_unref(r);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spa_loop_add_source(backend->main_loop, &rfcomm->source);
 | 
					 | 
				
			||||||
	spa_list_append(&backend->rfcomm_list, &rfcomm->link);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return DBUS_HANDLER_RESULT_HANDLED;
 | 
						return DBUS_HANDLER_RESULT_HANDLED;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fail_need_memory:
 | 
					fail_need_memory:
 | 
				
			||||||
| 
						 | 
					@ -1326,11 +1347,6 @@ static DBusHandlerResult profile_request_disconnection(DBusConnection *conn, DBu
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spa_list_for_each_safe(rfcomm, rfcomm_tmp, &backend->rfcomm_list, link) {
 | 
						spa_list_for_each_safe(rfcomm, rfcomm_tmp, &backend->rfcomm_list, link) {
 | 
				
			||||||
		if (rfcomm->device == d && rfcomm->profile == profile) {
 | 
							if (rfcomm->device == d && rfcomm->profile == profile) {
 | 
				
			||||||
			if (rfcomm->source.loop)
 | 
					 | 
				
			||||||
				spa_loop_remove_source(rfcomm->source.loop, &rfcomm->source);
 | 
					 | 
				
			||||||
			shutdown(rfcomm->source.fd, SHUT_RDWR);
 | 
					 | 
				
			||||||
			close (rfcomm->source.fd);
 | 
					 | 
				
			||||||
			rfcomm->source.fd = -1;
 | 
					 | 
				
			||||||
			rfcomm_free(rfcomm);
 | 
								rfcomm_free(rfcomm);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -675,6 +675,8 @@ static void device_free(struct spa_bt_device *device)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spa_log_debug(monitor->log, "%p", device);
 | 
						spa_log_debug(monitor->log, "%p", device);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spa_bt_device_emit_destroy(device);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	battery_remove(device);
 | 
						battery_remove(device);
 | 
				
			||||||
	device_stop_timer(device);
 | 
						device_stop_timer(device);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -386,6 +386,9 @@ struct spa_bt_device_events {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/** Profile configuration changed */
 | 
						/** Profile configuration changed */
 | 
				
			||||||
	void (*profiles_changed) (void *data, uint32_t prev_profiles, uint32_t prev_connected);
 | 
						void (*profiles_changed) (void *data, uint32_t prev_profiles, uint32_t prev_connected);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Device freed */
 | 
				
			||||||
 | 
						void (*destroy) (void *data);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct spa_bt_device {
 | 
					struct spa_bt_device {
 | 
				
			||||||
| 
						 | 
					@ -446,6 +449,7 @@ int spa_bt_device_report_battery_level(struct spa_bt_device *device, uint8_t per
 | 
				
			||||||
#define spa_bt_device_emit_connected(d,...)	        spa_bt_device_emit(d, connected, 0, __VA_ARGS__)
 | 
					#define spa_bt_device_emit_connected(d,...)	        spa_bt_device_emit(d, connected, 0, __VA_ARGS__)
 | 
				
			||||||
#define spa_bt_device_emit_codec_switched(d,...)	spa_bt_device_emit(d, codec_switched, 0, __VA_ARGS__)
 | 
					#define spa_bt_device_emit_codec_switched(d,...)	spa_bt_device_emit(d, codec_switched, 0, __VA_ARGS__)
 | 
				
			||||||
#define spa_bt_device_emit_profiles_changed(d,...)	spa_bt_device_emit(d, profiles_changed, 0, __VA_ARGS__)
 | 
					#define spa_bt_device_emit_profiles_changed(d,...)	spa_bt_device_emit(d, profiles_changed, 0, __VA_ARGS__)
 | 
				
			||||||
 | 
					#define spa_bt_device_emit_destroy(d)			spa_bt_device_emit(d, destroy, 0)
 | 
				
			||||||
#define spa_bt_device_add_listener(d,listener,events,data)           \
 | 
					#define spa_bt_device_add_listener(d,listener,events,data)           \
 | 
				
			||||||
	spa_hook_list_append(&(d)->listener_list, listener, events, data)
 | 
						spa_hook_list_append(&(d)->listener_list, listener, events, data)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue