Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Scan files in the ISO tree as well as the Joliet file tree #938

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
148 changes: 97 additions & 51 deletions libclamav/iso9660.c
Original file line number Diff line number Diff line change
Expand Up @@ -228,25 +228,36 @@ cl_error_t cli_scaniso(cli_ctx *ctx, size_t offset)
const uint8_t *privol, *next;
iso9660_t iso;
int i;
cl_error_t status = CL_SUCCESS;
cl_error_t ret = CL_SUCCESS;
uint32_t nextJoliet = 0;

if (offset < 32768)
return CL_SUCCESS; /* Need 16 sectors at least 2048 bytes long */
if (offset < 32768) {
/* Need 16 sectors at least 2048 bytes long */
goto done;
}

privol = fmap_need_off(ctx->fmap, offset, 2448 + 6);
if (!privol)
return CL_SUCCESS;
if (!privol) {
goto done;
}

next = (uint8_t *)cli_memstr((char *)privol + 2049, 2448 + 6 - 2049, "CD001", 5);
if (!next)
return CL_SUCCESS; /* Find next volume descriptor */
if (!next) {
/* Find next volume descriptor */
goto done;
}

iso.sectsz = (next - privol) - 1;
if (iso.sectsz * 16 > offset)
return CL_SUCCESS; /* Need room for 16 system sectors */
if (iso.sectsz * 16 > offset) {
/* Need room for 16 system sectors */
goto done;
}

iso.blocksz = cli_readint32(privol + 128) & 0xffff;
if (iso.blocksz != 512 && iso.blocksz != 1024 && iso.blocksz != 2048)
return CL_SUCCESS; /* Likely not a cdrom image */
/* Likely not a cdrom image */
goto done;

iso.base_offset = offset - iso.sectsz * 16;
iso.joliet = 0;
Expand Down Expand Up @@ -283,59 +294,94 @@ cl_error_t cli_scaniso(cli_ctx *ctx, size_t offset)

/* NOTE: freeing sector now. it is still safe to access as we don't alloc anymore */
fmap_unneed_off(ctx->fmap, offset, 2448);
if (iso.joliet)
privol = next;
if (!iso.joliet) {
next = NULL;
}

cli_dbgmsg("in cli_scaniso\n");
if (cli_debug_flag) {
cli_dbgmsg("cli_scaniso: Raw sector size: %u\n", iso.sectsz);
cli_dbgmsg("cli_scaniso: Block size: %u\n", iso.blocksz);
nextJoliet = iso.joliet;
iso.joliet = 0;

cli_dbgmsg("cli_scaniso: Volume descriptor version: %u\n", privol[6]);
do {
cli_dbgmsg("in cli_scaniso\n");
if (cli_debug_flag) {
cli_dbgmsg("cli_scaniso: Raw sector size: %u\n", iso.sectsz);
cli_dbgmsg("cli_scaniso: Block size: %u\n", iso.blocksz);

cli_dbgmsg("cli_scaniso: Volume descriptor version: %u\n", privol[6]);

#define ISOSTRING(src, len) iso_string(&iso, (src), (len))
cli_dbgmsg("cli_scaniso: System: %s\n", ISOSTRING(privol + 8, 32));
cli_dbgmsg("cli_scaniso: Volume: %s\n", ISOSTRING(privol + 40, 32));
cli_dbgmsg("cli_scaniso: System: %s\n", ISOSTRING(privol + 8, 32));
cli_dbgmsg("cli_scaniso: Volume: %s\n", ISOSTRING(privol + 40, 32));

cli_dbgmsg("cli_scaniso: Volume space size: 0x%x blocks\n", cli_readint32(&privol[80]));
cli_dbgmsg("cli_scaniso: Volume %u of %u\n", cli_readint32(privol + 124) & 0xffff, cli_readint32(privol + 120) & 0xffff);
cli_dbgmsg("cli_scaniso: Volume space size: 0x%x blocks\n", cli_readint32(&privol[80]));
cli_dbgmsg("cli_scaniso: Volume %u of %u\n", cli_readint32(privol + 124) & 0xffff, cli_readint32(privol + 120) & 0xffff);

cli_dbgmsg("cli_scaniso: Volume Set: %s\n", ISOSTRING(privol + 190, 128));
cli_dbgmsg("cli_scaniso: Publisher: %s\n", ISOSTRING(privol + 318, 128));
cli_dbgmsg("cli_scaniso: Data Preparer: %s\n", ISOSTRING(privol + 446, 128));
cli_dbgmsg("cli_scaniso: Application: %s\n", ISOSTRING(privol + 574, 128));
cli_dbgmsg("cli_scaniso: Volume Set: %s\n", ISOSTRING(privol + 190, 128));
cli_dbgmsg("cli_scaniso: Publisher: %s\n", ISOSTRING(privol + 318, 128));
cli_dbgmsg("cli_scaniso: Data Preparer: %s\n", ISOSTRING(privol + 446, 128));
cli_dbgmsg("cli_scaniso: Application: %s\n", ISOSTRING(privol + 574, 128));

#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])
ISOTIME("Volume creation time", 813);
ISOTIME("Volume modification time", 830);
ISOTIME("Volume expiration time", 847);
ISOTIME("Volume effective time", 864);

cli_dbgmsg("cli_scaniso: Path table size: 0x%x\n", cli_readint32(privol + 132) & 0xffff);
cli_dbgmsg("cli_scaniso: LSB Path Table: 0x%x\n", cli_readint32(privol + 140));
cli_dbgmsg("cli_scaniso: Opt LSB Path Table: 0x%x\n", cli_readint32(privol + 144));
cli_dbgmsg("cli_scaniso: MSB Path Table: 0x%x\n", cbswap32(cli_readint32(privol + 148)));
cli_dbgmsg("cli_scaniso: Opt MSB Path Table: 0x%x\n", cbswap32(cli_readint32(privol + 152)));
cli_dbgmsg("cli_scaniso: File Structure Version: %u\n", privol[881]);

if (iso.joliet)
cli_dbgmsg("cli_scaniso: Joliet level %u\n", iso.joliet);
}
ISOTIME("Volume creation time", 813);
ISOTIME("Volume modification time", 830);
ISOTIME("Volume expiration time", 847);
ISOTIME("Volume effective time", 864);

cli_dbgmsg("cli_scaniso: Path table size: 0x%x\n", cli_readint32(privol + 132) & 0xffff);
cli_dbgmsg("cli_scaniso: LSB Path Table: 0x%x\n", cli_readint32(privol + 140));
cli_dbgmsg("cli_scaniso: Opt LSB Path Table: 0x%x\n", cli_readint32(privol + 144));
cli_dbgmsg("cli_scaniso: MSB Path Table: 0x%x\n", cbswap32(cli_readint32(privol + 148)));
cli_dbgmsg("cli_scaniso: Opt MSB Path Table: 0x%x\n", cbswap32(cli_readint32(privol + 152)));
cli_dbgmsg("cli_scaniso: File Structure Version: %u\n", privol[881]);

if (iso.joliet)
cli_dbgmsg("cli_scaniso: Joliet level %u\n", iso.joliet);
}

if (privol[156 + 26] || privol[156 + 27]) {
cli_dbgmsg("cli_scaniso: Interleaved root directory is not supported\n");
return CL_SUCCESS;
if (privol[156 + 26] || privol[156 + 27]) {
cli_dbgmsg("cli_scaniso: Interleaved root directory is not supported\n");
status = CL_SUCCESS;
goto done;
}

iso.ctx = ctx;
ret = cli_hashset_init(&iso.dir_blocks, 1024, 80);
if (ret != CL_SUCCESS) {
status = ret;
goto done;
}

ret = iso_parse_dir(&iso, cli_readint32(privol + 156 + 2) + privol[156 + 1], cli_readint32(privol + 156 + 10));
cli_hashset_destroy(&iso.dir_blocks);
switch (ret) {
case CL_CLEAN:
/* fallthrough */
case CL_EFORMAT:
/* fallthrough */
case CL_EPARSE:
break;
default:
/*Recoverable errors are above, anything else we need to return.*/
status = ret;
goto done;
}
if (ret > status) {
status = ret;
}

privol = next;
next = NULL;
iso.joliet = nextJoliet;

} while (privol);

done:

if (status == CL_BREAK) {
status = CL_SUCCESS;
}

iso.ctx = ctx;
i = cli_hashset_init(&iso.dir_blocks, 1024, 80);
if (i != CL_SUCCESS)
return i;
i = iso_parse_dir(&iso, cli_readint32(privol + 156 + 2) + privol[156 + 1], cli_readint32(privol + 156 + 10));
cli_hashset_destroy(&iso.dir_blocks);
if (i == CL_BREAK)
return CL_SUCCESS;
return i;
return status;
}
26 changes: 26 additions & 0 deletions unit_tests/clamscan/assorted_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,3 +212,29 @@ def test_pe_cert_trust_archive(self):
unexpected_results = ['OK']

self.verify_output(output.out, expected=expected_results, unexpected=unexpected_results)

def test_iso_missing_joliet(self):
self.step_name('Test that we correctly extract files from an ISO even if the joliet file path is empty.')

test_path = TC.path_source / 'unit_tests' / 'input' / 'other_scanfiles'
sig_path = TC.path_source / 'unit_tests' / 'input' / 'other_sigs' / 'logo.hsb'

command = '{valgrind} {valgrind_args} {clamscan} \
-d {sig_path} \
--allmatch {testfile1} {testfile2}'.format(
valgrind=TC.valgrind, valgrind_args=TC.valgrind_args, clamscan=TC.clamscan,
sig_path=sig_path,
testfile1=test_path / 'iso_normal.logo.iso',
testfile2=test_path / 'iso_no_joliet.logo.iso',
)
output = self.execute_command(command)

assert output.ec == 1

expected_results = [
'iso_normal.logo.iso: logo.png.UNOFFICIAL FOUND',
'iso_no_joliet.logo.iso: logo.png.UNOFFICIAL FOUND',
]
unexpected_results = ['OK']

self.verify_output(output.out, expected=expected_results, unexpected=unexpected_results)
Binary file not shown.
Binary file not shown.
1 change: 1 addition & 0 deletions unit_tests/input/other_sigs/logo.hsb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
f083e9c704165003f8c065964e4ccb47da48bbad8a80521d571cbf0f1d4762c6:25476:logo.png
Loading