Browse code

Add support for scanning different types of iso9660 image files. The allowed sector size is within 2048 to 2448 (2352 raw + 96 sub). Right now only the only file system supported is plain iso9660 with optional Joliet extensions. Additionally files with multi extents and interleaved files are not supported.

Finally, due to the multiple possible ways to interpret the content
of a cd/dvd, I cannot guarantee that we scan the "right" files.

aCaB authored on 2011/11/15 05:23:15
Showing 14 changed files
... ...
@@ -1,3 +1,7 @@
1
+Mon Nov 14 21:22:26 CET 2011 (acab)
2
+-----------------------------------
3
+ * libclamav: add preliminary support for iso9660 image files
4
+
1 5
 Fri Nov  4 00:52:21 CET 2011 (acab)
2 6
 -----------------------------------
3 7
  * libclamav/pe.c: parse vinfo where varfileinfo occours before stringfileinfo
... ...
@@ -370,6 +370,8 @@ libclamav_la_SOURCES = \
370 370
 	jpeg.h \
371 371
 	png.c \
372 372
 	png.h \
373
+	iso9660.c \
374
+	iso9660.h \
373 375
 	arc4.c \
374 376
 	arc4.h
375 377
 
... ...
@@ -158,8 +158,8 @@ am__libclamav_la_SOURCES_DIST = clamav.h matcher-ac.c matcher-ac.h \
158 158
 	bytecode_api_decl.c bytecode_api.h bytecode_api_impl.h \
159 159
 	bytecode_hooks.h cache.c cache.h bytecode_detect.c \
160 160
 	bytecode_detect.h builtin_bytecodes.h events.c events.h swf.c \
161
-	swf.h jpeg.c jpeg.h png.c png.h arc4.c arc4.h bignum.c \
162
-	bignum_class.h
161
+	swf.h jpeg.c jpeg.h png.c png.h iso9660.c iso9660.h arc4.c \
162
+	arc4.h bignum.c bignum_class.h
163 163
 @LINK_TOMMATH_FALSE@am__objects_1 = libclamav_la-bignum.lo
164 164
 am_libclamav_la_OBJECTS = libclamav_la-matcher-ac.lo \
165 165
 	libclamav_la-matcher-bm.lo libclamav_la-matcher-hash.lo \
... ...
@@ -212,7 +212,7 @@ am_libclamav_la_OBJECTS = libclamav_la-matcher-ac.lo \
212 212
 	libclamav_la-bytecode_api_decl.lo libclamav_la-cache.lo \
213 213
 	libclamav_la-bytecode_detect.lo libclamav_la-events.lo \
214 214
 	libclamav_la-swf.lo libclamav_la-jpeg.lo libclamav_la-png.lo \
215
-	libclamav_la-arc4.lo $(am__objects_1)
215
+	libclamav_la-iso9660.lo libclamav_la-arc4.lo $(am__objects_1)
216 216
 libclamav_la_OBJECTS = $(am_libclamav_la_OBJECTS)
217 217
 AM_V_lt = $(am__v_lt_$(V))
218 218
 am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY))
... ...
@@ -671,7 +671,8 @@ libclamav_la_SOURCES = clamav.h matcher-ac.c matcher-ac.h matcher-bm.c \
671 671
 	bytecode_api_decl.c bytecode_api.h bytecode_api_impl.h \
672 672
 	bytecode_hooks.h cache.c cache.h bytecode_detect.c \
673 673
 	bytecode_detect.h builtin_bytecodes.h events.c events.h swf.c \
674
-	swf.h jpeg.c jpeg.h png.c png.h arc4.c arc4.h $(am__append_7)
674
+	swf.h jpeg.c jpeg.h png.c png.h iso9660.c iso9660.h arc4.c \
675
+	arc4.h $(am__append_7)
675 676
 noinst_LTLIBRARIES = libclamav_internal_utils.la libclamav_internal_utils_nothreads.la libclamav_nocxx.la
676 677
 COMMON_CLEANFILES = version.h version.h.tmp *.gcda *.gcno
677 678
 @MAINTAINER_MODE_TRUE@BUILT_SOURCES = jsparse/generated/operators.h jsparse/generated/keywords.h jsparse-keywords.gperf
... ...
@@ -840,6 +841,7 @@ distclean-compile:
840 840
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclamav_la-inflate64.Plo@am__quote@
841 841
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclamav_la-is_tar.Plo@am__quote@
842 842
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclamav_la-ishield.Plo@am__quote@
843
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclamav_la-iso9660.Plo@am__quote@
843 844
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclamav_la-jpeg.Plo@am__quote@
844 845
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclamav_la-js-norm.Plo@am__quote@
845 846
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclamav_la-line.Plo@am__quote@
... ...
@@ -1763,6 +1765,14 @@ libclamav_la-png.lo: png.c
1763 1763
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
1764 1764
 @am__fastdepCC_FALSE@	$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libclamav_la_CFLAGS) $(CFLAGS) -c -o libclamav_la-png.lo `test -f 'png.c' || echo '$(srcdir)/'`png.c
1765 1765
 
1766
+libclamav_la-iso9660.lo: iso9660.c
1767
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libclamav_la_CFLAGS) $(CFLAGS) -MT libclamav_la-iso9660.lo -MD -MP -MF $(DEPDIR)/libclamav_la-iso9660.Tpo -c -o libclamav_la-iso9660.lo `test -f 'iso9660.c' || echo '$(srcdir)/'`iso9660.c
1768
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libclamav_la-iso9660.Tpo $(DEPDIR)/libclamav_la-iso9660.Plo
1769
+@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
1770
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='iso9660.c' object='libclamav_la-iso9660.lo' libtool=yes @AMDEPBACKSLASH@
1771
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
1772
+@am__fastdepCC_FALSE@	$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libclamav_la_CFLAGS) $(CFLAGS) -c -o libclamav_la-iso9660.lo `test -f 'iso9660.c' || echo '$(srcdir)/'`iso9660.c
1773
+
1766 1774
 libclamav_la-arc4.lo: arc4.c
1767 1775
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libclamav_la_CFLAGS) $(CFLAGS) -MT libclamav_la-arc4.lo -MD -MP -MF $(DEPDIR)/libclamav_la-arc4.Tpo -c -o libclamav_la-arc4.lo `test -f 'arc4.c' || echo '$(srcdir)/'`arc4.c
1768 1776
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libclamav_la-arc4.Tpo $(DEPDIR)/libclamav_la-arc4.Plo
... ...
@@ -92,6 +92,7 @@ static struct dconf_module modules[] = {
92 92
     { "ARCHIVE",    "AUTOIT",	    ARCH_CONF_AUTOIT,	    1 },
93 93
     { "ARCHIVE",    "ISHIELD",	    ARCH_CONF_ISHIELD,	    1 },
94 94
     { "ARCHIVE",    "7zip",	    ARCH_CONF_7Z,	    1 },
95
+    { "ARCHIVE",    "ISO9660",	    ARCH_CONF_ISO9660,	    1 },
95 96
 
96 97
     { "DOCUMENT",   "HTML",	    DOC_CONF_HTML,	    1 },
97 98
     { "DOCUMENT",   "RTF",	    DOC_CONF_RTF,	    1 },
... ...
@@ -78,6 +78,7 @@ struct cli_dconf {
78 78
 #define ARCH_CONF_CPIO	    0x4000
79 79
 #define ARCH_CONF_ISHIELD   0x8000
80 80
 #define ARCH_CONF_7Z        0x10000
81
+#define ARCH_CONF_ISO9660   0x20000
81 82
 
82 83
 /* Document flags */
83 84
 #define DOC_CONF_HTML		0x1
... ...
@@ -97,6 +97,7 @@ static const struct ftmap_s {
97 97
     { "CL_TYPE_ISHIELD_MSI",	CL_TYPE_ISHIELD_MSI	},
98 98
     { "CL_TYPE_7Z",		CL_TYPE_7Z		},
99 99
     { "CL_TYPE_SWF",		CL_TYPE_SWF		},
100
+    { "CL_TYPE_ISO9660",	CL_TYPE_ISO9660		},
100 101
     { NULL,			CL_TYPE_IGNORED		}
101 102
 };
102 103
 
... ...
@@ -85,6 +85,7 @@ typedef enum {
85 85
     CL_TYPE_NULSFT, /* on the fly */
86 86
     CL_TYPE_AUTOIT,
87 87
     CL_TYPE_ISHIELD_MSI,
88
+    CL_TYPE_ISO9660,
88 89
     CL_TYPE_IGNORED /* please don't add anything below */
89 90
 } cli_file_t;
90 91
 
... ...
@@ -165,6 +165,7 @@ static const char *ftypes_int[] = {
165 165
   "0:0:53514c69746520666f726d6174203300:SQLite database:CL_TYPE_ANY:CL_TYPE_IGNORED",
166 166
   "0:0:d9d505f920a163d7:SQLite journal:CL_TYPE_ANY:CL_TYPE_IGNORED",
167 167
   "0:0:ffd9ffd8:JPEG (bad header):CL_TYPE_ANY:CL_TYPE_GRAPHICS:70",
168
+  "1:*:014344303031{2043-2443}4344303031:ISO9660:CL_TYPE_ANY:CL_TYPE_ISO9660:71",
168 169
   NULL
169 170
 };
170 171
 
171 172
new file mode 100644
... ...
@@ -0,0 +1,319 @@
0
+/*
1
+ *  Copyright (C) 2011 Sourcefire, Inc.
2
+ *
3
+ *  Authors: aCaB <acab@clamav.net>
4
+ *
5
+ *  This program is free software; you can redistribute it and/or modify
6
+ *  it under the terms of the GNU General Public License version 2 as
7
+ *  published by the Free Software Foundation.
8
+ *
9
+ *  This program is distributed in the hope that it will be useful,
10
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
+ *  GNU General Public License for more details.
13
+ *
14
+ *  You should have received a copy of the GNU General Public License
15
+ *  along with this program; if not, write to the Free Software
16
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17
+ *  MA 02110-1301, USA.
18
+ */
19
+
20
+#include <string.h>
21
+#include "scanners.h"
22
+#include "iso9660.h"
23
+#include "fmap.h"
24
+#include "str.h"
25
+#include "hashtab.h"
26
+
27
+typedef struct {
28
+    cli_ctx *ctx;
29
+    size_t base_offset;
30
+    unsigned int blocksz;
31
+    unsigned int sectsz;
32
+    unsigned int fileno;
33
+    unsigned int joliet;
34
+    char buf[260];
35
+    struct cli_hashset dir_blocks;
36
+} iso9660_t;
37
+
38
+
39
+static void *needblock(const iso9660_t *iso, unsigned int block, int temp) {
40
+    cli_ctx *ctx = iso->ctx;
41
+    size_t loff;
42
+    unsigned int blocks_per_sect = (2048 / iso->blocksz);
43
+    if(block > (((*ctx->fmap)->len - iso->base_offset) / iso->sectsz) * blocks_per_sect)
44
+	return NULL; /* Block is out of file */
45
+    loff = (block / blocks_per_sect) * iso->sectsz;   /* logical sector */
46
+    loff += (block % blocks_per_sect) * iso->blocksz; /* logical block within the secotor */
47
+    if(temp)
48
+	return fmap_need_off_once(*ctx->fmap, iso->base_offset + loff, iso->blocksz);
49
+    return fmap_need_off(*ctx->fmap, iso->base_offset + loff, iso->blocksz);
50
+}
51
+
52
+
53
+static int iso_scan_file(const iso9660_t *iso, unsigned int block, unsigned int len) {
54
+    char *tmpf;
55
+    int fd, ret;
56
+    if(cli_gentempfd(NULL, &tmpf, &fd) != CL_SUCCESS)
57
+	return CL_ETMPFILE;
58
+
59
+    cli_dbgmsg("iso_scan_file: dumping to %s\n", tmpf);
60
+    while(len) {
61
+	void *buf = needblock(iso, block, 1);
62
+	if(cli_writen(fd, buf, iso->blocksz) != iso->blocksz) {
63
+	    close(fd);
64
+	    ret = cli_unlink(tmpf);
65
+	    free(tmpf);
66
+	    if(ret)
67
+		return CL_EUNLINK;
68
+	    return CL_EWRITE;
69
+	}
70
+	len -= MIN(len, iso->blocksz);
71
+	block++;
72
+    }
73
+
74
+    ret = cli_magic_scandesc(fd, iso->ctx);
75
+
76
+    close(fd);
77
+
78
+    if(!iso->ctx->engine->keeptmp) {
79
+	if(cli_unlink(tmpf)) {
80
+	    free(tmpf);
81
+	    return CL_EUNLINK;
82
+	}
83
+    }
84
+
85
+    free(tmpf);
86
+    return ret;
87
+}
88
+
89
+static char *iso_string(iso9660_t *iso, void *src, unsigned int len) {
90
+    if(iso->joliet) {
91
+	char *utf8;
92
+	if(len > sizeof(iso->buf))
93
+	    len = sizeof(iso->buf) - 2;
94
+	memcpy(iso->buf, src, len);
95
+	iso->buf[len] = '\0';
96
+	iso->buf[len+1] = '\0';
97
+	utf8 = cli_utf16_to_utf8(iso->buf, len, UTF16_BE);
98
+	if(!utf8)
99
+	    utf8 = "";
100
+	strncpy(iso->buf, utf8, sizeof(iso->buf));
101
+	iso->buf[sizeof(iso->buf)-1] = '\0';
102
+	free(utf8);
103
+    } else {
104
+	memcpy(iso->buf, src, len);
105
+	iso->buf[len] = '\0';
106
+    }
107
+    return iso->buf;
108
+}
109
+
110
+
111
+static int iso_parse_dir(iso9660_t *iso, unsigned int block, unsigned int len) {
112
+    cli_ctx *ctx = iso->ctx;
113
+    int ret = CL_CLEAN;
114
+
115
+    if(len < 34) {
116
+	cli_dbgmsg("iso_parse_dir: Directory too small, skipping\n");
117
+	return CL_CLEAN;
118
+    }
119
+
120
+    for(; len && ret == CL_CLEAN; block++, len -= MIN(len, iso->blocksz)) {
121
+	uint8_t *dir, *dir_orig;
122
+	unsigned int dirsz;
123
+
124
+	if(iso->dir_blocks.count > 1024) {
125
+	    cli_dbgmsg("iso_parse_dir: Breaking out due to too many dir records\n");
126
+	    return CL_BREAK;
127
+	}
128
+
129
+	if(cli_hashset_contains(&iso->dir_blocks, block))
130
+	    continue;
131
+
132
+	if((ret = cli_hashset_addkey(&iso->dir_blocks, block)) != CL_CLEAN)
133
+	    return ret;
134
+
135
+	dir = dir_orig = needblock(iso, block, 0);
136
+	if(!dir)
137
+	    return CL_CLEAN;
138
+
139
+	for(dirsz = MIN(iso->blocksz, len);;) {
140
+	    unsigned int entrysz = *dir, fileoff, filesz;
141
+	    char *sep;
142
+
143
+	    if(!dirsz || !entrysz) /* continuing on next block, if any */
144
+		break;
145
+	    if(entrysz > dirsz) { /* record size overlaps onto the next sector, no point in looking in there */
146
+		cli_dbgmsg("iso_parse_dir: Directory entry overflow, breaking out %u %u\n", entrysz, dirsz);
147
+		len = 0;
148
+		break;
149
+	    }
150
+	    if(entrysz < 34) { /* this shouldn't happen really*/
151
+		cli_dbgmsg("iso_parse_dir: Too short directory entry, attempting to skip\n");
152
+		dirsz -= entrysz;
153
+		dir += entrysz;
154
+		continue;
155
+	    }
156
+	    filesz = dir[32];
157
+	    if(filesz == 1 && (dir[33] == 0 || dir[33] == 1)) { /* skip "." and ".." */
158
+		dirsz -= entrysz;
159
+		dir += entrysz;
160
+		continue;
161
+	    }
162
+
163
+	    if(filesz + 33 > dirsz) {
164
+		cli_dbgmsg("iso_parse_dir: Directory entry name overflow, clamping\n");
165
+		filesz = dirsz - 33;
166
+	    }
167
+	    iso_string(iso, &dir[33], filesz);
168
+	    sep = memchr(iso->buf, ';', filesz);
169
+	    if(sep)
170
+		*sep = '\0';
171
+	    else
172
+		iso->buf[filesz] = '\0';
173
+	    fileoff = cli_readint32(dir+2);
174
+	    fileoff += dir[1];
175
+	    filesz = cli_readint32(dir+10);
176
+
177
+	    cli_dbgmsg("iso_parse_dir: %s '%s': off %x - size %x - flags %x - unit size %x - gap size %x - volume %u\n", (dir[25] & 2) ? "Directory" : "File", iso->buf, fileoff, filesz, dir[25], dir[26], dir[27], cli_readint32(&dir[28]) & 0xffff);
178
+	    if(cli_matchmeta(ctx, iso->buf, filesz, filesz, 0, 0, 0, NULL) == CL_VIRUS) {
179
+		ret = CL_VIRUS;
180
+		break;
181
+	    }
182
+
183
+	    if(dir[26] || dir[27])
184
+		cli_dbgmsg("iso_parse_dir: Skipping interleaved file\n");
185
+	    else  {
186
+		/* TODO Handle multi-extent ? */
187
+		if(dir[25] & 2) {
188
+		    ret = iso_parse_dir(iso, fileoff, filesz);
189
+		} else {
190
+		    if(cli_checklimits("ISO9660", ctx, filesz, 0, 0) != CL_SUCCESS)
191
+			cli_dbgmsg("iso_parse_dir: Skipping overlimit file\n");
192
+		    else
193
+			ret = iso_scan_file(iso, fileoff, filesz);
194
+		}
195
+	    }
196
+	    dirsz -= entrysz;
197
+	    dir += entrysz;
198
+	}
199
+
200
+	fmap_unneed_ptr(*ctx->fmap, dir_orig, iso->blocksz);
201
+    }
202
+    return ret;
203
+}
204
+
205
+int cli_scaniso(cli_ctx *ctx, size_t offset) {
206
+    uint8_t *privol, *next;
207
+    iso9660_t iso;
208
+    int i;
209
+
210
+    if(offset < 32768)
211
+	return CL_CLEAN; /* Need 16 sectors at least 2048 bytes long */
212
+
213
+    privol = fmap_need_off(*ctx->fmap, offset, 2448 + 6);
214
+    if(!privol)
215
+	return CL_CLEAN;
216
+
217
+    next = (uint8_t *)cli_memstr((char *)privol + 2049, 2448 + 6 - 2049, "CD001", 5);
218
+    if(!next)
219
+	return CL_CLEAN; /* Find next volume descriptor */
220
+
221
+    iso.sectsz = (next - privol) - 1;
222
+    if(iso.sectsz * 16 > offset)
223
+	return CL_CLEAN; /* Need room for 16 system sectors */
224
+
225
+    iso.blocksz = cli_readint32(privol+128) & 0xffff;
226
+    if(iso.blocksz != 512 && iso.blocksz != 1024 && iso.blocksz != 2048)
227
+	return CL_CLEAN; /* Likely not a cdrom image */
228
+
229
+    iso.base_offset = offset - iso.sectsz * 16;
230
+    iso.joliet = 0;
231
+
232
+    for(i=16; i<32 ;i++) { /* scan for a joliet secondary volume descriptor */
233
+	next = fmap_need_off_once(*ctx->fmap, iso.base_offset + i * iso.sectsz, 2048);
234
+	if(!next)
235
+	    break; /* Out of disk */
236
+	if(*next == 0xff || memcmp(next+1, "CD001", 5))
237
+	    break; /* Not a volume descriptor */
238
+	if(*next != 2)
239
+	    continue; /* Not a secondary volume descriptor */
240
+	if(next[88] != 0x25 || next[89] != 0x2f)
241
+	    continue; /* Not a joliet descriptor */
242
+	if(next[156+26] || next[156+27])
243
+	    continue; /* Root is interleaved so we fallback to the primary descriptor */
244
+	switch(next[90]) {
245
+	case 0x40: /* Level 1 */
246
+	    iso.joliet = 1;
247
+	    break;
248
+	case 0x43: /* Level 2 */
249
+	    iso.joliet = 2;
250
+	    break;
251
+	case 0x45: /* Level 3 */
252
+	    iso.joliet = 3;
253
+	    break;
254
+	default: /* Not Joliet */
255
+	    continue;
256
+	}
257
+	break;
258
+    }
259
+
260
+    /* TODO rr, el torito, udf ? */
261
+
262
+    /* NOTE: freeing sector now. it is still safe to access as we don't alloc anymore */
263
+    fmap_unneed_off(*ctx->fmap, offset, 2448);
264
+    if(iso.joliet)
265
+	privol = next;
266
+
267
+    cli_dbgmsg("in cli_scaniso\n");
268
+    if(cli_debug_flag) {
269
+	cli_dbgmsg("cli_scaniso: Raw sector size: %u\n", iso.sectsz);
270
+	cli_dbgmsg("cli_scaniso: Block size: %u\n", iso.blocksz);
271
+
272
+	cli_dbgmsg("cli_scaniso: Volume descriptor version: %u\n", privol[6]);
273
+
274
+#define ISOSTRING(src, len) iso_string(&iso, (src), (len))
275
+	cli_dbgmsg("cli_scaniso: System: %s\n", ISOSTRING(privol + 8, 32));
276
+	cli_dbgmsg("cli_scaniso: Volume: %s\n", ISOSTRING(privol + 40, 32));
277
+
278
+	cli_dbgmsg("cli_scaniso: Volume space size: 0x%x blocks\n", cli_readint32(&privol[80]));
279
+	cli_dbgmsg("cli_scaniso: Volume %u of %u\n", cli_readint32(privol+124) & 0xffff, cli_readint32(privol+120) & 0xffff);
280
+
281
+	cli_dbgmsg("cli_scaniso: Volume Set: %s\n", ISOSTRING(privol + 190, 128));
282
+	cli_dbgmsg("cli_scaniso: Publisher: %s\n", ISOSTRING(privol + 318, 128));
283
+	cli_dbgmsg("cli_scaniso: Data Preparer: %s\n", ISOSTRING(privol + 446, 128));
284
+	cli_dbgmsg("cli_scaniso: Application: %s\n", ISOSTRING(privol + 574, 128));
285
+
286
+#define ISOTIME(s,n) cli_dbgmsg("cli_scaniso: "s": %c%c%c%c-%c%c-%c%c %c%c:%c%c:%c%c\n", privol[n],privol[n+1],privol[n+2],privol[n+3], privol[n+4],privol[n+5], privol[n+6],privol[n+7], privol[n+8],privol[n+9], privol[n+10],privol[n+11], privol[n+12],privol[n+13])
287
+	ISOTIME("Volume creation time",813);
288
+	ISOTIME("Volume modification time",830);
289
+	ISOTIME("Volume expiration time",847);
290
+	ISOTIME("Volume effective time",864);
291
+
292
+	cli_dbgmsg("cli_scaniso: Path table size: 0x%x\n", cli_readint32(privol+132) & 0xffff);
293
+	cli_dbgmsg("cli_scaniso: LSB Path Table: 0x%x\n", cli_readint32(privol+140));
294
+	cli_dbgmsg("cli_scaniso: Opt LSB Path Table: 0x%x\n", cli_readint32(privol+144));
295
+	cli_dbgmsg("cli_scaniso: MSB Path Table: 0x%x\n", cbswap32(cli_readint32(privol+148)));
296
+	cli_dbgmsg("cli_scaniso: Opt MSB Path Table: 0x%x\n", cbswap32(cli_readint32(privol+152)));
297
+	cli_dbgmsg("cli_scaniso: File Structure Version: %u\n", privol[881]);
298
+
299
+	if(iso.joliet)
300
+	    cli_dbgmsg("cli_scaniso: Joliet level %u\n", iso.joliet);
301
+    }
302
+
303
+    if(privol[156+26] || privol[156+27]) {
304
+	cli_dbgmsg("cli_scaniso: Interleaved root directory is not supported\n");
305
+	return CL_CLEAN;
306
+    }
307
+
308
+    iso.ctx = ctx;
309
+    i = cli_hashset_init(&iso.dir_blocks, 1024, 80);
310
+    if(i != CL_SUCCESS)
311
+	return i;
312
+    i = iso_parse_dir(&iso, cli_readint32(privol+156+2) + privol[156+1], cli_readint32(privol+156+10));
313
+    cli_hashset_destroy(&iso.dir_blocks);
314
+    if(i == CL_BREAK)
315
+	return CL_CLEAN;
316
+    return i;
317
+}
318
+
0 319
new file mode 100644
... ...
@@ -0,0 +1,28 @@
0
+/*
1
+ *  Copyright (C) 2011 Sourcefire, Inc.
2
+ *
3
+ *  Authors: aCaB <acab@clamav.net>
4
+ *
5
+ *  This program is free software; you can redistribute it and/or modify
6
+ *  it under the terms of the GNU General Public License version 2 as
7
+ *  published by the Free Software Foundation.
8
+ *
9
+ *  This program is distributed in the hope that it will be useful,
10
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
+ *  GNU General Public License for more details.
13
+ *
14
+ *  You should have received a copy of the GNU General Public License
15
+ *  along with this program; if not, write to the Free Software
16
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17
+ *  MA 02110-1301, USA.
18
+ */
19
+
20
+#ifndef __ISO9660_H
21
+#define __ISO9660_H
22
+
23
+#include "others.h"
24
+
25
+int cli_scaniso(cli_ctx *ctx, size_t offset);
26
+
27
+#endif
... ...
@@ -54,7 +54,7 @@
54 54
  * in re-enabling affected modules.
55 55
  */
56 56
 
57
-#define CL_FLEVEL 70
57
+#define CL_FLEVEL 71
58 58
 #define CL_FLEVEL_DCONF	CL_FLEVEL
59 59
 #define CL_FLEVEL_SIGTOOL CL_FLEVEL
60 60
 
... ...
@@ -93,6 +93,7 @@
93 93
 #include "swf.h"
94 94
 #include "jpeg.h"
95 95
 #include "png.h"
96
+#include "iso9660.h"
96 97
 
97 98
 #ifdef HAVE_BZLIB_H
98 99
 #include <bzlib.h>
... ...
@@ -1879,7 +1880,7 @@ static int cli_scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_file_
1879 1879
 {
1880 1880
 	int ret = CL_CLEAN, nret = CL_CLEAN;
1881 1881
 	struct cli_matched_type *ftoffset = NULL, *fpt;
1882
-	uint32_t lastzip, lastrar;
1882
+	uint32_t lastrar;
1883 1883
 	struct cli_exe_info peinfo;
1884 1884
 	unsigned int acmode = AC_SCAN_VIR, break_loop = 0;
1885 1885
 	fmap_t *map = *ctx->fmap;
... ...
@@ -1901,7 +1902,7 @@ static int cli_scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_file_
1901 1901
 	perf_nested_start(ctx, PERFT_RAWTYPENO, PERFT_SCAN);
1902 1902
 	ctx->recursion++;
1903 1903
 	if(nret != CL_VIRUS) {
1904
-	    lastzip = lastrar = 0xdeadbeef;
1904
+	    lastrar = 0xdeadbeef;
1905 1905
 	    fpt = ftoffset;
1906 1906
 	    while(fpt) {
1907 1907
 		if(fpt->offset) switch(fpt->type) {
... ...
@@ -1940,6 +1941,15 @@ static int cli_scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_file_
1940 1940
 			}
1941 1941
 			break;
1942 1942
 
1943
+		    case CL_TYPE_ISO9660:
1944
+			if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_ISO9660)) {
1945
+			    ctx->container_type = CL_TYPE_ISO9660;
1946
+			    ctx->container_size = map->len - fpt->offset; /* not precise */
1947
+			    cli_dbgmsg("ISO9660 signature found at %u\n", (unsigned int) fpt->offset);
1948
+			    nret = cli_scaniso(ctx, fpt->offset);
1949
+			}
1950
+			break;
1951
+
1943 1952
 		    case CL_TYPE_NULSFT:
1944 1953
 		        if(SCAN_ARCHIVE && type == CL_TYPE_MSEXE && (DCONF_ARCH & ARCH_CONF_NSIS) && fpt->offset > 4) {
1945 1954
 			    ctx->container_type = CL_TYPE_NULSFT;
... ...
@@ -592,3 +592,73 @@ int cli_hexnibbles(char *str, int len)
592 592
     }
593 593
     return 0;
594 594
 }
595
+
596
+char *cli_utf16_to_utf8(const char *utf16, size_t length, utf16_type type)
597
+{
598
+    /* utf8 -
599
+     * 4 bytes for utf16 high+low surrogate (4 bytes input)
600
+     * 3 bytes for utf16 otherwise (2 bytes input) */
601
+    size_t i, j;
602
+    size_t needed = length * 3/2 + 2;
603
+    char *s2;
604
+
605
+    if (length < 2)
606
+	return cli_strdup("");
607
+    if (length % 2) {
608
+	cli_warnmsg("utf16 length is not multiple of two: %lu\n", (long)length);
609
+	length--;
610
+    }
611
+
612
+    s2 = cli_malloc(needed);
613
+    if (!s2)
614
+	return NULL;
615
+
616
+    i = 0;
617
+
618
+    if((utf16[0] == '\xff' && utf16[1] == '\xfe') || (utf16[0] == '\xfe' && utf16[1] == '\xff')) {
619
+	i += 2;
620
+	if(type == UTF16_BOM)
621
+	    type = (utf16[0] == '\xff') ? UTF16_LE : UTF16_BE;
622
+    } else if(type == UTF16_BOM)
623
+	type = UTF16_BE;
624
+
625
+    for (j=0;i<length && j<needed;i += 2) {
626
+	uint16_t c = cli_readint16(&utf16[i]);
627
+	if(type == UTF16_BE)
628
+	    c = cbswap16(c);
629
+	if (c < 0x80) {
630
+	    s2[j++] = c;
631
+	} else if (c < 0x800) {
632
+	    s2[j] = 0xc0 | (c >>6);
633
+	    s2[j+1] = 0x80 | (c&0x3f);
634
+	    j += 2;
635
+	} else if (c < 0xd800 || c >= 0xe000) {
636
+	    s2[j] = 0xe0 | (c >> 12);
637
+	    s2[j+1] = 0x80 | ((c >> 6) & 0x3f);
638
+	    s2[j+2] = 0x80 | (c & 0x3f);
639
+	    j += 3;
640
+	} else if (c < 0xdc00 && i+3 < length) {
641
+	    uint16_t c2;
642
+	    /* UTF16 high+low surrogate */
643
+	    c = c - 0xd800 + 0x40;
644
+	    c2 = i+3 < length ? cli_readint16(&utf16[i+2]) : 0;
645
+	    c2 -= 0xdc00;
646
+	    s2[j] = 0xf0 | (c >> 8);
647
+	    s2[j+1] = 0x80 | ((c >> 2) & 0x3f);
648
+	    s2[j+2] = 0x80 | ((c&3) << 4) | (c2 >> 6);
649
+	    s2[j+3] = 0x80 | (c2 & 0x3f);
650
+	    j += 4;
651
+	    i += 2;
652
+	} else {
653
+	    cli_dbgmsg("UTF16 surrogate encountered at wrong pos\n");
654
+	    /* invalid char */
655
+	    s2[j++] = 0xef;
656
+	    s2[j++] = 0xbf;
657
+	    s2[j++] = 0xbd;
658
+	}
659
+    }
660
+    if (j >= needed)
661
+	j = needed-1;
662
+    s2[j] = '\0';
663
+    return s2;
664
+}
... ...
@@ -51,4 +51,11 @@ struct text_buffer;
51 51
 int  cli_textbuffer_append_normalize(struct text_buffer *buf, const char *str, size_t len);
52 52
 int cli_hexnibbles(char *str, int len);
53 53
 
54
+typedef enum {
55
+    UTF16_BE, /* Force big endian */
56
+    UTF16_LE, /* Force little endian */
57
+    UTF16_BOM /* Use BOM if available otherwise assume big endian */
58
+} utf16_type;
59
+char *cli_utf16_to_utf8(const char *utf16, size_t length, utf16_type type);
60
+
54 61
 #endif