Index: ChangeLog =================================================================== --- ChangeLog (revision 3787) +++ ChangeLog (revision 3788) @@ -1,3 +1,13 @@ +Mon Apr 14 21:35:11 CEST 2008 (tk) +---------------------------------- + * Check in 0.93 patches: + - libclamunrar: bb#541 (RAR - Version required to extract - Evasion) + - libclamav/spin.c: bb#876 (PeSpin Heap Overflow Vulnerability) + - libclamav/pe.c: bb#878 (Upack Buffer Overflow Vulnerability) + - libclamav/message.c: bb#881 (message.c: read beyond allocated region) + - libclamav/unarj.c: bb#897 (ARJ: Sample from CERT-FI hangs clamav) + - libclamunrar: bb#898 (RAR crashes on some fuzzed files from CERT-FI) + Mon Apr 14 13:19:17 CEST 2008 (tk) ---------------------------------- * test: add clam-aspack.exe, clam-pespin.exe and clam-upx.exe (bb#902) Index: libclamav/others.c =================================================================== --- libclamav/others.c (revision 3787) +++ libclamav/others.c (revision 3788) @@ -87,7 +87,7 @@ #define P_tmpdir "C:\\WINDOWS\\TEMP" #endif -#define CL_FLEVEL 28 /* don't touch it */ +#define CL_FLEVEL 29 /* don't touch it */ uint8_t cli_debug_flag = 0, cli_leavetemps_flag = 0; Index: libclamav/message.c =================================================================== --- libclamav/message.c (revision 3787) +++ libclamav/message.c (revision 3788) @@ -2563,6 +2563,7 @@ in++; continue; } + *p = '\0'; break; case '=': /*strcpy(p, in);*/ Index: libclamav/pe.c =================================================================== --- libclamav/pe.c (revision 3787) +++ libclamav/pe.c (revision 3788) @@ -1261,7 +1261,7 @@ CLI_UNPSIZELIMITS("Upack", MAX(MAX(dsize, ssize), exe_sections[1].ursz)); - if (exe_sections[1].rva - off > dsize || exe_sections[1].rva - off > dsize - exe_sections[1].ursz || (upack && (exe_sections[2].rva - exe_sections[0].rva > dsize || exe_sections[2].rva - exe_sections[0].rva > dsize - ssize)) || ssize > dsize) { + if (!CLI_ISCONTAINED(0, dsize, exe_sections[1].rva - off, exe_sections[1].ursz) || (upack && !CLI_ISCONTAINED(0, dsize, exe_sections[2].rva - exe_sections[0].rva, ssize)) || ssize > dsize) { cli_dbgmsg("Upack: probably malformed pe-header, skipping to next unpacker\n"); break; } Index: libclamav/unarj.c =================================================================== --- libclamav/unarj.c (revision 3787) +++ libclamav/unarj.c (revision 3788) @@ -162,6 +162,7 @@ unsigned char pt_len[NPT]; unsigned char sub_bit_buf; uint16_t pt_table[PTABLESIZE]; + int status; } arj_decode_t; static int fill_buf(arj_decode_t *decode_data, int n) @@ -172,6 +173,7 @@ if (decode_data->comp_size != 0) { decode_data->comp_size--; if (cli_readn(decode_data->fd, &decode_data->sub_bit_buf, 1) != 1) { + decode_data->status = CL_EIO; return CL_EIO; } } else { @@ -230,6 +232,7 @@ for (i = 0; (int)i < nchar; i++) { if (bitlen[i] >= 17) { cli_dbgmsg("UNARJ: bounds exceeded\n"); + decode_data->status = CL_EARJ; return CL_EARJ; } count[bitlen[i]]++; @@ -240,12 +243,14 @@ start[i+1] = start[i] + (count[i] << (16 - i)); } if (start[17] != (unsigned short) (1 << 16)) { + decode_data->status = CL_EARJ; return CL_EARJ; } jutbits = 16 - tablebits; if (tablebits >= 17) { cli_dbgmsg("UNARJ: bounds exceeded\n"); + decode_data->status = CL_EARJ; return CL_EARJ; } for (i = 1; (int)i <= tablebits; i++) { @@ -263,6 +268,7 @@ while (i != k) { if (i >= tablesize) { cli_dbgmsg("UNARJ: bounds exceeded\n"); + decode_data->status = CL_EARJ; return CL_EARJ; } table[i++] = 0; @@ -277,12 +283,14 @@ } if (len >= 17) { cli_dbgmsg("UNARJ: bounds exceeded\n"); + decode_data->status = CL_EARJ; return CL_EARJ; } k = start[len]; nextcode = k + weight[len]; if ((int)len <= tablebits) { if (nextcode > (unsigned int) tablesize) { + decode_data->status = CL_EARJ; return CL_EARJ; } for (i = start[len]; i < nextcode; i++) { @@ -295,6 +303,7 @@ if (*p == 0) { if (avail >= (2 * NC - 1)) { cli_dbgmsg("UNARJ: bounds exceeded\n"); + decode_data->status = CL_EARJ; return CL_EARJ; } decode_data->right[avail] = decode_data->left[avail] = 0; @@ -302,6 +311,7 @@ } if (*p >= (2 * NC - 1)) { cli_dbgmsg("UNARJ: bounds exceeded\n"); + decode_data->status = CL_EARJ; return CL_EARJ; } if (k & mask) { @@ -319,7 +329,7 @@ return CL_SUCCESS; } -static void read_pt_len(arj_decode_t *decode_data, int nn, int nbit, int i_special) +static int read_pt_len(arj_decode_t *decode_data, int nn, int nbit, int i_special) { int i, n; short c; @@ -329,7 +339,8 @@ if (n == 0) { if (nn > NPT) { cli_dbgmsg("UNARJ: bounds exceeded\n"); - return; + decode_data->status = CL_EARJ; + return CL_EARJ; } c = arj_getbits(decode_data, nbit); for (i = 0; i < nn; i++) { @@ -350,9 +361,15 @@ } } fill_buf(decode_data, (c < 7) ? 3 : (int)(c - 3)); + if (decode_data->status != CL_SUCCESS) { + return decode_data->status; + } decode_data->pt_len[i++] = (unsigned char) c; if (i == i_special) { c = arj_getbits(decode_data, 2); + if (decode_data->status != CL_SUCCESS) { + return decode_data->status; + } while ((--c >= 0) && (i < NPT)) { decode_data->pt_len[i++] = 0; } @@ -361,8 +378,11 @@ while ((i < nn) && (i < NPT)) { decode_data->pt_len[i++] = 0; } - make_table(decode_data, nn, decode_data->pt_len, 8, decode_data->pt_table, PTABLESIZE); + if (make_table(decode_data, nn, decode_data->pt_len, 8, decode_data->pt_table, PTABLESIZE) != CL_SUCCESS) { + return CL_EARJ; + } } + return CL_SUCCESS; } static int read_c_len(arj_decode_t *decode_data) @@ -371,8 +391,14 @@ unsigned short mask; n = arj_getbits(decode_data, CBIT); + if (decode_data->status != CL_SUCCESS) { + return decode_data->status; + } if (n == 0) { c = arj_getbits(decode_data, CBIT); + if (decode_data->status != CL_SUCCESS) { + return decode_data->status; + } for (i = 0; i < NC; i++) { decode_data->c_len[i] = 0; } @@ -388,6 +414,7 @@ do { if (c >= (2 * NC - 1)) { cli_warnmsg("ERROR: bounds exceeded\n"); + decode_data->status = CL_EFORMAT; return CL_EFORMAT; } if (decode_data->bit_buf & mask) { @@ -400,9 +427,13 @@ } if (c >= 19) { cli_dbgmsg("UNARJ: bounds exceeded\n"); + decode_data->status = CL_EARJ; return CL_EARJ; } fill_buf(decode_data, (int)(decode_data->pt_len[c])); + if (decode_data->status != CL_SUCCESS) { + return decode_data->status; + } if (c <= 2) { if (c == 0) { c = 1; @@ -411,9 +442,13 @@ } else { c = arj_getbits(decode_data, CBIT) + 20; } + if (decode_data->status != CL_SUCCESS) { + return decode_data->status; + } while (--c >= 0) { if (i >= NC) { cli_warnmsg("ERROR: bounds exceeded\n"); + decode_data->status = CL_EFORMAT; return CL_EFORMAT; } decode_data->c_len[i++] = 0; @@ -421,6 +456,7 @@ } else { if (i >= NC) { cli_warnmsg("ERROR: bounds exceeded\n"); + decode_data->status = CL_EFORMAT; return CL_EFORMAT; } decode_data->c_len[i++] = (unsigned char) (c - 2); @@ -429,7 +465,9 @@ while (i < NC) { decode_data->c_len[i++] = 0; } - make_table(decode_data, NC, decode_data->c_len, 12, decode_data->c_table, CTABLESIZE); + if (make_table(decode_data, NC, decode_data->c_len, 12, decode_data->c_table, CTABLESIZE) != CL_SUCCESS) { + return CL_EARJ; + } } return CL_SUCCESS; } @@ -452,6 +490,7 @@ do { if (j >= (2 * NC - 1)) { cli_warnmsg("ERROR: bounds exceeded\n"); + decode_data->status = CL_EARJ; return 0; } if (decode_data->bit_buf & mask) { @@ -476,6 +515,7 @@ do { if (j >= (2 * NC - 1)) { cli_warnmsg("ERROR: bounds exceeded\n"); + decode_data->status = CL_EARJ; return 0; } if (decode_data->bit_buf & mask) { @@ -510,8 +550,10 @@ decode_data.comp_size = metadata->comp_size; ret = decode_start(&decode_data); if (ret != CL_SUCCESS) { + free(decode_data.text); return ret; } + decode_data.status = CL_SUCCESS; while (count < metadata->orig_size) { if ((chr = decode_c(&decode_data)) <= UCHAR_MAX) { @@ -519,7 +561,10 @@ count++; if (++out_ptr >= DDICSIZ) { out_ptr = 0; - write_text(metadata->ofd, decode_data.text, DDICSIZ); + if (write_text(metadata->ofd, decode_data.text, DDICSIZ) != CL_SUCCESS) { + free(decode_data.text); + return CL_EIO; + } } } else { j = chr - (UCHAR_MAX + 1 - THRESHOLD); @@ -541,7 +586,10 @@ decode_data.text[out_ptr] = decode_data.text[i]; if (++out_ptr >= DDICSIZ) { out_ptr = 0; - write_text(metadata->ofd, decode_data.text, DDICSIZ); + if (write_text(metadata->ofd, decode_data.text, DDICSIZ) != CL_SUCCESS) { + free(decode_data.text); + return CL_EIO; + } } if (++i >= DDICSIZ) { i = 0; @@ -549,6 +597,10 @@ } } } + if (decode_data.status != CL_SUCCESS) { + free(decode_data.text); + return decode_data.status; + } } if (out_ptr != 0) { write_text(metadata->ofd, decode_data.text, out_ptr); @@ -625,21 +677,37 @@ return ret; } decode_data.getlen = decode_data.getbuf = 0; - + decode_data.status = CL_SUCCESS; + while (count < metadata->orig_size) { chr = decode_len(&decode_data); + if (decode_data.status != CL_SUCCESS) { + free(decode_data.text); + return decode_data.status; + } if (chr == 0) { ARJ_GETBITS(dd, chr, CHAR_BIT); + if (decode_data.status != CL_SUCCESS) { + free(decode_data.text); + return decode_data.status; + } decode_data.text[out_ptr] = (unsigned char) chr; count++; if (++out_ptr >= DDICSIZ) { out_ptr = 0; - write_text(metadata->ofd, decode_data.text, DDICSIZ); + if (write_text(metadata->ofd, decode_data.text, DDICSIZ) != CL_SUCCESS) { + free(decode_data.text); + return CL_EIO; + } } } else { j = chr - 1 + THRESHOLD; count += j; pos = decode_ptr(&decode_data); + if (decode_data.status != CL_SUCCESS) { + free(decode_data.text); + return decode_data.status; + } if ((i = out_ptr - pos - 1) < 0) { i += DDICSIZ; } @@ -651,7 +719,10 @@ decode_data.text[out_ptr] = decode_data.text[i]; if (++out_ptr >= DDICSIZ) { out_ptr = 0; - write_text(metadata->ofd, decode_data.text, DDICSIZ); + if (write_text(metadata->ofd, decode_data.text, DDICSIZ) != CL_SUCCESS) { + free(decode_data.text); + return CL_EIO; + } } if (++i >= DDICSIZ) { i = 0; @@ -1012,10 +1083,10 @@ case 1: case 2: case 3: - decode(fd, metadata); + ret = decode(fd, metadata); break; case 4: - decode_f(fd, metadata); + ret = decode_f(fd, metadata); break; default: ret = CL_EFORMAT; Index: libclamav/spin.c =================================================================== --- libclamav/spin.c (revision 3787) +++ libclamav/spin.c (revision 3788) @@ -435,7 +435,7 @@ /* len = cli_readint32(ep+0x2fc8); -- Using vsizes instead */ for (j=0; j key32) + if (sections[j].rva <= key32 && key32-sections[j].rva < sections[j].vsz && CLI_ISCONTAINED(src + sections[j].raw, sections[j].rsz, src + sections[j].raw, key32 - sections[j].rva)) break; } Index: libclamunrar/unrarppm.c =================================================================== --- libclamunrar/unrarppm.c (revision 3787) +++ libclamunrar/unrarppm.c (revision 3788) @@ -604,6 +604,9 @@ if ((p=pc->con_ut.u.stats)->symbol != up_state.symbol) { do { p++; + if ((void *)p > (void *) ppm_data->sub_alloc.heap_end) { + return NULL; + } } while (p->symbol != up_state.symbol); } cf = p->freq - 1; @@ -926,6 +929,13 @@ sub_allocator_stop_sub_allocator(&ppm_data->sub_alloc); } +void ppm_cleanup(ppm_data_t *ppm_data) +{ + sub_allocator_stop_sub_allocator(&ppm_data->sub_alloc); + sub_allocator_start_sub_allocator(&ppm_data->sub_alloc, 1); + start_model_rare(ppm_data, 2); +} + int ppm_decode_init(ppm_data_t *ppm_data, int fd, unpack_data_t *unpack_data, int *EscChar) { int max_order, Reset, MaxMB; Index: libclamunrar/unrarppm.h =================================================================== --- libclamunrar/unrarppm.h (revision 3787) +++ libclamunrar/unrarppm.h (revision 3788) @@ -111,6 +111,7 @@ } ppm_data_t; +void ppm_cleanup(ppm_data_t *ppm_data); int ppm_decode_init(ppm_data_t *ppm_data, int fd, struct unpack_data_tag *unpack_data, int *EscChar); int ppm_decode_char(ppm_data_t *ppm_data, int fd, struct unpack_data_tag *unpack_data); void ppm_constructor(ppm_data_t *ppm_data); Index: libclamunrar/unrar.c =================================================================== --- libclamunrar/unrar.c (revision 3787) +++ libclamunrar/unrar.c (revision 3788) @@ -886,18 +886,23 @@ memset(unpack_data->old_dist, 0, sizeof(unpack_data->old_dist)); unpack_data->old_dist_ptr= 0; memset(unpack_data->unp_old_table, 0, sizeof(unpack_data->unp_old_table)); + memset(&unpack_data->LD, 0, sizeof(unpack_data->LD)); + memset(&unpack_data->DD, 0, sizeof(unpack_data->DD)); + memset(&unpack_data->LDD, 0, sizeof(unpack_data->LDD)); + memset(&unpack_data->RD, 0, sizeof(unpack_data->RD)); + memset(&unpack_data->BD, 0, sizeof(unpack_data->BD)); unpack_data->last_dist= 0; unpack_data->last_length=0; unpack_data->ppm_esc_char = 2; unpack_data->unp_ptr = 0; unpack_data->wr_ptr = 0; + unpack_data->unp_block_type = BLOCK_LZ; rar_init_filters(unpack_data); } unpack_data->in_bit = 0; unpack_data->in_addr = 0; unpack_data->read_top = 0; - unpack_data->ppm_error = FALSE; - + unpack_data->read_border = 0; unpack_data->written_size = 0; rarvm_init(&unpack_data->rarvm_data); unpack_data->unp_crc = 0xffffffff; @@ -958,8 +963,9 @@ ch = ppm_decode_char(&unpack_data->ppm_data, fd, unpack_data); rar_dbgmsg("PPM char: %d\n", ch); if (ch == -1) { + ppm_cleanup(&unpack_data->ppm_data); + unpack_data->unp_block_type = BLOCK_LZ; retval = FALSE; - unpack_data->ppm_error = TRUE; break; } if (ch == unpack_data->ppm_esc_char) { @@ -968,7 +974,6 @@ rar_dbgmsg("PPM next char: %d\n", next_ch); if (next_ch == -1) { retval = FALSE; - unpack_data->ppm_error = TRUE; break; } if (next_ch == 0) { @@ -1158,6 +1163,12 @@ retval = rar_unpack29(fd, solid, unpack_data); break; default: + retval = rar_unpack29(fd, solid, unpack_data); + if(retval == FALSE) { + retval = rar_unpack20(fd, solid, unpack_data); + if(retval == FALSE) + retval = rar_unpack15(fd, solid, unpack_data); + } break; } return retval; Index: libclamunrar/unrar20.c =================================================================== --- libclamunrar/unrar20.c (revision 3787) +++ libclamunrar/unrar20.c (revision 3788) @@ -32,9 +32,11 @@ if (!solid) { unpack_data->unp_channel_delta = 0; unpack_data->unp_cur_channel = 0; + unpack_data->unp_audio_block = 0; unpack_data->unp_channels = 1; memset(unpack_data->audv, 0, sizeof(unpack_data->audv)); memset(unpack_data->unp_old_table20, 0, sizeof(unpack_data->unp_old_table20)); + memset(unpack_data->MD, 0, sizeof(unpack_data->MD)); } } Index: libclamunrar/unrar.h =================================================================== --- libclamunrar/unrar.h (revision 3787) +++ libclamunrar/unrar.h (revision 3788) @@ -212,7 +212,6 @@ unsigned int last_length; ppm_data_t ppm_data; int ppm_esc_char; - int ppm_error; rar_filter_array_t Filters; rar_filter_array_t PrgStack; int *old_filter_lengths;