Sat, 12 Apr 2014 22:30:26 -0700
Merge from release-2.x.y branch. No manual merges.
| ChangeLog | file | annotate | diff | comparison | revisions | |
| libpurple/protocols/mxit/markup.c | file | annotate | diff | comparison | revisions |
--- a/ChangeLog Sun Apr 13 02:17:31 2014 +0200 +++ b/ChangeLog Sat Apr 12 22:30:26 2014 -0700 @@ -69,15 +69,28 @@ * Doxygen has been replaced by gtk-doc for generating documentation. version 2.10.10 (?/?/?): + 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 + Finch: * Fix build against Python 3. (Ed Catmur) (#15969) Gadu-Gadu: * Updated internal libgadu to version 1.12.0-rc2. - Windows-Specific Changes: - * Updates to dependencies: - * NSS 3.16 and NSPR 4.10.4 + Groupwise: + * 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) + + MXit: + * Fix potential remote crash parsing a malformed emoticon response. + (Discovered by Yves Younan and Richard Johnson of Sourcefire VRT) + (CVE-2014-NNNN) version 2.10.9 (2/2/2014): XMPP:
--- a/libpurple/protocols/mxit/markup.c Sun Apr 13 02:17:31 2014 +0200 +++ b/libpurple/protocols/mxit/markup.c Sat Apr 12 22:30:26 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 ) { unsigned int len = 0; unsigned char bytes; unsigned char byte; int i; + if ( data_len < 1 ) { + /* missing first byte! */ + return -1; + } + /* first byte specifies the number of bytes in the length */ bytes = ( data[0] & ~0x80 ); if ( bytes > sizeof( unsigned int ) ) { @@ -183,6 +189,11 @@ } data++; + if ( data_len - 1 < bytes ) { + /* missing length! */ + return -1; + } + /* parse out the actual length */ for ( i = 0; i < bytes; i++ ) { byte = data[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 ) { unsigned int len; gchar *out_str; + if ( data_len < 2 ) { + /* missing type or length! */ + return -1; + } + /* validate the field type [1 byte] */ if ( data[0] != type ) { /* 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! */ + return -1; + } + out_str = g_malloc(len + 1); memcpy(out_str, &data[2], len); /* data field */ out_str[len] = '\0'; @@ -501,7 +523,7 @@ #endif /* 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" ); goto done; } @@ -515,7 +537,7 @@ pos++; /* get the frame image data length */ - res = asn_getlength( &data[pos], &em_size ); + res = asn_getlength( &data[pos], len - pos, &em_size ); if ( res <= 0 ) { purple_debug_error( MXIT_PLUGIN_ID, "Invalid emoticon received from wapsite (bad frame length)\n" ); goto done; @@ -526,7 +548,7 @@ #endif /* utf-8 (emoticon name) */ - res = asn_getUtf8( &data[pos], 0x0C, &str ); + res = asn_getUtf8( &data[pos], len - pos, 0x0C, &str ); if ( res <= 0 ) { purple_debug_error( MXIT_PLUGIN_ID, "Invalid emoticon received from wapsite (bad name string)\n" ); goto done; @@ -539,7 +561,7 @@ str = NULL; /* utf-8 (emoticon shortcut) */ - res = asn_getUtf8( &data[pos], 0x81, &str ); + res = asn_getUtf8( &data[pos], len - pos, 0x81, &str ); if ( res <= 0 ) { purple_debug_error( MXIT_PLUGIN_ID, "Invalid emoticon received from wapsite (bad shortcut string)\n" ); goto done; @@ -551,7 +573,7 @@ em_id = str; /* 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" ); g_free( em_id ); goto done; @@ -559,7 +581,7 @@ pos++; /* get the data length */ - res = asn_getlength( &data[pos], &em_size ); + res = asn_getlength( &data[pos], len - pos, &em_size ); if ( res <= 0 ) { /* bad frame length */ 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 ); #endif + 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"); + g_free( em_id ); + goto done; + } + /* 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 Sun Apr 13 02:17:31 2014 +0200 +++ b/libpurple/protocols/novell/nmevent.c Sat Apr 12 22:30:26 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; if (rc == NM_OK) { guid = g_new0(char, size + 1); @@ -164,7 +164,7 @@ /* Read the message text */ if (rc == NM_OK) { rc = nm_read_uint32(conn, &size); - if (size == MAX_UINT32) return NMERR_PROTOCOL; + if (size > 100000) return NMERR_PROTOCOL; if (rc == NM_OK) { 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; if (rc == NM_OK) { guid = g_new0(char, size + 1); @@ -280,7 +280,7 @@ /* Read the the message */ if (rc == NM_OK) { rc = nm_read_uint32(conn, &size); - if (size == MAX_UINT32) return NMERR_PROTOCOL; + if (size > 100000) return NMERR_PROTOCOL; if (rc == NM_OK) { 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; if (rc == NM_OK) { 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; if (rc == NM_OK) { 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; if (rc == NM_OK) { 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; if (rc == NM_OK) { 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; if (rc == NM_OK) { 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; if (rc == NM_OK) { 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; if (rc == NM_OK) { 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; if (rc == NM_OK) { guid = g_new0(char, size + 1); @@ -833,7 +833,10 @@ /* Read the event source */ rc = nm_read_uint32(conn, &size); if (rc == NM_OK) { - if (size > 0) { + if (size > 1000000) { + /* Size is larger than our 1MB sanity check. Ignore it. */ + rc = NMERR_PROTOCOL; + } else { source = g_new0(char, size); rc = nm_read_all(conn, source, size);
--- a/pidgin/win32/untar.c Sun Apr 13 02:17:31 2014 +0200 +++ b/pidgin/win32/untar.c Sat Apr 12 22:30:26 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 int 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); - name = nbuf; if ((tblk)->prefix[0]) { - strncpy(name, (tblk)->prefix, sizeof (tblk)->prefix); - strcat(name, "/"); - strncat(name + strlen(name), (tblk)->filename, - sizeof (tblk)->filename); + snprintf(nbuf, sizeof(nbuf), "%s/%s", + (tblk)->prefix, (tblk)->filename); } else { - strncpy(name, (tblk)->filename, - sizeof (tblk)->filename); + g_strlcpy(nbuf, (tblk)->filename, + sizeof (nbuf)); + } + + /* Possibly strip the drive from the path */ + if (!ABSPATH) { + /* 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, ':'); + if (lastcolon) { + 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. */ + name = nbuf; if (!ABSPATH && (*name == '/' || *name == '\\')) didabs = 1; for (n2 = nbuf; *name; name++) @@ -474,26 +483,6 @@ } #endif - /* If we have an "only" list, and this file isn't in it, - * then skip it. - */ - if (nonlys > 0) - { - for (i = 0; - i < nonlys - && strcmp(only[i], nbuf) - && (strncmp(only[i], nbuf, strlen(only[i])) - || nbuf[strlen(only[i])] != '/'); - i++) - { - } - if (i >= nonlys) - { - outfp = NULL; - return 1; - } - } - /* list the file */ if (VERBOSE) untar_verbose("%c %s", @@ -520,18 +509,19 @@ */ if (tblk->type == '5') { + char *tmp; if (LISTING) - n2 = " directory"; + tmp = " directory"; #ifdef _POSIX_SOURCE else if (mkdir(nbuf, mode) == 0) #else else if (g_mkdir(nbuf, 0755) == 0) #endif - n2 = " created"; + tmp = " created"; else - n2 = " ignored"; + tmp = " ignored"; if (VERBOSE) - untar_verbose("%s\n", n2); + untar_verbose("%s\n", tmp); return 1; }