--- a/ChangeLog Tue Jun 17 22:24:37 2014 -0700
+++ b/ChangeLog Tue Jun 17 23:21:07 2014 -0700
@@ -74,6 +74,9 @@
* Fix loading Google Talk and Facebook XMPP accounts.
Windows-Specific Changes:
+ * Don't allow overwriting arbitrary files on the file system when the + user installs a smiley theme via drag-and-drop. (Discovered by Yves + Younan of Sourcefire VRT) * Updates to dependencies:
* NSS 3.16 and NSPR 4.10.4
@@ -83,10 +86,20 @@
* Updated internal libgadu to version 1.12.0.
+ * Fix potential remote crash parsing server message that indicates that + a large amount of memory should be allocated. (Discovered by Yves Younan + and Richard Johnson of Sourcefire VRT) (CVE-2014-NNNN) * Fix a possible leak of unencrypted data when using /me command
with OTR. (Thijs Alkemade) (#15750)
+ * Fix potential remote crash parsing a malformed emoticon response. + (Discovered by Yves Younan and Richard Johnson of Sourcefire VRT) * Fix Facebook XMPP roster quirks. (#15041, #15957)
--- a/libpurple/protocols/mxit/markup.c Tue Jun 17 22:24:37 2014 -0700
+++ b/libpurple/protocols/mxit/markup.c Tue Jun 17 23:21:07 2014 -0700
@@ -165,16 +165,22 @@
* Extract an ASN.1 formatted length field from the data.
* @param data The source data
+ * @param data_len Length of data * @param size The extracted length
* @return The number of bytes extracted
-static unsigned int asn_getlength( const gchar* data, int* size )
+static unsigned int asn_getlength( const gchar* data, gsize data_len, int* size ) + /* missing first byte! */ /* first byte specifies the number of bytes in the length */
bytes = ( data[0] & ~0x80 );
if ( bytes > sizeof( unsigned int ) ) {
@@ -183,6 +189,11 @@
+ if ( data_len - 1 < bytes ) { /* parse out the actual length */
for ( i = 0; i < bytes; i++ ) {
@@ -199,15 +210,21 @@
* Extract an ASN.1 formatted UTF-8 string field from the data.
* @param data The source data
+ * @param data_len Length of data * @param type Expected type of string
* @param utf8 The extracted string. Must be deallocated by caller.
* @return The number of bytes extracted
-static int asn_getUtf8( const gchar* data, gchar type, char** utf8 )
+static int asn_getUtf8( const gchar* data, gsize data_len, gchar type, char** utf8 ) + /* missing type or length! */ /* validate the field type [1 byte] */
/* this is not a utf-8 string! */
@@ -216,6 +233,11 @@
len = (guint8)data[1]; /* length field [1 byte] */
+ if ( data_len - 2 < len ) { + /* not enough bytes left in data! */ out_str = g_malloc(len + 1);
memcpy(out_str, &data[2], len); /* data field */
@@ -501,7 +523,7 @@
/* validate that the returned data starts with the magic constant that indicates it is a custom emoticon */
- if ( memcmp( MXIT_FRAME_MAGIC, &data[pos], strlen( MXIT_FRAME_MAGIC ) ) != 0 ) {
+ if ( len - pos < strlen( MXIT_FRAME_MAGIC ) || memcmp( MXIT_FRAME_MAGIC, &data[pos], strlen( MXIT_FRAME_MAGIC ) ) != 0 ) { purple_debug_error( MXIT_PLUGIN_ID, "Invalid emoticon received from wapsite (bad magic)\n" );
@@ -515,7 +537,7 @@
/* get the frame image data length */
- res = asn_getlength( &data[pos], &em_size );
+ res = asn_getlength( &data[pos], len - pos, &em_size ); purple_debug_error( MXIT_PLUGIN_ID, "Invalid emoticon received from wapsite (bad frame length)\n" );
@@ -526,7 +548,7 @@
/* utf-8 (emoticon name) */
- res = asn_getUtf8( &data[pos], 0x0C, &str );
+ res = asn_getUtf8( &data[pos], len - pos, 0x0C, &str ); purple_debug_error( MXIT_PLUGIN_ID, "Invalid emoticon received from wapsite (bad name string)\n" );
@@ -539,7 +561,7 @@
/* utf-8 (emoticon shortcut) */
- res = asn_getUtf8( &data[pos], 0x81, &str );
+ res = asn_getUtf8( &data[pos], len - pos, 0x81, &str ); purple_debug_error( MXIT_PLUGIN_ID, "Invalid emoticon received from wapsite (bad shortcut string)\n" );
@@ -551,7 +573,7 @@
/* validate the image data type */
- if ( data[pos] != '\x82' ) {
+ if ( len - pos < 1 || data[pos] != '\x82' ) { purple_debug_error( MXIT_PLUGIN_ID, "Invalid emoticon received from wapsite (bad data type)\n" );
@@ -559,7 +581,7 @@
/* get the data length */
- res = asn_getlength( &data[pos], &em_size );
+ res = asn_getlength( &data[pos], len - pos, &em_size ); purple_debug_error( MXIT_PLUGIN_ID, "Invalid emoticon received from wapsite (bad data length)\n" );
@@ -571,6 +593,13 @@
purple_debug_info( MXIT_PLUGIN_ID, "read the length '%i'\n", em_size );
+ if ( len - pos < em_size ) { + /* not enough bytes left in data! */ + purple_debug_error( MXIT_PLUGIN_ID, "Invalid emoticon received from wapsite (data length too long)\n"); /* strip the mxit markup tags from the emoticon id (eg, .{XY} -> XY) */
if ( ( em_id[0] == '.' ) && ( em_id[1] == '{' ) ) {
char emo[MXIT_MAX_EMO_ID + 1];
--- a/libpurple/protocols/novell/nmevent.c Tue Jun 17 22:24:37 2014 -0700
+++ b/libpurple/protocols/novell/nmevent.c Tue Jun 17 23:21:07 2014 -0700
@@ -149,7 +149,7 @@
/* Read the conference guid */
rc = nm_read_uint32(conn, &size);
- if (size == MAX_UINT32) return NMERR_PROTOCOL;
+ if (size > 1000) return NMERR_PROTOCOL; guid = g_new0(char, size + 1);
@@ -164,7 +164,7 @@
/* Read the message text */
rc = nm_read_uint32(conn, &size);
- if (size == MAX_UINT32) return NMERR_PROTOCOL;
+ if (size > 100000) return NMERR_PROTOCOL; msg = g_new0(char, size + 1);
@@ -270,7 +270,7 @@
/* Read the conference guid */
rc = nm_read_uint32(conn, &size);
- if (size == MAX_UINT32) return NMERR_PROTOCOL;
+ if (size > 1000) return NMERR_PROTOCOL; guid = g_new0(char, size + 1);
@@ -280,7 +280,7 @@
/* Read the the message */
rc = nm_read_uint32(conn, &size);
- if (size == MAX_UINT32) return NMERR_PROTOCOL;
+ if (size > 100000) return NMERR_PROTOCOL; msg = g_new0(char, size + 1);
@@ -349,7 +349,7 @@
/* Read the conference guid */
rc = nm_read_uint32(conn, &size);
- if (size == MAX_UINT32) return NMERR_PROTOCOL;
+ if (size > 1000) return NMERR_PROTOCOL; guid = g_new0(char, size + 1);
@@ -401,7 +401,7 @@
/* Read the conference guid */
rc = nm_read_uint32(conn, &size);
- if (size == MAX_UINT32) return NMERR_PROTOCOL;
+ if (size > 1000) return NMERR_PROTOCOL; guid = g_new0(char, size + 1);
@@ -440,7 +440,7 @@
/* Read the conference guid */
rc = nm_read_uint32(conn, &size);
- if (size == MAX_UINT32) return NMERR_PROTOCOL;
+ if (size > 1000) return NMERR_PROTOCOL; guid = g_new0(char, size + 1);
@@ -490,7 +490,7 @@
/* Read the conference guid */
rc = nm_read_uint32(conn, &size);
- if (size == MAX_UINT32) return NMERR_PROTOCOL;
+ if (size > 1000) return NMERR_PROTOCOL; guid = g_new0(char, size + 1);
@@ -530,7 +530,7 @@
/* Read the conference guid */
rc = nm_read_uint32(conn, &size);
- if (size == MAX_UINT32) return NMERR_PROTOCOL;
+ if (size > 1000) return NMERR_PROTOCOL; guid = g_new0(char, size + 1);
@@ -589,7 +589,7 @@
/* Read the conference guid */
rc = nm_read_uint32(conn, &size);
- if (size == MAX_UINT32) return NMERR_PROTOCOL;
+ if (size > 1000) return NMERR_PROTOCOL; guid = g_new0(char, size + 1);
@@ -632,7 +632,7 @@
/* Read the status text */
rc = nm_read_uint32(conn, &size);
- if (size == MAX_UINT32) return NMERR_PROTOCOL;
+ if (size > 10000) return NMERR_PROTOCOL; text = g_new0(char, size + 1);
@@ -670,7 +670,7 @@
/* Read the conference guid */
rc = nm_read_uint32(conn, &size);
- if (size == MAX_UINT32) return NMERR_PROTOCOL;
+ if (size > 1000) return NMERR_PROTOCOL; guid = g_new0(char, size + 1);
@@ -833,7 +833,10 @@
/* Read the event source */
rc = nm_read_uint32(conn, &size);
+ /* Size is larger than our 1MB sanity check. Ignore it. */ source = g_new0(char, size);
rc = nm_read_all(conn, source, size);
--- a/pidgin/win32/untar.c Tue Jun 17 22:24:37 2014 -0700
+++ b/pidgin/win32/untar.c Tue Jun 17 23:21:07 2014 -0700
@@ -122,8 +122,6 @@
static FILE *infp = NULL; /* input byte stream */
static FILE *outfp = NULL; /* output stream, for file currently being extracted */
static Ulong_t outsize = 0; /* number of bytes remainin in file currently being extracted */
-static char **only = NULL; /* array of filenames to extract/list */
-static guint nonlys = 0; /* number of filenames in "only" array; 0=extract all */
static int didabs = 0; /* were any filenames affected by the absence of -p? */
static untar_opt untarops = 0; /* Untar options */
@@ -323,7 +321,7 @@
/* list files in an archive, and optionally extract them as well */
static int untar_block(Uchar_t *blk) {
- static char nbuf[256];/* storage space for prefix+name, combined */
+ static char nbuf[4096];/* storage space for prefix+name, combined */ static char *name,*n2;/* prefix and name, combined */
static int first = 1;/* Boolean: first block of archive? */
long sum; /* checksum for this block */
@@ -392,24 +390,35 @@
/* combine prefix and filename */
memset(nbuf, 0, sizeof nbuf);
- strncpy(name, (tblk)->prefix, sizeof (tblk)->prefix);
- strncat(name + strlen(name), (tblk)->filename,
- sizeof (tblk)->filename);
+ snprintf(nbuf, sizeof(nbuf), "%s/%s", + (tblk)->prefix, (tblk)->filename); - strncpy(name, (tblk)->filename,
- sizeof (tblk)->filename);
+ g_strlcpy(nbuf, (tblk)->filename, + /* Possibly strip the drive from the path */ + /* If the path contains a colon, assume everything before the + * colon is intended to be a drive name and ignore it. This + * should be just a single drive letter, but it should be safe + * to drop it even if it's longer. */ + const char *lastcolon = strrchr(nbuf, ':'); + memmove(nbuf, lastcolon, strlen(lastcolon) + 1); + didabs = 1; /* Path was changed from absolute to relative */ /* Convert any backslashes to forward slashes, and guard
* against doubled-up slashes. (Some DOS versions of "tar"
* get this wrong.) Also strip off leading slashes.
if (!ABSPATH && (*name == '/' || *name == '\\'))
for (n2 = nbuf; *name; name++)
@@ -474,26 +483,6 @@
- /* If we have an "only" list, and this file isn't in it,
- && strcmp(only[i], nbuf)
- && (strncmp(only[i], nbuf, strlen(only[i]))
- || nbuf[strlen(only[i])] != '/');
@@ -520,18 +509,19 @@
else if (mkdir(nbuf, mode) == 0)
else if (g_mkdir(nbuf, 0755) == 0)
- untar_verbose("%s\n", n2);
+ untar_verbose("%s\n", tmp);