[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Libcdio-devel] Rock Ridge and libisofs/xorriso 'AL' extension

From: Thomas Schmitt
Subject: Re: [Libcdio-devel] Rock Ridge and libisofs/xorriso 'AL' extension
Date: Wed, 26 Jul 2017 14:10:36 +0200


i think i found it. Proposals are at the end of this mail.


Stepping through the code (after changing all -O2 in ./configure to -O0),
i see a strange loop in lib/iso9660/iso9660_fs.c : iso9660_ifs_readdir()

When the 4 directory records of the root directory of the 50 KB ISO
(".", "..", "A", "B.TXT;1") are all read and the next byte to read is
a 0-byte indicating a directory record length of 0, the loop continues
reading while advancing in single byte steps:

    while (offset < (dirbuf_len))
        if (!iso9660_get_dir_len(p_iso9660_dir))

libisofs code (by Vreixo Formoso, not by me) takes a directory record
length of 0 as reason to advance to the next block start, where the
data size field of the directory would indicate its end.

During this supposed-to-be-idle loop my breakpoint in
get_rock_ridge_filename() gets hit, with an alleged SUSP field length
of 94 bytes.
The SUSP field signature is two 0 bytes. Read offset in
iso9660_ifs_readdir() of the overall directory record is 2012, i.e.
36 bytes before the end of the block.

Reason for this zombie activity is a stray byte with value 128 at byte
offset 47104 + 2012 = 49116 in the ISO.

libcdio obviously takes it for a directory record length without
noticing that it would constitute an illegal directory record that
spans over a block limit.
(A directory block has to be padded by zeros and the next directory
 has to be put at the start of the next block, if it does not fit
 fully into the previous block.)

With that directory length, the SUSP+RR reader functions feel entitled
to read into the next block, which is the data storage of directory "/A"
and contains non-zero bytes.
Those bytes and derived values are what is seen by get_rock_ridge_filename()
as SUSP field with 0x0000 as signature and 94 bytes of length.

Whatever happens from now on: It should not have begun on the first hand.

The specs:

ECMA-119 (ISO 9660) is not as painful to read as is ECMA-167 with UDF-2.60.
But it is hard enough to find the prescription how exactly the list of
directory records shall be terminated. says that the padding bytes count as part of the directory.
So having the full block size of 2048 as directory size is legal enough.
libisofs does it the same.
(One could argue that the padding in the last block of a directory is
 not padding and thus the directory could end already at the last valid
 directory record. But we shall live with full block sizes.) says "Unused byte positions after the last Directory Record in
a Logical Sector shall be set to (00)."
So the stray byte with value 128 in the 50 KB ISO is a violation of
the specs.

A directory record cannot be smaller than 34 bytes.
So a length value of 0 is already an unambiguous indication that the
partial list of directory records in that block has ended and that
reading has to advance to the start of the next block.

Insofar my predecessor as libisofs developer was right.


libcdio should take a length of zero as trigger to hop to the next
directory data block. It should not scan byte by byte for further
non-zeros in the previous block. If such bytes were ever part of a
directory record, then the directory took a data damaging hit meanwhile.

This would not help against a stray byte immediately after the
next directory record, of course.
Therefore i propose to consider whether to skip to the next directory
data block if a found directory record size reaches into that block.


I will go on with trying to implement my proposals later today.
Just wanted to give an intermediate report.

Have a nice day :)


reply via email to

[Prev in Thread] Current Thread [Next in Thread]