Browse code

restructure container typing system to use array (#2)

klin authored on 2017/01/20 02:24:46
Showing 6 changed files
... ...
@@ -525,13 +525,13 @@ int32_t cli_bcapi_extract_new(struct cli_bc_ctx *ctx, int32_t id)
525 525
     cli_dbgmsg("bytecode: scanning extracted file %s\n", ctx->tempfile);
526 526
     cctx = (cli_ctx*)ctx->ctx;
527 527
     if (cctx) {
528
-        cli_file_t current = cctx->container_type;
529
-        if (ctx->containertype != CL_TYPE_ANY)
530
-            cctx->container_type = ctx->containertype;
531 528
         cctx->recursion++;
529
+        if (ctx->containertype != CL_TYPE_ANY) {
530
+            size_t csize = cli_get_container_size(cctx, -1);
531
+            cli_set_container(cctx, ctx->containertype, csize);
532
+        }
532 533
         res = cli_magic_scandesc(ctx->outfd, cctx);
533 534
         cctx->recursion--;
534
-        cctx->container_type = current;
535 535
         if (res == CL_VIRUS) {
536 536
             ctx->virname = cli_get_last_virus(cctx);
537 537
             ctx->found = 1;
... ...
@@ -717,7 +717,7 @@ static int lsig_eval(cli_ctx *ctx, struct cli_matcher *root, struct cli_ac_data
717 717
     if (rc != CL_SUCCESS)
718 718
         return rc;
719 719
     if (cli_ac_chklsig(exp, exp_end, acdata->lsigcnt[lsid], &evalcnt, &evalids, 0) == 1) {
720
-        if(ac_lsig->tdb.container && ac_lsig->tdb.container[0] != ctx->container_type)
720
+        if(ac_lsig->tdb.container && ac_lsig->tdb.container[0] != cli_get_container_type(ctx, -1))
721 721
             return CL_CLEAN;
722 722
         if(ac_lsig->tdb.filesize && (ac_lsig->tdb.filesize[0] > map->len || ac_lsig->tdb.filesize[1] < map->len))
723 723
             return CL_CLEAN;
... ...
@@ -1211,11 +1211,11 @@ int cli_matchmeta(cli_ctx *ctx, const char *fname, size_t fsizec, size_t fsizer,
1211 1211
 	unsigned int viruses_found = 0;
1212 1212
 
1213 1213
     cli_dbgmsg("CDBNAME:%s:%llu:%s:%llu:%llu:%d:%u:%u:%p\n",
1214
-	       cli_ftname(ctx->container_type), (long long unsigned)fsizec, fname, (long long unsigned)fsizec, (long long unsigned)fsizer,
1214
+	       cli_ftname(cli_get_container_type(ctx, -1)), (long long unsigned)fsizec, fname, (long long unsigned)fsizec, (long long unsigned)fsizer,
1215 1215
 	       encrypted, filepos, res1, res2);
1216 1216
 
1217 1217
     if (ctx->engine && ctx->engine->cb_meta)
1218
-	if (ctx->engine->cb_meta(cli_ftname(ctx->container_type), fsizec, fname, fsizer, encrypted, filepos, ctx->cb_ctx) == CL_VIRUS) {
1218
+	if (ctx->engine->cb_meta(cli_ftname(cli_get_container_type(ctx, -1)), fsizec, fname, fsizer, encrypted, filepos, ctx->cb_ctx) == CL_VIRUS) {
1219 1219
 	    cli_dbgmsg("inner file blacklisted by callback: %s\n", fname);
1220 1220
 
1221 1221
 	    cli_append_virus(ctx, "Detected.By.Callback");
... ...
@@ -1228,7 +1228,7 @@ int cli_matchmeta(cli_ctx *ctx, const char *fname, size_t fsizec, size_t fsizer,
1228 1228
 	return CL_CLEAN;
1229 1229
 
1230 1230
     do {
1231
-	if(cdb->ctype != CL_TYPE_ANY && cdb->ctype != ctx->container_type)
1231
+	if(cdb->ctype != CL_TYPE_ANY && cdb->ctype != cli_get_container_type(ctx, -1))
1232 1232
 	    continue;
1233 1233
 
1234 1234
 	if(cdb->encrypted != 2 && cdb->encrypted != encrypted)
... ...
@@ -1246,7 +1246,7 @@ int cli_matchmeta(cli_ctx *ctx, const char *fname, size_t fsizec, size_t fsizer,
1246 1246
 		continue;						    \
1247 1247
 	}
1248 1248
 
1249
-	CDBRANGE(cdb->csize, ctx->container_size);
1249
+	CDBRANGE(cdb->csize, cli_get_container_size(ctx, -1));
1250 1250
 	CDBRANGE(cdb->fsizec, fsizec);
1251 1251
 	CDBRANGE(cdb->fsizer, fsizer);
1252 1252
 	CDBRANGE(cdb->filepos, filepos);
... ...
@@ -1134,6 +1134,30 @@ const char * cli_get_last_virus_str(const cli_ctx * ctx)
1134 1134
     return "";
1135 1135
 }
1136 1136
 
1137
+void cli_set_container(cli_ctx *ctx, cli_file_t type, size_t size)
1138
+{
1139
+    ctx->containers[ctx->recursion].type = type;
1140
+    ctx->containers[ctx->recursion].size = size;
1141
+}
1142
+
1143
+cli_file_t cli_get_container_type(cli_ctx *ctx, int index)
1144
+{
1145
+    if (index < 0)
1146
+	index = ctx->recursion + index + 1;
1147
+    if (index >= 0 || index <= ctx->recursion)
1148
+	return ctx->containers[index].type;
1149
+    return CL_TYPE_ANY;
1150
+}
1151
+
1152
+size_t cli_get_container_size(cli_ctx *ctx, int index)
1153
+{
1154
+    if (index < 0)
1155
+	index = ctx->recursion + index + 1;
1156
+    if (index >= 0 || index <= ctx->recursion)
1157
+	return ctx->containers[index].size;
1158
+    return 0;
1159
+}
1160
+
1137 1161
 
1138 1162
 
1139 1163
 #ifdef	C_WINDOWS
... ...
@@ -126,6 +126,11 @@ typedef struct bitset_tag
126 126
         unsigned long length;
127 127
 } bitset_t;
128 128
 
129
+typedef struct cli_ctx_container_tag {
130
+    cli_file_t type;
131
+    size_t size;
132
+} cli_ctx_container;
133
+
129 134
 /* internal clamav context */
130 135
 typedef struct cli_ctx_tag {
131 136
     const char **virname;
... ...
@@ -140,8 +145,7 @@ typedef struct cli_ctx_tag {
140 140
     unsigned int found_possibly_unwanted;
141 141
     unsigned int corrupted_input;
142 142
     unsigned int img_validate;
143
-    cli_file_t container_type; /* FIXME: to be made into a stack or array - see bb#1579 & bb#1293 */
144
-    size_t container_size;
143
+    cli_ctx_container *containers; /* set container type after recurse */
145 144
     unsigned char handlertype_hash[16];
146 145
     struct cli_dconf *dconf;
147 146
     fmap_t **fmap;
... ...
@@ -601,6 +605,10 @@ void cli_append_virus(cli_ctx *ctx, const char *virname);
601 601
 const char *cli_get_last_virus(const cli_ctx *ctx);
602 602
 const char *cli_get_last_virus_str(const cli_ctx *ctx);
603 603
 
604
+void cli_set_container(cli_ctx *ctx, cli_file_t type, size_t size);
605
+cli_file_t cli_get_container_type(cli_ctx *ctx, int index);
606
+size_t cli_get_container_size(cli_ctx *ctx, int index);
607
+
604 608
 /* used by: spin, yc (C) aCaB */
605 609
 #define __SHIFTBITS(a) (sizeof(a)<<3)
606 610
 #define __SHIFTMASK(a) (__SHIFTBITS(a)-1)
... ...
@@ -2134,8 +2134,6 @@ static int cli_scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_file_
2134 2134
 	struct cli_exe_info peinfo;
2135 2135
 	unsigned int acmode = AC_SCAN_VIR, break_loop = 0;
2136 2136
 	fmap_t *map = *ctx->fmap;
2137
-	cli_file_t current_container_type = ctx->container_type;
2138
-	size_t current_container_size = ctx->container_size;
2139 2137
 
2140 2138
 
2141 2139
     if(ctx->engine->maxreclevel && ctx->recursion >= ctx->engine->maxreclevel) {
... ...
@@ -2157,9 +2155,10 @@ static int cli_scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_file_
2157 2157
         fpt = ftoffset;
2158 2158
 
2159 2159
         while(fpt) {
2160
+            /* set current level as container AFTER recursing */
2161
+            cli_set_container(ctx, fpt->type, map->len);
2160 2162
             if(fpt->offset) switch(fpt->type) {
2161 2163
                 case CL_TYPE_MHTML:
2162
-                    ctx->container_type = CL_TYPE_MHTML;
2163 2164
                     if(SCAN_MAIL && (DCONF_MAIL & MAIL_CONF_MBOX)) {
2164 2165
                         cli_dbgmsg("MHTML signature found at %u\n", (unsigned int) fpt->offset);
2165 2166
                         ret = cli_scanmail(ctx);
... ...
@@ -2194,8 +2193,8 @@ static int cli_scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_file_
2194 2194
                     if(type != CL_TYPE_RAR && have_rar && SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_RAR)) {
2195 2195
                         char *tmpname = NULL;
2196 2196
                         int tmpfd = fmap_fd(map);
2197
-                        ctx->container_type = CL_TYPE_RAR;
2198
-                        ctx->container_size = map->len - fpt->offset; /* not precise */
2197
+                        size_t csize = map->len - fpt->offset; /* not precise */
2198
+                        cli_set_container(ctx, CL_TYPE_RAR, csize);
2199 2199
                         cli_dbgmsg("RAR/RAR-SFX signature found at %u\n", (unsigned int) fpt->offset);
2200 2200
                         /* if map is not file-backed, have to dump to file for scanrar */
2201 2201
                         if(tmpfd == -1) {
... ...
@@ -2225,8 +2224,8 @@ static int cli_scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_file_
2225 2225
 
2226 2226
                 case CL_TYPE_ZIPSFX:
2227 2227
                     if(type != CL_TYPE_ZIP && SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_ZIP)) {
2228
-                        ctx->container_type = CL_TYPE_ZIP;
2229
-                        ctx->container_size = map->len - fpt->offset; /* not precise */
2228
+                        size_t csize = map->len - fpt->offset; /* not precise */
2229
+                        cli_set_container(ctx, CL_TYPE_ZIP, csize);
2230 2230
                         cli_dbgmsg("ZIP/ZIP-SFX signature found at %u\n", (unsigned int) fpt->offset);
2231 2231
                         nret = cli_unzip_single(ctx, fpt->offset);
2232 2232
                     }
... ...
@@ -2234,8 +2233,8 @@ static int cli_scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_file_
2234 2234
 
2235 2235
                 case CL_TYPE_CABSFX:
2236 2236
                     if(type != CL_TYPE_MSCAB && SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_CAB)) {
2237
-                        ctx->container_type = CL_TYPE_MSCAB;
2238
-                        ctx->container_size = map->len - fpt->offset; /* not precise */
2237
+                        size_t csize = map->len - fpt->offset; /* not precise */
2238
+                        cli_set_container(ctx, CL_TYPE_MSCAB, csize);
2239 2239
                         cli_dbgmsg("CAB/CAB-SFX signature found at %u\n", (unsigned int) fpt->offset);
2240 2240
                         nret = cli_scanmscab(ctx, fpt->offset);
2241 2241
                     }
... ...
@@ -2243,8 +2242,8 @@ static int cli_scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_file_
2243 2243
 
2244 2244
                 case CL_TYPE_ARJSFX:
2245 2245
                     if(type != CL_TYPE_ARJ && SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_ARJ)) {
2246
-                        ctx->container_type = CL_TYPE_ARJ;
2247
-                        ctx->container_size = map->len - fpt->offset; /* not precise */
2246
+                        size_t csize = map->len - fpt->offset; /* not precise */
2247
+                        cli_set_container(ctx, CL_TYPE_ARJ, csize);
2248 2248
                         cli_dbgmsg("ARJ-SFX signature found at %u\n", (unsigned int) fpt->offset);
2249 2249
                         nret = cli_scanarj(ctx, fpt->offset, &lastrar);
2250 2250
                     }
... ...
@@ -2252,8 +2251,8 @@ static int cli_scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_file_
2252 2252
 
2253 2253
                 case CL_TYPE_7ZSFX:
2254 2254
                     if(type != CL_TYPE_7Z && SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_7Z)) {
2255
-                        ctx->container_type = CL_TYPE_7Z;
2256
-                        ctx->container_size = map->len - fpt->offset; /* not precise */
2255
+                        size_t csize = map->len - fpt->offset; /* not precise */
2256
+                        cli_set_container(ctx, CL_TYPE_7Z, csize);
2257 2257
                         cli_dbgmsg("7Zip-SFX signature found at %u\n", (unsigned int) fpt->offset);
2258 2258
                         nret = cli_7unz(ctx, fpt->offset);
2259 2259
                     }
... ...
@@ -2261,8 +2260,8 @@ static int cli_scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_file_
2261 2261
 
2262 2262
                 case CL_TYPE_ISO9660:
2263 2263
                     if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_ISO9660)) {
2264
-                        ctx->container_type = CL_TYPE_ISO9660;
2265
-                        ctx->container_size = map->len - fpt->offset; /* not precise */
2264
+                        size_t csize = map->len - fpt->offset; /* not precise */
2265
+                        cli_set_container(ctx, CL_TYPE_ISO9660, csize);
2266 2266
                         cli_dbgmsg("ISO9660 signature found at %u\n", (unsigned int) fpt->offset);
2267 2267
                         nret = cli_scaniso(ctx, fpt->offset);
2268 2268
                     }
... ...
@@ -2271,8 +2270,8 @@ static int cli_scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_file_
2271 2271
                 case CL_TYPE_NULSFT:
2272 2272
                     if(SCAN_ARCHIVE && type == CL_TYPE_MSEXE && (DCONF_ARCH & ARCH_CONF_NSIS) &&
2273 2273
                        fpt->offset > 4) {
2274
-                        ctx->container_type = CL_TYPE_NULSFT;
2275
-                        ctx->container_size = map->len - fpt->offset; /* not precise */
2274
+                        size_t csize = map->len - fpt->offset; /* not precise */
2275
+                        cli_set_container(ctx, CL_TYPE_NULSFT, csize);
2276 2276
                         cli_dbgmsg("NSIS signature found at %u\n", (unsigned int) fpt->offset-4);
2277 2277
                         nret = cli_scannulsft(ctx, fpt->offset - 4);
2278 2278
                     }
... ...
@@ -2280,8 +2279,8 @@ static int cli_scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_file_
2280 2280
 
2281 2281
                 case CL_TYPE_AUTOIT:
2282 2282
                     if(SCAN_ARCHIVE && type == CL_TYPE_MSEXE && (DCONF_ARCH & ARCH_CONF_AUTOIT)) {
2283
-                        ctx->container_type = CL_TYPE_AUTOIT;
2284
-                        ctx->container_size = map->len - fpt->offset; /* not precise */
2283
+                        size_t csize = map->len - fpt->offset; /* not precise */
2284
+                        cli_set_container(ctx, CL_TYPE_AUTOIT, csize);
2285 2285
                         cli_dbgmsg("AUTOIT signature found at %u\n", (unsigned int) fpt->offset);
2286 2286
                         nret = cli_scanautoit(ctx, fpt->offset + 23);
2287 2287
                     }
... ...
@@ -2289,8 +2288,8 @@ static int cli_scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_file_
2289 2289
 
2290 2290
                 case CL_TYPE_ISHIELD_MSI:
2291 2291
                     if(SCAN_ARCHIVE && type == CL_TYPE_MSEXE && (DCONF_ARCH & ARCH_CONF_ISHIELD)) {
2292
-                        ctx->container_type = CL_TYPE_AUTOIT;
2293
-                        ctx->container_size = map->len - fpt->offset; /* not precise */
2292
+                        size_t csize = map->len - fpt->offset; /* not precise */
2293
+                        cli_set_container(ctx, CL_TYPE_AUTOIT, csize);
2294 2294
                         cli_dbgmsg("ISHIELD-MSI signature found at %u\n", (unsigned int) fpt->offset);
2295 2295
                         nret = cli_scanishield_msi(ctx, fpt->offset + 14);
2296 2296
                     }
... ...
@@ -2298,7 +2297,6 @@ static int cli_scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_file_
2298 2298
 
2299 2299
                 case CL_TYPE_DMG:
2300 2300
                     if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_DMG)) {
2301
-                        ctx->container_type = CL_TYPE_DMG;
2302 2301
                         cli_dbgmsg("DMG signature found at %u\n", (unsigned int) fpt->offset);
2303 2302
                         nret = cli_scandmg(ctx);
2304 2303
                     }
... ...
@@ -2309,12 +2307,11 @@ static int cli_scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_file_
2309 2309
                         int iret = cli_mbr_check2(ctx, 0);
2310 2310
                         if ((iret == CL_TYPE_GPT) && (DCONF_ARCH & ARCH_CONF_GPT)) {
2311 2311
                             cli_dbgmsg("Recognized GUID Partition Table file\n");
2312
-                            ctx->container_type = CL_TYPE_GPT;
2312
+                            cli_set_container(ctx, CL_TYPE_GPT, map->len);
2313 2313
                             cli_dbgmsg("GPT signature found at %u\n", (unsigned int) fpt->offset);
2314 2314
                             nret = cli_scangpt(ctx, 0);
2315 2315
                         }
2316 2316
                         else if ((iret == CL_CLEAN) && (DCONF_ARCH & ARCH_CONF_MBR)) {
2317
-                            ctx->container_type = CL_TYPE_MBR;
2318 2317
                             cli_dbgmsg("MBR signature found at %u\n", (unsigned int) fpt->offset);
2319 2318
                             nret = cli_scanmbr(ctx, 0);
2320 2319
                         }
... ...
@@ -2323,8 +2320,8 @@ static int cli_scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_file_
2323 2323
 
2324 2324
                 case CL_TYPE_PDF:
2325 2325
                     if(type != CL_TYPE_PDF && SCAN_PDF && (DCONF_DOC & DOC_CONF_PDF)) {
2326
-                        ctx->container_type = CL_TYPE_PDF;
2327
-                        ctx->container_size = map->len - fpt->offset; /* not precise */
2326
+                        size_t csize = map->len - fpt->offset; /* not precise */
2327
+                        cli_set_container(ctx, CL_TYPE_PDF, csize);
2328 2328
                         cli_dbgmsg("PDF signature found at %u\n", (unsigned int) fpt->offset);
2329 2329
                         nret = cli_scanpdf(ctx, fpt->offset);
2330 2330
                     }
... ...
@@ -2334,13 +2331,13 @@ static int cli_scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_file_
2334 2334
                     if(SCAN_PE && (type == CL_TYPE_MSEXE || type == CL_TYPE_ZIP || type == CL_TYPE_MSOLE2)
2335 2335
                        && ctx->dconf->pe) {
2336 2336
                         uint64_t curr_len = map->len;
2337
+                        size_t csize = map->len - fpt->offset; /* not precise */
2337 2338
                         /* CL_ENGINE_MAX_EMBEDDED_PE */
2338 2339
                         if(curr_len > ctx->engine->maxembeddedpe) {
2339 2340
                             cli_dbgmsg("cli_scanraw: MaxEmbeddedPE exceeded\n");
2340 2341
                             break;
2341 2342
                         }
2342
-                        ctx->container_type = CL_TYPE_MSEXE; /* PE is a container for another executable here */
2343
-                        ctx->container_size = map->len - fpt->offset; /* not precise */
2343
+                        cli_set_container(ctx, CL_TYPE_MSEXE, csize);
2344 2344
                         memset(&peinfo, 0, sizeof(struct cli_exe_info));
2345 2345
                         peinfo.offset = fpt->offset;
2346 2346
                         if(cli_peheader(map, &peinfo) == 0) {
... ...
@@ -2369,13 +2366,11 @@ static int cli_scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_file_
2369 2369
 
2370 2370
             fpt = fpt->next;
2371 2371
         }
2372
-        ctx->container_type = current_container_type;
2373
-        ctx->container_size = current_container_size;
2374 2372
         
2375 2373
 	if(nret != CL_VIRUS) switch(ret) {
2376 2374
 	    case CL_TYPE_HTML:
2377 2375
 		/* bb#11196 - autoit script file misclassified as HTML */
2378
-		if (ctx->container_type == CL_TYPE_AUTOIT) {
2376
+		if (cli_get_container_type(ctx, -1) == CL_TYPE_AUTOIT) {
2379 2377
 		    ret = CL_TYPE_TEXT_ASCII;
2380 2378
 		} else if (SCAN_HTML && (type == CL_TYPE_TEXT_ASCII || type == CL_TYPE_GRAPHICS) &&
2381 2379
                     (DCONF_DOC & DOC_CONF_HTML)) {
... ...
@@ -2385,14 +2380,11 @@ static int cli_scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_file_
2385 2385
 		break;
2386 2386
 
2387 2387
 	    case CL_TYPE_MAIL:
2388
-		ctx->container_type = CL_TYPE_MAIL;
2389
-		ctx->container_size = map->len;
2388
+		cli_set_container(ctx, CL_TYPE_MAIL, map->len);
2390 2389
 		if(SCAN_MAIL && type == CL_TYPE_TEXT_ASCII && (DCONF_MAIL & MAIL_CONF_MBOX)) {
2391 2390
 		    *dettype = CL_TYPE_MAIL;
2392 2391
 		    nret = cli_scanmail(ctx);
2393 2392
 		}
2394
-		ctx->container_type = current_container_type;
2395
-		ctx->container_size = current_container_size;
2396 2393
 		break;
2397 2394
 
2398 2395
 	    default:
... ...
@@ -2535,17 +2527,16 @@ static int magic_scandesc(cli_ctx *ctx, cli_file_t type)
2535 2535
 	int ret = CL_CLEAN;
2536 2536
 	cli_file_t dettype = 0;
2537 2537
 	uint8_t typercg = 1;
2538
-	cli_file_t current_container_type = ctx->container_type;
2539
-	size_t current_container_size = ctx->container_size, hashed_size;
2538
+	size_t hashed_size;
2540 2539
 	unsigned char hash[16] = {'\0'};
2541 2540
 	bitset_t *old_hook_lsig_matches;
2542 2541
 	const char *filetype;
2543 2542
 	int cache_clean = 0, res;
2544
-    int run_cleanup = 0;
2543
+	int run_cleanup = 0;
2545 2544
 #if HAVE_JSON
2546 2545
 	struct json_object *parent_property = NULL;
2547 2546
 #else
2548
-    void *parent_property = NULL;
2547
+	void *parent_property = NULL;
2549 2548
 #endif
2550 2549
 
2551 2550
     if(!ctx->engine) {
... ...
@@ -2759,7 +2750,8 @@ static int magic_scandesc(cli_ctx *ctx, cli_file_t type)
2759 2759
 
2760 2760
     ctx->recursion++;
2761 2761
     perf_nested_start(ctx, PERFT_CONTAINER, PERFT_SCAN);
2762
-    ctx->container_size = (*ctx->fmap)->len;
2762
+    /* set current level as container AFTER recursing */
2763
+    cli_set_container(ctx, type, (*ctx->fmap)->len);
2763 2764
     switch(type) {
2764 2765
 	case CL_TYPE_IGNORED:
2765 2766
 	    break;
... ...
@@ -2795,7 +2787,6 @@ static int magic_scandesc(cli_ctx *ctx, cli_file_t type)
2795 2795
 	    break;
2796 2796
 
2797 2797
 	case CL_TYPE_RAR:
2798
-	    ctx->container_type = CL_TYPE_RAR;
2799 2798
 	    if(have_rar && SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_RAR)) {
2800 2799
 		char *tmpname = NULL;
2801 2800
 		int desc = fmap_fd(*ctx->fmap);
... ...
@@ -2841,7 +2832,6 @@ static int magic_scandesc(cli_ctx *ctx, cli_file_t type)
2841 2841
 	    }
2842 2842
 #endif
2843 2843
 	case CL_TYPE_ZIP:
2844
-	    ctx->container_type = CL_TYPE_ZIP;
2845 2844
 	    if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_ZIP))
2846 2845
 		ret = cli_unzip(ctx);
2847 2846
 	    break;
... ...
@@ -2872,19 +2862,16 @@ static int magic_scandesc(cli_ctx *ctx, cli_file_t type)
2872 2872
 	    break;
2873 2873
 
2874 2874
 	case CL_TYPE_ARJ:
2875
-	    ctx->container_type = CL_TYPE_ARJ;
2876 2875
 	    if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_ARJ))
2877 2876
 		ret = cli_scanarj(ctx, 0, NULL);
2878 2877
 	    break;
2879 2878
 
2880 2879
         case CL_TYPE_NULSFT:
2881
-	    ctx->container_type = CL_TYPE_NULSFT;
2882 2880
 	    if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_NSIS))
2883 2881
 		ret = cli_scannulsft(ctx, 0);
2884 2882
 	    break;
2885 2883
 
2886 2884
         case CL_TYPE_AUTOIT:
2887
-	    ctx->container_type = CL_TYPE_AUTOIT;
2888 2885
 	    if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_AUTOIT))
2889 2886
 		ret = cli_scanautoit(ctx, 23);
2890 2887
 	    break;
... ...
@@ -2895,7 +2882,6 @@ static int magic_scandesc(cli_ctx *ctx, cli_file_t type)
2895 2895
 	    break;
2896 2896
 
2897 2897
 	case CL_TYPE_MSCAB:
2898
-	    ctx->container_type = CL_TYPE_MSCAB;
2899 2898
 	    if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_CAB))
2900 2899
 		ret = cli_scanmscab(ctx, 0);
2901 2900
 	    break;
... ...
@@ -2921,19 +2907,16 @@ static int magic_scandesc(cli_ctx *ctx, cli_file_t type)
2921 2921
 	    break;
2922 2922
 
2923 2923
 	case CL_TYPE_RTF:
2924
-	    ctx->container_type = CL_TYPE_RTF;
2925 2924
 	    if(SCAN_ARCHIVE && (DCONF_DOC & DOC_CONF_RTF))
2926 2925
 		ret = cli_scanrtf(ctx);
2927 2926
 	    break;
2928 2927
 
2929 2928
 	case CL_TYPE_MAIL:
2930
-	    ctx->container_type = CL_TYPE_MAIL;
2931 2929
 	    if(SCAN_MAIL && (DCONF_MAIL & MAIL_CONF_MBOX))
2932 2930
 		ret = cli_scanmail(ctx);
2933 2931
 	    break;
2934 2932
 
2935 2933
 	case CL_TYPE_MHTML:
2936
-	    ctx->container_type = CL_TYPE_MHTML;
2937 2934
 	    if(SCAN_MAIL && (DCONF_MAIL & MAIL_CONF_MBOX))
2938 2935
 		ret = cli_scanmail(ctx);
2939 2936
 	    break;
... ...
@@ -2949,55 +2932,46 @@ static int magic_scandesc(cli_ctx *ctx, cli_file_t type)
2949 2949
 	    break;
2950 2950
 
2951 2951
 	case CL_TYPE_MSCHM:
2952
-	    ctx->container_type = CL_TYPE_MSCHM;
2953 2952
 	    if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_CHM))
2954 2953
 		ret = cli_scanmschm(ctx);
2955 2954
 	    break;
2956 2955
 
2957 2956
 	case CL_TYPE_MSOLE2:
2958
-	    ctx->container_type = CL_TYPE_MSOLE2;
2959 2957
 	    if(SCAN_OLE2 && (DCONF_ARCH & ARCH_CONF_OLE2))
2960 2958
 		ret = cli_scanole2(ctx);
2961 2959
 	    break;
2962 2960
 
2963 2961
 	case CL_TYPE_7Z:
2964
-	    ctx->container_type = CL_TYPE_7Z;
2965 2962
 	    if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_7Z))
2966 2963
 		ret = cli_7unz(ctx, 0);
2967 2964
 	    break;
2968 2965
 
2969 2966
 	case CL_TYPE_POSIX_TAR:
2970
-	    ctx->container_type = CL_TYPE_POSIX_TAR;
2971 2967
 	    if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_TAR))
2972 2968
 		ret = cli_scantar(ctx, 1);
2973 2969
 	    break;
2974 2970
 
2975 2971
 	case CL_TYPE_OLD_TAR:
2976
-	    ctx->container_type = CL_TYPE_OLD_TAR;
2977 2972
 	    if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_TAR))
2978 2973
 		ret = cli_scantar(ctx, 0);
2979 2974
 	    break;
2980 2975
 
2981 2976
 	case CL_TYPE_CPIO_OLD:
2982
-	    ctx->container_type = CL_TYPE_CPIO_OLD;
2983 2977
 	    if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_CPIO))
2984 2978
 		ret = cli_scancpio_old(ctx);
2985 2979
 	    break;
2986 2980
 
2987 2981
 	case CL_TYPE_CPIO_ODC:
2988
-	    ctx->container_type = CL_TYPE_CPIO_ODC;
2989 2982
 	    if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_CPIO))
2990 2983
 		ret = cli_scancpio_odc(ctx);
2991 2984
 	    break;
2992 2985
 
2993 2986
 	case CL_TYPE_CPIO_NEWC:
2994
-	    ctx->container_type = CL_TYPE_CPIO_NEWC;
2995 2987
 	    if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_CPIO))
2996 2988
 		ret = cli_scancpio_newc(ctx, 0);
2997 2989
 	    break;
2998 2990
 
2999 2991
 	case CL_TYPE_CPIO_CRC:
3000
-	    ctx->container_type = CL_TYPE_CPIO_CRC;
3001 2992
 	    if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_CPIO))
3002 2993
 		ret = cli_scancpio_newc(ctx, 1);
3003 2994
 	    break;
... ...
@@ -3036,7 +3010,6 @@ static int magic_scandesc(cli_ctx *ctx, cli_file_t type)
3036 3036
 	    break;
3037 3037
 
3038 3038
 	case CL_TYPE_PDF: /* FIXMELIMITS: pdf should be an archive! */
3039
-	    ctx->container_type = CL_TYPE_PDF;
3040 3039
 	    if(SCAN_PDF && (DCONF_DOC & DOC_CONF_PDF))
3041 3040
 		ret = cli_scanpdf(ctx, 0);
3042 3041
 	    break;
... ...
@@ -3062,19 +3035,16 @@ static int magic_scandesc(cli_ctx *ctx, cli_file_t type)
3062 3062
 	    break;
3063 3063
 
3064 3064
 	case CL_TYPE_SIS:
3065
-	    ctx->container_type = CL_TYPE_SIS;
3066 3065
 	    if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_SIS))
3067 3066
 		ret = cli_scansis(ctx);
3068 3067
 	    break;
3069 3068
 
3070 3069
 	case CL_TYPE_XAR:
3071
-	    ctx->container_type = CL_TYPE_XAR;
3072 3070
 	    if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_XAR))
3073 3071
 		ret = cli_scanxar(ctx);
3074 3072
 	    break;
3075 3073
 
3076 3074
 	case CL_TYPE_PART_HFSPLUS:
3077
-	    ctx->container_type = CL_TYPE_PART_HFSPLUS;
3078 3075
 	    if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_HFSPLUS))
3079 3076
 		ret = cli_scanhfsplus(ctx);
3080 3077
 	    break;
... ...
@@ -3099,8 +3069,6 @@ static int magic_scandesc(cli_ctx *ctx, cli_file_t type)
3099 3099
     }
3100 3100
     perf_nested_stop(ctx, PERFT_CONTAINER, PERFT_SCAN);
3101 3101
     ctx->recursion--;
3102
-    ctx->container_type = current_container_type;
3103
-    ctx->container_size = current_container_size;
3104 3102
 
3105 3103
     if(ret == CL_VIRUS) {
3106 3104
 	ret = cli_checkfp(hash, hashed_size, ctx);
... ...
@@ -3176,7 +3144,7 @@ static int magic_scandesc(cli_ctx *ctx, cli_file_t type)
3176 3176
 	    perf_nested_start(ctx, PERFT_SCRIPT, PERFT_SCAN);
3177 3177
 	    if((DCONF_DOC & DOC_CONF_SCRIPT) && dettype != CL_TYPE_HTML && (ret != CL_VIRUS || SCAN_ALL) && SCAN_HTML)
3178 3178
 	        ret = cli_scanscript(ctx);
3179
-	    if(SCAN_MAIL && (DCONF_MAIL & MAIL_CONF_MBOX) && ret != CL_VIRUS && (ctx->container_type == CL_TYPE_MAIL || dettype == CL_TYPE_MAIL)) {
3179
+	    if(SCAN_MAIL && (DCONF_MAIL & MAIL_CONF_MBOX) && ret != CL_VIRUS && (cli_get_container_type(ctx, -1) == CL_TYPE_MAIL || dettype == CL_TYPE_MAIL)) {
3180 3180
 		ret = cli_fmap_scandesc(ctx, CL_TYPE_MAIL, 0, NULL, AC_SCAN_VIR, NULL, NULL);
3181 3181
 	    }
3182 3182
 	    perf_nested_stop(ctx, PERFT_SCRIPT, PERFT_SCAN);
... ...
@@ -3452,8 +3420,10 @@ static int scan_common(int desc, cl_fmap_t *map, const char **virname, unsigned
3452 3452
     ctx.scanned = scanned;
3453 3453
     ctx.options = scanoptions;
3454 3454
     ctx.found_possibly_unwanted = 0;
3455
-    ctx.container_type = CL_TYPE_ANY;
3456
-    ctx.container_size = 0;
3455
+    ctx.containers = cli_calloc(sizeof(cli_ctx_container), ctx.engine->maxreclevel + 2);
3456
+    if(!ctx.containers)
3457
+	return CL_EMEM;
3458
+    cli_set_container(&ctx, CL_TYPE_ANY, 0);
3457 3459
     ctx.dconf = (struct cli_dconf *) engine->dconf;
3458 3460
     ctx.cb_ctx = context;
3459 3461
     ctx.fmap = cli_calloc(sizeof(fmap_t *), ctx.engine->maxreclevel + 2);
... ...
@@ -202,7 +202,12 @@ static int hashpe(const char *filename, unsigned int class, int type)
202 202
     memset(&ctx, '\0', sizeof(cli_ctx));
203 203
     ctx.engine = engine;
204 204
     ctx.options = CL_SCAN_STDOPT;
205
-    ctx.container_type = CL_TYPE_ANY;
205
+    ctx.containers = cli_calloc(sizeof(cli_ctx_container), engine->maxreclevel + 2);
206
+    if(!ctx.containers) {
207
+	cl_engine_free(engine);
208
+	return -1;
209
+    }
210
+    ctx.containers[0].type = CL_TYPE_ANY;
206 211
     ctx.dconf = (struct cli_dconf *) engine->dconf;
207 212
     ctx.fmap = calloc(sizeof(fmap_t *), 1);
208 213
     if(!ctx.fmap) {
... ...
@@ -2227,7 +2232,12 @@ static void matchsig(const char *sig, const char *offset, int fd)
2227 2227
     memset(&ctx, '\0', sizeof(cli_ctx));
2228 2228
     ctx.engine = engine;
2229 2229
     ctx.options = CL_SCAN_STDOPT;
2230
-    ctx.container_type = CL_TYPE_ANY;
2230
+    ctx.containers = cli_calloc(sizeof(cli_ctx_container), engine->maxreclevel + 2);
2231
+    if(!ctx.containers) {
2232
+	cl_engine_free(engine);
2233
+	return;
2234
+    }
2235
+    ctx.containers[0].type = CL_TYPE_ANY;
2231 2236
     ctx.dconf = (struct cli_dconf *) engine->dconf;
2232 2237
     ctx.fmap = calloc(sizeof(fmap_t *), 1);
2233 2238
     if(!ctx.fmap) {
... ...
@@ -3413,7 +3423,12 @@ static int dumpcerts(const struct optstruct *opts)
3413 3413
     memset(&ctx, '\0', sizeof(cli_ctx));
3414 3414
     ctx.engine = engine;
3415 3415
     ctx.options = CL_SCAN_STDOPT;
3416
-    ctx.container_type = CL_TYPE_ANY;
3416
+    ctx.containers = cli_calloc(sizeof(cli_ctx_container), engine->maxreclevel + 2);
3417
+    if(!ctx.containers) {
3418
+	cl_engine_free(engine);
3419
+	return -1;
3420
+    }
3421
+    ctx.containers[0].type = CL_TYPE_ANY;
3417 3422
     ctx.dconf = (struct cli_dconf *) engine->dconf;
3418 3423
     ctx.fmap = calloc(sizeof(fmap_t *), 1);
3419 3424
     if(!ctx.fmap) {