]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
iso9660: Fix infinite loop in Joliet ID generation 2978/head
authorTobias Stoeckmann <tobias@stoeckmann.org>
Tue, 21 Apr 2026 16:48:11 +0000 (18:48 +0200)
committerTobias Stoeckmann <tobias@stoeckmann.org>
Sat, 9 May 2026 10:22:01 +0000 (12:22 +0200)
3 characters/digits base 36 means that 46656 combinations are possible.
If a directory with even more conflicting identifiers is encountered, the
code would trigger an endless loop.

Fail with an error in such a case instead.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
libarchive/archive_write_set_format_iso9660.c

index 576b3ba52b0c7506b3e5bdc453dded1a5ff18fee..83c265f539c23eac39e6993d11d4580c0f467808 100644 (file)
@@ -119,6 +119,8 @@ static const unsigned char zisofs_magic[8] = {
 #define ZF_LOG2_BS     15      /* log2 block size; 32K bytes. */
 #define ZF_BLOCK_SIZE  (1UL << ZF_LOG2_BS)
 
+#define MAX_JOLIET_ID_NUM      46656 /* 3 base 36 digits */
+
 /*
  * Manage extra records.
  */
@@ -1008,7 +1010,7 @@ static int        idr_start(struct archive_write *, struct idr *,
 static void    idr_register(struct idr *, struct isoent *, int,
                    int);
 static void    idr_extend_identifier(struct idrent *, int, int);
-static void    idr_resolve(struct idr *, void (*)(unsigned char *, int));
+static int     idr_resolve(struct idr *, void (*)(unsigned char *, int));
 static void    idr_set_num(unsigned char *, int);
 static void    idr_set_num_beutf16(unsigned char *, int);
 static int     isoent_gen_iso9660_identifier(struct archive_write *,
@@ -5939,7 +5941,7 @@ idr_extend_identifier(struct idrent *wnp, int numsize, int nullsize)
        }
 }
 
-static void
+static int
 idr_resolve(struct idr *idr, void (*fsetnum)(unsigned char *p, int num))
 {
        struct idrent *n;
@@ -5949,10 +5951,13 @@ idr_resolve(struct idr *idr, void (*fsetnum)(unsigned char *p, int num))
                idr_extend_identifier(n, idr->num_size, idr->null_size);
                p = (unsigned char *)n->isoent->identifier + n->noff;
                do {
+                       if (n->avail->rename_num >= MAX_JOLIET_ID_NUM)
+                               return (-ERANGE);
                        fsetnum(p, n->avail->rename_num++);
                } while (!__archive_rb_tree_insert_node(
                    &(idr->rbtree), &(n->rbnode)));
        }
+       return (0);
 }
 
 static void
@@ -6217,7 +6222,11 @@ isoent_gen_iso9660_identifier(struct archive_write *a, struct isoent *isoent,
        }
 
        /* Resolve duplicate identifier. */
-       idr_resolve(idr, idr_set_num);
+       r = idr_resolve(idr, idr_set_num);
+       if (r < 0) {
+               archive_set_error(&a->archive, -r, "Too many duplicated identifiers");
+               return (ARCHIVE_FATAL);
+       }
 
        /* Add a period and a version number to identifiers. */
        for (np = isoent->children.first; np != NULL; np = np->chnext) {
@@ -6361,7 +6370,11 @@ isoent_gen_joliet_identifier(struct archive_write *a, struct isoent *isoent,
        }
 
        /* Resolve duplicate identifier with Joliet Volume. */
-       idr_resolve(idr, idr_set_num_beutf16);
+       r = idr_resolve(idr, idr_set_num_beutf16);
+       if (r < 0) {
+               archive_set_error(&a->archive, -r, "Too many duplicated identifiers");
+               return (ARCHIVE_FATAL);
+       }
 
        return (ARCHIVE_OK);
 }