libcdio-devel
[Top][All Lists]
Advanced

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

[Libcdio-devel] [PATCH v2 2/2] Add processing of Rock Ridge CE records


From: Pete Batard
Subject: [Libcdio-devel] [PATCH v2 2/2] Add processing of Rock Ridge CE records
Date: Sat, 18 Mar 2023 22:26:35 +0000
User-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:102.0) Gecko/20100101 Thunderbird/102.8.0

Use the processed cont_extent to read the relevant continuation block
into a double buffer and then, once the current extensions have been
processed, use that block, along with cont_offset and cont_size, to
carry out further Rock Ridge data processing. The double buffering is
designed to handle chained CE blocks if needed, and we also add code
to detect ISOs that are abusing the specs to loop CEs.
Also clean up the CHECK...() macros and fix some whitespace issues.
---
 lib/iso9660/rock.c | 104 ++++++++++++++++++++++++++++-----------------
 1 file changed, 66 insertions(+), 38 deletions(-)

diff --git a/lib/iso9660/rock.c b/lib/iso9660/rock.c
index ff420dca..0ae57d90 100644
--- a/lib/iso9660/rock.c
+++ b/lib/iso9660/rock.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 2020 Pete Batard <pete@akeo.ie>
+  Copyright (C) 2020, 2023 Pete Batard <pete@akeo.ie>
   Copyright (C) 2005, 2008, 2010-2011, 2014, 2017, 2022 Rocky Bernstein
   <rocky@gnu.org>
 @@ -20,7 +20,8 @@
 */
 /* Rock Ridge Extensions to iso9660 */
 -
+
+
 #ifdef HAVE_CONFIG_H
 # include "config.h"
 #endif
@@ -94,34 +95,39 @@ realloc_symlink(/*in/out*/ iso9660_stat_t *p_stat, uint8_t i_grow)
  /* This is a way of ensuring that we have something in the system
    use fields that is compatible with Rock Ridge */
-#define CHECK_SP(FAIL)                         \
-      if(rr->u.SP.magic[0] != 0xbe) FAIL;   \
-      if(rr->u.SP.magic[1] != 0xef) FAIL;       \
+#define CHECK_SP(FAIL)                         \
+      if (rr->u.SP.magic[0] != 0xbe) FAIL;  \
+      if (rr->u.SP.magic[1] != 0xef) FAIL;  \
       p_stat->rr.s_rock_offset = rr->u.SP.skip;
 /* We define a series of macros because each function must do exactly the
same thing in certain places. We use the macros to ensure that everything
    is done correctly */
  #define CONTINUE_DECLS \
-  int cont_extent = 0, cont_offset = 0, cont_size = 0;   \
-  void *buffer = NULL
-
-#define CHECK_CE                                \
-  { cont_extent = from_733(*rr->u.CE.extent);        \
-    cont_offset = from_733(*rr->u.CE.offset);        \
-    cont_size = from_733(*rr->u.CE.size);    \
-    (void)cont_extent; (void)cont_offset, (void)cont_size; }
+  uint32_t cont_extent = 0, cont_offset = 0, cont_size = 0;    \
+  uint8_t* buffer[2] = { NULL, NULL };                         \
+  uint8_t buffer_index = 0, ce_count = 0;
+
+#define CONTINUE_NEXT_INDEX    ((buffer_index + 1) % 2)
+
+#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;   \
+  }
 -#define SETUP_ROCK_RIDGE(DE,CHR,LEN)                          \
+#define SETUP_ROCK_RIDGE(DE,CHR,LEN)                           \
   {                                                            \
     LEN= sizeof(iso9660_dir_t) + DE->filename.len;          \
-    if(LEN & 1) LEN++;                                             \
+    if (LEN & 1) LEN++;                                            \
     CHR = ((unsigned char *) DE) + LEN;                                \
     LEN = *((unsigned char *) DE) - LEN;                       \
     if (0xff != p_stat->rr.s_rock_offset)                   \
       {                                                                \
-       LEN -= p_stat->rr.s_rock_offset;                     \
-       CHR += p_stat->rr.s_rock_offset;                     \
+       LEN -= p_stat->rr.s_rock_offset;                     \
+       CHR += p_stat->rr.s_rock_offset;                     \
        if (LEN<0) LEN=0;                                    \
       }                                                                \
   }
@@ -130,22 +136,22 @@ realloc_symlink(/*in/out*/ iso9660_stat_t *p_stat, uint8_t i_grow)
    the specified field of a iso_rock_statbuf_t.
    non-paramater variables are p_stat, rr, and cnt.
 */
-#define add_time(FLAG, TIME_FIELD)                               \
-  if (rr->u.TF.flags & FLAG) {                                    \
-    p_stat->rr.TIME_FIELD.b_used = true;                      \
-    p_stat->rr.TIME_FIELD.b_longdate =                                \
-      (0 != (rr->u.TF.flags & ISO_ROCK_TF_LONG_FORM));            \
-    if (p_stat->rr.TIME_FIELD.b_longdate) {                   \
-      memcpy(&(p_stat->rr.TIME_FIELD.t.ltime),                    \
-            &(rr->u.TF.time_bytes[cnt]),                          \
-            sizeof(iso9660_ltime_t));                            \
-      cnt += sizeof(iso9660_ltime_t);                            \
-    } else {                                                     \
-      memcpy(&(p_stat->rr.TIME_FIELD.t.dtime),                    \
-            &(rr->u.TF.time_bytes[cnt]),                          \
-            sizeof(iso9660_dtime_t));                            \
-      cnt += sizeof(iso9660_dtime_t);                            \
-    }                                                            \
+#define add_time(FLAG, TIME_FIELD)                             \
+  if (rr->u.TF.flags & FLAG) {                                  \
+    p_stat->rr.TIME_FIELD.b_used = true;                    \
+    p_stat->rr.TIME_FIELD.b_longdate =                              \
+      (0 != (rr->u.TF.flags & ISO_ROCK_TF_LONG_FORM));          \
+    if (p_stat->rr.TIME_FIELD.b_longdate) {                 \
+      memcpy(&(p_stat->rr.TIME_FIELD.t.ltime),                  \
+            &(rr->u.TF.time_bytes[cnt]),                        \
+            sizeof(iso9660_ltime_t));                          \
+      cnt += sizeof(iso9660_ltime_t);                          \
+    } else {                                                   \
+      memcpy(&(p_stat->rr.TIME_FIELD.t.dtime),                  \
+            &(rr->u.TF.time_bytes[cnt]),                        \
+            sizeof(iso9660_dtime_t));                          \
+      cnt += sizeof(iso9660_dtime_t);                          \
+    }                                                          \
   }
  /* Indicates if we should process deep directory entries */
@@ -179,7 +185,7 @@ get_rock_ridge_filename(iso9660_dir_t * p_iso9660_dir,
   *psz_name = 0;
    SETUP_ROCK_RIDGE(p_iso9660_dir, chr, len);
-  /*repeat:*/
+repeat:
   {
     iso_extension_record_t * rr;
     int sig;
@@ -202,7 +208,7 @@ get_rock_ridge_filename(iso9660_dir_t * p_iso9660_dir,
        switch(sig) {
       case SIG('S','P'):
-       CHECK_SP(goto out);
+       CHECK_SP({cdio_warn("Invalid Rock Ridge SP field"); goto out;});
        p_stat->rr.u_su_fields |= ISO_ROCK_SUF_SP;
        break;
       case SIG('C','E'):
@@ -213,8 +219,17 @@ get_rock_ridge_filename(iso9660_dir_t * p_iso9660_dir,
          if ('\1' == p_iso9660_dir->filename.str[1] && 1 == i_fname)
            break;
        }
-       CHECK_CE;
+       CHECK_CE({cdio_warn("Invalid Rock Ridge CE field"); goto out;});
        p_stat->rr.u_su_fields |= ISO_ROCK_SUF_CE;
+       /* Though no mastering utility in its right mind would produce anything
+          like this, the specs make it theoretically possible to have more RR
+          extensions after a CE, so we delay the CE block processing for later.
+       */
+       buffer[CONTINUE_NEXT_INDEX] = calloc(1, ISO_BLOCKSIZE);
+       if (!buffer[CONTINUE_NEXT_INDEX])
+         goto out;
+ if (iso9660_iso_seek_read(p_image, buffer[CONTINUE_NEXT_INDEX], cont_extent, 1) != ISO_BLOCKSIZE)
+         goto out;
        break;
       case SIG('E','R'):
        cdio_debug("ISO 9660 Extensions: ");
@@ -368,12 +383,25 @@ get_rock_ridge_filename(iso9660_dir_t * p_iso9660_dir,
       }
     }
   }
-  free(buffer);
+  free(buffer[buffer_index]);
+  buffer[buffer_index] = NULL;
+  /* Now process any delayed CE block */
+  buffer_index = CONTINUE_NEXT_INDEX;
+  if (buffer[buffer_index] != NULL) {
+    chr = &buffer[buffer_index][cont_offset];
+    len = cont_size;
+    /* Someone abusing the specs may also be creating looping CEs */
+    if (ce_count++ < 64)
+       goto repeat;
+    else
+       cdio_warn("More than 64 consecutive Rock Ridge CEs detected");
+  }
   if (p_stat->rr.u_su_fields & ISO_ROCK_SUF_FORMAL)
     p_stat->rr.b3_rock = yep;
   return i_namelen; /* If 0, this file did not have a NM field */
 out:
-  free(buffer);
+  free(buffer[0]);
+  free(buffer[1]);
   return 0;
 }
 -- 2.39.1.windows.1




reply via email to

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