... | ... |
@@ -250,11 +250,11 @@ int cli_scanishield_msi(int desc, cli_ctx *ctx, off_t off) { |
250 | 250 |
csize -= z.avail_in; |
251 | 251 |
z.next_in = buf; |
252 | 252 |
do { |
253 |
- int def; |
|
253 |
+ int inf; |
|
254 | 254 |
z.avail_out = sizeof(obuf); |
255 | 255 |
z.next_out = obuf; |
256 |
- def = inflate(&z, 0); |
|
257 |
- if(def != Z_OK && def != Z_STREAM_END && def != Z_BUF_ERROR) { |
|
256 |
+ inf = inflate(&z, 0); |
|
257 |
+ if(inf != Z_OK && inf != Z_STREAM_END && inf != Z_BUF_ERROR) { |
|
258 | 258 |
cli_dbgmsg("ishield-msi: bad stream\n"); |
259 | 259 |
csize = 0; |
260 | 260 |
lseek(desc, csize, SEEK_CUR); |
... | ... |
@@ -307,8 +307,8 @@ struct IS_CABSTUFF { |
307 | 307 |
}; |
308 | 308 |
|
309 | 309 |
static void md5str(uint8_t *sum); |
310 |
-static int is_parse_hdr(int desc, struct IS_CABSTUFF *c); |
|
311 |
- |
|
310 |
+static int is_parse_hdr(int desc, cli_ctx *ctx, struct IS_CABSTUFF *c); |
|
311 |
+static int is_extract_cab(int desc, cli_ctx *ctx, uint64_t off, uint64_t size, uint64_t csize); |
|
312 | 312 |
|
313 | 313 |
/* Extract the content of older (non-MSI) IS */ |
314 | 314 |
int cli_scanishield(int desc, cli_ctx *ctx, off_t off, size_t sz) { |
... | ... |
@@ -392,7 +392,7 @@ int cli_scanishield(int desc, cli_ctx *ctx, off_t off, size_t sz) { |
392 | 392 |
} |
393 | 393 |
|
394 | 394 |
if(ret == CL_CLEAN && (c.cabcnt || c.hdr != -1)) { |
395 |
- if(is_parse_hdr(desc, &c) == CL_CLEAN /* FIXMEISHIELD */) { |
|
395 |
+ if(is_parse_hdr(desc, ctx, &c) == CL_CLEAN /* FIXMEISHIELD */) { |
|
396 | 396 |
unsigned int i; |
397 | 397 |
if(c.hdr != -1) ret = is_dump_and_scan(desc, ctx, c.hdr, c.hdrsz); |
398 | 398 |
for(i=0; i<c.cabcnt && ret == CL_CLEAN; i++) { |
... | ... |
@@ -461,7 +461,7 @@ struct IS_HDR { |
461 | 461 |
}; |
462 | 462 |
|
463 | 463 |
|
464 |
-static int is_parse_hdr(int desc, struct IS_CABSTUFF *c) { /* FIXMEISHIELD: tell parent whether we completed the task or not */ |
|
464 |
+static int is_parse_hdr(int desc, cli_ctx *ctx, struct IS_CABSTUFF *c) { /* FIXMEISHIELD: tell parent whether we completed the task or not */ |
|
465 | 465 |
uint32_t h1_data_off, objs_files_cnt, objs_dirs_off; |
466 | 466 |
unsigned int off, i; |
467 | 467 |
char hash[33], *hdr; |
... | ... |
@@ -472,10 +472,10 @@ static int is_parse_hdr(int desc, struct IS_CABSTUFF *c) { /* FIXMEISHIELD: tell |
472 | 472 |
|
473 | 473 |
/* FIXMEISHIELD: sanitize c here */ |
474 | 474 |
|
475 |
- if(!(hdr = (char *)cli_malloc(c->hdrsz))) |
|
475 |
+ if(!(hdr = (char *)cli_malloc(c->hdrsz))) /* FIXMEISHIELD: mmap if large */ |
|
476 | 476 |
return CL_EMEM; |
477 | 477 |
|
478 |
- if(pread(desc, hdr, c->hdrsz, c->hdr) < c->hdrsz) { |
|
478 |
+ if(pread(desc, hdr, c->hdrsz, c->hdr) < (ssize_t)c->hdrsz) { |
|
479 | 479 |
cli_errmsg("is_parse_hdr: short read for header\n"); |
480 | 480 |
free(hdr); |
481 | 481 |
return CL_EREAD; |
... | ... |
@@ -574,7 +574,11 @@ static int is_parse_hdr(int desc, struct IS_CABSTUFF *c) { /* FIXMEISHIELD: tell |
574 | 574 |
cli_errmsg("is_parse_hdr: not scanned (dup)\n"); |
575 | 575 |
else { |
576 | 576 |
if(file->size) { /* FIXMEISHIELD: limits */ |
577 |
- //is_extract(inhash, hash, file->stream_off, file->size, file->csize); |
|
577 |
+ int ret = is_extract_cab(desc, ctx, le64_to_host(file->stream_off), le64_to_host(file->size), le64_to_host(file->csize)); |
|
578 |
+ if(ret != CL_CLEAN) { |
|
579 |
+ free(hdr); |
|
580 |
+ return ret; |
|
581 |
+ } |
|
578 | 582 |
} |
579 | 583 |
} |
580 | 584 |
break; |
... | ... |
@@ -585,7 +589,8 @@ static int is_parse_hdr(int desc, struct IS_CABSTUFF *c) { /* FIXMEISHIELD: tell |
585 | 585 |
cli_errmsg("is_parse_hdr: FILEITEM out of bounds\n"); |
586 | 586 |
off+=sizeof(*file); |
587 | 587 |
} |
588 |
- return 0; |
|
588 |
+ free(hdr); |
|
589 |
+ return CL_CLEAN; |
|
589 | 590 |
} |
590 | 591 |
|
591 | 592 |
|
... | ... |
@@ -601,3 +606,115 @@ static void md5str(uint8_t *sum) { |
601 | 601 |
} |
602 | 602 |
sum[32] = '\0'; |
603 | 603 |
} |
604 |
+ |
|
605 |
+ |
|
606 |
+#define IS_CABBUFSZ 65536 |
|
607 |
+ |
|
608 |
+static int is_extract_cab(int desc, cli_ctx *ctx, uint64_t off, uint64_t size, uint64_t csize) { |
|
609 |
+ uint8_t *inbuf, *outbuf; |
|
610 |
+ char *tempfile; |
|
611 |
+ FILE *in; |
|
612 |
+ int ofd, ret = CL_CLEAN; |
|
613 |
+ z_stream z; |
|
614 |
+ uint64_t outsz = 0; |
|
615 |
+ int success = 0; |
|
616 |
+ |
|
617 |
+ if((ofd=dup(desc)) < 0) { |
|
618 |
+ cli_errmsg("is_extract_cab: dup failed\n"); |
|
619 |
+ return CL_EDUP; |
|
620 |
+ } |
|
621 |
+ if(!(in = fdopen(ofd, "rb"))) { |
|
622 |
+ cli_errmsg("is_extract_cab: fdopen failed\n"); |
|
623 |
+ close(ofd); |
|
624 |
+ return CL_EOPEN; |
|
625 |
+ } |
|
626 |
+ if(fseeko(in, off, SEEK_SET)) { |
|
627 |
+ cli_errmsg("is_extract_cab: fseek failed\n"); |
|
628 |
+ fclose(in); |
|
629 |
+ return CL_ESEEK; |
|
630 |
+ } |
|
631 |
+ if(!(inbuf = cli_malloc(IS_CABBUFSZ))) { |
|
632 |
+ fclose(in); |
|
633 |
+ return CL_EMEM; |
|
634 |
+ } |
|
635 |
+ if(!(outbuf = cli_malloc(IS_CABBUFSZ))) { |
|
636 |
+ free(inbuf); |
|
637 |
+ fclose(in); |
|
638 |
+ return CL_EMEM; |
|
639 |
+ } |
|
640 |
+ if(!(tempfile = cli_gentemp(ctx->engine->tmpdir))) return CL_EMEM; |
|
641 |
+ if((ofd = open(tempfile, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, S_IRUSR|S_IWUSR)) < 0) { |
|
642 |
+ cli_errmsg("is_extract_cab: failed to create file %s\n", tempfile); |
|
643 |
+ free(tempfile); |
|
644 |
+ fclose(in); |
|
645 |
+ return CL_ECREAT; |
|
646 |
+ } |
|
647 |
+ |
|
648 |
+ while(csize) { |
|
649 |
+ uint16_t chunksz; |
|
650 |
+ success = 0; |
|
651 |
+ if(csize<2) { |
|
652 |
+ cli_errmsg("is_extract_cab: no room for chunk size\n"); |
|
653 |
+ break; |
|
654 |
+ } |
|
655 |
+ csize -= 2; |
|
656 |
+ if(!fread(outbuf, 2, 1, in)) { |
|
657 |
+ cli_dbgmsg("is_extract_cab: short read for chunk size\n"); |
|
658 |
+ break; |
|
659 |
+ } |
|
660 |
+ chunksz = outbuf[0] | (outbuf[1] << 8); |
|
661 |
+ if(!chunksz) { |
|
662 |
+ cli_dbgmsg("is_extract_cab: zero sized chunk\n"); |
|
663 |
+ continue; |
|
664 |
+ } |
|
665 |
+ if(csize < chunksz) { |
|
666 |
+ cli_dbgmsg("is_extract_cab: chunk is bigger than csize\n"); |
|
667 |
+ break; |
|
668 |
+ } |
|
669 |
+ csize -= chunksz; |
|
670 |
+ if(!fread(inbuf, chunksz, 1, in)) { |
|
671 |
+ cli_dbgmsg("is_extract_cab: short read for chunk\n"); |
|
672 |
+ break; |
|
673 |
+ } |
|
674 |
+ memset(&z, 0, sizeof(z)); |
|
675 |
+ inflateInit2(&z, -MAX_WBITS); |
|
676 |
+ z.next_in = (uint8_t *)inbuf; |
|
677 |
+ z.avail_in = chunksz; |
|
678 |
+ while(1) { |
|
679 |
+ int zret; |
|
680 |
+ z.next_out = outbuf; |
|
681 |
+ z.avail_out = IS_CABBUFSZ; |
|
682 |
+ zret = inflate(&z, 0); |
|
683 |
+ if(zret == Z_OK || zret == Z_STREAM_END || zret == Z_BUF_ERROR) { |
|
684 |
+ unsigned int umpd = IS_CABBUFSZ - z.avail_out; |
|
685 |
+ if(cli_writen(ofd, outbuf, umpd) < (ssize_t)umpd) |
|
686 |
+ break; |
|
687 |
+ outsz += umpd; |
|
688 |
+ if(zret == Z_STREAM_END || z.avail_out == IS_CABBUFSZ /* FIXMEISHIELD: is the latter ok? */) { |
|
689 |
+ success = 1; |
|
690 |
+ break; |
|
691 |
+ } |
|
692 |
+ continue; |
|
693 |
+ } |
|
694 |
+ cli_dbgmsg("is_extract_cab: file decompression failed with %d\n", zret); |
|
695 |
+ break; |
|
696 |
+ } |
|
697 |
+ inflateEnd(&z); |
|
698 |
+ if(!success) break; |
|
699 |
+ } |
|
700 |
+ fclose(in); |
|
701 |
+ if(success) { |
|
702 |
+ if (outsz != size) |
|
703 |
+ cli_dbgmsg("is_extract_cab: extracted %llu bytes to %s, expected %llu, scanning anyway.\n", outsz, tempfile, size); |
|
704 |
+ else |
|
705 |
+ cli_dbgmsg("is_extract_cab: extracted to %s\n", tempfile); |
|
706 |
+ lseek(ofd, 0, SEEK_SET); |
|
707 |
+ ret = cli_magic_scandesc(ofd, ctx); |
|
708 |
+ } |
|
709 |
+ |
|
710 |
+ close(ofd); |
|
711 |
+ if(!ctx->engine->keeptmp) |
|
712 |
+ if(cli_unlink(tempfile)) ret = CL_EUNLINK; |
|
713 |
+ free(tempfile); |
|
714 |
+ return success ? ret : CL_CLEAN; |
|
715 |
+} |