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.
... | ... |
@@ -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); |