File giflib-CVE-2023-39742.patch of Package giflib.34873

--- giflib-5.0.5/util/getarg.c	2024-07-23 08:33:42.771452333 +0200
+++ giflib-5.0.5/util/getarg.c	2024-07-23 09:16:03.292639531 +0200
@@ -76,7 +76,9 @@
    parameters actually matched this sequence, and the second
    one is a pointer to pointer to ? (? **), and will return an
    address to a block of pointers to ? kind, terminated with
-   NULL pointer. NO pre-allocation is required.
+   NULL pointer. NO pre-allocation is required. The caller is
+   responsible for freeing this memory, including the pointed to
+   memory.
 
 Note that these two variables are pretty like the argv/argc pair...
 
@@ -123,29 +125,29 @@
 #define ISCTRLCHAR(x) (((x) == '%') || ((x) == '!'))
 
 static char *GAErrorToken;  /* On error, ErrorToken is set to point to it. */
-static int GATestAllSatis(char *CtrlStrCopy, char *CtrlStr, int *argc,
-                          char ***argv, int *Parameters[MAX_PARAM],
+static int GATestAllSatis(char *CtrlStrCopy, char *CtrlStr, char **argv_end,
+                          char ***argv, void *Parameters[MAX_PARAM],
                           int *ParamCount);
-static bool GAUpdateParameters(int *Parameters[], int *ParamCount,
+static bool GAUpdateParameters(void *Parameters[], int *ParamCount,
                               char *Option, char *CtrlStrCopy, char *CtrlStr,
-                              int *argc, char ***argv);
-static int GAGetParmeters(int *Parameters[], int *ParamCount,
-                          char *CtrlStrCopy, char *Option, int *argc,
+                              char **argv_end, char ***argv);
+static int GAGetParmeters(void *Parameters[], int *ParamCount,
+                          char *CtrlStrCopy, char *Option, char **argv_end,
                           char ***argv);
-static int GAGetMultiParmeters(int *Parameters[], int *ParamCount,
-                               char *CtrlStrCopy, int *argc, char ***argv);
+static int GAGetMultiParmeters(void *Parameters[], int *ParamCount,
+                               char *CtrlStrCopy, char **argv_end, char ***argv);
 static void GASetParamCount(char *CtrlStr, int Max, int *ParamCount);
-static bool GAOptionExists(int argc, char **argv);
+static bool GAOptionExists(char **argv_end, char **argv);
 
 /***************************************************************************
  Allocate or die
 ***************************************************************************/
-static char *
+static void *
 xmalloc(unsigned size) {
 
-    char *p;
+    void *p;
 
-    if ((p = (char *)malloc(size)) != NULL)
+    if ((p = malloc(size)) != NULL)
         return p;
 
     fprintf(stderr, "Not enough memory, exit.\n");
@@ -164,30 +166,30 @@
 
     int i, ParamCount = 0;
     bool Error = false;
-    int *Parameters[MAX_PARAM];     /* Save here parameter addresses. */
+    void *Parameters[MAX_PARAM];     /* Save here parameter addresses. */
     char *Option, CtrlStrCopy[CTRL_STR_MAX_LEN];
+    char **argv_end = argv + argc;
     va_list ap;
 
     strncpy(CtrlStrCopy, CtrlStr, sizeof(CtrlStrCopy)-1);
+    GASetParamCount(CtrlStr, strlen(CtrlStr), &ParamCount);
     va_start(ap, CtrlStr);
-    for (i = 1; i <= MAX_PARAM; i++)
-        Parameters[i - 1] = va_arg(ap, int *);
+    for (i = 1; i <= ParamCount; i++)
+        Parameters[i - 1] = va_arg(ap, void *);
     va_end(ap);
 
-    --argc;
     argv++;    /* Skip the program name (first in argv/c list). */
-    while (argc >= 0) {
-        if (!GAOptionExists(argc, argv))
+    while (argv < argv_end) {
+        if (!GAOptionExists(argv_end, argv))
             break;    /* The loop. */
-        argc--;
         Option = *argv++;
         if ((Error = GAUpdateParameters(Parameters, &ParamCount, Option,
-                                        CtrlStrCopy, CtrlStr, &argc,
+                                        CtrlStrCopy, CtrlStr, argv_end,
                                         &argv)) != false)
             return Error;
     }
     /* Check for results and update trail of command line: */
-    return GATestAllSatis(CtrlStrCopy, CtrlStr, &argc, &argv, Parameters,
+    return GATestAllSatis(CtrlStrCopy, CtrlStr, argv_end, &argv, Parameters,
                           &ParamCount) != ARG_OK;
 }
 
@@ -201,9 +203,9 @@
 static int
 GATestAllSatis(char *CtrlStrCopy,
                char *CtrlStr,
-               int *argc,
+               char **argv_end,
                char ***argv,
-               int *Parameters[MAX_PARAM],
+               void *Parameters[MAX_PARAM],
                int *ParamCount) {
 
     int i;
@@ -223,9 +225,8 @@
     for (i = strlen(CtrlStr) - 1; i > 0 && !ISSPACE(CtrlStr[i]); i--) ;
     if (!ISCTRLCHAR(CtrlStr[i + 2])) {
         GASetParamCount(CtrlStr, i, ParamCount); /* Point in correct param. */
-        *Parameters[(*ParamCount)++] = *argc;
-        memcpy((char *)Parameters[(*ParamCount)++], (char *)argv,
-                   sizeof(char *));
+        *(int *)Parameters[(*ParamCount)++] = argv_end - *argv;
+	*(char ***)Parameters[(*ParamCount)++] = *argv;
     }
 
     i = 0;
@@ -243,12 +244,12 @@
  Routine to update the parameters according to the given Option:
  **************************************************************************/
 static bool
-GAUpdateParameters(int *Parameters[],
+GAUpdateParameters(void *Parameters[],
                    int *ParamCount,
                    char *Option,
                    char *CtrlStrCopy,
                    char *CtrlStr,
-                   int *argc,
+                   char **argv_end,
                    char ***argv) {
 
     int i;
@@ -278,7 +279,7 @@
                                                 correct prm. */
     i += 3;
     /* Set boolean flag for that option. */
-    *Parameters[(*ParamCount)++] = BooleanTrue;
+    *(bool *)Parameters[(*ParamCount)++] = BooleanTrue;
     if (ISSPACE(CtrlStrCopy[i]))
         return ARG_OK;    /* Only a boolean flag is needed. */
 
@@ -287,23 +288,29 @@
         i++;
     /* Get the parameters and return the appropriete return code: */
     return GAGetParmeters(Parameters, ParamCount, &CtrlStrCopy[i],
-                          Option, argc, argv);
+                          Option, argv_end, argv);
 }
 
 /***************************************************************************
  Routine to get parameters according to the CtrlStr given from argv/argc
 ***************************************************************************/
 static int
-GAGetParmeters(int *Parameters[],
+GAGetParmeters(void *Parameters[],
                int *ParamCount,
                char *CtrlStrCopy,
                char *Option,
-               int *argc,
+               char **argv_end,
                char ***argv) {
 
     int i = 0, ScanRes;
 
     while (!(ISSPACE(CtrlStrCopy[i]))) {
+
+        if ((*argv) == argv_end) {
+            GAErrorToken = Option;
+            return CMD_ERR_NumRead;
+        }
+
         switch (CtrlStrCopy[i + 1]) {
           case 'd':    /* Get signed integers. */
 	      // cppcheck-suppress invalidscanf 
@@ -349,7 +356,7 @@
 	      // cppcheck-suppress invalidscanf 
               ScanRes = sscanf(*((*argv)++), "%f",
                                (float *)Parameters[(*ParamCount)++]);
-	      /*@fallthrough@*/
+	      break;
           case 'F':    /* Get double float number. */
 	      // cppcheck-suppress invalidscanf 
               ScanRes = sscanf(*((*argv)++), "%lf",
@@ -357,12 +364,11 @@
               break;
           case 's':    /* It as a string. */
               ScanRes = 1;    /* Allways O.K. */
-              memcpy((char *)Parameters[(*ParamCount)++],
-                         (char *)((*argv)++), sizeof(char *));
+	      *(char **)Parameters[(*ParamCount)++] = *((*argv)++);
               break;
           case '*':    /* Get few parameters into one: */
               ScanRes = GAGetMultiParmeters(Parameters, ParamCount,
-                                            &CtrlStrCopy[i], argc, argv);
+                                            &CtrlStrCopy[i], argv_end, argv);
               if ((ScanRes == 0) && (CtrlStrCopy[i] == '!')) {
                   GAErrorToken = Option;
                   return CMD_ERR_WildEmpty;
@@ -377,7 +383,6 @@
             return CMD_ERR_NumRead;
         }
         if (CtrlStrCopy[i + 1] != '*') {
-            (*argc)--;    /* Everything is OK - update to next parameter: */
             i += 2;    /* Skip to next parameter (if any). */
         } else
             i += 3;    /* Skip the '*' also! */
@@ -395,15 +400,17 @@
  same size (and the union below is totally ovelapped bteween dif. arrays)
 ***************************************************************************/
 static int
-GAGetMultiParmeters(int *Parameters[],
+GAGetMultiParmeters(void *Parameters[],
                     int *ParamCount,
                     char *CtrlStrCopy,
-                    int *argc,
+                    char **argv_end,
                     char ***argv) {
 
-    int i = 0, ScanRes, NumOfPrm = 0, **Pmain, **Ptemp;
+    int i = 0, ScanRes, NumOfPrm = 0;
+    void **Pmain, **Ptemp;
     union TmpArray {    /* Save here the temporary data before copying it to */
-        int *IntArray[MAX_PARAM];    /* the returned pointer block. */
+        void *VoidArray[MAX_PARAM];    /* the returned pointer block. */
+        int *IntArray[MAX_PARAM];
         long *LngArray[MAX_PARAM];
         float *FltArray[MAX_PARAM];
         double *DblArray[MAX_PARAM];
@@ -413,73 +420,71 @@
     do {
         switch (CtrlStrCopy[2]) { /* CtrlStr == '!*?' or '%*?' where ? is. */
           case 'd':    /* Format to read the parameters: */
-              TmpArray.IntArray[NumOfPrm] = (int *)xmalloc(sizeof(int));
+              TmpArray.IntArray[NumOfPrm] = xmalloc(sizeof(int));
 	      // cppcheck-suppress invalidscanf 
               ScanRes = sscanf(*((*argv)++), "%d",
                                (int *)TmpArray.IntArray[NumOfPrm++]);
               break;
           case 'u':
-              TmpArray.IntArray[NumOfPrm] = (int *)xmalloc(sizeof(int));
+              TmpArray.IntArray[NumOfPrm] = xmalloc(sizeof(int));
 	      // cppcheck-suppress invalidscanf 
               ScanRes = sscanf(*((*argv)++), "%u",
                                (unsigned int *)TmpArray.IntArray[NumOfPrm++]);
               break;
           case 'o':
-              TmpArray.IntArray[NumOfPrm] = (int *)xmalloc(sizeof(int));
+              TmpArray.IntArray[NumOfPrm] = xmalloc(sizeof(int));
 	      // cppcheck-suppress invalidscanf 
               ScanRes = sscanf(*((*argv)++), "%o",
                                (unsigned int *)TmpArray.IntArray[NumOfPrm++]);
               break;
           case 'x':
-              TmpArray.IntArray[NumOfPrm] = (int *)xmalloc(sizeof(int));
+              TmpArray.IntArray[NumOfPrm] = xmalloc(sizeof(int));
 	      // cppcheck-suppress invalidscanf 
               ScanRes = sscanf(*((*argv)++), "%x",
                                (unsigned int *)TmpArray.IntArray[NumOfPrm++]);
               break;
           case 'D':
-              TmpArray.LngArray[NumOfPrm] = (long *)xmalloc(sizeof(long));
+              TmpArray.LngArray[NumOfPrm] = xmalloc(sizeof(long));
 	      // cppcheck-suppress invalidscanf 
               ScanRes = sscanf(*((*argv)++), "%ld",
                                (long *)TmpArray.IntArray[NumOfPrm++]);
               break;
           case 'U':
-              TmpArray.LngArray[NumOfPrm] = (long *)xmalloc(sizeof(long));
+              TmpArray.LngArray[NumOfPrm] = xmalloc(sizeof(long));
 	      // cppcheck-suppress invalidscanf 
               ScanRes = sscanf(*((*argv)++), "%lu",
                                (unsigned long *)TmpArray.
                                IntArray[NumOfPrm++]);
               break;
           case 'O':
-              TmpArray.LngArray[NumOfPrm] = (long *)xmalloc(sizeof(long));
+              TmpArray.LngArray[NumOfPrm] = xmalloc(sizeof(long));
 	      // cppcheck-suppress invalidscanf 
               ScanRes = sscanf(*((*argv)++), "%lo",
                                (unsigned long *)TmpArray.
                                IntArray[NumOfPrm++]);
               break;
           case 'X':
-              TmpArray.LngArray[NumOfPrm] = (long *)xmalloc(sizeof(long));
+              TmpArray.LngArray[NumOfPrm] = xmalloc(sizeof(long));
 	      // cppcheck-suppress invalidscanf 
               ScanRes = sscanf(*((*argv)++), "%lx",
                                (unsigned long *)TmpArray.
                                IntArray[NumOfPrm++]);
               break;
           case 'f':
-              TmpArray.FltArray[NumOfPrm] = (float *)xmalloc(sizeof(float));
+              TmpArray.FltArray[NumOfPrm] = xmalloc(sizeof(float));
 	      // cppcheck-suppress invalidscanf 
               ScanRes = sscanf(*((*argv)++), "%f",
                                (float *)TmpArray.LngArray[NumOfPrm++]);
               break;
           case 'F':
-              TmpArray.DblArray[NumOfPrm] =
-                 (double *)xmalloc(sizeof(double));
+              TmpArray.DblArray[NumOfPrm] = xmalloc(sizeof(double));
 	      // cppcheck-suppress invalidscanf 
               ScanRes = sscanf(*((*argv)++), "%lf",
                                (double *)TmpArray.LngArray[NumOfPrm++]);
               break;
           case 's':
-              while ((*argc) && ((**argv)[0] != '-')) {
+              while ((*argv < argv_end) && ((**argv)[0] != '-')) {
                   TmpArray.ChrArray[NumOfPrm++] = *((*argv)++);
-                  (*argc)--;
               }
               ScanRes = 0;    /* Force quit from do - loop. */
               NumOfPrm++;    /* Updated again immediately after loop! */
@@ -488,27 +493,23 @@
           default:
               ScanRes = 0;    /* Make optimizer warning silent. */
         }
-        (*argc)--;
     }
     while (ScanRes == 1);    /* Exactly one parameter was read. */
     (*argv)--;
     NumOfPrm--;
-    (*argc)++;
 
     /* Now allocate the block with the exact size, and set it: */
-    Ptemp = Pmain =
-       (int **)xmalloc((unsigned)(NumOfPrm + 1) * sizeof(int *));
+    Ptemp = Pmain = xmalloc((unsigned)(NumOfPrm + 1) * sizeof(void *));
     /* And here we use the assumption that all pointers are the same: */
     for (i = 0; i < NumOfPrm; i++)
-        *Ptemp++ = TmpArray.IntArray[i];
+        *Ptemp++ = TmpArray.VoidArray[i];
     *Ptemp = NULL;    /* Close the block with NULL pointer. */
 
     /* That it save the number of parameters read as first parameter to
      * return and the pointer to the block as second, and return: */
-    *Parameters[(*ParamCount)++] = NumOfPrm;
-    memcpy((char *)Parameters[(*ParamCount)++], (char *)&Pmain,
-               sizeof(char *));
-    free(Pmain);
+    *(int *)Parameters[(*ParamCount)++] = NumOfPrm;
+    *(void ***)Parameters[(*ParamCount)++] = Pmain;
+    /* free(Pmain); -- can not free here as caller needs to access memory */
     return NumOfPrm;
 }
 
@@ -542,10 +543,10 @@
  given list argc, argv:
 ***************************************************************************/
 static bool
-GAOptionExists(int argc,
+GAOptionExists(char **argv_end,
                char **argv) {
 
-    while (argc--)
+    while (argv < argv_end)
         if ((*argv++)[0] == '-')
             return true;
     return false;
openSUSE Build Service is sponsored by