gobex: Fix segfault caused by interrupted transfer
authorDenis Grigorev <d.grigorev@omprussia.ru>
Tue, 30 Jun 2020 13:47:31 +0000 (16:47 +0300)
committerAyush Garg <ayush.garg@samsung.com>
Mon, 12 Apr 2021 09:00:49 +0000 (14:30 +0530)
When a obex transfer is interrupted by a peer in the middle, the response
G_OBEX_RSP_FORBIDDEN comes and the transfer is freed in transfer_complete.
However gobex is still ref'ed and gobex->io continues to be writable,
so write_data() and then g_obex_abort() are called. When the abort response
comes, struct obc_transfer is already freed, which leads to the crash.

Backtrace :
__GI___pthread_mutex_lock (mutex=0x65732f74) at pthread_mutex_lock.c:67
0xecc6eeda in dbus_connection_get_object_path_data () from libdbus-1.so.3
0x000457d4 in g_dbus_emit_property_changed_full () at gdbus/object.c:1794
0x00045868 in g_dbus_emit_property_changed () at gdbus/object.c:1832
0x000367f0 in transfer_set_status () at obexd/client/transfer.c:211
0x0003681e in transfer_set_status () at obexd/client/transfer.c:206
xfer_complete () at obexd/client/transfer.c:672
0x00022df6 in transfer_complete () at gobex/gobex-transfer.c:103
0x00022f44 in transfer_abort_response () at gobex/gobex-transfer.c:124
0x00020a0e in handle_response () at gobex/gobex.c:1128
0x00020dde in incoming_data () at gobex/gobex.c:1373

This commit introduces g_obex_drop_tx_queue(), which will be called if
a transfer error detected. After the tx queue is dropped, obex shuts
down gracefully.

Signed-off-by: Anuj Jain <anuj01.jain@samsung.com>
Signed-off-by: Ayush Garg <ayush.garg@samsung.com>
gobex/gobex-transfer.c
gobex/gobex.c
gobex/gobex.h

index bc99306..e96e61f 100755 (executable)
@@ -100,6 +100,11 @@ static void transfer_complete(struct transfer *transfer, GError *err)
 
        g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", id);
 
+       if (err) {
+               /* No further tx must be performed */
+               g_obex_drop_tx_queue(transfer->obex);
+       }
+
        transfer->complete_func(transfer->obex, err, transfer->user_data);
        /* Check if the complete_func removed the transfer */
        if (find_transfer(id) == NULL)
index 6229128..23b300e 100644 (file)
@@ -521,6 +521,16 @@ static void enable_tx(GObex *obex)
        obex->write_source = g_io_add_watch(obex->io, cond, write_data, obex);
 }
 
+void g_obex_drop_tx_queue(GObex *obex)
+{
+       struct pending_pkt *p;
+
+       g_obex_debug(G_OBEX_DEBUG_COMMAND, "");
+
+       while ((p = g_queue_pop_head(obex->tx_queue)))
+               pending_pkt_free(p);
+}
+
 static gboolean g_obex_send_internal(GObex *obex, struct pending_pkt *p,
                                                                GError **err)
 {
index a33fc60..a3282ef 100644 (file)
@@ -63,6 +63,7 @@ gboolean g_obex_remove_request_function(GObex *obex, guint id);
 void g_obex_suspend(GObex *obex);
 void g_obex_resume(GObex *obex);
 gboolean g_obex_srm_active(GObex *obex);
+void g_obex_drop_tx_queue(GObex *obex);
 
 GObex *g_obex_new(GIOChannel *io, GObexTransportType transport_type,
                                                gssize rx_mtu, gssize tx_mtu);