bluez5: free rfcomm when device is freed

Avoids use-after-free if device gets freed before the corresponding
rfcomm.
This commit is contained in:
Pauli Virtanen 2021-04-10 17:59:13 +03:00 committed by Wim Taymans
parent 0beb6bfc6c
commit 87aa18edb1
3 changed files with 33 additions and 11 deletions

View file

@ -88,6 +88,7 @@ struct rfcomm {
struct spa_source source;
struct impl *backend;
struct spa_bt_device *device;
struct spa_hook device_listener;
struct spa_bt_transport *transport;
struct spa_hook transport_listener;
enum spa_bt_profile profile;
@ -174,8 +175,18 @@ static void rfcomm_free(struct rfcomm *rfcomm)
spa_hook_remove(&rfcomm->transport_listener);
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_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);
}
@ -664,8 +675,6 @@ static void rfcomm_event(struct spa_source *source)
if (source->rmask & (SPA_IO_HUP | SPA_IO_ERR)) {
spa_log_info(backend->log, NAME": lost RFCOMM connection.");
if (source->loop)
spa_loop_remove_source(source->loop, source);
rfcomm_free(rfcomm);
return;
}
@ -1157,6 +1166,17 @@ static int backend_native_ensure_codec(void *data, struct spa_bt_device *device,
#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)
{
struct impl *backend = userdata;
@ -1221,6 +1241,10 @@ static DBusHandlerResult profile_new_connection(DBusConnection *conn, DBusMessag
rfcomm->source.mask = SPA_IO_IN;
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")))
rfcomm->msbc_support_enabled_in_config = strcmp(str, "true") == 0 || atoi(str) == 1;
else
@ -1270,9 +1294,6 @@ static DBusHandlerResult profile_new_connection(DBusConnection *conn, DBusMessag
goto fail_need_memory;
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;
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) {
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);
}
}

View file

@ -675,6 +675,8 @@ static void device_free(struct spa_bt_device *device)
spa_log_debug(monitor->log, "%p", device);
spa_bt_device_emit_destroy(device);
battery_remove(device);
device_stop_timer(device);

View file

@ -386,6 +386,9 @@ struct spa_bt_device_events {
/** Profile configuration changed */
void (*profiles_changed) (void *data, uint32_t prev_profiles, uint32_t prev_connected);
/** Device freed */
void (*destroy) (void *data);
};
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_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_destroy(d) spa_bt_device_emit(d, destroy, 0)
#define spa_bt_device_add_listener(d,listener,events,data) \
spa_hook_list_append(&(d)->listener_list, listener, events, data)