Browse code

workaround for unrar not supporting fmap.

When we try to scan a fmap-ed file, and the fmap is not backed by a file
descriptor then dump to a tmpfile, and give that to unrar.
This can only happen if you scan a fmap created with cl_fmap_open_*,
it won't happen with clamscan and clamd.

Török Edvin authored on 2012/01/04 22:33:33
Showing 2 changed files
... ...
@@ -732,11 +732,9 @@ static inline unsigned int fmap_which_page(fmap_t *m, size_t at) {
732 732
 
733 733
 int fmap_fd(fmap_t *m)
734 734
 {
735
-    int fd;
736
-    if (!m->handle_is_fd) {
737
-	cli_warnmsg("fmap: trying to retrieve descriptor from something that is not\n");
735
+    int fd, ret;
736
+    if (!m->handle_is_fd)
738 737
 	return -1;
739
-    }
740 738
     fd = (int)(ssize_t)m->handle;
741 739
     lseek(fd, 0, SEEK_SET);
742 740
     return fd;
... ...
@@ -2051,7 +2051,7 @@ static void emax_reached(cli_ctx *ctx) {
2051 2051
 	cli_dbgmsg("cli_magic_scandesc: returning %d %s\n", retcode, __AT__); 			\
2052 2052
 	if(ctx->engine->cb_post_scan) {								\
2053 2053
 	    perf_start(ctx, PERFT_POSTCB);							\
2054
-	    switch(ctx->engine->cb_post_scan(desc, retcode, retcode == CL_VIRUS && ctx->virname ? *ctx->virname : NULL, ctx->cb_ctx)) {	\
2054
+	    switch(ctx->engine->cb_post_scan(fmap_fd(*ctx->fmap), retcode, retcode == CL_VIRUS && ctx->virname ? *ctx->virname : NULL, ctx->cb_ctx)) {	\
2055 2055
 	    case CL_BREAK:									\
2056 2056
 		cli_dbgmsg("cli_magic_scandesc: file whitelisted by post_scan callback\n"); 	\
2057 2057
 		perf_stop(ctx, PERFT_POSTCB);							\
... ...
@@ -2081,7 +2081,7 @@ static void emax_reached(cli_ctx *ctx) {
2081 2081
 #define CALL_PRESCAN_CB(scanfn)	                                                     \
2082 2082
     if(ctx->engine->scanfn) {				\
2083 2083
 	perf_start(ctx, PERFT_PRECB);                                                        \
2084
-	switch(ctx->engine->scanfn(desc, filetype, ctx->cb_ctx)) {	\
2084
+	switch(ctx->engine->scanfn(fmap_fd(*ctx->fmap), filetype, ctx->cb_ctx)) {	\
2085 2085
 	case CL_BREAK:                                                                       \
2086 2086
 	    cli_dbgmsg("cli_magic_scandesc: file whitelisted by "#scanfn" callback\n");                \
2087 2087
 	    perf_stop(ctx, PERFT_PRECB);                                                     \
... ...
@@ -2113,7 +2113,6 @@ static int magic_scandesc(cli_ctx *ctx, cli_file_t type)
2113 2113
 	bitset_t *old_hook_lsig_matches;
2114 2114
 	const char *filetype;
2115 2115
 	int cache_clean = 0;
2116
-	int desc = fmap_fd(*ctx->fmap);/* TODO: port the rest to fmap, and keep this just for pre/post callbacks */
2117 2116
 
2118 2117
     if(ctx->engine->maxreclevel && ctx->recursion > ctx->engine->maxreclevel) {
2119 2118
         cli_dbgmsg("cli_magic_scandesc: Archive recursion limit exceeded (%u, max: %u)\n", ctx->recursion, ctx->engine->maxreclevel);
... ...
@@ -2167,7 +2166,7 @@ static int magic_scandesc(cli_ctx *ctx, cli_file_t type)
2167 2167
 	CALL_PRESCAN_CB(cb_pre_scan);
2168 2168
 	/* ret_from_magicscan can be used below here*/
2169 2169
 	if((ret = cli_fmap_scandesc(ctx, 0, 0, NULL, AC_SCAN_VIR, NULL, hash)) == CL_VIRUS)
2170
-	    cli_dbgmsg("%s found in descriptor %d\n", *ctx->virname, desc);
2170
+	    cli_dbgmsg("%s found in descriptor %d\n", *ctx->virname, fmap_fd(*ctx->fmap));
2171 2171
 	else if(ret == CL_CLEAN) {
2172 2172
 	    if(ctx->recursion != ctx->engine->maxreclevel)
2173 2173
 		cache_clean = 1; /* Only cache if limits are not reached */
... ...
@@ -2210,8 +2209,42 @@ static int magic_scandesc(cli_ctx *ctx, cli_file_t type)
2210 2210
 
2211 2211
 	case CL_TYPE_RAR:
2212 2212
 	    ctx->container_type = CL_TYPE_RAR;
2213
-	    if(have_rar && SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_RAR))
2213
+	    if(have_rar && SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_RAR)) {
2214
+		char *tmpname = NULL;
2215
+		int desc = fmap_fd(*ctx->fmap);
2216
+		if (desc == -1) {
2217
+		    size_t pos = 0, len;
2218
+
2219
+		    cli_dbgmsg("fmap not backed by file, dumping ...\n");
2220
+		    if ((ret = cli_gentempfd(((cli_ctx*)ctx)->engine->tmpdir, &tmpname, &desc)) != CL_SUCCESS) {
2221
+			cli_dbgmsg("fmap_fd: failed to generate temporary file.\n");
2222
+			break;
2223
+		    }
2224
+		    do {
2225
+			char *b;
2226
+
2227
+			len = 0;
2228
+			b = fmap_need_off_once_len(*ctx->fmap, pos, BUFSIZ, &len);
2229
+			pos += len;
2230
+			if (b && len > 0) {
2231
+			    if (cli_writen(desc, b, len) != len) {
2232
+				close(desc);
2233
+				unlink(tmpname);
2234
+				cli_warnmsg("fmap_fd_dump: write failed\n");
2235
+				ret = CL_EWRITE;
2236
+				break;
2237
+			    }
2238
+			}
2239
+		    } while (len > 0);
2240
+		    lseek(desc, 0, SEEK_SET);
2241
+		}
2214 2242
 		ret = cli_scanrar(desc, ctx, 0, NULL);
2243
+		if (tmpname) {
2244
+		    close(desc);
2245
+		    unlink(tmpname);
2246
+		    free(tmpname);
2247
+		}
2248
+	    }
2215 2249
 	    break;
2216 2250
 
2217 2251
 	case CL_TYPE_ZIP:
... ...
@@ -2505,7 +2538,7 @@ static int magic_scandesc(cli_ctx *ctx, cli_file_t type)
2505 2505
 	case CL_EMAXREC:
2506 2506
 	case CL_EMAXSIZE:
2507 2507
 	case CL_EMAXFILES:
2508
-	    cli_dbgmsg("Descriptor[%d]: %s\n", desc, cl_strerror(ret));
2508
+	    cli_dbgmsg("Descriptor[%d]: %s\n", fmap_fd(*ctx->fmap), cl_strerror(ret));
2509 2509
 	case CL_CLEAN:
2510 2510
 	    cache_clean = 1;
2511 2511
 	    ret_from_magicscan(CL_CLEAN);