[syslinux] isolinux.bin checksum

Thomas Schmitt scdbackup at gmx.net
Tue Jan 9 08:41:52 PST 2018


Hi,

i think i found a suspect in lzo/prepcore.c and it would indeed be a
wrong range of checksumming (speculative congratulations to Ady).

Looking at
  http://repo.or.cz/syslinux.git/blob/0d82b71304d596d80f3c4520f9dcf90048ca50b7:/lzo/prepcore.c
it seems that this change in line 374 could yield correct checksums:

         unsigned int ptr;
-        for (ptr = 64; ptr < offset; ptr += 4)
+        for (ptr = start+64; ptr < offset; ptr += 4)
             csum += get_32((uint32_t *)(infile+ptr));


A test whether it works would be to produce isolinux.bin, read the 4 checksum
bytes from it at offset 20, put isolinux.bin into an ISO with mkisofs option
-boot-info-table, and check whether the 4 bytes at offset 20 are still the
same.
(If you use mkisofs or genisoimage, isolinux.bin on hard disk will change.
 With xorrisofs the change will only appear in the file isolinux.bin in the
 ISO filesystem.)

--------------------------------------------------------------------------
Reasoning:

- The prescription for Boot Info Table says that checksumming begins 
  at byte 64 of isolinux.bin. (See for example man mkisofs paragraph
  "EL TORITO BOOT INFORMATION TABLE".)

- prepcore.c constructs isolinux.bin from an unencrypted piece out of
  the input file isolinux.raw (which stems from an objcopy -S run) and
  from a compressed part.
  So it begins to compute the checksum on the input file bytes

    for (ptr = 64; ptr < offset; ptr += 4)
        csum += get_32((uint32_t *)(infile+ptr));

  and then continues on the compressed part

    for (ptr = 0; ptr < outfile_len; ptr += 4)
        csum += get_32((uint32_t *)(out+ptr));

- But prepcore.c copies infile data to isolinux.bin starting with an
  offset named "start" which i strongly believe is not zero:

    if (fwrite(infile+start,1,offset-start,f) != offset-start ||

  If "start" is not zero, then this is not the same byte range as with
  the checksum loop over (infile+ptr).

- "start" obviously is used to skip at least the 32 byte header which
  prepcore.c interprets at the beginning of the input file:

    struct prefix {
        uint32_t pfx_start;
        uint32_t pfx_compressed;
        uint32_t pfx_cdatalen;
        uint32_t pfx_checksum;
    };
    ...
    struct prefix *prefix;
    ...
    infile_len = (lzo_uint) fread(infile,1,infile_len,f);
    ...
    prefix = (struct prefix *)infile;
    start = get_32(&prefix->pfx_start);
    offset = get_32(&prefix->pfx_compressed);

  Such header bytes with plausible values are not to see at the beginning of
  isolinux.bin:

    fa  ea  6c  7c  00  00  90  90  10  00  00  00  00  00  00  00

  The struct members pfx_start and pfx_compressed are read as little endian
  unsigned integers and used as offsets in the isolinux.raw file. 
  0x7c6ceafa and 0x90900000 are much too large to have served for that
  purpose.
  So the original prefix header was skipped, and thus "start" was not zero.


Have a nice day :)

Thomas



More information about the Syslinux mailing list