libcdio-devel
[Top][All Lists]
Advanced

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

Re: [Libcdio-devel] Shall we rectify the defintion of iso_su_ce_t for 64


From: Pete Batard
Subject: Re: [Libcdio-devel] Shall we rectify the defintion of iso_su_ce_t for 64 bit alignment ?
Date: Wed, 22 Mar 2023 00:48:58 +0000
User-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:102.0) Gecko/20100101 Thunderbird/102.9.0

Hi Thomas,

First of all, thanks for the great investigative work on this!

I'm going to vote for switching to using GNUC_PACKED iso733_t instead of unpacked uint8_t*, especially since that's what we use for struct iso_rock_px_s.

I ran a quick test in Rufus and saw no downside to the switch (in the context of long names and resolving symbolic links), so I am planning to send a v3 with this change, and that also includes the fix for the extra semicolumn.

Depending on other factors, it may however be 3 to 4 weeks before I get a chance to do so.

Regards,

/Pete

On 2023.03.21 15:00, Thomas Schmitt wrote:
Hi,

i need opinions about resolving a possible alignment problem with
using members of iso_su_ce_t as input of function from_733(), which
expects uint64_t.
Different from the other SUSP representing structs, its 2x32-bit numbers
are declared as uint8_t array[8] rather than as iso733_t, which is
actually uint64_t.

Shouldn't we change in include/cdio/rock.h

   typedef struct iso_su_ce_s {
     uint8_t       extent[8];
     uint8_t       offset[8];
     uint8_t       size[8];
   } iso_su_ce_t;

to

   typedef struct iso_su_ce_s {
     iso733_t      extent;
     iso733_t      offset;
     iso733_t      size;
   } GNUC_PACKED iso_su_ce_t;

to avoid any alignment problems with from_733() ?

The current macro definition CHECK_CE is broken anyways (see below).
It could be adapted to the new declaration of iso_su_ce_t by simply
removing the '*' operators, so that it looks like:

   #define CHECK_CE(FAIL)                          \
     { cont_extent = from_733(rr->u.CE.extent);    \
       cont_offset = from_733(rr->u.CE.offset);    \
       if (cont_offset >= ISO_BLOCKSIZE) FAIL;     \
       cont_size = from_733(rr->u.CE.size);        \
       if (cont_size >= ISO_BLOCKSIZE) FAIL;       \
     }

I tested this with iso-info and it seems to work well.

---------------------------------------------------------------------
Long story:

After getting an applicable patch from Pete Batard, i found a new
harmless problem and an old nasty one:

- A surplus semicolon in the new definition of CONTINUE_DECLS causes
   with gcc:
    rock.c: In function 'get_rock_ridge_filename':
    rock.c:180:3: warning: ISO C90 forbids mixed declarations and code 
[-Wdeclaration-after-statement]
    int i_namelen = 0;
    ^

- The old '*' operators in the calls to from_733() in the definition of
   CHECK_CE truncate the numbers of the CE entry to single-byte values.
   If the values are actually larger than 255, this leads to a wrong read
   address in the loaded continuation area block. In the end  iso-info
   fails with a SIGSEGV in print_fs_attrs() because
   p_statbuf->rr.psz_symlink is NULL.

Possible fixes are:

- Either remove the new semicolon at the end of the definition of
   CONTINUE_DECLS or remove the old semicolon at the invocation of
   CONTINUE_DECLS.

- Change in the definition of CHECK_CE the gesture
     from_733(*rr->u.CE.xxxxx);
   to
     from_733(*((uint64_t *) rr->u.CE.xxxxx));

The first fix is unproblematic.

But the second one could still invite trouble with 64-bit alignment.
In practice the function parameter declared in include/cdio/bytesex.h is
not used as its type but immediately converted back to a byte array:

   static CDIO_INLINE uint32_t
   from_733 (uint64_t p)
   {
     uint8_t *u = (uint8_t *) &p;
     /* Return the little-endian part always, to handle non-specs-compliant 
images */
     return (u[0] | (u[1] << 8) | (u[2] << 16) | (u[3] << 24));
   }

gcc seems to create stable code from this on a 64-bit x86 machine.
But we do not know what ideas future compilers might try to apply.
After all this code uses the address of a potentially non-aligned
uint64_t.

In lib/iso9660/iso9660.c the input to from_733() is surely aligned,
because in the end it is declared as iso733_t which is typedef uint64_t.
But in lib/iso9660/rock.c CE_CHECK it gets fed by uint8_t array[8], which
is not guaranteed to be aligned to 64 bit:

   typedef struct iso_su_ce_s {
     uint8_t       extent[8];
     uint8_t       offset[8];
     uint8_t       size[8];
   } iso_su_ce_t;

Other structs of which members are input to from_733() are:
  iso_rock_px_s, iso_rock_pn_s, iso_rock_cl_s
Their submitted elements are all iso733_t.

So changing struct iso_su_ce_s to:

   typedef struct iso_su_ce_s {
     iso733_t      extent;
     iso733_t      offset;
     iso733_t      size;
   } GNUC_PACKED iso_su_ce_t;

would bring iso_su_ce_t nearer to other SUSP struct definitions like:

   typedef struct iso_rock_px_s {
     iso733_t st_mode;       /*! file mode permissions; same as st_mode
                               of POSIX:5.6.1 */
     iso733_t st_nlinks;     /*! number of links to file; same as st_nlinks
                               of POSIX:5.6.1 */
     iso733_t st_uid;        /*! user id owner of file; same as st_uid
                               of POSIX:5.6.1 */
     iso733_t st_gid;        /*! group id of file; same as st_gid of
                               of POSIX:5.6.1 */
   } GNUC_PACKED iso_rock_px_t ;


Have a nice day :)

Thomas






reply via email to

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