ofono/gatchat/gatmux.c

1333 lines
28 KiB
C
Raw Normal View History

2009-09-05 09:52:31 +00:00
/*
*
* AT chat library with GLib integration
2009-09-05 09:52:31 +00:00
*
2011-10-10 20:39:25 +00:00
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
* Copyright (C) 2009 Trolltech ASA.
2009-09-05 09:52:31 +00:00
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <alloca.h>
2009-09-05 09:52:31 +00:00
#pragma GCC diagnostic ignored "-Wpragmas"
#pragma GCC diagnostic ignored "-Wcast-function-type"
2009-09-05 09:52:31 +00:00
#include <glib.h>
#include "ringbuffer.h"
2009-09-05 09:52:31 +00:00
#include "gatmux.h"
#include "gsm0710.h"
2009-09-05 09:52:31 +00:00
static const char *cmux_prefix[] = { "+CMUX:", NULL };
static const char *none_prefix[] = { NULL };
typedef struct _GAtMuxChannel GAtMuxChannel;
typedef struct _GAtMuxWatch GAtMuxWatch;
typedef void (*GAtMuxWriteFrame)(GAtMux *mux, guint8 dlc, guint8 control,
const guint8 *data, int len);
/* While 63 channels are theoretically possible, channel 62 and 63 is reserved
* by 27.010 for use as the beginning of frame and end of frame flags.
* Refer to Section 5.6 in 27.007
*/
#define MAX_CHANNELS 61
#define BITMAP_SIZE 8
#define MUX_CHANNEL_BUFFER_SIZE 4096
#define MUX_BUFFER_SIZE 4096
struct _GAtMuxChannel
{
GIOChannel channel;
GAtMux *mux;
GIOCondition condition;
struct ring_buffer *buffer;
GSList *sources;
gboolean throttled;
guint dlc;
};
struct _GAtMuxWatch
{
GSource source;
GIOChannel *channel;
GIOCondition condition;
};
2009-09-05 09:52:31 +00:00
struct _GAtMux {
gint ref_count; /* Ref count */
guint read_watch; /* GSource read id, 0 if none */
guint write_watch; /* GSource write id, 0 if none */
GIOChannel *channel; /* main serial channel */
GAtDisconnectFunc user_disconnect; /* user disconnect func */
gpointer user_disconnect_data; /* user disconnect data */
GAtDebugFunc debugf; /* debugging output function */
gpointer debug_data; /* Data to pass to debug func */
GAtMuxChannel *dlcs[MAX_CHANNELS]; /* DLCs opened by the MUX */
guint8 newdata[BITMAP_SIZE]; /* Channels that got new data */
const GAtMuxDriver *driver; /* Driver functions */
void *driver_data; /* Driver data */
char buf[MUX_BUFFER_SIZE]; /* Buffer on the main mux */
int buf_used; /* Bytes of buf being used */
gboolean shutdown;
2009-09-05 09:52:31 +00:00
};
struct mux_setup_data {
GAtChat *chat;
GAtMuxSetupFunc func;
gpointer user;
GDestroyNotify destroy;
guint mode;
guint frame_size;
};
static inline void debug(GAtMux *mux, const char *format, ...)
{
char str[256];
va_list ap;
if (mux->debugf == NULL)
return;
va_start(ap, format);
if (vsnprintf(str, sizeof(str), format, ap) > 0)
mux->debugf(str, mux->debug_data);
va_end(ap);
}
static void dispatch_sources(GAtMuxChannel *channel, GIOCondition condition)
{
GSList *c;
GSList *p;
gatmux: Remove finalized watches from the list Leaving them there may result in invalid reads like this: ==2312== Invalid read of size 4 ==2312== at 0xAB8C0: dispatch_sources (gatmux.c:134) ==2312== by 0xAC5D3: channel_close (gatmux.c:479) ==2312== by 0x4AE8885: g_io_channel_shutdown (giochannel.c:523) ==2312== by 0x4AE8A1D: g_io_channel_unref (giochannel.c:240) ==2312== by 0xAC423: watch_finalize (gatmux.c:426) ==2312== by 0x4AF2CC9: g_source_unref_internal (gmain.c:2048) ==2312== by 0x4AF44E1: g_source_destroy_internal (gmain.c:1230) ==2312== by 0x4AF44E1: g_source_destroy (gmain.c:1256) ==2312== by 0x4AF5257: g_source_remove (gmain.c:2282) ==2312== by 0xAB5CB: io_shutdown (gatio.c:325) ==2312== by 0xAB667: g_at_io_unref (gatio.c:345) ==2312== by 0xA72C7: at_chat_unref (gatchat.c:972) ==2312== by 0xA829B: g_at_chat_unref (gatchat.c:1446) ==2312== Address 0x51420f0 is 56 bytes inside a block of size 60 free'd ==2312== at 0x4840B28: free (vg_replace_malloc.c:530) ==2312== by 0x4AF2D33: g_source_unref_internal (gmain.c:2075) ==2312== by 0x4AF44E1: g_source_destroy_internal (gmain.c:1230) ==2312== by 0x4AF44E1: g_source_destroy (gmain.c:1256) ==2312== by 0x4AF5257: g_source_remove (gmain.c:2282) ==2312== by 0xAB46B: g_at_io_set_write_handler (gatio.c:283) ==2312== by 0xA713F: at_chat_suspend (gatchat.c:938) ==2312== by 0xA72B7: at_chat_unref (gatchat.c:971) ==2312== by 0xA829B: g_at_chat_unref (gatchat.c:1446) ==2312== Block was alloc'd at ==2312== at 0x4841BF0: calloc (vg_replace_malloc.c:711) ==2312== by 0x4AFB117: g_malloc0 (gmem.c:124) ==2312== by 0x4AF401F: g_source_new (gmain.c:892) ==2312== by 0xAC6A7: channel_create_watch (gatmux.c:506) ==2312== by 0x4AE7C4F: g_io_add_watch_full (giochannel.c:649) ==2312== by 0xAB4EB: g_at_io_set_write_handler (gatio.c:297) ==2312== by 0xA7103: chat_wakeup_writer (gatchat.c:931) ==2312== by 0xA753F: at_chat_send_common (gatchat.c:1045) ==2312== by 0xA850F: g_at_chat_send (gatchat.c:1502) It's also necessary to add additional references to the sources for the duration of the dispatch_sources loop because any source can be removed when any callback is invoked (and not necessarily the one being dispatched).
2017-10-23 09:17:30 +00:00
GSList *refs;
/*
* Don't reference destroyed sources, they may have zero reference
* count if this function is invoked from the source's finalize
* callback, in which case incrementing and then decrementing
* the count would result in double free (first when we decrement
* the reference count and then when we return from the finalize
* callback).
*/
p = NULL;
gatmux: Remove finalized watches from the list Leaving them there may result in invalid reads like this: ==2312== Invalid read of size 4 ==2312== at 0xAB8C0: dispatch_sources (gatmux.c:134) ==2312== by 0xAC5D3: channel_close (gatmux.c:479) ==2312== by 0x4AE8885: g_io_channel_shutdown (giochannel.c:523) ==2312== by 0x4AE8A1D: g_io_channel_unref (giochannel.c:240) ==2312== by 0xAC423: watch_finalize (gatmux.c:426) ==2312== by 0x4AF2CC9: g_source_unref_internal (gmain.c:2048) ==2312== by 0x4AF44E1: g_source_destroy_internal (gmain.c:1230) ==2312== by 0x4AF44E1: g_source_destroy (gmain.c:1256) ==2312== by 0x4AF5257: g_source_remove (gmain.c:2282) ==2312== by 0xAB5CB: io_shutdown (gatio.c:325) ==2312== by 0xAB667: g_at_io_unref (gatio.c:345) ==2312== by 0xA72C7: at_chat_unref (gatchat.c:972) ==2312== by 0xA829B: g_at_chat_unref (gatchat.c:1446) ==2312== Address 0x51420f0 is 56 bytes inside a block of size 60 free'd ==2312== at 0x4840B28: free (vg_replace_malloc.c:530) ==2312== by 0x4AF2D33: g_source_unref_internal (gmain.c:2075) ==2312== by 0x4AF44E1: g_source_destroy_internal (gmain.c:1230) ==2312== by 0x4AF44E1: g_source_destroy (gmain.c:1256) ==2312== by 0x4AF5257: g_source_remove (gmain.c:2282) ==2312== by 0xAB46B: g_at_io_set_write_handler (gatio.c:283) ==2312== by 0xA713F: at_chat_suspend (gatchat.c:938) ==2312== by 0xA72B7: at_chat_unref (gatchat.c:971) ==2312== by 0xA829B: g_at_chat_unref (gatchat.c:1446) ==2312== Block was alloc'd at ==2312== at 0x4841BF0: calloc (vg_replace_malloc.c:711) ==2312== by 0x4AFB117: g_malloc0 (gmem.c:124) ==2312== by 0x4AF401F: g_source_new (gmain.c:892) ==2312== by 0xAC6A7: channel_create_watch (gatmux.c:506) ==2312== by 0x4AE7C4F: g_io_add_watch_full (giochannel.c:649) ==2312== by 0xAB4EB: g_at_io_set_write_handler (gatio.c:297) ==2312== by 0xA7103: chat_wakeup_writer (gatchat.c:931) ==2312== by 0xA753F: at_chat_send_common (gatchat.c:1045) ==2312== by 0xA850F: g_at_chat_send (gatchat.c:1502) It's also necessary to add additional references to the sources for the duration of the dispatch_sources loop because any source can be removed when any callback is invoked (and not necessarily the one being dispatched).
2017-10-23 09:17:30 +00:00
refs = NULL;
gatmux: Remove finalized watches from the list Leaving them there may result in invalid reads like this: ==2312== Invalid read of size 4 ==2312== at 0xAB8C0: dispatch_sources (gatmux.c:134) ==2312== by 0xAC5D3: channel_close (gatmux.c:479) ==2312== by 0x4AE8885: g_io_channel_shutdown (giochannel.c:523) ==2312== by 0x4AE8A1D: g_io_channel_unref (giochannel.c:240) ==2312== by 0xAC423: watch_finalize (gatmux.c:426) ==2312== by 0x4AF2CC9: g_source_unref_internal (gmain.c:2048) ==2312== by 0x4AF44E1: g_source_destroy_internal (gmain.c:1230) ==2312== by 0x4AF44E1: g_source_destroy (gmain.c:1256) ==2312== by 0x4AF5257: g_source_remove (gmain.c:2282) ==2312== by 0xAB5CB: io_shutdown (gatio.c:325) ==2312== by 0xAB667: g_at_io_unref (gatio.c:345) ==2312== by 0xA72C7: at_chat_unref (gatchat.c:972) ==2312== by 0xA829B: g_at_chat_unref (gatchat.c:1446) ==2312== Address 0x51420f0 is 56 bytes inside a block of size 60 free'd ==2312== at 0x4840B28: free (vg_replace_malloc.c:530) ==2312== by 0x4AF2D33: g_source_unref_internal (gmain.c:2075) ==2312== by 0x4AF44E1: g_source_destroy_internal (gmain.c:1230) ==2312== by 0x4AF44E1: g_source_destroy (gmain.c:1256) ==2312== by 0x4AF5257: g_source_remove (gmain.c:2282) ==2312== by 0xAB46B: g_at_io_set_write_handler (gatio.c:283) ==2312== by 0xA713F: at_chat_suspend (gatchat.c:938) ==2312== by 0xA72B7: at_chat_unref (gatchat.c:971) ==2312== by 0xA829B: g_at_chat_unref (gatchat.c:1446) ==2312== Block was alloc'd at ==2312== at 0x4841BF0: calloc (vg_replace_malloc.c:711) ==2312== by 0x4AFB117: g_malloc0 (gmem.c:124) ==2312== by 0x4AF401F: g_source_new (gmain.c:892) ==2312== by 0xAC6A7: channel_create_watch (gatmux.c:506) ==2312== by 0x4AE7C4F: g_io_add_watch_full (giochannel.c:649) ==2312== by 0xAB4EB: g_at_io_set_write_handler (gatio.c:297) ==2312== by 0xA7103: chat_wakeup_writer (gatchat.c:931) ==2312== by 0xA753F: at_chat_send_common (gatchat.c:1045) ==2312== by 0xA850F: g_at_chat_send (gatchat.c:1502) It's also necessary to add additional references to the sources for the duration of the dispatch_sources loop because any source can be removed when any callback is invoked (and not necessarily the one being dispatched).
2017-10-23 09:17:30 +00:00
for (c = channel->sources; c; c = c->next) {
GSource *s = c->data;
if (!g_source_is_destroyed(s)) {
GSList *l = g_slist_append(NULL, g_source_ref(s));
if (p)
p->next = l;
else
refs = l;
gatmux: Remove finalized watches from the list Leaving them there may result in invalid reads like this: ==2312== Invalid read of size 4 ==2312== at 0xAB8C0: dispatch_sources (gatmux.c:134) ==2312== by 0xAC5D3: channel_close (gatmux.c:479) ==2312== by 0x4AE8885: g_io_channel_shutdown (giochannel.c:523) ==2312== by 0x4AE8A1D: g_io_channel_unref (giochannel.c:240) ==2312== by 0xAC423: watch_finalize (gatmux.c:426) ==2312== by 0x4AF2CC9: g_source_unref_internal (gmain.c:2048) ==2312== by 0x4AF44E1: g_source_destroy_internal (gmain.c:1230) ==2312== by 0x4AF44E1: g_source_destroy (gmain.c:1256) ==2312== by 0x4AF5257: g_source_remove (gmain.c:2282) ==2312== by 0xAB5CB: io_shutdown (gatio.c:325) ==2312== by 0xAB667: g_at_io_unref (gatio.c:345) ==2312== by 0xA72C7: at_chat_unref (gatchat.c:972) ==2312== by 0xA829B: g_at_chat_unref (gatchat.c:1446) ==2312== Address 0x51420f0 is 56 bytes inside a block of size 60 free'd ==2312== at 0x4840B28: free (vg_replace_malloc.c:530) ==2312== by 0x4AF2D33: g_source_unref_internal (gmain.c:2075) ==2312== by 0x4AF44E1: g_source_destroy_internal (gmain.c:1230) ==2312== by 0x4AF44E1: g_source_destroy (gmain.c:1256) ==2312== by 0x4AF5257: g_source_remove (gmain.c:2282) ==2312== by 0xAB46B: g_at_io_set_write_handler (gatio.c:283) ==2312== by 0xA713F: at_chat_suspend (gatchat.c:938) ==2312== by 0xA72B7: at_chat_unref (gatchat.c:971) ==2312== by 0xA829B: g_at_chat_unref (gatchat.c:1446) ==2312== Block was alloc'd at ==2312== at 0x4841BF0: calloc (vg_replace_malloc.c:711) ==2312== by 0x4AFB117: g_malloc0 (gmem.c:124) ==2312== by 0x4AF401F: g_source_new (gmain.c:892) ==2312== by 0xAC6A7: channel_create_watch (gatmux.c:506) ==2312== by 0x4AE7C4F: g_io_add_watch_full (giochannel.c:649) ==2312== by 0xAB4EB: g_at_io_set_write_handler (gatio.c:297) ==2312== by 0xA7103: chat_wakeup_writer (gatchat.c:931) ==2312== by 0xA753F: at_chat_send_common (gatchat.c:1045) ==2312== by 0xA850F: g_at_chat_send (gatchat.c:1502) It's also necessary to add additional references to the sources for the duration of the dispatch_sources loop because any source can be removed when any callback is invoked (and not necessarily the one being dispatched).
2017-10-23 09:17:30 +00:00
p = l;
}
}
gatmux: Remove finalized watches from the list Leaving them there may result in invalid reads like this: ==2312== Invalid read of size 4 ==2312== at 0xAB8C0: dispatch_sources (gatmux.c:134) ==2312== by 0xAC5D3: channel_close (gatmux.c:479) ==2312== by 0x4AE8885: g_io_channel_shutdown (giochannel.c:523) ==2312== by 0x4AE8A1D: g_io_channel_unref (giochannel.c:240) ==2312== by 0xAC423: watch_finalize (gatmux.c:426) ==2312== by 0x4AF2CC9: g_source_unref_internal (gmain.c:2048) ==2312== by 0x4AF44E1: g_source_destroy_internal (gmain.c:1230) ==2312== by 0x4AF44E1: g_source_destroy (gmain.c:1256) ==2312== by 0x4AF5257: g_source_remove (gmain.c:2282) ==2312== by 0xAB5CB: io_shutdown (gatio.c:325) ==2312== by 0xAB667: g_at_io_unref (gatio.c:345) ==2312== by 0xA72C7: at_chat_unref (gatchat.c:972) ==2312== by 0xA829B: g_at_chat_unref (gatchat.c:1446) ==2312== Address 0x51420f0 is 56 bytes inside a block of size 60 free'd ==2312== at 0x4840B28: free (vg_replace_malloc.c:530) ==2312== by 0x4AF2D33: g_source_unref_internal (gmain.c:2075) ==2312== by 0x4AF44E1: g_source_destroy_internal (gmain.c:1230) ==2312== by 0x4AF44E1: g_source_destroy (gmain.c:1256) ==2312== by 0x4AF5257: g_source_remove (gmain.c:2282) ==2312== by 0xAB46B: g_at_io_set_write_handler (gatio.c:283) ==2312== by 0xA713F: at_chat_suspend (gatchat.c:938) ==2312== by 0xA72B7: at_chat_unref (gatchat.c:971) ==2312== by 0xA829B: g_at_chat_unref (gatchat.c:1446) ==2312== Block was alloc'd at ==2312== at 0x4841BF0: calloc (vg_replace_malloc.c:711) ==2312== by 0x4AFB117: g_malloc0 (gmem.c:124) ==2312== by 0x4AF401F: g_source_new (gmain.c:892) ==2312== by 0xAC6A7: channel_create_watch (gatmux.c:506) ==2312== by 0x4AE7C4F: g_io_add_watch_full (giochannel.c:649) ==2312== by 0xAB4EB: g_at_io_set_write_handler (gatio.c:297) ==2312== by 0xA7103: chat_wakeup_writer (gatchat.c:931) ==2312== by 0xA753F: at_chat_send_common (gatchat.c:1045) ==2312== by 0xA850F: g_at_chat_send (gatchat.c:1502) It's also necessary to add additional references to the sources for the duration of the dispatch_sources loop because any source can be removed when any callback is invoked (and not necessarily the one being dispatched).
2017-10-23 09:17:30 +00:00
/*
* Keep the references to all sources for the duration of the loop.
* Callbacks may add and remove the sources, i.e. channel->sources
* may keep changing during the loop.
*/
gatmux: Remove finalized watches from the list Leaving them there may result in invalid reads like this: ==2312== Invalid read of size 4 ==2312== at 0xAB8C0: dispatch_sources (gatmux.c:134) ==2312== by 0xAC5D3: channel_close (gatmux.c:479) ==2312== by 0x4AE8885: g_io_channel_shutdown (giochannel.c:523) ==2312== by 0x4AE8A1D: g_io_channel_unref (giochannel.c:240) ==2312== by 0xAC423: watch_finalize (gatmux.c:426) ==2312== by 0x4AF2CC9: g_source_unref_internal (gmain.c:2048) ==2312== by 0x4AF44E1: g_source_destroy_internal (gmain.c:1230) ==2312== by 0x4AF44E1: g_source_destroy (gmain.c:1256) ==2312== by 0x4AF5257: g_source_remove (gmain.c:2282) ==2312== by 0xAB5CB: io_shutdown (gatio.c:325) ==2312== by 0xAB667: g_at_io_unref (gatio.c:345) ==2312== by 0xA72C7: at_chat_unref (gatchat.c:972) ==2312== by 0xA829B: g_at_chat_unref (gatchat.c:1446) ==2312== Address 0x51420f0 is 56 bytes inside a block of size 60 free'd ==2312== at 0x4840B28: free (vg_replace_malloc.c:530) ==2312== by 0x4AF2D33: g_source_unref_internal (gmain.c:2075) ==2312== by 0x4AF44E1: g_source_destroy_internal (gmain.c:1230) ==2312== by 0x4AF44E1: g_source_destroy (gmain.c:1256) ==2312== by 0x4AF5257: g_source_remove (gmain.c:2282) ==2312== by 0xAB46B: g_at_io_set_write_handler (gatio.c:283) ==2312== by 0xA713F: at_chat_suspend (gatchat.c:938) ==2312== by 0xA72B7: at_chat_unref (gatchat.c:971) ==2312== by 0xA829B: g_at_chat_unref (gatchat.c:1446) ==2312== Block was alloc'd at ==2312== at 0x4841BF0: calloc (vg_replace_malloc.c:711) ==2312== by 0x4AFB117: g_malloc0 (gmem.c:124) ==2312== by 0x4AF401F: g_source_new (gmain.c:892) ==2312== by 0xAC6A7: channel_create_watch (gatmux.c:506) ==2312== by 0x4AE7C4F: g_io_add_watch_full (giochannel.c:649) ==2312== by 0xAB4EB: g_at_io_set_write_handler (gatio.c:297) ==2312== by 0xA7103: chat_wakeup_writer (gatchat.c:931) ==2312== by 0xA753F: at_chat_send_common (gatchat.c:1045) ==2312== by 0xA850F: g_at_chat_send (gatchat.c:1502) It's also necessary to add additional references to the sources for the duration of the dispatch_sources loop because any source can be removed when any callback is invoked (and not necessarily the one being dispatched).
2017-10-23 09:17:30 +00:00
for (c = refs; c; c = c->next) {
GAtMuxWatch *w = c->data;
GSource *s = &w->source;
if (g_source_is_destroyed(s))
continue;
debug(channel->mux, "checking source: %p", s);
if (condition & w->condition) {
gpointer user_data = NULL;
GSourceFunc callback = NULL;
gatmux: Remove finalized watches from the list Leaving them there may result in invalid reads like this: ==2312== Invalid read of size 4 ==2312== at 0xAB8C0: dispatch_sources (gatmux.c:134) ==2312== by 0xAC5D3: channel_close (gatmux.c:479) ==2312== by 0x4AE8885: g_io_channel_shutdown (giochannel.c:523) ==2312== by 0x4AE8A1D: g_io_channel_unref (giochannel.c:240) ==2312== by 0xAC423: watch_finalize (gatmux.c:426) ==2312== by 0x4AF2CC9: g_source_unref_internal (gmain.c:2048) ==2312== by 0x4AF44E1: g_source_destroy_internal (gmain.c:1230) ==2312== by 0x4AF44E1: g_source_destroy (gmain.c:1256) ==2312== by 0x4AF5257: g_source_remove (gmain.c:2282) ==2312== by 0xAB5CB: io_shutdown (gatio.c:325) ==2312== by 0xAB667: g_at_io_unref (gatio.c:345) ==2312== by 0xA72C7: at_chat_unref (gatchat.c:972) ==2312== by 0xA829B: g_at_chat_unref (gatchat.c:1446) ==2312== Address 0x51420f0 is 56 bytes inside a block of size 60 free'd ==2312== at 0x4840B28: free (vg_replace_malloc.c:530) ==2312== by 0x4AF2D33: g_source_unref_internal (gmain.c:2075) ==2312== by 0x4AF44E1: g_source_destroy_internal (gmain.c:1230) ==2312== by 0x4AF44E1: g_source_destroy (gmain.c:1256) ==2312== by 0x4AF5257: g_source_remove (gmain.c:2282) ==2312== by 0xAB46B: g_at_io_set_write_handler (gatio.c:283) ==2312== by 0xA713F: at_chat_suspend (gatchat.c:938) ==2312== by 0xA72B7: at_chat_unref (gatchat.c:971) ==2312== by 0xA829B: g_at_chat_unref (gatchat.c:1446) ==2312== Block was alloc'd at ==2312== at 0x4841BF0: calloc (vg_replace_malloc.c:711) ==2312== by 0x4AFB117: g_malloc0 (gmem.c:124) ==2312== by 0x4AF401F: g_source_new (gmain.c:892) ==2312== by 0xAC6A7: channel_create_watch (gatmux.c:506) ==2312== by 0x4AE7C4F: g_io_add_watch_full (giochannel.c:649) ==2312== by 0xAB4EB: g_at_io_set_write_handler (gatio.c:297) ==2312== by 0xA7103: chat_wakeup_writer (gatchat.c:931) ==2312== by 0xA753F: at_chat_send_common (gatchat.c:1045) ==2312== by 0xA850F: g_at_chat_send (gatchat.c:1502) It's also necessary to add additional references to the sources for the duration of the dispatch_sources loop because any source can be removed when any callback is invoked (and not necessarily the one being dispatched).
2017-10-23 09:17:30 +00:00
GSourceCallbackFuncs *cb_funcs = s->callback_funcs;
gpointer cb_data = s->callback_data;
gboolean destroy;
gatmux: Remove finalized watches from the list Leaving them there may result in invalid reads like this: ==2312== Invalid read of size 4 ==2312== at 0xAB8C0: dispatch_sources (gatmux.c:134) ==2312== by 0xAC5D3: channel_close (gatmux.c:479) ==2312== by 0x4AE8885: g_io_channel_shutdown (giochannel.c:523) ==2312== by 0x4AE8A1D: g_io_channel_unref (giochannel.c:240) ==2312== by 0xAC423: watch_finalize (gatmux.c:426) ==2312== by 0x4AF2CC9: g_source_unref_internal (gmain.c:2048) ==2312== by 0x4AF44E1: g_source_destroy_internal (gmain.c:1230) ==2312== by 0x4AF44E1: g_source_destroy (gmain.c:1256) ==2312== by 0x4AF5257: g_source_remove (gmain.c:2282) ==2312== by 0xAB5CB: io_shutdown (gatio.c:325) ==2312== by 0xAB667: g_at_io_unref (gatio.c:345) ==2312== by 0xA72C7: at_chat_unref (gatchat.c:972) ==2312== by 0xA829B: g_at_chat_unref (gatchat.c:1446) ==2312== Address 0x51420f0 is 56 bytes inside a block of size 60 free'd ==2312== at 0x4840B28: free (vg_replace_malloc.c:530) ==2312== by 0x4AF2D33: g_source_unref_internal (gmain.c:2075) ==2312== by 0x4AF44E1: g_source_destroy_internal (gmain.c:1230) ==2312== by 0x4AF44E1: g_source_destroy (gmain.c:1256) ==2312== by 0x4AF5257: g_source_remove (gmain.c:2282) ==2312== by 0xAB46B: g_at_io_set_write_handler (gatio.c:283) ==2312== by 0xA713F: at_chat_suspend (gatchat.c:938) ==2312== by 0xA72B7: at_chat_unref (gatchat.c:971) ==2312== by 0xA829B: g_at_chat_unref (gatchat.c:1446) ==2312== Block was alloc'd at ==2312== at 0x4841BF0: calloc (vg_replace_malloc.c:711) ==2312== by 0x4AFB117: g_malloc0 (gmem.c:124) ==2312== by 0x4AF401F: g_source_new (gmain.c:892) ==2312== by 0xAC6A7: channel_create_watch (gatmux.c:506) ==2312== by 0x4AE7C4F: g_io_add_watch_full (giochannel.c:649) ==2312== by 0xAB4EB: g_at_io_set_write_handler (gatio.c:297) ==2312== by 0xA7103: chat_wakeup_writer (gatchat.c:931) ==2312== by 0xA753F: at_chat_send_common (gatchat.c:1045) ==2312== by 0xA850F: g_at_chat_send (gatchat.c:1502) It's also necessary to add additional references to the sources for the duration of the dispatch_sources loop because any source can be removed when any callback is invoked (and not necessarily the one being dispatched).
2017-10-23 09:17:30 +00:00
debug(channel->mux, "dispatching source: %p", s);
gatmux: Remove finalized watches from the list Leaving them there may result in invalid reads like this: ==2312== Invalid read of size 4 ==2312== at 0xAB8C0: dispatch_sources (gatmux.c:134) ==2312== by 0xAC5D3: channel_close (gatmux.c:479) ==2312== by 0x4AE8885: g_io_channel_shutdown (giochannel.c:523) ==2312== by 0x4AE8A1D: g_io_channel_unref (giochannel.c:240) ==2312== by 0xAC423: watch_finalize (gatmux.c:426) ==2312== by 0x4AF2CC9: g_source_unref_internal (gmain.c:2048) ==2312== by 0x4AF44E1: g_source_destroy_internal (gmain.c:1230) ==2312== by 0x4AF44E1: g_source_destroy (gmain.c:1256) ==2312== by 0x4AF5257: g_source_remove (gmain.c:2282) ==2312== by 0xAB5CB: io_shutdown (gatio.c:325) ==2312== by 0xAB667: g_at_io_unref (gatio.c:345) ==2312== by 0xA72C7: at_chat_unref (gatchat.c:972) ==2312== by 0xA829B: g_at_chat_unref (gatchat.c:1446) ==2312== Address 0x51420f0 is 56 bytes inside a block of size 60 free'd ==2312== at 0x4840B28: free (vg_replace_malloc.c:530) ==2312== by 0x4AF2D33: g_source_unref_internal (gmain.c:2075) ==2312== by 0x4AF44E1: g_source_destroy_internal (gmain.c:1230) ==2312== by 0x4AF44E1: g_source_destroy (gmain.c:1256) ==2312== by 0x4AF5257: g_source_remove (gmain.c:2282) ==2312== by 0xAB46B: g_at_io_set_write_handler (gatio.c:283) ==2312== by 0xA713F: at_chat_suspend (gatchat.c:938) ==2312== by 0xA72B7: at_chat_unref (gatchat.c:971) ==2312== by 0xA829B: g_at_chat_unref (gatchat.c:1446) ==2312== Block was alloc'd at ==2312== at 0x4841BF0: calloc (vg_replace_malloc.c:711) ==2312== by 0x4AFB117: g_malloc0 (gmem.c:124) ==2312== by 0x4AF401F: g_source_new (gmain.c:892) ==2312== by 0xAC6A7: channel_create_watch (gatmux.c:506) ==2312== by 0x4AE7C4F: g_io_add_watch_full (giochannel.c:649) ==2312== by 0xAB4EB: g_at_io_set_write_handler (gatio.c:297) ==2312== by 0xA7103: chat_wakeup_writer (gatchat.c:931) ==2312== by 0xA753F: at_chat_send_common (gatchat.c:1045) ==2312== by 0xA850F: g_at_chat_send (gatchat.c:1502) It's also necessary to add additional references to the sources for the duration of the dispatch_sources loop because any source can be removed when any callback is invoked (and not necessarily the one being dispatched).
2017-10-23 09:17:30 +00:00
if (cb_funcs) {
cb_funcs->ref(cb_data);
gatmux: Remove finalized watches from the list Leaving them there may result in invalid reads like this: ==2312== Invalid read of size 4 ==2312== at 0xAB8C0: dispatch_sources (gatmux.c:134) ==2312== by 0xAC5D3: channel_close (gatmux.c:479) ==2312== by 0x4AE8885: g_io_channel_shutdown (giochannel.c:523) ==2312== by 0x4AE8A1D: g_io_channel_unref (giochannel.c:240) ==2312== by 0xAC423: watch_finalize (gatmux.c:426) ==2312== by 0x4AF2CC9: g_source_unref_internal (gmain.c:2048) ==2312== by 0x4AF44E1: g_source_destroy_internal (gmain.c:1230) ==2312== by 0x4AF44E1: g_source_destroy (gmain.c:1256) ==2312== by 0x4AF5257: g_source_remove (gmain.c:2282) ==2312== by 0xAB5CB: io_shutdown (gatio.c:325) ==2312== by 0xAB667: g_at_io_unref (gatio.c:345) ==2312== by 0xA72C7: at_chat_unref (gatchat.c:972) ==2312== by 0xA829B: g_at_chat_unref (gatchat.c:1446) ==2312== Address 0x51420f0 is 56 bytes inside a block of size 60 free'd ==2312== at 0x4840B28: free (vg_replace_malloc.c:530) ==2312== by 0x4AF2D33: g_source_unref_internal (gmain.c:2075) ==2312== by 0x4AF44E1: g_source_destroy_internal (gmain.c:1230) ==2312== by 0x4AF44E1: g_source_destroy (gmain.c:1256) ==2312== by 0x4AF5257: g_source_remove (gmain.c:2282) ==2312== by 0xAB46B: g_at_io_set_write_handler (gatio.c:283) ==2312== by 0xA713F: at_chat_suspend (gatchat.c:938) ==2312== by 0xA72B7: at_chat_unref (gatchat.c:971) ==2312== by 0xA829B: g_at_chat_unref (gatchat.c:1446) ==2312== Block was alloc'd at ==2312== at 0x4841BF0: calloc (vg_replace_malloc.c:711) ==2312== by 0x4AFB117: g_malloc0 (gmem.c:124) ==2312== by 0x4AF401F: g_source_new (gmain.c:892) ==2312== by 0xAC6A7: channel_create_watch (gatmux.c:506) ==2312== by 0x4AE7C4F: g_io_add_watch_full (giochannel.c:649) ==2312== by 0xAB4EB: g_at_io_set_write_handler (gatio.c:297) ==2312== by 0xA7103: chat_wakeup_writer (gatchat.c:931) ==2312== by 0xA753F: at_chat_send_common (gatchat.c:1045) ==2312== by 0xA850F: g_at_chat_send (gatchat.c:1502) It's also necessary to add additional references to the sources for the duration of the dispatch_sources loop because any source can be removed when any callback is invoked (and not necessarily the one being dispatched).
2017-10-23 09:17:30 +00:00
cb_funcs->get(cb_data, s, &callback,
&user_data);
}
gatmux: Remove finalized watches from the list Leaving them there may result in invalid reads like this: ==2312== Invalid read of size 4 ==2312== at 0xAB8C0: dispatch_sources (gatmux.c:134) ==2312== by 0xAC5D3: channel_close (gatmux.c:479) ==2312== by 0x4AE8885: g_io_channel_shutdown (giochannel.c:523) ==2312== by 0x4AE8A1D: g_io_channel_unref (giochannel.c:240) ==2312== by 0xAC423: watch_finalize (gatmux.c:426) ==2312== by 0x4AF2CC9: g_source_unref_internal (gmain.c:2048) ==2312== by 0x4AF44E1: g_source_destroy_internal (gmain.c:1230) ==2312== by 0x4AF44E1: g_source_destroy (gmain.c:1256) ==2312== by 0x4AF5257: g_source_remove (gmain.c:2282) ==2312== by 0xAB5CB: io_shutdown (gatio.c:325) ==2312== by 0xAB667: g_at_io_unref (gatio.c:345) ==2312== by 0xA72C7: at_chat_unref (gatchat.c:972) ==2312== by 0xA829B: g_at_chat_unref (gatchat.c:1446) ==2312== Address 0x51420f0 is 56 bytes inside a block of size 60 free'd ==2312== at 0x4840B28: free (vg_replace_malloc.c:530) ==2312== by 0x4AF2D33: g_source_unref_internal (gmain.c:2075) ==2312== by 0x4AF44E1: g_source_destroy_internal (gmain.c:1230) ==2312== by 0x4AF44E1: g_source_destroy (gmain.c:1256) ==2312== by 0x4AF5257: g_source_remove (gmain.c:2282) ==2312== by 0xAB46B: g_at_io_set_write_handler (gatio.c:283) ==2312== by 0xA713F: at_chat_suspend (gatchat.c:938) ==2312== by 0xA72B7: at_chat_unref (gatchat.c:971) ==2312== by 0xA829B: g_at_chat_unref (gatchat.c:1446) ==2312== Block was alloc'd at ==2312== at 0x4841BF0: calloc (vg_replace_malloc.c:711) ==2312== by 0x4AFB117: g_malloc0 (gmem.c:124) ==2312== by 0x4AF401F: g_source_new (gmain.c:892) ==2312== by 0xAC6A7: channel_create_watch (gatmux.c:506) ==2312== by 0x4AE7C4F: g_io_add_watch_full (giochannel.c:649) ==2312== by 0xAB4EB: g_at_io_set_write_handler (gatio.c:297) ==2312== by 0xA7103: chat_wakeup_writer (gatchat.c:931) ==2312== by 0xA753F: at_chat_send_common (gatchat.c:1045) ==2312== by 0xA850F: g_at_chat_send (gatchat.c:1502) It's also necessary to add additional references to the sources for the duration of the dispatch_sources loop because any source can be removed when any callback is invoked (and not necessarily the one being dispatched).
2017-10-23 09:17:30 +00:00
destroy = !s->source_funcs->dispatch(s, callback,
user_data);
if (cb_funcs)
cb_funcs->unref(cb_data);
gatmux: Remove finalized watches from the list Leaving them there may result in invalid reads like this: ==2312== Invalid read of size 4 ==2312== at 0xAB8C0: dispatch_sources (gatmux.c:134) ==2312== by 0xAC5D3: channel_close (gatmux.c:479) ==2312== by 0x4AE8885: g_io_channel_shutdown (giochannel.c:523) ==2312== by 0x4AE8A1D: g_io_channel_unref (giochannel.c:240) ==2312== by 0xAC423: watch_finalize (gatmux.c:426) ==2312== by 0x4AF2CC9: g_source_unref_internal (gmain.c:2048) ==2312== by 0x4AF44E1: g_source_destroy_internal (gmain.c:1230) ==2312== by 0x4AF44E1: g_source_destroy (gmain.c:1256) ==2312== by 0x4AF5257: g_source_remove (gmain.c:2282) ==2312== by 0xAB5CB: io_shutdown (gatio.c:325) ==2312== by 0xAB667: g_at_io_unref (gatio.c:345) ==2312== by 0xA72C7: at_chat_unref (gatchat.c:972) ==2312== by 0xA829B: g_at_chat_unref (gatchat.c:1446) ==2312== Address 0x51420f0 is 56 bytes inside a block of size 60 free'd ==2312== at 0x4840B28: free (vg_replace_malloc.c:530) ==2312== by 0x4AF2D33: g_source_unref_internal (gmain.c:2075) ==2312== by 0x4AF44E1: g_source_destroy_internal (gmain.c:1230) ==2312== by 0x4AF44E1: g_source_destroy (gmain.c:1256) ==2312== by 0x4AF5257: g_source_remove (gmain.c:2282) ==2312== by 0xAB46B: g_at_io_set_write_handler (gatio.c:283) ==2312== by 0xA713F: at_chat_suspend (gatchat.c:938) ==2312== by 0xA72B7: at_chat_unref (gatchat.c:971) ==2312== by 0xA829B: g_at_chat_unref (gatchat.c:1446) ==2312== Block was alloc'd at ==2312== at 0x4841BF0: calloc (vg_replace_malloc.c:711) ==2312== by 0x4AFB117: g_malloc0 (gmem.c:124) ==2312== by 0x4AF401F: g_source_new (gmain.c:892) ==2312== by 0xAC6A7: channel_create_watch (gatmux.c:506) ==2312== by 0x4AE7C4F: g_io_add_watch_full (giochannel.c:649) ==2312== by 0xAB4EB: g_at_io_set_write_handler (gatio.c:297) ==2312== by 0xA7103: chat_wakeup_writer (gatchat.c:931) ==2312== by 0xA753F: at_chat_send_common (gatchat.c:1045) ==2312== by 0xA850F: g_at_chat_send (gatchat.c:1502) It's also necessary to add additional references to the sources for the duration of the dispatch_sources loop because any source can be removed when any callback is invoked (and not necessarily the one being dispatched).
2017-10-23 09:17:30 +00:00
if (destroy) {
debug(channel->mux, "removing source: %p", s);
g_source_destroy(s);
}
}
gatmux: Remove finalized watches from the list Leaving them there may result in invalid reads like this: ==2312== Invalid read of size 4 ==2312== at 0xAB8C0: dispatch_sources (gatmux.c:134) ==2312== by 0xAC5D3: channel_close (gatmux.c:479) ==2312== by 0x4AE8885: g_io_channel_shutdown (giochannel.c:523) ==2312== by 0x4AE8A1D: g_io_channel_unref (giochannel.c:240) ==2312== by 0xAC423: watch_finalize (gatmux.c:426) ==2312== by 0x4AF2CC9: g_source_unref_internal (gmain.c:2048) ==2312== by 0x4AF44E1: g_source_destroy_internal (gmain.c:1230) ==2312== by 0x4AF44E1: g_source_destroy (gmain.c:1256) ==2312== by 0x4AF5257: g_source_remove (gmain.c:2282) ==2312== by 0xAB5CB: io_shutdown (gatio.c:325) ==2312== by 0xAB667: g_at_io_unref (gatio.c:345) ==2312== by 0xA72C7: at_chat_unref (gatchat.c:972) ==2312== by 0xA829B: g_at_chat_unref (gatchat.c:1446) ==2312== Address 0x51420f0 is 56 bytes inside a block of size 60 free'd ==2312== at 0x4840B28: free (vg_replace_malloc.c:530) ==2312== by 0x4AF2D33: g_source_unref_internal (gmain.c:2075) ==2312== by 0x4AF44E1: g_source_destroy_internal (gmain.c:1230) ==2312== by 0x4AF44E1: g_source_destroy (gmain.c:1256) ==2312== by 0x4AF5257: g_source_remove (gmain.c:2282) ==2312== by 0xAB46B: g_at_io_set_write_handler (gatio.c:283) ==2312== by 0xA713F: at_chat_suspend (gatchat.c:938) ==2312== by 0xA72B7: at_chat_unref (gatchat.c:971) ==2312== by 0xA829B: g_at_chat_unref (gatchat.c:1446) ==2312== Block was alloc'd at ==2312== at 0x4841BF0: calloc (vg_replace_malloc.c:711) ==2312== by 0x4AFB117: g_malloc0 (gmem.c:124) ==2312== by 0x4AF401F: g_source_new (gmain.c:892) ==2312== by 0xAC6A7: channel_create_watch (gatmux.c:506) ==2312== by 0x4AE7C4F: g_io_add_watch_full (giochannel.c:649) ==2312== by 0xAB4EB: g_at_io_set_write_handler (gatio.c:297) ==2312== by 0xA7103: chat_wakeup_writer (gatchat.c:931) ==2312== by 0xA753F: at_chat_send_common (gatchat.c:1045) ==2312== by 0xA850F: g_at_chat_send (gatchat.c:1502) It's also necessary to add additional references to the sources for the duration of the dispatch_sources loop because any source can be removed when any callback is invoked (and not necessarily the one being dispatched).
2017-10-23 09:17:30 +00:00
}
gatmux: Remove finalized watches from the list Leaving them there may result in invalid reads like this: ==2312== Invalid read of size 4 ==2312== at 0xAB8C0: dispatch_sources (gatmux.c:134) ==2312== by 0xAC5D3: channel_close (gatmux.c:479) ==2312== by 0x4AE8885: g_io_channel_shutdown (giochannel.c:523) ==2312== by 0x4AE8A1D: g_io_channel_unref (giochannel.c:240) ==2312== by 0xAC423: watch_finalize (gatmux.c:426) ==2312== by 0x4AF2CC9: g_source_unref_internal (gmain.c:2048) ==2312== by 0x4AF44E1: g_source_destroy_internal (gmain.c:1230) ==2312== by 0x4AF44E1: g_source_destroy (gmain.c:1256) ==2312== by 0x4AF5257: g_source_remove (gmain.c:2282) ==2312== by 0xAB5CB: io_shutdown (gatio.c:325) ==2312== by 0xAB667: g_at_io_unref (gatio.c:345) ==2312== by 0xA72C7: at_chat_unref (gatchat.c:972) ==2312== by 0xA829B: g_at_chat_unref (gatchat.c:1446) ==2312== Address 0x51420f0 is 56 bytes inside a block of size 60 free'd ==2312== at 0x4840B28: free (vg_replace_malloc.c:530) ==2312== by 0x4AF2D33: g_source_unref_internal (gmain.c:2075) ==2312== by 0x4AF44E1: g_source_destroy_internal (gmain.c:1230) ==2312== by 0x4AF44E1: g_source_destroy (gmain.c:1256) ==2312== by 0x4AF5257: g_source_remove (gmain.c:2282) ==2312== by 0xAB46B: g_at_io_set_write_handler (gatio.c:283) ==2312== by 0xA713F: at_chat_suspend (gatchat.c:938) ==2312== by 0xA72B7: at_chat_unref (gatchat.c:971) ==2312== by 0xA829B: g_at_chat_unref (gatchat.c:1446) ==2312== Block was alloc'd at ==2312== at 0x4841BF0: calloc (vg_replace_malloc.c:711) ==2312== by 0x4AFB117: g_malloc0 (gmem.c:124) ==2312== by 0x4AF401F: g_source_new (gmain.c:892) ==2312== by 0xAC6A7: channel_create_watch (gatmux.c:506) ==2312== by 0x4AE7C4F: g_io_add_watch_full (giochannel.c:649) ==2312== by 0xAB4EB: g_at_io_set_write_handler (gatio.c:297) ==2312== by 0xA7103: chat_wakeup_writer (gatchat.c:931) ==2312== by 0xA753F: at_chat_send_common (gatchat.c:1045) ==2312== by 0xA850F: g_at_chat_send (gatchat.c:1502) It's also necessary to add additional references to the sources for the duration of the dispatch_sources loop because any source can be removed when any callback is invoked (and not necessarily the one being dispatched).
2017-10-23 09:17:30 +00:00
/*
* Remove destroyed sources from channel->sources. During this
* loop we are not invoking any callbacks, so the consistency is
* guaranteed.
*/
gatmux: Remove finalized watches from the list Leaving them there may result in invalid reads like this: ==2312== Invalid read of size 4 ==2312== at 0xAB8C0: dispatch_sources (gatmux.c:134) ==2312== by 0xAC5D3: channel_close (gatmux.c:479) ==2312== by 0x4AE8885: g_io_channel_shutdown (giochannel.c:523) ==2312== by 0x4AE8A1D: g_io_channel_unref (giochannel.c:240) ==2312== by 0xAC423: watch_finalize (gatmux.c:426) ==2312== by 0x4AF2CC9: g_source_unref_internal (gmain.c:2048) ==2312== by 0x4AF44E1: g_source_destroy_internal (gmain.c:1230) ==2312== by 0x4AF44E1: g_source_destroy (gmain.c:1256) ==2312== by 0x4AF5257: g_source_remove (gmain.c:2282) ==2312== by 0xAB5CB: io_shutdown (gatio.c:325) ==2312== by 0xAB667: g_at_io_unref (gatio.c:345) ==2312== by 0xA72C7: at_chat_unref (gatchat.c:972) ==2312== by 0xA829B: g_at_chat_unref (gatchat.c:1446) ==2312== Address 0x51420f0 is 56 bytes inside a block of size 60 free'd ==2312== at 0x4840B28: free (vg_replace_malloc.c:530) ==2312== by 0x4AF2D33: g_source_unref_internal (gmain.c:2075) ==2312== by 0x4AF44E1: g_source_destroy_internal (gmain.c:1230) ==2312== by 0x4AF44E1: g_source_destroy (gmain.c:1256) ==2312== by 0x4AF5257: g_source_remove (gmain.c:2282) ==2312== by 0xAB46B: g_at_io_set_write_handler (gatio.c:283) ==2312== by 0xA713F: at_chat_suspend (gatchat.c:938) ==2312== by 0xA72B7: at_chat_unref (gatchat.c:971) ==2312== by 0xA829B: g_at_chat_unref (gatchat.c:1446) ==2312== Block was alloc'd at ==2312== at 0x4841BF0: calloc (vg_replace_malloc.c:711) ==2312== by 0x4AFB117: g_malloc0 (gmem.c:124) ==2312== by 0x4AF401F: g_source_new (gmain.c:892) ==2312== by 0xAC6A7: channel_create_watch (gatmux.c:506) ==2312== by 0x4AE7C4F: g_io_add_watch_full (giochannel.c:649) ==2312== by 0xAB4EB: g_at_io_set_write_handler (gatio.c:297) ==2312== by 0xA7103: chat_wakeup_writer (gatchat.c:931) ==2312== by 0xA753F: at_chat_send_common (gatchat.c:1045) ==2312== by 0xA850F: g_at_chat_send (gatchat.c:1502) It's also necessary to add additional references to the sources for the duration of the dispatch_sources loop because any source can be removed when any callback is invoked (and not necessarily the one being dispatched).
2017-10-23 09:17:30 +00:00
p = NULL;
c = channel->sources;
gatmux: Remove finalized watches from the list Leaving them there may result in invalid reads like this: ==2312== Invalid read of size 4 ==2312== at 0xAB8C0: dispatch_sources (gatmux.c:134) ==2312== by 0xAC5D3: channel_close (gatmux.c:479) ==2312== by 0x4AE8885: g_io_channel_shutdown (giochannel.c:523) ==2312== by 0x4AE8A1D: g_io_channel_unref (giochannel.c:240) ==2312== by 0xAC423: watch_finalize (gatmux.c:426) ==2312== by 0x4AF2CC9: g_source_unref_internal (gmain.c:2048) ==2312== by 0x4AF44E1: g_source_destroy_internal (gmain.c:1230) ==2312== by 0x4AF44E1: g_source_destroy (gmain.c:1256) ==2312== by 0x4AF5257: g_source_remove (gmain.c:2282) ==2312== by 0xAB5CB: io_shutdown (gatio.c:325) ==2312== by 0xAB667: g_at_io_unref (gatio.c:345) ==2312== by 0xA72C7: at_chat_unref (gatchat.c:972) ==2312== by 0xA829B: g_at_chat_unref (gatchat.c:1446) ==2312== Address 0x51420f0 is 56 bytes inside a block of size 60 free'd ==2312== at 0x4840B28: free (vg_replace_malloc.c:530) ==2312== by 0x4AF2D33: g_source_unref_internal (gmain.c:2075) ==2312== by 0x4AF44E1: g_source_destroy_internal (gmain.c:1230) ==2312== by 0x4AF44E1: g_source_destroy (gmain.c:1256) ==2312== by 0x4AF5257: g_source_remove (gmain.c:2282) ==2312== by 0xAB46B: g_at_io_set_write_handler (gatio.c:283) ==2312== by 0xA713F: at_chat_suspend (gatchat.c:938) ==2312== by 0xA72B7: at_chat_unref (gatchat.c:971) ==2312== by 0xA829B: g_at_chat_unref (gatchat.c:1446) ==2312== Block was alloc'd at ==2312== at 0x4841BF0: calloc (vg_replace_malloc.c:711) ==2312== by 0x4AFB117: g_malloc0 (gmem.c:124) ==2312== by 0x4AF401F: g_source_new (gmain.c:892) ==2312== by 0xAC6A7: channel_create_watch (gatmux.c:506) ==2312== by 0x4AE7C4F: g_io_add_watch_full (giochannel.c:649) ==2312== by 0xAB4EB: g_at_io_set_write_handler (gatio.c:297) ==2312== by 0xA7103: chat_wakeup_writer (gatchat.c:931) ==2312== by 0xA753F: at_chat_send_common (gatchat.c:1045) ==2312== by 0xA850F: g_at_chat_send (gatchat.c:1502) It's also necessary to add additional references to the sources for the duration of the dispatch_sources loop because any source can be removed when any callback is invoked (and not necessarily the one being dispatched).
2017-10-23 09:17:30 +00:00
while (c) {
GSList *n = c->next;
GSource *s = c->data;
if (g_source_is_destroyed(s)) {
if (p)
gatmux: Remove finalized watches from the list Leaving them there may result in invalid reads like this: ==2312== Invalid read of size 4 ==2312== at 0xAB8C0: dispatch_sources (gatmux.c:134) ==2312== by 0xAC5D3: channel_close (gatmux.c:479) ==2312== by 0x4AE8885: g_io_channel_shutdown (giochannel.c:523) ==2312== by 0x4AE8A1D: g_io_channel_unref (giochannel.c:240) ==2312== by 0xAC423: watch_finalize (gatmux.c:426) ==2312== by 0x4AF2CC9: g_source_unref_internal (gmain.c:2048) ==2312== by 0x4AF44E1: g_source_destroy_internal (gmain.c:1230) ==2312== by 0x4AF44E1: g_source_destroy (gmain.c:1256) ==2312== by 0x4AF5257: g_source_remove (gmain.c:2282) ==2312== by 0xAB5CB: io_shutdown (gatio.c:325) ==2312== by 0xAB667: g_at_io_unref (gatio.c:345) ==2312== by 0xA72C7: at_chat_unref (gatchat.c:972) ==2312== by 0xA829B: g_at_chat_unref (gatchat.c:1446) ==2312== Address 0x51420f0 is 56 bytes inside a block of size 60 free'd ==2312== at 0x4840B28: free (vg_replace_malloc.c:530) ==2312== by 0x4AF2D33: g_source_unref_internal (gmain.c:2075) ==2312== by 0x4AF44E1: g_source_destroy_internal (gmain.c:1230) ==2312== by 0x4AF44E1: g_source_destroy (gmain.c:1256) ==2312== by 0x4AF5257: g_source_remove (gmain.c:2282) ==2312== by 0xAB46B: g_at_io_set_write_handler (gatio.c:283) ==2312== by 0xA713F: at_chat_suspend (gatchat.c:938) ==2312== by 0xA72B7: at_chat_unref (gatchat.c:971) ==2312== by 0xA829B: g_at_chat_unref (gatchat.c:1446) ==2312== Block was alloc'd at ==2312== at 0x4841BF0: calloc (vg_replace_malloc.c:711) ==2312== by 0x4AFB117: g_malloc0 (gmem.c:124) ==2312== by 0x4AF401F: g_source_new (gmain.c:892) ==2312== by 0xAC6A7: channel_create_watch (gatmux.c:506) ==2312== by 0x4AE7C4F: g_io_add_watch_full (giochannel.c:649) ==2312== by 0xAB4EB: g_at_io_set_write_handler (gatio.c:297) ==2312== by 0xA7103: chat_wakeup_writer (gatchat.c:931) ==2312== by 0xA753F: at_chat_send_common (gatchat.c:1045) ==2312== by 0xA850F: g_at_chat_send (gatchat.c:1502) It's also necessary to add additional references to the sources for the duration of the dispatch_sources loop because any source can be removed when any callback is invoked (and not necessarily the one being dispatched).
2017-10-23 09:17:30 +00:00
p->next = n;
else
gatmux: Remove finalized watches from the list Leaving them there may result in invalid reads like this: ==2312== Invalid read of size 4 ==2312== at 0xAB8C0: dispatch_sources (gatmux.c:134) ==2312== by 0xAC5D3: channel_close (gatmux.c:479) ==2312== by 0x4AE8885: g_io_channel_shutdown (giochannel.c:523) ==2312== by 0x4AE8A1D: g_io_channel_unref (giochannel.c:240) ==2312== by 0xAC423: watch_finalize (gatmux.c:426) ==2312== by 0x4AF2CC9: g_source_unref_internal (gmain.c:2048) ==2312== by 0x4AF44E1: g_source_destroy_internal (gmain.c:1230) ==2312== by 0x4AF44E1: g_source_destroy (gmain.c:1256) ==2312== by 0x4AF5257: g_source_remove (gmain.c:2282) ==2312== by 0xAB5CB: io_shutdown (gatio.c:325) ==2312== by 0xAB667: g_at_io_unref (gatio.c:345) ==2312== by 0xA72C7: at_chat_unref (gatchat.c:972) ==2312== by 0xA829B: g_at_chat_unref (gatchat.c:1446) ==2312== Address 0x51420f0 is 56 bytes inside a block of size 60 free'd ==2312== at 0x4840B28: free (vg_replace_malloc.c:530) ==2312== by 0x4AF2D33: g_source_unref_internal (gmain.c:2075) ==2312== by 0x4AF44E1: g_source_destroy_internal (gmain.c:1230) ==2312== by 0x4AF44E1: g_source_destroy (gmain.c:1256) ==2312== by 0x4AF5257: g_source_remove (gmain.c:2282) ==2312== by 0xAB46B: g_at_io_set_write_handler (gatio.c:283) ==2312== by 0xA713F: at_chat_suspend (gatchat.c:938) ==2312== by 0xA72B7: at_chat_unref (gatchat.c:971) ==2312== by 0xA829B: g_at_chat_unref (gatchat.c:1446) ==2312== Block was alloc'd at ==2312== at 0x4841BF0: calloc (vg_replace_malloc.c:711) ==2312== by 0x4AFB117: g_malloc0 (gmem.c:124) ==2312== by 0x4AF401F: g_source_new (gmain.c:892) ==2312== by 0xAC6A7: channel_create_watch (gatmux.c:506) ==2312== by 0x4AE7C4F: g_io_add_watch_full (giochannel.c:649) ==2312== by 0xAB4EB: g_at_io_set_write_handler (gatio.c:297) ==2312== by 0xA7103: chat_wakeup_writer (gatchat.c:931) ==2312== by 0xA753F: at_chat_send_common (gatchat.c:1045) ==2312== by 0xA850F: g_at_chat_send (gatchat.c:1502) It's also necessary to add additional references to the sources for the duration of the dispatch_sources loop because any source can be removed when any callback is invoked (and not necessarily the one being dispatched).
2017-10-23 09:17:30 +00:00
channel->sources = n;
gatmux: Remove finalized watches from the list Leaving them there may result in invalid reads like this: ==2312== Invalid read of size 4 ==2312== at 0xAB8C0: dispatch_sources (gatmux.c:134) ==2312== by 0xAC5D3: channel_close (gatmux.c:479) ==2312== by 0x4AE8885: g_io_channel_shutdown (giochannel.c:523) ==2312== by 0x4AE8A1D: g_io_channel_unref (giochannel.c:240) ==2312== by 0xAC423: watch_finalize (gatmux.c:426) ==2312== by 0x4AF2CC9: g_source_unref_internal (gmain.c:2048) ==2312== by 0x4AF44E1: g_source_destroy_internal (gmain.c:1230) ==2312== by 0x4AF44E1: g_source_destroy (gmain.c:1256) ==2312== by 0x4AF5257: g_source_remove (gmain.c:2282) ==2312== by 0xAB5CB: io_shutdown (gatio.c:325) ==2312== by 0xAB667: g_at_io_unref (gatio.c:345) ==2312== by 0xA72C7: at_chat_unref (gatchat.c:972) ==2312== by 0xA829B: g_at_chat_unref (gatchat.c:1446) ==2312== Address 0x51420f0 is 56 bytes inside a block of size 60 free'd ==2312== at 0x4840B28: free (vg_replace_malloc.c:530) ==2312== by 0x4AF2D33: g_source_unref_internal (gmain.c:2075) ==2312== by 0x4AF44E1: g_source_destroy_internal (gmain.c:1230) ==2312== by 0x4AF44E1: g_source_destroy (gmain.c:1256) ==2312== by 0x4AF5257: g_source_remove (gmain.c:2282) ==2312== by 0xAB46B: g_at_io_set_write_handler (gatio.c:283) ==2312== by 0xA713F: at_chat_suspend (gatchat.c:938) ==2312== by 0xA72B7: at_chat_unref (gatchat.c:971) ==2312== by 0xA829B: g_at_chat_unref (gatchat.c:1446) ==2312== Block was alloc'd at ==2312== at 0x4841BF0: calloc (vg_replace_malloc.c:711) ==2312== by 0x4AFB117: g_malloc0 (gmem.c:124) ==2312== by 0x4AF401F: g_source_new (gmain.c:892) ==2312== by 0xAC6A7: channel_create_watch (gatmux.c:506) ==2312== by 0x4AE7C4F: g_io_add_watch_full (giochannel.c:649) ==2312== by 0xAB4EB: g_at_io_set_write_handler (gatio.c:297) ==2312== by 0xA7103: chat_wakeup_writer (gatchat.c:931) ==2312== by 0xA753F: at_chat_send_common (gatchat.c:1045) ==2312== by 0xA850F: g_at_chat_send (gatchat.c:1502) It's also necessary to add additional references to the sources for the duration of the dispatch_sources loop because any source can be removed when any callback is invoked (and not necessarily the one being dispatched).
2017-10-23 09:17:30 +00:00
g_slist_free_1(c);
} else {
p = c;
}
gatmux: Remove finalized watches from the list Leaving them there may result in invalid reads like this: ==2312== Invalid read of size 4 ==2312== at 0xAB8C0: dispatch_sources (gatmux.c:134) ==2312== by 0xAC5D3: channel_close (gatmux.c:479) ==2312== by 0x4AE8885: g_io_channel_shutdown (giochannel.c:523) ==2312== by 0x4AE8A1D: g_io_channel_unref (giochannel.c:240) ==2312== by 0xAC423: watch_finalize (gatmux.c:426) ==2312== by 0x4AF2CC9: g_source_unref_internal (gmain.c:2048) ==2312== by 0x4AF44E1: g_source_destroy_internal (gmain.c:1230) ==2312== by 0x4AF44E1: g_source_destroy (gmain.c:1256) ==2312== by 0x4AF5257: g_source_remove (gmain.c:2282) ==2312== by 0xAB5CB: io_shutdown (gatio.c:325) ==2312== by 0xAB667: g_at_io_unref (gatio.c:345) ==2312== by 0xA72C7: at_chat_unref (gatchat.c:972) ==2312== by 0xA829B: g_at_chat_unref (gatchat.c:1446) ==2312== Address 0x51420f0 is 56 bytes inside a block of size 60 free'd ==2312== at 0x4840B28: free (vg_replace_malloc.c:530) ==2312== by 0x4AF2D33: g_source_unref_internal (gmain.c:2075) ==2312== by 0x4AF44E1: g_source_destroy_internal (gmain.c:1230) ==2312== by 0x4AF44E1: g_source_destroy (gmain.c:1256) ==2312== by 0x4AF5257: g_source_remove (gmain.c:2282) ==2312== by 0xAB46B: g_at_io_set_write_handler (gatio.c:283) ==2312== by 0xA713F: at_chat_suspend (gatchat.c:938) ==2312== by 0xA72B7: at_chat_unref (gatchat.c:971) ==2312== by 0xA829B: g_at_chat_unref (gatchat.c:1446) ==2312== Block was alloc'd at ==2312== at 0x4841BF0: calloc (vg_replace_malloc.c:711) ==2312== by 0x4AFB117: g_malloc0 (gmem.c:124) ==2312== by 0x4AF401F: g_source_new (gmain.c:892) ==2312== by 0xAC6A7: channel_create_watch (gatmux.c:506) ==2312== by 0x4AE7C4F: g_io_add_watch_full (giochannel.c:649) ==2312== by 0xAB4EB: g_at_io_set_write_handler (gatio.c:297) ==2312== by 0xA7103: chat_wakeup_writer (gatchat.c:931) ==2312== by 0xA753F: at_chat_send_common (gatchat.c:1045) ==2312== by 0xA850F: g_at_chat_send (gatchat.c:1502) It's also necessary to add additional references to the sources for the duration of the dispatch_sources loop because any source can be removed when any callback is invoked (and not necessarily the one being dispatched).
2017-10-23 09:17:30 +00:00
c = n;
}
gatmux: Remove finalized watches from the list Leaving them there may result in invalid reads like this: ==2312== Invalid read of size 4 ==2312== at 0xAB8C0: dispatch_sources (gatmux.c:134) ==2312== by 0xAC5D3: channel_close (gatmux.c:479) ==2312== by 0x4AE8885: g_io_channel_shutdown (giochannel.c:523) ==2312== by 0x4AE8A1D: g_io_channel_unref (giochannel.c:240) ==2312== by 0xAC423: watch_finalize (gatmux.c:426) ==2312== by 0x4AF2CC9: g_source_unref_internal (gmain.c:2048) ==2312== by 0x4AF44E1: g_source_destroy_internal (gmain.c:1230) ==2312== by 0x4AF44E1: g_source_destroy (gmain.c:1256) ==2312== by 0x4AF5257: g_source_remove (gmain.c:2282) ==2312== by 0xAB5CB: io_shutdown (gatio.c:325) ==2312== by 0xAB667: g_at_io_unref (gatio.c:345) ==2312== by 0xA72C7: at_chat_unref (gatchat.c:972) ==2312== by 0xA829B: g_at_chat_unref (gatchat.c:1446) ==2312== Address 0x51420f0 is 56 bytes inside a block of size 60 free'd ==2312== at 0x4840B28: free (vg_replace_malloc.c:530) ==2312== by 0x4AF2D33: g_source_unref_internal (gmain.c:2075) ==2312== by 0x4AF44E1: g_source_destroy_internal (gmain.c:1230) ==2312== by 0x4AF44E1: g_source_destroy (gmain.c:1256) ==2312== by 0x4AF5257: g_source_remove (gmain.c:2282) ==2312== by 0xAB46B: g_at_io_set_write_handler (gatio.c:283) ==2312== by 0xA713F: at_chat_suspend (gatchat.c:938) ==2312== by 0xA72B7: at_chat_unref (gatchat.c:971) ==2312== by 0xA829B: g_at_chat_unref (gatchat.c:1446) ==2312== Block was alloc'd at ==2312== at 0x4841BF0: calloc (vg_replace_malloc.c:711) ==2312== by 0x4AFB117: g_malloc0 (gmem.c:124) ==2312== by 0x4AF401F: g_source_new (gmain.c:892) ==2312== by 0xAC6A7: channel_create_watch (gatmux.c:506) ==2312== by 0x4AE7C4F: g_io_add_watch_full (giochannel.c:649) ==2312== by 0xAB4EB: g_at_io_set_write_handler (gatio.c:297) ==2312== by 0xA7103: chat_wakeup_writer (gatchat.c:931) ==2312== by 0xA753F: at_chat_send_common (gatchat.c:1045) ==2312== by 0xA850F: g_at_chat_send (gatchat.c:1502) It's also necessary to add additional references to the sources for the duration of the dispatch_sources loop because any source can be removed when any callback is invoked (and not necessarily the one being dispatched).
2017-10-23 09:17:30 +00:00
/* Release temporary references */
g_slist_free_full(refs, (GDestroyNotify) g_source_unref);
}
static gboolean received_data(GIOChannel *channel, GIOCondition cond,
gpointer data)
{
GAtMux *mux = data;
int i;
GIOStatus status;
gsize bytes_read;
gatmux: take reference to mux object while processing incoming data When closing down a cmux object, the address sanitizer detects a use-after-free in gatmux.c (see below). Avoid this by taking a reference to the mux object during the processing in received_data(). ofonod[3640549]: ../git/plugins/quectel.c:cfun_disable() 0x610000000b40 ofonod[3640549]: ../git/plugins/quectel.c:close_serial() 0x610000000b40 ofonod[3640549]: ../git/plugins/quectel.c:close_mux() 0x610000000b40 ofonod[3640549]: ../git/examples/emulator.c:powered_watch() Removing modem 0x610000000b40 from the list ofonod[3640549]: ../git/examples/emulator.c:powered_watch() Removing server watch: 106 ofonod[3640549]: ../git/src/modem.c:modem_change_state() old state: 0, new state: 0 ================================================================= ==3640549==ERROR: AddressSanitizer: heap-use-after-free on address 0x62100073dd28 at pc 0x5566b6402a21 bp 0x7ffe7a2db0e0 sp 0x7ffe7a2db0d0 READ of size 8 at 0x62100073dd28 thread T0 #0 0x5566b6402a20 in debug ../git/gatchat/gatmux.c:109 #1 0x5566b6404bd7 in channel_close ../git/gatchat/gatmux.c:525 #2 0x7fa0516e44a6 in g_io_channel_shutdown (/usr/lib/libglib-2.0.so.0+0x774a6) #3 0x7fa0516e4644 in g_io_channel_unref (/usr/lib/libglib-2.0.so.0+0x77644) #4 0x5566b64048a4 in watch_finalize ../git/gatchat/gatmux.c:474 #5 0x7fa0516d6f6f (/usr/lib/libglib-2.0.so.0+0x69f6f) #6 0x7fa0516ac6a7 in g_slist_foreach (/usr/lib/libglib-2.0.so.0+0x3f6a7) #7 0x7fa0516b277b in g_slist_free_full (/usr/lib/libglib-2.0.so.0+0x4577b) #8 0x5566b6403413 in dispatch_sources ../git/gatchat/gatmux.c:224 #9 0x5566b64039ea in received_data ../git/gatchat/gatmux.c:268 #10 0x7fa0516d727e in g_main_context_dispatch (/usr/lib/libglib-2.0.so.0+0x6a27e) #11 0x7fa0516d91c0 (/usr/lib/libglib-2.0.so.0+0x6c1c0) #12 0x7fa0516da0d2 in g_main_loop_run (/usr/lib/libglib-2.0.so.0+0x6d0d2) #13 0x5566b6429b1b in main ../git/src/main.c:286 #14 0x7fa05147fee2 in __libc_start_main (/usr/lib/libc.so.6+0x26ee2) #15 0x5566b62531ad in _start (/home/martin/projects/ofono/x86/src/ofonod+0xfc1ad) 0x62100073dd28 is located 40 bytes inside of 4672-byte region [0x62100073dd00,0x62100073ef40) freed by thread T0 here: #0 0x7fa0519256c0 in __interceptor_free /build/gcc/src/gcc/libsanitizer/asan/asan_malloc_linux.cc:122 #1 0x5566b64052d7 in g_at_mux_unref ../git/gatchat/gatmux.c:645 #2 0x5566b63d6d19 in close_mux ../git/plugins/quectel.c:199 #3 0x5566b63d7047 in close_serial ../git/plugins/quectel.c:223 #4 0x5566b63db62a in cfun_disable ../git/plugins/quectel.c:1056 #5 0x5566b63f6ae1 in at_chat_finish_command ../git/gatchat/gatchat.c:459 #6 0x5566b63f701b in at_chat_handle_command_response ../git/gatchat/gatchat.c:521 #7 0x5566b63f785b in have_line ../git/gatchat/gatchat.c:600 #8 0x5566b63f87f1 in new_bytes ../git/gatchat/gatchat.c:759 #9 0x5566b640174c in received_data ../git/gatchat/gatio.c:122 #10 0x5566b64047b4 in watch_dispatch ../git/gatchat/gatmux.c:464 #11 0x5566b640313b in dispatch_sources ../git/gatchat/gatmux.c:183 #12 0x5566b64039ea in received_data ../git/gatchat/gatmux.c:268 #13 0x7fa0516d727e in g_main_context_dispatch (/usr/lib/libglib-2.0.so.0+0x6a27e) previously allocated by thread T0 here: #0 0x7fa051925ce8 in __interceptor_calloc /build/gcc/src/gcc/libsanitizer/asan/asan_malloc_linux.cc:153 #1 0x5566b6405009 in g_at_mux_new ../git/gatchat/gatmux.c:606 #2 0x5566b6407f6b in g_at_mux_new_gsm0710_basic ../git/gatchat/gatmux.c:1165 #3 0x5566b63da9ba in cmux_cb ../git/plugins/quectel.c:882 #4 0x5566b63f6ae1 in at_chat_finish_command ../git/gatchat/gatchat.c:459 #5 0x5566b63f701b in at_chat_handle_command_response ../git/gatchat/gatchat.c:521 #6 0x5566b63f785b in have_line ../git/gatchat/gatchat.c:600 #7 0x5566b63f87f1 in new_bytes ../git/gatchat/gatchat.c:759 #8 0x5566b640174c in received_data ../git/gatchat/gatio.c:122 #9 0x7fa0516d727e in g_main_context_dispatch (/usr/lib/libglib-2.0.so.0+0x6a27e) SUMMARY: AddressSanitizer: heap-use-after-free ../git/gatchat/gatmux.c:109 in debug Shadow bytes around the buggy address: 0x0c42800dfb50: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c42800dfb60: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c42800dfb70: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c42800dfb80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c42800dfb90: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa =>0x0c42800dfba0: fd fd fd fd fd[fd]fd fd fd fd fd fd fd fd fd fd 0x0c42800dfbb0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c42800dfbc0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c42800dfbd0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c42800dfbe0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c42800dfbf0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe Left alloca redzone: ca Right alloca redzone: cb Shadow gap: cc ==3640549==ABORTING
2019-10-08 18:44:40 +00:00
gboolean buffer_full = FALSE;
if (cond & G_IO_NVAL)
return FALSE;
debug(mux, "received data");
bytes_read = 0;
status = g_io_channel_read_chars(mux->channel, mux->buf + mux->buf_used,
sizeof(mux->buf) - mux->buf_used,
2011-02-08 22:25:14 +00:00
&bytes_read, NULL);
mux->buf_used += bytes_read;
if (bytes_read > 0 && mux->driver->feed_data) {
int nread;
memset(mux->newdata, 0, BITMAP_SIZE);
nread = mux->driver->feed_data(mux, mux->buf, mux->buf_used);
mux->buf_used -= nread;
if (mux->buf_used > 0)
memmove(mux->buf, mux->buf + nread, mux->buf_used);
gatmux: take reference to mux object while processing incoming data When closing down a cmux object, the address sanitizer detects a use-after-free in gatmux.c (see below). Avoid this by taking a reference to the mux object during the processing in received_data(). ofonod[3640549]: ../git/plugins/quectel.c:cfun_disable() 0x610000000b40 ofonod[3640549]: ../git/plugins/quectel.c:close_serial() 0x610000000b40 ofonod[3640549]: ../git/plugins/quectel.c:close_mux() 0x610000000b40 ofonod[3640549]: ../git/examples/emulator.c:powered_watch() Removing modem 0x610000000b40 from the list ofonod[3640549]: ../git/examples/emulator.c:powered_watch() Removing server watch: 106 ofonod[3640549]: ../git/src/modem.c:modem_change_state() old state: 0, new state: 0 ================================================================= ==3640549==ERROR: AddressSanitizer: heap-use-after-free on address 0x62100073dd28 at pc 0x5566b6402a21 bp 0x7ffe7a2db0e0 sp 0x7ffe7a2db0d0 READ of size 8 at 0x62100073dd28 thread T0 #0 0x5566b6402a20 in debug ../git/gatchat/gatmux.c:109 #1 0x5566b6404bd7 in channel_close ../git/gatchat/gatmux.c:525 #2 0x7fa0516e44a6 in g_io_channel_shutdown (/usr/lib/libglib-2.0.so.0+0x774a6) #3 0x7fa0516e4644 in g_io_channel_unref (/usr/lib/libglib-2.0.so.0+0x77644) #4 0x5566b64048a4 in watch_finalize ../git/gatchat/gatmux.c:474 #5 0x7fa0516d6f6f (/usr/lib/libglib-2.0.so.0+0x69f6f) #6 0x7fa0516ac6a7 in g_slist_foreach (/usr/lib/libglib-2.0.so.0+0x3f6a7) #7 0x7fa0516b277b in g_slist_free_full (/usr/lib/libglib-2.0.so.0+0x4577b) #8 0x5566b6403413 in dispatch_sources ../git/gatchat/gatmux.c:224 #9 0x5566b64039ea in received_data ../git/gatchat/gatmux.c:268 #10 0x7fa0516d727e in g_main_context_dispatch (/usr/lib/libglib-2.0.so.0+0x6a27e) #11 0x7fa0516d91c0 (/usr/lib/libglib-2.0.so.0+0x6c1c0) #12 0x7fa0516da0d2 in g_main_loop_run (/usr/lib/libglib-2.0.so.0+0x6d0d2) #13 0x5566b6429b1b in main ../git/src/main.c:286 #14 0x7fa05147fee2 in __libc_start_main (/usr/lib/libc.so.6+0x26ee2) #15 0x5566b62531ad in _start (/home/martin/projects/ofono/x86/src/ofonod+0xfc1ad) 0x62100073dd28 is located 40 bytes inside of 4672-byte region [0x62100073dd00,0x62100073ef40) freed by thread T0 here: #0 0x7fa0519256c0 in __interceptor_free /build/gcc/src/gcc/libsanitizer/asan/asan_malloc_linux.cc:122 #1 0x5566b64052d7 in g_at_mux_unref ../git/gatchat/gatmux.c:645 #2 0x5566b63d6d19 in close_mux ../git/plugins/quectel.c:199 #3 0x5566b63d7047 in close_serial ../git/plugins/quectel.c:223 #4 0x5566b63db62a in cfun_disable ../git/plugins/quectel.c:1056 #5 0x5566b63f6ae1 in at_chat_finish_command ../git/gatchat/gatchat.c:459 #6 0x5566b63f701b in at_chat_handle_command_response ../git/gatchat/gatchat.c:521 #7 0x5566b63f785b in have_line ../git/gatchat/gatchat.c:600 #8 0x5566b63f87f1 in new_bytes ../git/gatchat/gatchat.c:759 #9 0x5566b640174c in received_data ../git/gatchat/gatio.c:122 #10 0x5566b64047b4 in watch_dispatch ../git/gatchat/gatmux.c:464 #11 0x5566b640313b in dispatch_sources ../git/gatchat/gatmux.c:183 #12 0x5566b64039ea in received_data ../git/gatchat/gatmux.c:268 #13 0x7fa0516d727e in g_main_context_dispatch (/usr/lib/libglib-2.0.so.0+0x6a27e) previously allocated by thread T0 here: #0 0x7fa051925ce8 in __interceptor_calloc /build/gcc/src/gcc/libsanitizer/asan/asan_malloc_linux.cc:153 #1 0x5566b6405009 in g_at_mux_new ../git/gatchat/gatmux.c:606 #2 0x5566b6407f6b in g_at_mux_new_gsm0710_basic ../git/gatchat/gatmux.c:1165 #3 0x5566b63da9ba in cmux_cb ../git/plugins/quectel.c:882 #4 0x5566b63f6ae1 in at_chat_finish_command ../git/gatchat/gatchat.c:459 #5 0x5566b63f701b in at_chat_handle_command_response ../git/gatchat/gatchat.c:521 #6 0x5566b63f785b in have_line ../git/gatchat/gatchat.c:600 #7 0x5566b63f87f1 in new_bytes ../git/gatchat/gatchat.c:759 #8 0x5566b640174c in received_data ../git/gatchat/gatio.c:122 #9 0x7fa0516d727e in g_main_context_dispatch (/usr/lib/libglib-2.0.so.0+0x6a27e) SUMMARY: AddressSanitizer: heap-use-after-free ../git/gatchat/gatmux.c:109 in debug Shadow bytes around the buggy address: 0x0c42800dfb50: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c42800dfb60: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c42800dfb70: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c42800dfb80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c42800dfb90: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa =>0x0c42800dfba0: fd fd fd fd fd[fd]fd fd fd fd fd fd fd fd fd fd 0x0c42800dfbb0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c42800dfbc0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c42800dfbd0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c42800dfbe0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c42800dfbf0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe Left alloca redzone: ca Right alloca redzone: cb Shadow gap: cc ==3640549==ABORTING
2019-10-08 18:44:40 +00:00
g_at_mux_ref(mux);
for (i = 1; i <= MAX_CHANNELS; i++) {
int offset = i / 8;
int bit = i % 8;
if (!(mux->newdata[offset] & (1 << bit)))
continue;
debug(mux, "dispatching sources for channel: %p",
mux->dlcs[i-1]);
dispatch_sources(mux->dlcs[i-1], G_IO_IN);
}
gatmux: take reference to mux object while processing incoming data When closing down a cmux object, the address sanitizer detects a use-after-free in gatmux.c (see below). Avoid this by taking a reference to the mux object during the processing in received_data(). ofonod[3640549]: ../git/plugins/quectel.c:cfun_disable() 0x610000000b40 ofonod[3640549]: ../git/plugins/quectel.c:close_serial() 0x610000000b40 ofonod[3640549]: ../git/plugins/quectel.c:close_mux() 0x610000000b40 ofonod[3640549]: ../git/examples/emulator.c:powered_watch() Removing modem 0x610000000b40 from the list ofonod[3640549]: ../git/examples/emulator.c:powered_watch() Removing server watch: 106 ofonod[3640549]: ../git/src/modem.c:modem_change_state() old state: 0, new state: 0 ================================================================= ==3640549==ERROR: AddressSanitizer: heap-use-after-free on address 0x62100073dd28 at pc 0x5566b6402a21 bp 0x7ffe7a2db0e0 sp 0x7ffe7a2db0d0 READ of size 8 at 0x62100073dd28 thread T0 #0 0x5566b6402a20 in debug ../git/gatchat/gatmux.c:109 #1 0x5566b6404bd7 in channel_close ../git/gatchat/gatmux.c:525 #2 0x7fa0516e44a6 in g_io_channel_shutdown (/usr/lib/libglib-2.0.so.0+0x774a6) #3 0x7fa0516e4644 in g_io_channel_unref (/usr/lib/libglib-2.0.so.0+0x77644) #4 0x5566b64048a4 in watch_finalize ../git/gatchat/gatmux.c:474 #5 0x7fa0516d6f6f (/usr/lib/libglib-2.0.so.0+0x69f6f) #6 0x7fa0516ac6a7 in g_slist_foreach (/usr/lib/libglib-2.0.so.0+0x3f6a7) #7 0x7fa0516b277b in g_slist_free_full (/usr/lib/libglib-2.0.so.0+0x4577b) #8 0x5566b6403413 in dispatch_sources ../git/gatchat/gatmux.c:224 #9 0x5566b64039ea in received_data ../git/gatchat/gatmux.c:268 #10 0x7fa0516d727e in g_main_context_dispatch (/usr/lib/libglib-2.0.so.0+0x6a27e) #11 0x7fa0516d91c0 (/usr/lib/libglib-2.0.so.0+0x6c1c0) #12 0x7fa0516da0d2 in g_main_loop_run (/usr/lib/libglib-2.0.so.0+0x6d0d2) #13 0x5566b6429b1b in main ../git/src/main.c:286 #14 0x7fa05147fee2 in __libc_start_main (/usr/lib/libc.so.6+0x26ee2) #15 0x5566b62531ad in _start (/home/martin/projects/ofono/x86/src/ofonod+0xfc1ad) 0x62100073dd28 is located 40 bytes inside of 4672-byte region [0x62100073dd00,0x62100073ef40) freed by thread T0 here: #0 0x7fa0519256c0 in __interceptor_free /build/gcc/src/gcc/libsanitizer/asan/asan_malloc_linux.cc:122 #1 0x5566b64052d7 in g_at_mux_unref ../git/gatchat/gatmux.c:645 #2 0x5566b63d6d19 in close_mux ../git/plugins/quectel.c:199 #3 0x5566b63d7047 in close_serial ../git/plugins/quectel.c:223 #4 0x5566b63db62a in cfun_disable ../git/plugins/quectel.c:1056 #5 0x5566b63f6ae1 in at_chat_finish_command ../git/gatchat/gatchat.c:459 #6 0x5566b63f701b in at_chat_handle_command_response ../git/gatchat/gatchat.c:521 #7 0x5566b63f785b in have_line ../git/gatchat/gatchat.c:600 #8 0x5566b63f87f1 in new_bytes ../git/gatchat/gatchat.c:759 #9 0x5566b640174c in received_data ../git/gatchat/gatio.c:122 #10 0x5566b64047b4 in watch_dispatch ../git/gatchat/gatmux.c:464 #11 0x5566b640313b in dispatch_sources ../git/gatchat/gatmux.c:183 #12 0x5566b64039ea in received_data ../git/gatchat/gatmux.c:268 #13 0x7fa0516d727e in g_main_context_dispatch (/usr/lib/libglib-2.0.so.0+0x6a27e) previously allocated by thread T0 here: #0 0x7fa051925ce8 in __interceptor_calloc /build/gcc/src/gcc/libsanitizer/asan/asan_malloc_linux.cc:153 #1 0x5566b6405009 in g_at_mux_new ../git/gatchat/gatmux.c:606 #2 0x5566b6407f6b in g_at_mux_new_gsm0710_basic ../git/gatchat/gatmux.c:1165 #3 0x5566b63da9ba in cmux_cb ../git/plugins/quectel.c:882 #4 0x5566b63f6ae1 in at_chat_finish_command ../git/gatchat/gatchat.c:459 #5 0x5566b63f701b in at_chat_handle_command_response ../git/gatchat/gatchat.c:521 #6 0x5566b63f785b in have_line ../git/gatchat/gatchat.c:600 #7 0x5566b63f87f1 in new_bytes ../git/gatchat/gatchat.c:759 #8 0x5566b640174c in received_data ../git/gatchat/gatio.c:122 #9 0x7fa0516d727e in g_main_context_dispatch (/usr/lib/libglib-2.0.so.0+0x6a27e) SUMMARY: AddressSanitizer: heap-use-after-free ../git/gatchat/gatmux.c:109 in debug Shadow bytes around the buggy address: 0x0c42800dfb50: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c42800dfb60: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c42800dfb70: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c42800dfb80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c42800dfb90: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa =>0x0c42800dfba0: fd fd fd fd fd[fd]fd fd fd fd fd fd fd fd fd fd 0x0c42800dfbb0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c42800dfbc0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c42800dfbd0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c42800dfbe0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c42800dfbf0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe Left alloca redzone: ca Right alloca redzone: cb Shadow gap: cc ==3640549==ABORTING
2019-10-08 18:44:40 +00:00
buffer_full = mux->buf_used == sizeof(mux->buf);
g_at_mux_unref(mux);
}
if (cond & (G_IO_HUP | G_IO_ERR))
return FALSE;
if (status != G_IO_STATUS_NORMAL && status != G_IO_STATUS_AGAIN)
return FALSE;
gatmux: take reference to mux object while processing incoming data When closing down a cmux object, the address sanitizer detects a use-after-free in gatmux.c (see below). Avoid this by taking a reference to the mux object during the processing in received_data(). ofonod[3640549]: ../git/plugins/quectel.c:cfun_disable() 0x610000000b40 ofonod[3640549]: ../git/plugins/quectel.c:close_serial() 0x610000000b40 ofonod[3640549]: ../git/plugins/quectel.c:close_mux() 0x610000000b40 ofonod[3640549]: ../git/examples/emulator.c:powered_watch() Removing modem 0x610000000b40 from the list ofonod[3640549]: ../git/examples/emulator.c:powered_watch() Removing server watch: 106 ofonod[3640549]: ../git/src/modem.c:modem_change_state() old state: 0, new state: 0 ================================================================= ==3640549==ERROR: AddressSanitizer: heap-use-after-free on address 0x62100073dd28 at pc 0x5566b6402a21 bp 0x7ffe7a2db0e0 sp 0x7ffe7a2db0d0 READ of size 8 at 0x62100073dd28 thread T0 #0 0x5566b6402a20 in debug ../git/gatchat/gatmux.c:109 #1 0x5566b6404bd7 in channel_close ../git/gatchat/gatmux.c:525 #2 0x7fa0516e44a6 in g_io_channel_shutdown (/usr/lib/libglib-2.0.so.0+0x774a6) #3 0x7fa0516e4644 in g_io_channel_unref (/usr/lib/libglib-2.0.so.0+0x77644) #4 0x5566b64048a4 in watch_finalize ../git/gatchat/gatmux.c:474 #5 0x7fa0516d6f6f (/usr/lib/libglib-2.0.so.0+0x69f6f) #6 0x7fa0516ac6a7 in g_slist_foreach (/usr/lib/libglib-2.0.so.0+0x3f6a7) #7 0x7fa0516b277b in g_slist_free_full (/usr/lib/libglib-2.0.so.0+0x4577b) #8 0x5566b6403413 in dispatch_sources ../git/gatchat/gatmux.c:224 #9 0x5566b64039ea in received_data ../git/gatchat/gatmux.c:268 #10 0x7fa0516d727e in g_main_context_dispatch (/usr/lib/libglib-2.0.so.0+0x6a27e) #11 0x7fa0516d91c0 (/usr/lib/libglib-2.0.so.0+0x6c1c0) #12 0x7fa0516da0d2 in g_main_loop_run (/usr/lib/libglib-2.0.so.0+0x6d0d2) #13 0x5566b6429b1b in main ../git/src/main.c:286 #14 0x7fa05147fee2 in __libc_start_main (/usr/lib/libc.so.6+0x26ee2) #15 0x5566b62531ad in _start (/home/martin/projects/ofono/x86/src/ofonod+0xfc1ad) 0x62100073dd28 is located 40 bytes inside of 4672-byte region [0x62100073dd00,0x62100073ef40) freed by thread T0 here: #0 0x7fa0519256c0 in __interceptor_free /build/gcc/src/gcc/libsanitizer/asan/asan_malloc_linux.cc:122 #1 0x5566b64052d7 in g_at_mux_unref ../git/gatchat/gatmux.c:645 #2 0x5566b63d6d19 in close_mux ../git/plugins/quectel.c:199 #3 0x5566b63d7047 in close_serial ../git/plugins/quectel.c:223 #4 0x5566b63db62a in cfun_disable ../git/plugins/quectel.c:1056 #5 0x5566b63f6ae1 in at_chat_finish_command ../git/gatchat/gatchat.c:459 #6 0x5566b63f701b in at_chat_handle_command_response ../git/gatchat/gatchat.c:521 #7 0x5566b63f785b in have_line ../git/gatchat/gatchat.c:600 #8 0x5566b63f87f1 in new_bytes ../git/gatchat/gatchat.c:759 #9 0x5566b640174c in received_data ../git/gatchat/gatio.c:122 #10 0x5566b64047b4 in watch_dispatch ../git/gatchat/gatmux.c:464 #11 0x5566b640313b in dispatch_sources ../git/gatchat/gatmux.c:183 #12 0x5566b64039ea in received_data ../git/gatchat/gatmux.c:268 #13 0x7fa0516d727e in g_main_context_dispatch (/usr/lib/libglib-2.0.so.0+0x6a27e) previously allocated by thread T0 here: #0 0x7fa051925ce8 in __interceptor_calloc /build/gcc/src/gcc/libsanitizer/asan/asan_malloc_linux.cc:153 #1 0x5566b6405009 in g_at_mux_new ../git/gatchat/gatmux.c:606 #2 0x5566b6407f6b in g_at_mux_new_gsm0710_basic ../git/gatchat/gatmux.c:1165 #3 0x5566b63da9ba in cmux_cb ../git/plugins/quectel.c:882 #4 0x5566b63f6ae1 in at_chat_finish_command ../git/gatchat/gatchat.c:459 #5 0x5566b63f701b in at_chat_handle_command_response ../git/gatchat/gatchat.c:521 #6 0x5566b63f785b in have_line ../git/gatchat/gatchat.c:600 #7 0x5566b63f87f1 in new_bytes ../git/gatchat/gatchat.c:759 #8 0x5566b640174c in received_data ../git/gatchat/gatio.c:122 #9 0x7fa0516d727e in g_main_context_dispatch (/usr/lib/libglib-2.0.so.0+0x6a27e) SUMMARY: AddressSanitizer: heap-use-after-free ../git/gatchat/gatmux.c:109 in debug Shadow bytes around the buggy address: 0x0c42800dfb50: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c42800dfb60: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c42800dfb70: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c42800dfb80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c42800dfb90: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa =>0x0c42800dfba0: fd fd fd fd fd[fd]fd fd fd fd fd fd fd fd fd fd 0x0c42800dfbb0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c42800dfbc0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c42800dfbd0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c42800dfbe0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c42800dfbf0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe Left alloca redzone: ca Right alloca redzone: cb Shadow gap: cc ==3640549==ABORTING
2019-10-08 18:44:40 +00:00
if (buffer_full)
return FALSE;
return TRUE;
}
static void write_watcher_destroy_notify(gpointer user_data)
{
GAtMux *mux = user_data;
mux->write_watch = 0;
}
2012-07-15 23:06:43 +00:00
static gboolean can_write_data(GIOChannel *chan, GIOCondition cond,
gpointer data)
{
GAtMux *mux = data;
int dlc;
if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR))
return FALSE;
debug(mux, "can write data");
for (dlc = 0; dlc < MAX_CHANNELS; dlc += 1) {
GAtMuxChannel *channel = mux->dlcs[dlc];
if (channel == NULL)
continue;
debug(mux, "checking channel for write: %p", channel);
if (channel->throttled)
continue;
debug(mux, "dispatching write sources: %p", channel);
dispatch_sources(channel, G_IO_OUT);
}
for (dlc = 0; dlc < MAX_CHANNELS; dlc += 1) {
GAtMuxChannel *channel = mux->dlcs[dlc];
GSList *l;
GAtMuxWatch *source;
if (channel == NULL)
continue;
if (channel->throttled)
continue;
for (l = channel->sources; l; l = l->next) {
source = l->data;
if (source->condition & G_IO_OUT)
return TRUE;
}
}
return FALSE;
}
static void wakeup_writer(GAtMux *mux)
{
if (mux->write_watch != 0)
return;
debug(mux, "waking up writer");
mux->write_watch = g_io_add_watch_full(mux->channel,
G_PRIORITY_DEFAULT,
G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
can_write_data, mux,
write_watcher_destroy_notify);
}
int g_at_mux_raw_write(GAtMux *mux, const void *data, int towrite)
{
gssize count = towrite;
gsize bytes_written;
2010-02-04 06:00:00 +00:00
g_io_channel_write_chars(mux->channel, (gchar *) data,
2011-02-08 22:25:14 +00:00
count, &bytes_written, NULL);
return bytes_written;
}
void g_at_mux_feed_dlc_data(GAtMux *mux, guint8 dlc,
const void *data, int tofeed)
{
GAtMuxChannel *channel;
int written;
int offset;
int bit;
debug(mux, "deliver_data: dlc: %hu", dlc);
if (dlc < 1 || dlc > MAX_CHANNELS)
return;
channel = mux->dlcs[dlc-1];
if (channel == NULL)
return;
written = ring_buffer_write(channel->buffer, data, tofeed);
if (written < 0)
return;
offset = dlc / 8;
bit = dlc % 8;
mux->newdata[offset] |= 1 << bit;
channel->condition |= G_IO_IN;
}
void g_at_mux_set_dlc_status(GAtMux *mux, guint8 dlc, int status)
{
GAtMuxChannel *channel;
debug(mux, "got status %d, for channel %hu", status, dlc);
if (dlc < 1 || dlc > MAX_CHANNELS)
return;
channel = mux->dlcs[dlc-1];
if (channel == NULL)
return;
if (status & G_AT_MUX_DLC_STATUS_RTR) {
GSList *l;
mux->dlcs[dlc-1]->throttled = FALSE;
debug(mux, "setting throttled to FALSE");
for (l = mux->dlcs[dlc-1]->sources; l; l = l->next) {
GAtMuxWatch *source = l->data;
if (source->condition & G_IO_OUT) {
wakeup_writer(mux);
break;
}
}
} else
mux->dlcs[dlc-1]->throttled = TRUE;
}
2009-10-12 20:40:31 +00:00
void g_at_mux_set_data(GAtMux *mux, void *data)
{
if (mux == NULL)
return;
mux->driver_data = data;
}
void *g_at_mux_get_data(GAtMux *mux)
{
if (mux == NULL)
return NULL;
return mux->driver_data;
}
static gboolean watch_check(GSource *source)
{
return FALSE;
}
static gboolean watch_prepare(GSource *source, gint *timeout)
{
*timeout = -1;
return FALSE;
}
static gboolean watch_dispatch(GSource *source, GSourceFunc callback,
gpointer user_data)
{
GIOFunc func = (GIOFunc) callback;
GAtMuxWatch *watch = (GAtMuxWatch *) source;
GAtMuxChannel *channel = (GAtMuxChannel *) watch->channel;
if (func == NULL)
return FALSE;
return func(watch->channel, channel->condition & watch->condition,
user_data);
}
static void watch_finalize(GSource *source)
{
GAtMuxWatch *watch = (GAtMuxWatch *) source;
gatmux: Remove finalized watches from the list Leaving them there may result in invalid reads like this: ==2312== Invalid read of size 4 ==2312== at 0xAB8C0: dispatch_sources (gatmux.c:134) ==2312== by 0xAC5D3: channel_close (gatmux.c:479) ==2312== by 0x4AE8885: g_io_channel_shutdown (giochannel.c:523) ==2312== by 0x4AE8A1D: g_io_channel_unref (giochannel.c:240) ==2312== by 0xAC423: watch_finalize (gatmux.c:426) ==2312== by 0x4AF2CC9: g_source_unref_internal (gmain.c:2048) ==2312== by 0x4AF44E1: g_source_destroy_internal (gmain.c:1230) ==2312== by 0x4AF44E1: g_source_destroy (gmain.c:1256) ==2312== by 0x4AF5257: g_source_remove (gmain.c:2282) ==2312== by 0xAB5CB: io_shutdown (gatio.c:325) ==2312== by 0xAB667: g_at_io_unref (gatio.c:345) ==2312== by 0xA72C7: at_chat_unref (gatchat.c:972) ==2312== by 0xA829B: g_at_chat_unref (gatchat.c:1446) ==2312== Address 0x51420f0 is 56 bytes inside a block of size 60 free'd ==2312== at 0x4840B28: free (vg_replace_malloc.c:530) ==2312== by 0x4AF2D33: g_source_unref_internal (gmain.c:2075) ==2312== by 0x4AF44E1: g_source_destroy_internal (gmain.c:1230) ==2312== by 0x4AF44E1: g_source_destroy (gmain.c:1256) ==2312== by 0x4AF5257: g_source_remove (gmain.c:2282) ==2312== by 0xAB46B: g_at_io_set_write_handler (gatio.c:283) ==2312== by 0xA713F: at_chat_suspend (gatchat.c:938) ==2312== by 0xA72B7: at_chat_unref (gatchat.c:971) ==2312== by 0xA829B: g_at_chat_unref (gatchat.c:1446) ==2312== Block was alloc'd at ==2312== at 0x4841BF0: calloc (vg_replace_malloc.c:711) ==2312== by 0x4AFB117: g_malloc0 (gmem.c:124) ==2312== by 0x4AF401F: g_source_new (gmain.c:892) ==2312== by 0xAC6A7: channel_create_watch (gatmux.c:506) ==2312== by 0x4AE7C4F: g_io_add_watch_full (giochannel.c:649) ==2312== by 0xAB4EB: g_at_io_set_write_handler (gatio.c:297) ==2312== by 0xA7103: chat_wakeup_writer (gatchat.c:931) ==2312== by 0xA753F: at_chat_send_common (gatchat.c:1045) ==2312== by 0xA850F: g_at_chat_send (gatchat.c:1502) It's also necessary to add additional references to the sources for the duration of the dispatch_sources loop because any source can be removed when any callback is invoked (and not necessarily the one being dispatched).
2017-10-23 09:17:30 +00:00
GAtMuxChannel *dlc = (GAtMuxChannel *) watch->channel;
gatmux: Remove finalized watches from the list Leaving them there may result in invalid reads like this: ==2312== Invalid read of size 4 ==2312== at 0xAB8C0: dispatch_sources (gatmux.c:134) ==2312== by 0xAC5D3: channel_close (gatmux.c:479) ==2312== by 0x4AE8885: g_io_channel_shutdown (giochannel.c:523) ==2312== by 0x4AE8A1D: g_io_channel_unref (giochannel.c:240) ==2312== by 0xAC423: watch_finalize (gatmux.c:426) ==2312== by 0x4AF2CC9: g_source_unref_internal (gmain.c:2048) ==2312== by 0x4AF44E1: g_source_destroy_internal (gmain.c:1230) ==2312== by 0x4AF44E1: g_source_destroy (gmain.c:1256) ==2312== by 0x4AF5257: g_source_remove (gmain.c:2282) ==2312== by 0xAB5CB: io_shutdown (gatio.c:325) ==2312== by 0xAB667: g_at_io_unref (gatio.c:345) ==2312== by 0xA72C7: at_chat_unref (gatchat.c:972) ==2312== by 0xA829B: g_at_chat_unref (gatchat.c:1446) ==2312== Address 0x51420f0 is 56 bytes inside a block of size 60 free'd ==2312== at 0x4840B28: free (vg_replace_malloc.c:530) ==2312== by 0x4AF2D33: g_source_unref_internal (gmain.c:2075) ==2312== by 0x4AF44E1: g_source_destroy_internal (gmain.c:1230) ==2312== by 0x4AF44E1: g_source_destroy (gmain.c:1256) ==2312== by 0x4AF5257: g_source_remove (gmain.c:2282) ==2312== by 0xAB46B: g_at_io_set_write_handler (gatio.c:283) ==2312== by 0xA713F: at_chat_suspend (gatchat.c:938) ==2312== by 0xA72B7: at_chat_unref (gatchat.c:971) ==2312== by 0xA829B: g_at_chat_unref (gatchat.c:1446) ==2312== Block was alloc'd at ==2312== at 0x4841BF0: calloc (vg_replace_malloc.c:711) ==2312== by 0x4AFB117: g_malloc0 (gmem.c:124) ==2312== by 0x4AF401F: g_source_new (gmain.c:892) ==2312== by 0xAC6A7: channel_create_watch (gatmux.c:506) ==2312== by 0x4AE7C4F: g_io_add_watch_full (giochannel.c:649) ==2312== by 0xAB4EB: g_at_io_set_write_handler (gatio.c:297) ==2312== by 0xA7103: chat_wakeup_writer (gatchat.c:931) ==2312== by 0xA753F: at_chat_send_common (gatchat.c:1045) ==2312== by 0xA850F: g_at_chat_send (gatchat.c:1502) It's also necessary to add additional references to the sources for the duration of the dispatch_sources loop because any source can be removed when any callback is invoked (and not necessarily the one being dispatched).
2017-10-23 09:17:30 +00:00
dlc->sources = g_slist_remove(dlc->sources, watch);
g_io_channel_unref(watch->channel);
}
static GSourceFuncs watch_funcs = {
watch_prepare,
watch_check,
watch_dispatch,
watch_finalize
};
static GIOStatus channel_read(GIOChannel *channel, gchar *buf, gsize count,
gsize *bytes_read, GError **err)
{
GAtMuxChannel *mux_channel = (GAtMuxChannel *) channel;
unsigned int avail = ring_buffer_len_no_wrap(mux_channel->buffer);
if (avail > count)
avail = count;
*bytes_read = ring_buffer_read(mux_channel->buffer, buf, avail);
if (*bytes_read == 0)
return G_IO_STATUS_AGAIN;
return G_IO_STATUS_NORMAL;
}
static GIOStatus channel_write(GIOChannel *channel, const gchar *buf,
gsize count, gsize *bytes_written, GError **err)
{
GAtMuxChannel *mux_channel = (GAtMuxChannel *) channel;
GAtMux *mux = mux_channel->mux;
if (mux->driver->write)
mux->driver->write(mux, mux_channel->dlc, buf, count);
*bytes_written = count;
return G_IO_STATUS_NORMAL;
}
static GIOStatus channel_seek(GIOChannel *channel, gint64 offset,
GSeekType type, GError **err)
{
return G_IO_STATUS_NORMAL;
}
static GIOStatus channel_close(GIOChannel *channel, GError **err)
{
GAtMuxChannel *mux_channel = (GAtMuxChannel *) channel;
GAtMux *mux = mux_channel->mux;
debug(mux, "closing channel: %d", mux_channel->dlc);
dispatch_sources(mux_channel, G_IO_NVAL);
if (mux->driver->close_dlc)
mux->driver->close_dlc(mux, mux_channel->dlc);
mux->dlcs[mux_channel->dlc - 1] = NULL;
return G_IO_STATUS_NORMAL;
}
static void channel_free(GIOChannel *channel)
{
GAtMuxChannel *mux_channel = (GAtMuxChannel *) channel;
ring_buffer_free(mux_channel->buffer);
g_free(channel);
}
static GSource *channel_create_watch(GIOChannel *channel,
GIOCondition condition)
{
GSource *source;
GAtMuxWatch *watch;
GAtMuxChannel *dlc = (GAtMuxChannel *) channel;
GAtMux *mux = dlc->mux;
source = g_source_new(&watch_funcs, sizeof(GAtMuxWatch));
watch = (GAtMuxWatch *) source;
watch->channel = channel;
g_io_channel_ref(channel);
watch->condition = condition;
if ((watch->condition & G_IO_OUT) && dlc->throttled == FALSE)
wakeup_writer(mux);
debug(mux, "creating source: %p, channel: %p, writer: %d, reader: %d",
watch, channel,
condition & G_IO_OUT,
condition & G_IO_IN);
dlc->sources = g_slist_prepend(dlc->sources, watch);
return source;
}
static GIOStatus channel_set_flags(GIOChannel *channel, GIOFlags flags,
GError **err)
{
return G_IO_STATUS_NORMAL;
}
static GIOFlags channel_get_flags(GIOChannel *channel)
{
GIOFlags flags = 0;
return flags;
}
static GIOFuncs channel_funcs = {
channel_read,
channel_write,
channel_seek,
channel_close,
channel_create_watch,
channel_free,
channel_set_flags,
channel_get_flags,
};
GAtMux *g_at_mux_new(GIOChannel *channel, const GAtMuxDriver *driver)
2009-10-12 16:56:41 +00:00
{
GAtMux *mux;
if (channel == NULL)
2009-10-12 16:56:41 +00:00
return NULL;
mux = g_try_new0(GAtMux, 1);
if (mux == NULL)
2009-10-12 16:56:41 +00:00
return NULL;
mux->ref_count = 1;
mux->driver = driver;
mux->shutdown = TRUE;
2009-10-12 16:56:41 +00:00
mux->channel = channel;
g_io_channel_ref(channel);
g_io_channel_set_close_on_unref(channel, TRUE);
return mux;
}
GAtMux *g_at_mux_ref(GAtMux *mux)
{
if (mux == NULL)
return NULL;
g_atomic_int_inc(&mux->ref_count);
return mux;
}
void g_at_mux_unref(GAtMux *mux)
{
if (mux == NULL)
return;
if (g_atomic_int_dec_and_test(&mux->ref_count)) {
g_at_mux_shutdown(mux);
g_io_channel_unref(mux->channel);
if (mux->driver->remove)
mux->driver->remove(mux);
2009-10-12 16:56:41 +00:00
g_free(mux);
}
}
gboolean g_at_mux_start(GAtMux *mux)
{
if (mux->channel == NULL)
return FALSE;
if (mux->driver->startup == NULL)
return FALSE;
if (mux->driver->startup(mux) == FALSE)
return FALSE;
2009-10-12 16:56:41 +00:00
mux->read_watch = g_io_add_watch_full(mux->channel, G_PRIORITY_DEFAULT,
G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
gatmux: disable destroy notification on read watcher With the reference in place in received_data(), the address sanitizer now encounters a use-after-free when the destroy notification is dispatched for the read watcher (see below). Fix this by remove the destroy notification callback, as it isn't really used except in the shutdown function. ==5797==ERROR: AddressSanitizer: heap-use-after-free on address 0x621000ac5904 at pc 0x55c1243b1f14 bp 0x7ffdef001340 sp 0x7ffdef001330 WRITE of size 4 at 0x621000ac5904 thread T0 #0 0x55c1243b1f13 in read_watcher_destroy_notify ../git/gatchat/gatmux.c:660 #1 0x7f08a8676742 (/usr/lib/libglib-2.0.so.0+0x62742) #2 0x7f08a867e2e4 in g_main_context_dispatch (/usr/lib/libglib-2.0.so.0+0x6a2e4) #3 0x7f08a8680210 (/usr/lib/libglib-2.0.so.0+0x6c210) #4 0x7f08a8681122 in g_main_loop_run (/usr/lib/libglib-2.0.so.0+0x6d122) #5 0x55c1243d6703 in main ../git/src/main.c:286 #6 0x7f08a8423152 in __libc_start_main (/usr/lib/libc.so.6+0x27152) #7 0x55c1241fe1ad in _start (/home/martin/projects/ofono/x86/src/ofonod+0xfd1ad) 0x621000ac5904 is located 4 bytes inside of 4672-byte region [0x621000ac5900,0x621000ac6b40) freed by thread T0 here: #0 0x7f08a88cc6b0 in __interceptor_free /build/gcc/src/gcc/libsanitizer/asan/asan_malloc_linux.cc:122 #1 0x55c1243b1ebf in g_at_mux_unref ../git/gatchat/gatmux.c:652 #2 0x55c1243b062c in received_data ../git/gatchat/gatmux.c:276 #3 0x7f08a867e2ce in g_main_context_dispatch (/usr/lib/libglib-2.0.so.0+0x6a2ce) previously allocated by thread T0 here: #0 0x7f08a88cccd8 in __interceptor_calloc /build/gcc/src/gcc/libsanitizer/asan/asan_malloc_linux.cc:153 #1 0x55c1243b1bf1 in g_at_mux_new ../git/gatchat/gatmux.c:613 #2 0x55c1243b4b53 in g_at_mux_new_gsm0710_basic ../git/gatchat/gatmux.c:1172 #3 0x55c124386abd in cmux_gatmux ../git/plugins/quectel.c:871 #4 0x55c12438779f in cmux_cb ../git/plugins/quectel.c:1023 #5 0x55c1243a368e in at_chat_finish_command ../git/gatchat/gatchat.c:459 #6 0x55c1243a3bc8 in at_chat_handle_command_response ../git/gatchat/gatchat.c:521 #7 0x55c1243a4408 in have_line ../git/gatchat/gatchat.c:600 #8 0x55c1243a539e in new_bytes ../git/gatchat/gatchat.c:759 #9 0x55c1243ae2f9 in received_data ../git/gatchat/gatio.c:122 #10 0x7f08a867e2ce in g_main_context_dispatch (/usr/lib/libglib-2.0.so.0+0x6a2ce) SUMMARY: AddressSanitizer: heap-use-after-free ../git/gatchat/gatmux.c:660 in read_watcher_destroy_notify Shadow bytes around the buggy address: 0x0c4280150ad0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c4280150ae0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c4280150af0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c4280150b00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c4280150b10: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa =>0x0c4280150b20:[fd]fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c4280150b30: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c4280150b40: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c4280150b50: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c4280150b60: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c4280150b70: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe Left alloca redzone: ca Right alloca redzone: cb Shadow gap: cc ==5797==ABORTING
2019-10-08 18:44:41 +00:00
received_data, mux, NULL);
2009-10-12 16:56:41 +00:00
mux->shutdown = FALSE;
2009-10-12 16:56:41 +00:00
return TRUE;
}
gboolean g_at_mux_shutdown(GAtMux *mux)
{
int i;
if (mux->shutdown == TRUE)
return FALSE;
if (mux->channel == NULL)
return FALSE;
gatmux: disable destroy notification on read watcher With the reference in place in received_data(), the address sanitizer now encounters a use-after-free when the destroy notification is dispatched for the read watcher (see below). Fix this by remove the destroy notification callback, as it isn't really used except in the shutdown function. ==5797==ERROR: AddressSanitizer: heap-use-after-free on address 0x621000ac5904 at pc 0x55c1243b1f14 bp 0x7ffdef001340 sp 0x7ffdef001330 WRITE of size 4 at 0x621000ac5904 thread T0 #0 0x55c1243b1f13 in read_watcher_destroy_notify ../git/gatchat/gatmux.c:660 #1 0x7f08a8676742 (/usr/lib/libglib-2.0.so.0+0x62742) #2 0x7f08a867e2e4 in g_main_context_dispatch (/usr/lib/libglib-2.0.so.0+0x6a2e4) #3 0x7f08a8680210 (/usr/lib/libglib-2.0.so.0+0x6c210) #4 0x7f08a8681122 in g_main_loop_run (/usr/lib/libglib-2.0.so.0+0x6d122) #5 0x55c1243d6703 in main ../git/src/main.c:286 #6 0x7f08a8423152 in __libc_start_main (/usr/lib/libc.so.6+0x27152) #7 0x55c1241fe1ad in _start (/home/martin/projects/ofono/x86/src/ofonod+0xfd1ad) 0x621000ac5904 is located 4 bytes inside of 4672-byte region [0x621000ac5900,0x621000ac6b40) freed by thread T0 here: #0 0x7f08a88cc6b0 in __interceptor_free /build/gcc/src/gcc/libsanitizer/asan/asan_malloc_linux.cc:122 #1 0x55c1243b1ebf in g_at_mux_unref ../git/gatchat/gatmux.c:652 #2 0x55c1243b062c in received_data ../git/gatchat/gatmux.c:276 #3 0x7f08a867e2ce in g_main_context_dispatch (/usr/lib/libglib-2.0.so.0+0x6a2ce) previously allocated by thread T0 here: #0 0x7f08a88cccd8 in __interceptor_calloc /build/gcc/src/gcc/libsanitizer/asan/asan_malloc_linux.cc:153 #1 0x55c1243b1bf1 in g_at_mux_new ../git/gatchat/gatmux.c:613 #2 0x55c1243b4b53 in g_at_mux_new_gsm0710_basic ../git/gatchat/gatmux.c:1172 #3 0x55c124386abd in cmux_gatmux ../git/plugins/quectel.c:871 #4 0x55c12438779f in cmux_cb ../git/plugins/quectel.c:1023 #5 0x55c1243a368e in at_chat_finish_command ../git/gatchat/gatchat.c:459 #6 0x55c1243a3bc8 in at_chat_handle_command_response ../git/gatchat/gatchat.c:521 #7 0x55c1243a4408 in have_line ../git/gatchat/gatchat.c:600 #8 0x55c1243a539e in new_bytes ../git/gatchat/gatchat.c:759 #9 0x55c1243ae2f9 in received_data ../git/gatchat/gatio.c:122 #10 0x7f08a867e2ce in g_main_context_dispatch (/usr/lib/libglib-2.0.so.0+0x6a2ce) SUMMARY: AddressSanitizer: heap-use-after-free ../git/gatchat/gatmux.c:660 in read_watcher_destroy_notify Shadow bytes around the buggy address: 0x0c4280150ad0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c4280150ae0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c4280150af0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c4280150b00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c4280150b10: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa =>0x0c4280150b20:[fd]fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c4280150b30: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c4280150b40: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c4280150b50: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c4280150b60: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c4280150b70: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe Left alloca redzone: ca Right alloca redzone: cb Shadow gap: cc ==5797==ABORTING
2019-10-08 18:44:41 +00:00
if (mux->read_watch > 0) {
2009-10-12 16:56:41 +00:00
g_source_remove(mux->read_watch);
gatmux: disable destroy notification on read watcher With the reference in place in received_data(), the address sanitizer now encounters a use-after-free when the destroy notification is dispatched for the read watcher (see below). Fix this by remove the destroy notification callback, as it isn't really used except in the shutdown function. ==5797==ERROR: AddressSanitizer: heap-use-after-free on address 0x621000ac5904 at pc 0x55c1243b1f14 bp 0x7ffdef001340 sp 0x7ffdef001330 WRITE of size 4 at 0x621000ac5904 thread T0 #0 0x55c1243b1f13 in read_watcher_destroy_notify ../git/gatchat/gatmux.c:660 #1 0x7f08a8676742 (/usr/lib/libglib-2.0.so.0+0x62742) #2 0x7f08a867e2e4 in g_main_context_dispatch (/usr/lib/libglib-2.0.so.0+0x6a2e4) #3 0x7f08a8680210 (/usr/lib/libglib-2.0.so.0+0x6c210) #4 0x7f08a8681122 in g_main_loop_run (/usr/lib/libglib-2.0.so.0+0x6d122) #5 0x55c1243d6703 in main ../git/src/main.c:286 #6 0x7f08a8423152 in __libc_start_main (/usr/lib/libc.so.6+0x27152) #7 0x55c1241fe1ad in _start (/home/martin/projects/ofono/x86/src/ofonod+0xfd1ad) 0x621000ac5904 is located 4 bytes inside of 4672-byte region [0x621000ac5900,0x621000ac6b40) freed by thread T0 here: #0 0x7f08a88cc6b0 in __interceptor_free /build/gcc/src/gcc/libsanitizer/asan/asan_malloc_linux.cc:122 #1 0x55c1243b1ebf in g_at_mux_unref ../git/gatchat/gatmux.c:652 #2 0x55c1243b062c in received_data ../git/gatchat/gatmux.c:276 #3 0x7f08a867e2ce in g_main_context_dispatch (/usr/lib/libglib-2.0.so.0+0x6a2ce) previously allocated by thread T0 here: #0 0x7f08a88cccd8 in __interceptor_calloc /build/gcc/src/gcc/libsanitizer/asan/asan_malloc_linux.cc:153 #1 0x55c1243b1bf1 in g_at_mux_new ../git/gatchat/gatmux.c:613 #2 0x55c1243b4b53 in g_at_mux_new_gsm0710_basic ../git/gatchat/gatmux.c:1172 #3 0x55c124386abd in cmux_gatmux ../git/plugins/quectel.c:871 #4 0x55c12438779f in cmux_cb ../git/plugins/quectel.c:1023 #5 0x55c1243a368e in at_chat_finish_command ../git/gatchat/gatchat.c:459 #6 0x55c1243a3bc8 in at_chat_handle_command_response ../git/gatchat/gatchat.c:521 #7 0x55c1243a4408 in have_line ../git/gatchat/gatchat.c:600 #8 0x55c1243a539e in new_bytes ../git/gatchat/gatchat.c:759 #9 0x55c1243ae2f9 in received_data ../git/gatchat/gatio.c:122 #10 0x7f08a867e2ce in g_main_context_dispatch (/usr/lib/libglib-2.0.so.0+0x6a2ce) SUMMARY: AddressSanitizer: heap-use-after-free ../git/gatchat/gatmux.c:660 in read_watcher_destroy_notify Shadow bytes around the buggy address: 0x0c4280150ad0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c4280150ae0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c4280150af0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c4280150b00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c4280150b10: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa =>0x0c4280150b20:[fd]fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c4280150b30: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c4280150b40: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c4280150b50: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c4280150b60: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c4280150b70: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe Left alloca redzone: ca Right alloca redzone: cb Shadow gap: cc ==5797==ABORTING
2019-10-08 18:44:41 +00:00
mux->read_watch = 0;
}
2009-10-12 16:56:41 +00:00
if (mux->write_watch > 0)
g_source_remove(mux->write_watch);
2009-10-12 16:56:41 +00:00
for (i = 0; i < MAX_CHANNELS; i++) {
if (mux->dlcs[i] == NULL)
continue;
channel_close((GIOChannel *) mux->dlcs[i], NULL);
}
if (mux->driver->shutdown)
mux->driver->shutdown(mux);
2009-10-12 16:56:41 +00:00
mux->shutdown = TRUE;
2009-10-12 16:56:41 +00:00
return TRUE;
}
gboolean g_at_mux_set_disconnect_function(GAtMux *mux,
GAtDisconnectFunc disconnect, gpointer user_data)
{
if (mux == NULL)
return FALSE;
mux->user_disconnect = disconnect;
mux->user_disconnect_data = user_data;
return TRUE;
}
gboolean g_at_mux_set_debug(GAtMux *mux, GAtDebugFunc func, gpointer user_data)
2009-10-12 16:56:41 +00:00
{
if (mux == NULL)
return FALSE;
mux->debugf = func;
mux->debug_data = user_data;
2009-10-12 16:56:41 +00:00
return TRUE;
}
GIOChannel *g_at_mux_create_channel(GAtMux *mux)
{
GAtMuxChannel *mux_channel;
GIOChannel *channel;
int i;
for (i = 0; i < MAX_CHANNELS; i++) {
if (mux->dlcs[i] == NULL)
break;
}
if (i == MAX_CHANNELS)
return NULL;
mux_channel = g_try_new0(GAtMuxChannel, 1);
if (mux_channel == NULL)
return NULL;
if (mux->driver->open_dlc)
mux->driver->open_dlc(mux, i+1);
channel = (GIOChannel *) mux_channel;
g_io_channel_init(channel);
channel->close_on_unref = TRUE;
channel->funcs = &channel_funcs;
channel->is_seekable = FALSE;
channel->is_readable = TRUE;
channel->is_writeable = TRUE;
channel->do_encode = FALSE;
mux_channel->mux = mux;
mux_channel->dlc = i+1;
mux_channel->buffer = ring_buffer_new(MUX_CHANNEL_BUFFER_SIZE);
mux_channel->throttled = FALSE;
mux->dlcs[i] = mux_channel;
debug(mux, "created channel %p, dlc: %d", channel, i+1);
return channel;
}
static void msd_free(gpointer user_data)
{
struct mux_setup_data *msd = user_data;
if (msd->chat)
g_at_chat_unref(msd->chat);
g_free(msd);
}
static void mux_setup_cb(gboolean ok, GAtResult *result, gpointer user_data)
{
struct mux_setup_data *msd = user_data;
GIOFlags flags;
GIOChannel *channel;
GAtMux *mux = NULL;
if (!ok)
goto error;
channel = g_at_chat_get_channel(msd->chat);
channel = g_io_channel_ref(channel);
g_at_chat_unref(msd->chat);
msd->chat = NULL;
flags = g_io_channel_get_flags(channel) | G_IO_FLAG_NONBLOCK;
g_io_channel_set_flags(channel, flags, NULL);
g_io_channel_set_encoding(channel, NULL, NULL);
g_io_channel_set_buffered(channel, FALSE);
if (msd->mode == 0)
mux = g_at_mux_new_gsm0710_basic(channel, msd->frame_size);
else
mux = g_at_mux_new_gsm0710_advanced(channel, msd->frame_size);
g_io_channel_unref(channel);
error:
msd->func(mux, msd->user);
if (msd->destroy)
msd->destroy(msd->user);
}
static void mux_query_cb(gboolean ok, GAtResult *result, gpointer user_data)
{
struct mux_setup_data *msd = user_data;
struct mux_setup_data *nmsd;
GAtResultIter iter;
int min, max;
int speed;
char buf[64];
/* CMUX query not supported, abort */
if (!ok)
goto error;
g_at_result_iter_init(&iter, result);
if (!g_at_result_iter_next(&iter, "+CMUX:"))
goto error;
/* Mode */
if (!g_at_result_iter_open_list(&iter))
goto error;
if (!g_at_result_iter_next_range(&iter, &min, &max))
goto error;
if (!g_at_result_iter_close_list(&iter))
goto error;
if (min <= 1 && 1 <= max)
msd->mode = 1;
else if (min <= 0 && 0 <= max)
msd->mode = 0;
else
goto error;
/* Subset */
if (!g_at_result_iter_open_list(&iter))
goto error;
if (!g_at_result_iter_next_range(&iter, &min, &max))
goto error;
if (!g_at_result_iter_close_list(&iter))
goto error;
if (min > 0)
goto error;
/* Speed, pick highest */
if (g_at_result_iter_open_list(&iter)) {
if (!g_at_result_iter_next_range(&iter, &min, &max))
goto error;
if (!g_at_result_iter_close_list(&iter))
goto error;
speed = max;
} else {
if (!g_at_result_iter_skip_next(&iter))
goto error;
/* not available/used */
speed = -1;
}
/* Frame size, pick defaults */
if (!g_at_result_iter_open_list(&iter))
goto error;
if (!g_at_result_iter_next_range(&iter, &min, &max))
goto error;
if (!g_at_result_iter_close_list(&iter))
goto error;
if (msd->mode == 0) {
if (min > 31 || max < 31)
goto error;
msd->frame_size = 31;
} else if (msd->mode == 1) {
if (min > 64 || max < 64)
goto error;
msd->frame_size = 64;
} else
goto error;
nmsd = g_memdup(msd, sizeof(struct mux_setup_data));
g_at_chat_ref(nmsd->chat);
if (speed < 0)
sprintf(buf, "AT+CMUX=%u,0,,%u", msd->mode, msd->frame_size);
else
sprintf(buf, "AT+CMUX=%u,0,%u,%u", msd->mode, speed,
msd->frame_size);
if (g_at_chat_send(msd->chat, buf, none_prefix,
mux_setup_cb, nmsd, msd_free) > 0)
return;
msd_free(nmsd);
error:
msd->func(NULL, msd->user);
if (msd->destroy)
msd->destroy(msd->user);
}
gboolean g_at_mux_setup_gsm0710(GAtChat *chat,
GAtMuxSetupFunc notify, gpointer user_data,
GDestroyNotify destroy)
{
struct mux_setup_data *msd;
if (chat == NULL)
return FALSE;
if (notify == NULL)
return FALSE;
msd = g_new0(struct mux_setup_data, 1);
msd->chat = g_at_chat_ref(chat);
msd->func = notify;
msd->user = user_data;
msd->destroy = destroy;
if (g_at_chat_send(chat, "AT+CMUX=?", cmux_prefix,
mux_query_cb, msd, msd_free) > 0)
return TRUE;
2019-04-29 19:29:21 +00:00
msd_free(msd);
return FALSE;
}
#define GSM0710_BUFFER_SIZE 4096
struct gsm0710_data {
int frame_size;
};
/* Process an incoming GSM 07.10 packet */
static gboolean gsm0710_packet(GAtMux *mux, int dlc, guint8 control,
const unsigned char *data, int len,
GAtMuxWriteFrame write_frame)
{
if (control == 0xEF || control == 0x03) {
if (dlc >= 1 && dlc <= 63) {
g_at_mux_feed_dlc_data(mux, dlc, data, len);
return TRUE;
}
if (dlc == 0) {
/* An embedded command or response on channel 0 */
if (len >= 2 && data[0] == GSM0710_STATUS_SET) {
return gsm0710_packet(mux, dlc,
GSM0710_STATUS_ACK,
data + 2, len - 2,
write_frame);
} else if (len >= 2 && data[0] == 0x43) {
/* Test command from other side - send the same bytes back */
unsigned char *resp = alloca(len);
memcpy(resp, data, len);
resp[0] = 0x41; /* Clear the C/R bit in the response */
write_frame(mux, 0, GSM0710_DATA, resp, len);
}
}
} else if (control == GSM0710_STATUS_ACK && dlc == 0) {
unsigned char resp[33];
/* Status change message */
if (len >= 2) {
/* Handle status changes on other channels */
dlc = ((data[0] & 0xFC) >> 2);
if (dlc >= 1 && dlc <= 63)
g_at_mux_set_dlc_status(mux, dlc, data[1]);
}
/* Send the response to the status change request to ACK it */
debug(mux, "received status line signal, sending response");
if (len > 31)
len = 31;
resp[0] = GSM0710_STATUS_ACK;
resp[1] = ((len << 1) | 0x01);
memcpy(resp + 2, data, len);
write_frame(mux, 0, GSM0710_DATA, resp, len + 2);
}
return TRUE;
}
static void gsm0710_basic_write_frame(GAtMux *mux, guint8 dlc, guint8 control,
const guint8 *data, int towrite)
{
struct gsm0710_data *gd = g_at_mux_get_data(mux);
guint8 *frame = alloca(gd->frame_size + 7);
int frame_size;
frame_size = gsm0710_basic_fill_frame(frame, dlc, control,
data, towrite);
g_at_mux_raw_write(mux, frame, frame_size);
}
#define COMPOSE_STATUS_FRAME(data, dlc, status) \
guint8 data[4]; \
data[0] = GSM0710_STATUS_SET; \
data[1] = 0x03; \
data[2] = ((dlc << 2) | 0x03); \
data[3] = status
static void gsm0710_basic_remove(GAtMux *mux)
{
struct gsm0710_data *gd = g_at_mux_get_data(mux);
g_free(gd);
g_at_mux_set_data(mux, NULL);
}
static gboolean gsm0710_basic_startup(GAtMux *mux)
{
guint8 frame[6];
int frame_size;
frame_size = gsm0710_basic_fill_frame(frame, 0, GSM0710_OPEN_CHANNEL,
NULL, 0);
g_at_mux_raw_write(mux, frame, frame_size);
return TRUE;
}
static gboolean gsm0710_basic_shutdown(GAtMux *mux)
{
guint8 frame[6];
int frame_size;
frame_size = gsm0710_basic_fill_frame(frame, 0, GSM0710_CLOSE_CHANNEL,
NULL, 0);
g_at_mux_raw_write(mux, frame, frame_size);
return TRUE;
}
static gboolean gsm0710_basic_open_dlc(GAtMux *mux, guint8 dlc)
{
guint8 frame[6];
int frame_size;
frame_size = gsm0710_basic_fill_frame(frame, dlc, GSM0710_OPEN_CHANNEL,
NULL, 0);
g_at_mux_raw_write(mux, frame, frame_size);
return TRUE;
}
static gboolean gsm0710_basic_close_dlc(GAtMux *mux, guint8 dlc)
{
guint8 frame[6];
int frame_size;
frame_size = gsm0710_basic_fill_frame(frame, dlc, GSM0710_CLOSE_CHANNEL,
NULL, 0);
g_at_mux_raw_write(mux, frame, frame_size);
return TRUE;
}
static int gsm0710_basic_feed_data(GAtMux *mux, void *data, int len)
{
int total = 0;
int nread;
guint8 dlc;
guint8 ctrl;
guint8 *frame;
int frame_len;
do {
frame = NULL;
nread = gsm0710_basic_extract_frame(data, len, &dlc, &ctrl,
&frame, &frame_len);
total += nread;
data += nread;
len -= nread;
if (frame == NULL)
break;
gsm0710_packet(mux, dlc, ctrl, frame, frame_len,
gsm0710_basic_write_frame);
} while (nread > 0);
return total;
}
static void gsm0710_basic_set_status(GAtMux *mux, guint8 dlc, guint8 status)
{
struct gsm0710_data *gd = g_at_mux_get_data(mux);
guint8 *frame = alloca(gd->frame_size + 7);
int frame_size;
COMPOSE_STATUS_FRAME(data, dlc, status);
frame_size = gsm0710_basic_fill_frame(frame, 0, GSM0710_DATA, data, 4);
g_at_mux_raw_write(mux, frame, frame_size);
}
static void gsm0710_basic_write(GAtMux *mux, guint8 dlc,
const void *data, int towrite)
{
struct gsm0710_data *gd = g_at_mux_get_data(mux);
guint8 *frame = alloca(gd->frame_size + 7);
int max;
int frame_size;
while (towrite > 0) {
max = MIN(towrite, gd->frame_size);
frame_size = gsm0710_basic_fill_frame(frame, dlc,
GSM0710_DATA, data, max);
g_at_mux_raw_write(mux, frame, frame_size);
data = data + max;
towrite -= max;
}
}
static GAtMuxDriver gsm0710_basic_driver = {
.remove = gsm0710_basic_remove,
.startup = gsm0710_basic_startup,
.shutdown = gsm0710_basic_shutdown,
.open_dlc = gsm0710_basic_open_dlc,
.close_dlc = gsm0710_basic_close_dlc,
.feed_data = gsm0710_basic_feed_data,
.set_status = gsm0710_basic_set_status,
.write = gsm0710_basic_write,
};
GAtMux *g_at_mux_new_gsm0710_basic(GIOChannel *channel, int frame_size)
{
GAtMux *mux;
struct gsm0710_data *gd;
mux = g_at_mux_new(channel, &gsm0710_basic_driver);
if (mux == NULL)
return NULL;
gd = g_new0(struct gsm0710_data, 1);
gd->frame_size = frame_size;
g_at_mux_set_data(mux, gd);
return mux;
}
static void gsm0710_advanced_write_frame(GAtMux *mux, guint8 dlc, guint8 control,
const guint8 *data, int towrite)
{
struct gsm0710_data *gd = g_at_mux_get_data(mux);
guint8 *frame = alloca(gd->frame_size * 2 + 7);
int frame_size;
frame_size = gsm0710_advanced_fill_frame(frame, dlc, control,
data, towrite);
g_at_mux_raw_write(mux, frame, frame_size);
}
static void gsm0710_advanced_remove(GAtMux *mux)
{
struct gsm0710_data *gd = g_at_mux_get_data(mux);
g_free(gd);
g_at_mux_set_data(mux, NULL);
}
static gboolean gsm0710_advanced_startup(GAtMux *mux)
{
guint8 frame[8]; /* Account for escapes */
int frame_size;
frame_size = gsm0710_advanced_fill_frame(frame, 0,
GSM0710_OPEN_CHANNEL, NULL, 0);
g_at_mux_raw_write(mux, frame, frame_size);
return TRUE;
}
static gboolean gsm0710_advanced_shutdown(GAtMux *mux)
{
guint8 frame[8]; /* Account for escapes */
int frame_size;
frame_size = gsm0710_advanced_fill_frame(frame, 0,
GSM0710_CLOSE_CHANNEL, NULL, 0);
g_at_mux_raw_write(mux, frame, frame_size);
return TRUE;
}
static gboolean gsm0710_advanced_open_dlc(GAtMux *mux, guint8 dlc)
{
guint8 frame[8]; /* Account for escapes */
int frame_size;
frame_size = gsm0710_advanced_fill_frame(frame, dlc,
GSM0710_OPEN_CHANNEL, NULL, 0);
g_at_mux_raw_write(mux, frame, frame_size);
return TRUE;
}
static gboolean gsm0710_advanced_close_dlc(GAtMux *mux, guint8 dlc)
{
guint8 frame[8]; /* Account for escapes */
int frame_size;
frame_size = gsm0710_advanced_fill_frame(frame, dlc,
GSM0710_CLOSE_CHANNEL, NULL, 0);
g_at_mux_raw_write(mux, frame, frame_size);
return TRUE;
}
static int gsm0710_advanced_feed_data(GAtMux *mux, void *data, int len)
{
int total = 0;
int nread;
guint8 dlc;
guint8 ctrl;
guint8 *frame;
int frame_len;
do {
frame = NULL;
nread = gsm0710_advanced_extract_frame(data, len, &dlc, &ctrl,
&frame, &frame_len);
total += nread;
data += nread;
len -= nread;
if (frame == NULL)
break;
gsm0710_packet(mux, dlc, ctrl, frame, frame_len,
gsm0710_advanced_write_frame);
} while (nread > 0);
return total;
}
static void gsm0710_advanced_set_status(GAtMux *mux, guint8 dlc, guint8 status)
{
struct gsm0710_data *gd = g_at_mux_get_data(mux);
guint8 *frame = alloca(gd->frame_size * 2 + 7);
int frame_size;
COMPOSE_STATUS_FRAME(data, dlc, status);
frame_size = gsm0710_advanced_fill_frame(frame, 0,
GSM0710_DATA, data, 4);
g_at_mux_raw_write(mux, frame, frame_size);
}
static void gsm0710_advanced_write(GAtMux *mux, guint8 dlc,
const void *data, int towrite)
{
struct gsm0710_data *gd = g_at_mux_get_data(mux);
guint8 *frame = alloca(gd->frame_size * 2 + 7);
int max;
int frame_size;
while (towrite > 0) {
max = MIN(towrite, gd->frame_size);
frame_size = gsm0710_advanced_fill_frame(frame, dlc,
GSM0710_DATA, data, max);
g_at_mux_raw_write(mux, frame, frame_size);
data = data + max;
towrite -= max;
}
}
static GAtMuxDriver gsm0710_advanced_driver = {
.remove = gsm0710_advanced_remove,
.startup = gsm0710_advanced_startup,
.shutdown = gsm0710_advanced_shutdown,
.open_dlc = gsm0710_advanced_open_dlc,
.close_dlc = gsm0710_advanced_close_dlc,
.feed_data = gsm0710_advanced_feed_data,
.set_status = gsm0710_advanced_set_status,
.write = gsm0710_advanced_write,
};
GAtMux *g_at_mux_new_gsm0710_advanced(GIOChannel *channel, int frame_size)
{
GAtMux *mux;
struct gsm0710_data *gd;
mux = g_at_mux_new(channel, &gsm0710_advanced_driver);
if (mux == NULL)
return NULL;
gd = g_new0(struct gsm0710_data, 1);
gd->frame_size = frame_size;
g_at_mux_set_data(mux, gd);
return mux;
}