[System]
You are a security patch backporting assistant for SUSE/openSUSE.

Given a CVE description and an upstream fix, adapt the patch to work with
the target SUSE package version. Output the backported patch in unified
diff format. If the upstream fix applies directly, output it unchanged.

[User]
## CVE: CVE-2024-33601

nscd: netgroup cache may terminate daemon on memory allocation failure

The Name Service Cache Daemon's (nscd) netgroup cache uses xmalloc or
xrealloc and these functions may terminate the process due to a memory
allocation failure resulting in a denial of service to the clients.  The
flaw was introduced in glibc 2.15 when the cache was added to nscd.

This vulnerability is only present in the nscd binary.

Severity: HIGH
CVSS Score: 7.3

## Package
glibc

## Files to modify
- nscd/netgroupcache.c

## Upstream Fix
```diff
From c04a21e050d64a1193a6daab872bca2528bda44b Mon Sep 17 00:00:00 2001
From: Florian Weimer <fweimer@redhat.com>
Date: Thu, 25 Apr 2024 15:01:07 +0200
Subject: [PATCH 4/4] CVE-2024-33601, CVE-2024-33602: nscd: netgroup: Use two
 buffers in addgetnetgrentX (bug 31680)

This avoids potential memory corruption when the underlying NSS
callback function does not use the buffer space to store all strings
(e.g., for constant strings).

Instead of custom buffer management, two scratch buffers are used.
This increases stack usage somewhat.

Scratch buffer allocation failure is handled by return -1
(an invalid timeout value) instead of terminating the process.
This fixes bug 31679.

Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
---
 nscd/netgroupcache.c | 219 ++++++++++++++++++++++++-------------------
 1 file changed, 121 insertions(+), 98 deletions(-)

diff --git a/nscd/netgroupcache.c b/nscd/netgroupcache.c
index e22ffa5884..e8fe041846 100644
--- a/nscd/netgroupcache.c
+++ b/nscd/netgroupcache.c
@@ -23,6 +23,7 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <sys/mman.h>
+#include <scratch_buffer.h>

 #include "../inet/netgroup.h"
 #include "nscd.h"
@@ -65,6 +66,16 @@ struct dataset
   char strdata[0];
 };

+/* Send a notfound response to FD.  Always returns -1 to indicate an
+   ephemeral error.  */
+static time_t
+send_notfound (int fd)
+{
+  if (fd != -1)
+    TEMP_FAILURE_RETRY (send (fd, &notfound, sizeof (notfound), MSG_NOSIGNAL));
+  return -1;
+}
+
 /* Sends a notfound message and prepares a notfound dataset to write to the
    cache.  Returns true if there was enough memory to allocate the dataset and
    returns the dataset in DATASETP, total bytes to write in TOTALP and the
@@ -83,8 +94,7 @@ do_notfound (struct database_dyn *db, int fd, request_header *req,
   total = sizeof (notfound);
   timeout = time (NULL) + db->negtimeout;

-  if (fd != -1)
-    TEMP_FAILURE_RETRY (send (fd, &notfound, total, MSG_NOSIGNAL));
+  send_notfound (fd);

   dataset = mempool_alloc (db, sizeof (struct dataset) + req->key_len, 1);
   /* If we cannot permanently store the result, so be it.  */
@@ -109,11 +119,78 @@ do_notfound (struct database_dyn *db, int fd, request_header *req,
   return cacheable;
 }

+struct addgetnetgrentX_scratch
+{
+  /* This is the result that the caller should use.  It can be NULL,
+     point into buffer, or it can be in the cache.  */
+  struct dataset *dataset;
+
+  struct scratch_buffer buffer;
+
+  /* Used internally in addgetnetgrentX as a staging area.  */
+  struct scratch_buffer tmp;
+
+  /* Number of bytes in buffer that are actually used.  */
+  size_t buffer_used;
+};
+
+static void
+addgetnetgrentX_scratch_init (struct addgetnetgrentX_scratch *scratch)
+{
+  scratch->dataset = NULL;
+  scratch_buffer_init (&scratch->buffer);
+  scratch_buffer_init (&scratch->tmp);
+
+  /* Reserve space for the header.  */
+  scratch->buffer_used = sizeof (struct dataset);
+  static_assert (sizeof (struct dataset) < sizeof (scratch->tmp.__space),
+		 "initial buffer space");
+  memset (scratch->tmp.data, 0, sizeof (struct dataset));
+}
+
+static void
+addgetnetgrentX_scratch_free (struct addgetnetgrentX_scratch *scratch)
+{
+  scratch_buffer_free (&scratch->buffer);
+  scratch_buffer_free (&scratch->tmp);
+}
+
+/* Copy LENGTH bytes from S into SCRATCH.  Returns NULL if SCRATCH
+   could not be resized, otherwise a pointer to the copy.  */
+static char *
+addgetnetgrentX_append_n (struct addgetnetgrentX_scratch *scratch,
+			  const char *s, size_t length)
+{
+  while (true)
+    {
+      size_t remaining = scratch->buffer.length - scratch->buffer_used;
+      if (remaining >= length)
+	break;
+      if (!scratch_buffer_grow_preserve (&scratch->buffer))
+	return NULL;
+    }
+  char *copy = scratch->buffer.data + scratch->buffer_used;
+  memcpy (copy, s, length);
+  scratch->buffer_used += length;
+  return copy;
+}
+
+/* Copy S into SCRATCH, including its null terminator.  Returns false
+   if SCRATCH could not be resized.  */
+static bool
+addgetnetgrentX_append (struct addgetnetgrentX_scratch *scratch, const char *s)
+{
+  if (s == NULL)
+    s = "";
+  return addgetnetgrentX_append_n (scratch, s, strlen (s) + 1) != NULL;
+}
+
+/* Caller must initialize and free *SCRATCH.  If the return value is
+   negative, this function has sent a notfound response.  */
 static time_t
 addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
 		 const char *key, uid_t uid, struct hashentry *he,
-		 struct datahead *dh, struct dataset **resultp,
-		 void **tofreep)
+		 struct datahead *dh, struct addgetnetgrentX_scratch *scratch)
 {
   if (__glibc_unlikely (debug_level > 0))
     {
@@ -132,14 +209,10 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,

   char *key_copy = NULL;
   struct __netgrent data;
-  size_t buflen = MAX (1024, sizeof (*dataset) + req->key_len);
-  size_t buffilled = sizeof (*dataset);
-  char *buffer = NULL;
   size_t nentries = 0;
   size_t group_len = strlen (key) + 1;
   struct name_list *first_needed
     = alloca (sizeof (struct name_list) + group_len);
-  *tofreep = NULL;

   if (netgroup_database == NULL
       && !__nss_database_get (nss_database_netgroup, &netgroup_database))
@@ -151,8 +224,6 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
     }

   memset (&data, '\0', sizeof (data));
-  buffer = xmalloc (buflen);
-  *tofreep = buffer;
   first_needed->next = first_needed;
   memcpy (first_needed->name, key, group_len);
   data.needed_groups = first_needed;
@@ -195,8 +266,8 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
 		while (1)
 		  {
 		    int e;
-		    status = getfct.f (&data, buffer + buffilled,
-				       buflen - buffilled - req->key_len, &e);
+		    status = getfct.f (&data, scratch->tmp.data,
+				       scratch->tmp.length, &e);
 		    if (status == NSS_STATUS_SUCCESS)
 		      {
 			if (data.type == triple_val)
@@ -204,68 +275,10 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
 			    const char *nhost = data.val.triple.host;
 			    const char *nuser = data.val.triple.user;
 			    const char *ndomain = data.val.triple.domain;
-
-			    size_t hostlen = strlen (nhost ?: "") + 1;
-			    size_t userlen = strlen (nuser ?: "") + 1;
-			    size_t domainlen = strlen (ndomain ?: "") + 1;
-
-			    if (nhost == NULL || nuser == NULL || ndomain == NULL
-				|| nhost > nuser || nuser > ndomain)
-			      {
-				const char *last = nhost;
-				if (last == NULL
-				    || (nuser != NULL && nuser > last))
-				  last = nuser;
-				if (last == NULL
-				    || (ndomain != NULL && ndomain > last))
-				  last = ndomain;
-
-				size_t bufused
-				  = (last == NULL
-				     ? buffilled
-				     : last + strlen (last) + 1 - buffer);
-
-				/* We have to make temporary copies.  */
-				size_t needed = hostlen + userlen + domainlen;
-
-				if (buflen - req->key_len - bufused < needed)
-				  {
-				    buflen += MAX (buflen, 2 * needed);
-				    /* Save offset in the old buffer.  We don't
-				       bother with the NULL check here since
-				       we'll do that later anyway.  */
-				    size_t nhostdiff = nhost - buffer;
-				    size_t nuserdiff = nuser - buffer;
-				    size_t ndomaindiff = ndomain - buffer;
-
-				    char *newbuf = xrealloc (buffer, buflen);
-				    /* Fix up the triplet pointers into the new
-				       buffer.  */
-				    nhost = (nhost ? newbuf + nhostdiff
-					     : NULL);
-				    nuser = (nuser ? newbuf + nuserdiff
-					     : NULL);
-				    ndomain = (ndomain ? newbuf + ndomaindiff
-					       : NULL);
-				    *tofreep = buffer = newbuf;
-				  }
-
-				nhost = memcpy (buffer + bufused,
-						nhost ?: "", hostlen);
-				nuser = memcpy ((char *) nhost + hostlen,
-						nuser ?: "", userlen);
-				ndomain = memcpy ((char *) nuser + userlen,
-						  ndomain ?: "", domainlen);
-			      }
-
-			    char *wp = buffer + buffilled;
-			    wp =
... (truncated)
```

Generate a backported patch for the SUSE target version.

[Assistant]
From c04a21e050d64a1193a6daab872bca2528bda44b Mon Sep 17 00:00:00 2001
From: Florian Weimer <fweimer@redhat.com>
Date: Thu, 25 Apr 2024 15:01:07 +0200
Subject: [PATCH 4/4] CVE-2024-33601, CVE-2024-33602: nscd: netgroup: Use two
 buffers in addgetnetgrentX (bug 31680)

This avoids potential memory corruption when the underlying NSS
callback function does not use the buffer space to store all strings
(e.g., for constant strings).

Instead of custom buffer management, two scratch buffers are used.
This increases stack usage somewhat.

Scratch buffer allocation failure is handled by return -1
(an invalid timeout value) instead of terminating the process.
This fixes bug 31679.

Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
---
 nscd/netgroupcache.c | 219 ++++++++++++++++++++++++-------------------
 1 file changed, 121 insertions(+), 98 deletions(-)

diff --git a/nscd/netgroupcache.c b/nscd/netgroupcache.c
index e22ffa5884..e8fe041846 100644
--- a/nscd/netgroupcache.c
+++ b/nscd/netgroupcache.c
@@ -23,6 +23,7 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <sys/mman.h>
+#include <scratch_buffer.h>

 #include "../inet/netgroup.h"
 #include "nscd.h"
@@ -65,6 +66,16 @@ struct dataset
   char strdata[0];
 };

+/* Send a notfound response to FD.  Always returns -1 to indicate an
+   ephemeral error.  */
+static time_t
+send_notfound (int fd)
+{
+  if (fd != -1)
+    TEMP_FAILURE_RETRY (send (fd, &notfound, sizeof (notfound), MSG_NOSIGNAL));
+  return -1;
+}
+
 /* Sends a notfound message and prepares a notfound dataset to write to the
    cache.  Returns true if there was enough memory to allocate the dataset and
    returns the dataset in DATASETP, total bytes to write in TOTALP and the
@@ -83,8 +94,7 @@ do_notfound (struct database_dyn *db, int fd, request_header *req,
   total = sizeof (notfound);
   timeout = time (NULL) + db->negtimeout;

-  if (fd != -1)
-    TEMP_FAILURE_RETRY (send (fd, &notfound, total, MSG_NOSIGNAL));
+  send_notfound (fd);

   dataset = mempool_alloc (db, sizeof (struct dataset) + req->key_len, 1);
   /* If we cannot permanently store the result, so be it.  */
@@ -109,11 +119,78 @@ do_notfound (struct database_dyn *db, int fd, request_header *req,
   return cacheable;
 }

+struct addgetnetgrentX_scratch
+{
+  /* This is the result that the caller should use.  It can be NULL,
+     point into buffer, or it can be in the cache.  */
+  struct dataset *dataset;
+
+  struct scratch_buffer buffer;
+
+  /* Used internally in addgetnetgrentX as a staging area.  */
+  struct scratch_buffer tmp;
+
+  /* Number of bytes in buffer that are actually used.  */
+  size_t buffer_used;
+};
+
+static void
+addgetnetgrentX_scratch_init (struct addgetnetgrentX_scratch *scratch)
+{
+  scratch->dataset = NULL;
+  scratch_buffer_init (&scratch->buffer);
+  scratch_buffer_init (&scratch->tmp);
+
+  /* Reserve space for the header.  */
+  scratch->buffer_used = sizeof (struct dataset);
+  static_assert (sizeof (struct dataset) < sizeof (scratch->tmp.__space),
+		 "initial buffer space");
+  memset (scratch->tmp.data, 0, sizeof (struct dataset));
+}
+
+static void
+addgetnetgrentX_scratch_free (struct addgetnetgrentX_scratch *scratch)
+{
+  scratch_buffer_free (&scratch->buffer);
+  scratch_buffer_free (&scratch->tmp);
+}
+
+/* Copy LENGTH bytes from S into SCRATCH.  Returns NULL if SCRATCH
+   could not be resized, otherwise a pointer to the copy.  */
+static char *
+addgetnetgrentX_append_n (struct addgetnetgrentX_scratch *scratch,
+			  const char *s, size_t length)
+{
+  while (true)
+    {
+      size_t remaining = scratch->buffer.length - scratch->buffer_used;
+      if (remaining >= length)
+	break;
+      if (!scratch_buffer_grow_preserve (&scratch->buffer))
+	return NULL;
+    }
+  char *copy = scratch->buffer.data + scratch->buffer_used;
+  memcpy (copy, s, length);
+  scratch->buffer_used += length;
+  return copy;
+}
+
+/* Copy S into SCRATCH, including its null terminator.  Returns false
+   if SCRATCH could not be resized.  */
+static bool
+addgetnetgrentX_append (struct addgetnetgrentX_scratch *scratch, const char *s)
+{
+  if (s == NULL)
+    s = "";
+  return addgetnetgrentX_append_n (scratch, s, strlen (s) + 1) != NULL;
+}
+
+/* Caller must initialize and free *SCRATCH.  If the return value is
+   negative, this function has sent a notfound response.  */
 static time_t
 addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
 		 const char *key, uid_t uid, struct hashentry *he,
-		 struct datahead *dh, struct dataset **resultp,
-		 void **tofreep)
+		 struct datahead *dh, struct addgetnetgrentX_scratch *scratch)
 {
   if (__glibc_unlikely (debug_level > 0))
     {
@@ -132,14 +209,10 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,

   char *key_copy = NULL;
   struct __netgrent data;
-  size_t buflen = MAX (1024, sizeof (*dataset) + req->key_len);
-  size_t buffilled = sizeof (*dataset);
-  char *buffer = NULL;
   size_t nentries = 0;
   size_t group_len = strlen (key) + 1;
   struct name_list *first_needed
     = alloca (sizeof (struct name_list) + group_len);
-  *tofreep = NULL;

   if (netgroup_database == NULL
       && !__nss_database_get (nss_database_netgroup, &netgroup_database))
@@ -151,8 +224,6 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
     }

   memset (&data, '\0', sizeof (data));
-  buffer = xmalloc (buflen);
-  *tofreep = buffer;
   first_needed->next = first_needed;
   memcpy (first_needed->name, key, group_len);
   data.needed_groups = first_needed;
@@ -195,8 +266,8 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
 		while (1)
 		  {
 		    int e;
-		    status = getfct.f (&data, buffer + buffilled,
-				       buflen - buffilled - req->key_len, &e);
+		    status = getfct.f (&data, scratch->tmp.data,
+				       scratch->tmp.length, &e);
 		    if (status == NSS_STATUS_SUCCESS)
 		      {
 			if (data.type == triple_val)
@@ -204,68 +275,10 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
 			    const char *nhost = data.val.triple.host;
 			    const char *nuser = data.val.triple.user;
 			    const char *ndomain = data.val.triple.domain;
-
-			    size_t hostlen = strlen (nhost ?: "") + 1;
-			    size_t userlen = strlen (nuser ?: "") + 1;
-			    size_t domainlen = strlen (ndomain ?: "") + 1;
-
-			    if (nhost == NULL || nuser == NULL || ndomain == NULL
-				|| nhost > nuser || nuser > ndomain)
-			      {
-				const char *last = nhost;
-				if (last == NULL
-				    || (nuser != NULL && nuser > last))
-				  last = nuser;
-				if (last == NULL
-				    || (ndomain != NULL && ndomain > last))
-				  last = ndomain;
-
-				size_t bufused
-				  = (last == NULL
-				     ? buffilled
-				     : last + strlen (last) + 1 - buffer);
-
-				/* We have to make temporary copies.  */
-				size_t needed = hostlen + userlen + domainlen;
-
-				if (buflen - req->key_len - bufused < needed)
-				  {
-				    buflen += MAX (buflen, 2 * needed);
-				    /* Save offset in the old buffer.  We don't
-				       bother with the NULL check here since
-				       we'll do that later anyway.  */
-				    size_t nhostdiff = nhost - buffer;
-				    size_t nuserdiff = nuser - buffer;
-				    size_t ndomaindiff = ndomain - buffer;
-
-				    char *newbuf = xrealloc (buffer, buflen);
-				    /* Fix up the triplet pointers into the new
-				       buffer.  */
-				    nhost = (nhost ? newbuf + nhostdiff
-					     : NULL);
-				    nuser = (nuser ? newbuf + nuserdiff
-					     : NULL);
-				    ndomain = (ndomain ? newbuf + ndomaindiff
-					       : NULL);
-				    *tofreep = buffer = newbuf;
-				  }
-
-				nhost = memcpy (buffer + bufused,
-						nhost ?: "", hostlen);
-				nuser = memcpy ((char *) nhost + hostlen,
-						nuser ?: "", userlen);
-				ndomain = memcpy ((char *) nuser + userlen,
-						  ndomain ?: "", domainlen);
-			      }
-
-			    char *wp = buffer + buffilled;
-			    wp = memmove (wp, nhost ?: "", hostlen);
-			    wp += hostlen;
-			    wp = memmove (wp, nuser ?: "", userlen);
-			    wp += userlen;
-			    wp = memmove (wp, ndomain ?: "", domainlen);
-			    wp += domainlen;
-			    buffilled = wp - buffer;
+			    if (!(addgetnetgrentX_append (scratch, nhost)
+				  && addgetnetgrentX_append (scratch, nuser)
+				  && addgetnetgrentX_append (scratch, ndomain)))
+			      return send_notfound (fd);
 			    ++nentries;
 			  }
 			else
@@ -317,8 +330,8 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
 		      }
 		    else if (status == NSS_STATUS_TRYAGAIN && e == ERANGE)
 		      {
-			buflen *= 2;
-			*tofreep = buffer = xrealloc (buffer, buflen);
+			if (!scratch_buffer_grow (&scratch->tmp))
+			  return send_notfound (fd);
 		      }
 		    else if (status == NSS_STATUS_RETURN
 			     || status == NSS_STATUS_NOTFOUND
@@ -351,10 +364,17 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
       goto maybe_cache_add;
     }

-  total = buffilled;
+  /* Capture the result size without the key appended.   */
+  total = scratch->buffer_used;
+
+  /* Make a copy of the key.  The scratch buffer must not move after
+     this point.  */
+  key_copy = addgetnetgrentX_append_n (scratch, key, req->key_len);
+  if (key_copy == NULL)
+    return send_notfound (fd);

   /* Fill in the dataset.  */
-  dataset = (struct dataset *) buffer;
+  dataset = scratch->buffer.data;
   timeout = datahead_init_pos (&dataset->head, total + req->key_len,
 			       total - offsetof (struct dataset, resp),
 			       he == NULL ? 0 : dh->nreloads + 1,
@@ -363,11 +383,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
   dataset->resp.version = NSCD_VERSION;
   dataset->resp.found = 1;
   dataset->resp.nresults = nentries;
-  dataset->resp.result_len = buffilled - sizeof (*dataset);
-
-  assert (buflen - buffilled >= req->key_len);
-  key_copy = memcpy (buffer + buffilled, key, req->key_len);
-  buffilled += req->key_len;
+  dataset->resp.result_len = total - sizeof (*dataset);

   /* Now we can determine whether on refill we have to create a new
      record or not.  */
@@ -398,7 +414,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
     if (__glibc_likely (newp != NULL))
       {
 	/* Adjust pointer into the memory block.  */
-	key_copy = (char *) newp + (key_copy - buffer);
+	key_copy = (char *) newp + (key_copy - (char *) dataset);

 	dataset = memcpy (newp, dataset, total + req->key_len);
 	cacheable = true;
@@ -439,7 +455,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
     }

  out:
-  *resultp = dataset;
+  scratch->dataset = dataset;

   return timeout;
 }
@@ -460,6 +476,9 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req,
   if (user != NULL)
     key = strchr (key, '\0') + 1;
   const char *domain = *key++ ? key : NULL;
+  struct addgetnetgrentX_scratch scratch;
+
+  addgetnetgrentX_scratch_init (&scratch);

   if (__glibc_unlikely (debug_level > 0))
     {
@@ -475,12 +494,8 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req,
 							    group, group_len,
 							    db, uid);
   time_t timeout;
-  void *tofree;
   if (result != NULL)
-    {
-      timeout = result->head.timeout;
-      tofree = NULL;
-    }
+    timeout = result->head.timeout;
   else
     {
       request_header req_get =
@@ -489,7 +504,10 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req,
 	  .key_len = group_len
 	};
       timeout = addgetnetgrentX (db, -1, &req_get, group, uid, NULL, NULL,
-				 &result, &tofree);
+				 &scratch);
+      result = scratch.dataset;
+      if (timeout < 0)
+	goto out;
     }

   struct indataset
@@ -603,7 +621,7 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req,
     }

  out:
-  free (tofree);
+  addgetnetgrentX_scratch_free (&scratch);
   return timeout;
 }

@@ -613,11 +631,12 @@ addgetnetgrentX_ignore (struct database_dyn *db, int fd, request_header *req,
 			const char *key, uid_t uid, struct hashentry *he,
 			struct datahead *dh)
 {
-  struct dataset *ignore;
-  void *tofree;
-  time_t timeout = addgetnetgrentX (db, fd, req, key, uid, he, dh,
-				    &ignore, &tofree);
-  free (tofree);
+  struct addgetnetgrentX_scratch scratch;
+  addgetnetgrentX_scratch_init (&scratch);
+  time_t timeout = addgetnetgrentX (db, fd, req, key, uid, he, dh, &scratch);
+  addgetnetgrentX_scratch_free (&scratch);
+  if (timeout < 0)
+    timeout = 0;
   return timeout;
 }

@@ -661,5 +680,9 @@ readdinnetgr (struct database_dyn *db, struct hashentry *he,
       .key_len = he->len
     };

-  return addinnetgrX (db, -1, &req, db->data + he->key, he->owner, he, dh);
+  int timeout = addinnetgrX (db, -1, &req, db->data + he->key, he->owner,
+			     he, dh);
+  if (timeout < 0)
+    timeout = 0;
+  return timeout;
 }
--
2.35.3


[System]
You are a security patch backporting assistant for SUSE/openSUSE.

Given a CVE description and an upstream fix, adapt the patch to work with
the target SUSE package version. Output the backported patch in unified
diff format. If the upstream fix applies directly, output it unchanged.

[User]
## CVE: CVE-2016-6250

Integer overflow in the ISO9660 writer in libarchive before 3.2.1 allows remote attackers to cause a denial of service (application crash) or execute arbitrary code via vectors related to verifying filename lengths when writing an ISO9660 archive, which trigger a buffer overflow.

## Package
libarchive

## Files to modify
- libarchive-3.1.2.orig/libarchive/archive_read_support_format_7zip.c
- libarchive/archive_read_support_format_7zip.c

## Target Source Code

### libarchive/archive_read_support_format_7zip.c

#### region() [lines 285-371]
```c
		unsigned char		*next_out;
		int64_t			 avail_out;
		int64_t			 total_out;
		int			 overconsumed;
	} ppstream;
	int			 ppmd7_valid;

	/* Decoding BCJ and BCJ2 data. */
	uint32_t		 bcj_state;
	size_t			 odd_bcj_size;
	unsigned char		 odd_bcj[4];
	/* Decoding BCJ data. */
	size_t			 bcj_prevPosT;
	uint32_t		 bcj_prevMask;
	uint32_t		 bcj_ip;

	/* Decoding BCJ2 data. */
	size_t			 main_stream_bytes_remaining;
	unsigned char		*sub_stream_buff[3];
	size_t			 sub_stream_size[3];
	size_t			 sub_stream_bytes_remaining[3];
	unsigned char		*tmp_stream_buff;
	size_t			 tmp_stream_buff_size;
	size_t			 tmp_stream_bytes_avail;
	size_t			 tmp_stream_bytes_remaining;
#ifdef _LZMA_PROB32
#define CProb uint32_t
#else
#define CProb uint16_t
#endif
	CProb			 bcj2_p[256 + 2];
	uint8_t			 bcj2_prevByte;
	uint32_t		 bcj2_range;
	uint32_t		 bcj2_code;
	uint64_t		 bcj2_outPos;

	/* Filename character-set conversion data. */
	struct archive_string_conv *sconv;

	char			 format_name[64];
};

static int	archive_read_format_7zip_bid(struct archive_read *, int);
static int	archive_read_format_7zip_cleanup(struct archive_read *);
static int	archive_read_format_7zip_read_data(struct archive_read *,
		    const void **, size_t *, int64_t *);
static int	archive_read_format_7zip_read_data_skip(struct archive_read *);
static int	archive_read_format_7zip_read_header(struct archive_read *,
		    struct archive_entry *);
static int	check_7zip_header_in_sfx(const char *);
static unsigned long decode_codec_id(const unsigned char *, size_t);
static int	decode_encoded_header_info(struct archive_read *,
		    struct _7z_stream_info *);
static int	decompress(struct archive_read *, struct _7zip *,
		    void *, size_t *, const void *, size_t *);
static ssize_t	extract_pack_stream(struct archive_read *, size_t);
static void	fileTimeToUtc(uint64_t, time_t *, long *);
static uint64_t folder_uncompressed_size(struct _7z_folder *);
static void	free_CodersInfo(struct _7z_coders_info *);
static void	free_Digest(struct _7z_digests *);
static void	free_Folder(struct _7z_folder *);
static void	free_Header(struct _7z_header_info *);
static void	free_PackInfo(struct _7z_pack_info *);
static void	free_StreamsInfo(struct _7z_stream_info *);
static void	free_SubStreamsInfo(struct _7z_substream_info *);
static int	free_decompression(struct archive_read *, struct _7zip *);
static ssize_t	get_uncompressed_data(struct archive_read *, const void **,
		    size_t, size_t);
static const unsigned char * header_bytes(struct archive_read *, size_t);
static int	init_decompression(struct archive_read *, struct _7zip *,
		    const struct _7z_coder *, const struct _7z_coder *);
static int	parse_7zip_uint64(struct archive_read *, uint64_t *);
static int	read_Bools(struct archive_read *, unsigned char *, size_t);
static int	read_CodersInfo(struct archive_read *,
		    struct _7z_coders_info *);
static int	read_Digests(struct archive_read *, struct _7z_digests *,
		    size_t);
static int	read_Folder(struct archive_read *, struct _7z_folder *);
static int	read_Header(struct archive_read *, struct _7z_header_info *,
		    int);
static int	read_PackInfo(struct archive_read *, struct _7z_pack_info *);
static int	read_StreamsInfo(struct archive_read *,
		    struct _7z_stream_info *);
static int	read_SubStreamsInfo(struct archive_read *,
		    struct _7z_substream_info *, struct _7z_folder *, size_t);
static int	read_Times(struct archive_read *, struct _7z_header_info *,
		    int);
```

#### read_PackInfo() [lines 1650-1728]
```c
}

static int
read_PackInfo(struct archive_read *a, struct _7z_pack_info *pi)
{
	const unsigned char *p;
	unsigned i;

	memset(pi, 0, sizeof(*pi));

	/*
	 * Read PackPos.
	 */
	if (parse_7zip_uint64(a, &(pi->pos)) < 0)
		return (-1);

	/*
	 * Read NumPackStreams.
	 */
	if (parse_7zip_uint64(a, &(pi->numPackStreams)) < 0)
		return (-1);
	if (pi->numPackStreams == 0)
		return (-1);
	if (1000000 < pi->numPackStreams)
		return (-1);

	/*
	 * Read PackSizes[num]
	 */
	if ((p = header_bytes(a, 1)) == NULL)
		return (-1);
	if (*p == kEnd)
		/* PackSizes[num] are not present. */
		return (0);
	if (*p != kSize)
		return (-1);
	pi->sizes = calloc((size_t)pi->numPackStreams, sizeof(uint64_t));
	pi->positions = calloc((size_t)pi->numPackStreams, sizeof(uint64_t));
	if (pi->sizes == NULL || pi->positions == NULL)
		return (-1);

	for (i = 0; i < pi->numPackStreams; i++) {
		if (parse_7zip_uint64(a, &(pi->sizes[i])) < 0)
			return (-1);
	}

	/*
	 * Read PackStreamDigests[num]
	 */
	if ((p = header_bytes(a, 1)) == NULL)
		return (-1);
	if (*p == kEnd) {
		/* PackStreamDigests[num] are not present. */
		pi->digest.defineds =
		    calloc((size_t)pi->numPackStreams, sizeof(*pi->digest.defineds));
		pi->digest.digests =
		    calloc((size_t)pi->numPackStreams, sizeof(*pi->digest.digests));
		if (pi->digest.defineds == NULL || pi->digest.digests == NULL)
			return (-1);
		return (0);
	}

	if (*p != kSize)
		return (-1);

	if (read_Digests(a, &(pi->digest), (size_t)pi->numPackStreams) < 0)
		return (-1);

	/*
	 *  Must be marked by kEnd.
	 */
	if ((p = header_bytes(a, 1)) == NULL)
		return (-1);
	if (*p != kEnd)
		return (-1);
	return (0);
}

static void
```

#### read_Folder() [lines 1742-1887]
```c
}

static int
read_Folder(struct archive_read *a, struct _7z_folder *f)
{
	struct _7zip *zip = (struct _7zip *)a->format->data;
	const unsigned char *p;
	uint64_t numInStreamsTotal = 0;
	uint64_t numOutStreamsTotal = 0;
	unsigned i;

	memset(f, 0, sizeof(*f));

	/*
	 * Read NumCoders.
	 */
	if (parse_7zip_uint64(a, &(f->numCoders)) < 0)
		return (-1);
	if (f->numCoders > 4)
		/* Too many coders. */
		return (-1);

	f->coders = calloc((size_t)f->numCoders, sizeof(*f->coders));
	if (f->coders == NULL)
		return (-1);
	for (i = 0; i< f->numCoders; i++) {
		size_t codec_size;
		int simple, attr;

		if ((p = header_bytes(a, 1)) == NULL)
			return (-1);
		/*
		 * 0:3 CodecIdSize
		 * 4:  0 - IsSimple
		 *     1 - Is not Simple
		 * 5:  0 - No Attributes
		 *     1 - There are Attributes;
		 * 7:  Must be zero.
		 */
		codec_size = *p & 0xf;
/* ... 8 lines omitted ... */
		if ((p = header_bytes(a, codec_size)) == NULL)
			return (-1);

		f->coders[i].codec = decode_codec_id(p, codec_size);

		if (simple) {
			f->coders[i].numInStreams = 1;
			f->coders[i].numOutStreams = 1;
		} else {
			if (parse_7zip_uint64(
			    a, &(f->coders[i].numInStreams)) < 0)
				return (-1);
			if (1000000 < f->coders[i].numInStreams)
				return (-1);
			if (parse_7zip_uint64(
			    a, &(f->coders[i].numOutStreams)) < 0)
				return (-1);
			if (1000000 < f->coders[i].numOutStreams)
				return (-1);
		}

		if (attr) {
			if (parse_7zip_uint64(
			    a, &(f->coders[i].propertiesSize)) < 0)
				return (-1);
			if ((p = header_bytes(
			    a, (size_t)f->coders[i].propertiesSize)) == NULL)
				return (-1);
			f->coders[i].properties =
			    malloc((size_t)f->coders[i].propertiesSize);
			if (f->coders[i].properties == NULL)
				return (-1);
/* ... 46 lines omitted ... */
				break;
		}
		if (i == numInStreamsTotal)
			return (-1);
		f->packedStreams[0] = i;
	} else {
		for (i = 0; i < f->numPackedStreams; i++) {
			if (parse_7zip_uint64(a, &(f->packedStreams[i])) < 0)
				return (-1);
			if (1000000 < f->packedStreams[i])
				return (-1);
		}
	}
	f->numInStreams = numInStreamsTotal;
	f->numOutStreams = numOutStreamsTotal;

	return (0);
}

static void
```

#### read_CodersInfo() [lines 1897-1995]
```c
}

static int
read_CodersInfo(struct archive_read *a, struct _7z_coders_info *ci)
{
	const unsigned char *p;
	struct _7z_digests digest;
	unsigned i;

	memset(ci, 0, sizeof(*ci));
	memset(&digest, 0, sizeof(digest));

	if ((p = header_bytes(a, 1)) == NULL)
		goto failed;
	if (*p != kFolder)
		goto failed;

	/*
	 * Read NumFolders.
	 */
	if (parse_7zip_uint64(a, &(ci->numFolders)) < 0)
		goto failed;
	if (1000000 < ci->numFolders)
			return (-1);

	/*
	 * Read External.
	 */
	if ((p = header_bytes(a, 1)) == NULL)
		goto failed;
	switch (*p) {
	case 0:
		ci->folders =
			calloc((size_t)ci->numFolders, sizeof(*ci->folders));
		if (ci->folders == NULL)
			return (-1);
		for (i = 0; i < ci->numFolders; i++) {
			if (read_Folder(a, &(ci->folders[i])) < 0)
				goto failed;
		}
		break;
	case 1:
		if (parse_7zip_uint64(a, &(ci->dataStreamIndex)) < 0)
			return (-1);
		if (1000000 < ci->dataStreamIndex)
			return (-1);
		break;
	}

	if ((p = header_bytes(a, 1)) == NULL)
		goto failed;
	if (*p != kCodersUnPackSize)
		goto failed;

	for (i = 0; i < ci->numFolders; i++) {
		struct _7z_folder *folder = &(ci->folders[i]);
		unsigned j;

		folder->unPackSize =
		    calloc((size_t)folder->numOutStreams, sizeof(*folder->unPackSize));
		if (folder->unPackSize == NULL)
			goto failed;
		for (j = 0; j < folder->numOutStreams; j++) {
			if (parse_7zip_uint64(a, &(folder->unPackSize[j])) < 0)
				goto failed;
		}
	}

	/*
	 * Read CRCs.
	 */
	if ((p = header_bytes(a, 1)) == NULL)
		goto failed;
	if (*p == kEnd)
		return (0);
	if (*p != kCRC)
		goto failed;
	if (read_Digests(a, &digest, (size_t)ci->numFolders) < 0)
		goto failed;
	for (i = 0; i < ci->numFolders; i++) {
		ci->folders[i].digest_defined = digest.defineds[i];
		ci->folders[i].digest = digest.digests[i];
	}

	/*
	 *  Must be kEnd.
	 */
	if ((p = header_bytes(a, 1)) == NULL)
		goto failed;
	if (*p != kEnd)
		goto failed;
	free_Digest(&digest);
	return (0);
failed:
	free_Digest(&digest);
	return (-1);
}

static uint64_t
```

#### read_SubStreamsInfo() [lines 2019-2146]
```c
}

static int
read_SubStreamsInfo(struct archive_read *a, struct _7z_substream_info *ss,
    struct _7z_folder *f, size_t numFolders)
{
	const unsigned char *p;
	uint64_t *usizes;
	size_t unpack_streams;
	int type;
	unsigned i;
	uint32_t numDigests;

	memset(ss, 0, sizeof(*ss));

	for (i = 0; i < numFolders; i++)
		f[i].numUnpackStreams = 1;

	if ((p = header_bytes(a, 1)) == NULL)
		return (-1);
	type = *p;

	if (type == kNumUnPackStream) {
		unpack_streams = 0;
		for (i = 0; i < numFolders; i++) {
			if (parse_7zip_uint64(a, &(f[i].numUnpackStreams)) < 0)
				return (-1);
			if (1000000 < f[i].numUnpackStreams)
				return (-1);
			unpack_streams += (size_t)f[i].numUnpackStreams;
		}
		if ((p = header_bytes(a, 1)) == NULL)
			return (-1);
		type = *p;
	} else
		unpack_streams = numFolders;

	ss->unpack_streams = unpack_streams;
	if (unpack_streams) {
		ss->unpackSizes = calloc(unpack_streams,
		    sizeof(*ss->unpackSizes));
		ss->digestsDefined = calloc(unpack_streams,
		    sizeof(*ss->digestsDefined));
		ss->digests = calloc(unpack_streams,
		    sizeof(*ss->digests));
		if (ss->unpackSizes == NULL || ss->digestsDefined == NULL ||
		    ss->digests == NULL)
			return (-1);
	}

	usizes = ss->unpackSizes;
	for (i = 0; i < numFolders; i++) {
/* ... 56 lines omitted ... */
					*digests++ =
					    tmpDigests.digests[di];
				}
			}
		}
		free_Digest(&tmpDigests);
		if ((p = header_bytes(a, 1)) == NULL)
			return (-1);
		type = *p;
	}

	/*
	 *  Must be kEnd.
	 */
	if (type != kEnd)
		return (-1);
	return (0);
}

static void
```

#### read_Header() [lines 2231-2546]
```c
}

static int
read_Header(struct archive_read *a, struct _7z_header_info *h,
    int check_header_id)
{
	struct _7zip *zip = (struct _7zip *)a->format->data;
	const unsigned char *p;
	struct _7z_folder *folders;
	struct _7z_stream_info *si = &(zip->si);
	struct _7zip_entry *entries;
	uint32_t folderIndex, indexInFolder;
	unsigned i;
	int eindex, empty_streams, sindex;

	if (check_header_id) {
		/*
		 * Read Header.
		 */
		if ((p = header_bytes(a, 1)) == NULL)
			return (-1);
		if (*p != kHeader)
			return (-1);
	}

	/*
	 * Read ArchiveProperties.
	 */
	if ((p = header_bytes(a, 1)) == NULL)
		return (-1);
	if (*p == kArchiveProperties) {
		for (;;) {
			uint64_t size;
			if ((p = header_bytes(a, 1)) == NULL)
				return (-1);
			if (*p == 0)
				break;
			if (parse_7zip_uint64(a, &size) < 0)
				return (-1);
		}
/* ... 21 lines omitted ... */

	if (parse_7zip_uint64(a, &(zip->numFiles)) < 0)
		return (-1);
	if (1000000 < zip->numFiles)
			return (-1);

	zip->entries = calloc((size_t)zip->numFiles, sizeof(*zip->entries));
	if (zip->entries == NULL)
		return (-1);
	entries = zip->entries;

	empty_streams = 0;
	for (;;) {
		int type;
		uint64_t size;
		size_t ll;

		if ((p = header_bytes(a, 1)) == NULL)
			return (-1);
		type = *p;
		if (type == kEnd)
			break;

		if (parse_7zip_uint64(a, &size) < 0)
			return (-1);
		if (zip->header_bytes_remaining < size)
			return (-1);
		ll = (size_t)size;
/* ... 207 lines omitted ... */
					return (-1);
				if (folders[folderIndex].numUnpackStreams)
					break;
				folderIndex++;
			}
		}
		entries[i].folderIndex = folderIndex;
		if ((entries[i].flg & HAS_STREAM) == 0)
			continue;
		indexInFolder++;
		if (inde
/* ... truncated ... */
```

## Upstream Fix
```diff
commit e79ef306afe332faf22e9b442a2c6b59cb175573
Author: Tim Kientzle <kientzle@acm.org>
Date:   Sun Jun 19 14:14:09 2016 -0700

    Issue #718: Fix TALOS-CAN-152

    If a 7-Zip archive declares a rediculously large number of substreams,
    it can overflow an internal counter, leading a subsequent memory
    allocation to be too small for the substream data.

    Thanks to the Open Source and Threat Intelligence project at Cisco
    for reporting this issue.

Index: libarchive-3.1.2/libarchive/archive_read_support_format_7zip.c
===================================================================
--- libarchive-3.1.2.orig/libarchive/archive_read_support_format_7zip.c
+++ libarchive-3.1.2/libarchive/archive_read_support_format_7zip.c
@@ -324,6 +324,11 @@ struct _7zip {
 	char			 format_name[64];
 };

+/* Maximum entry size. This limitation prevents reading intentional
+ * corrupted 7-zip files on assuming there are not so many entries in
+ * the files. */
+#define UMAX_ENTRY     ARCHIVE_LITERAL_ULL(100000000)
+
 static int	archive_read_format_7zip_bid(struct archive_read *, int);
 static int	archive_read_format_7zip_cleanup(struct archive_read *);
 static int	archive_read_format_7zip_read_data(struct archive_read *,
@@ -1670,7 +1675,7 @@ read_PackInfo(struct archive_read *a, st
 		return (-1);
 	if (pi->numPackStreams == 0)
 		return (-1);
-	if (1000000 < pi->numPackStreams)
+	if (UMAX_ENTRY < pi->numPackStreams)
 		return (-1);

 	/*
@@ -1799,12 +1804,12 @@ read_Folder(struct archive_read *a, stru
 			if (parse_7zip_uint64(
 			    a, &(f->coders[i].numInStreams)) < 0)
 				return (-1);
-			if (1000000 < f->coders[i].numInStreams)
+			if (UMAX_ENTRY < f->coders[i].numInStreams)
 				return (-1);
 			if (parse_7zip_uint64(
 			    a, &(f->coders[i].numOutStreams)) < 0)
 				return (-1);
-			if (1000000 < f->coders[i].numOutStreams)
+			if (UMAX_ENTRY < f->coders[i].numOutStreams)
 				return (-1);
 		}

@@ -1844,11 +1849,11 @@ read_Folder(struct archive_read *a, stru
 	for (i = 0; i < f->numBindPairs; i++) {
 		if (parse_7zip_uint64(a, &(f->bindPairs[i].inIndex)) < 0)
 			return (-1);
-		if (1000000 < f->bindPairs[i].inIndex)
+		if (UMAX_ENTRY < f->bindPairs[i].inIndex)
 			return (-1);
 		if (parse_7zip_uint64(a, &(f->bindPairs[i].outIndex)) < 0)
 			return (-1);
-		if (1000000 < f->bindPairs[i].outIndex)
+		if (UMAX_ENTRY < f->bindPairs[i].outIndex)
 			return (-1);
 	}

@@ -1874,7 +1879,7 @@ read_Folder(struct archive_read *a, stru
 		for (i = 0; i < f->numPackedStreams; i++) {
 			if (parse_7zip_uint64(a, &(f->packedStreams[i])) < 0)
 				return (-1);
-			if (1000000 < f->packedStreams[i])
+			if (UMAX_ENTRY < f->packedStreams[i])
 				return (-1);
 		}
 	}
@@ -1916,8 +1921,8 @@ read_CodersInfo(struct archive_read *a,
 	 */
 	if (parse_7zip_uint64(a, &(ci->numFolders)) < 0)
 		goto failed;
-	if (1000000 < ci->numFolders)
-			return (-1);
+	if (UMAX_ENTRY < ci->numFolders)
+		return (-1);

 	/*
 	 * Read External.
@@ -1938,7 +1943,7 @@ read_CodersInfo(struct archive_read *a,
 	case 1:
 		if (parse_7zip_uint64(a, &(ci->dataStreamIndex)) < 0)
 			return (-1);
-		if (1000000 < ci->dataStreamIndex)
+		if (UMAX_ENTRY < ci->dataStreamIndex)
 			return (-1);
 		if (ci->numFolders > 0) {
 			archive_set_error(&a->archive, -1,
@@ -2052,8 +2057,11 @@ read_SubStreamsInfo(struct archive_read
 		for (i = 0; i < numFolders; i++) {
 			if (parse_7zip_uint64(a, &(f[i].numUnpackStreams)) < 0)
 				return (-1);
-			if (1000000 < f[i].numUnpackStreams)
+			if (UMAX_ENTRY < f[i].numUnpackStreams)
 				return (-1);
+			if (unpack_streams > SIZE_MAX - UMAX_ENTRY) {
+			        return (-1);
+			}
 			unpack_streams += (size_t)f[i].numUnpackStreams;
 		}
 		if ((p = header_bytes(a, 1)) == NULL)
@@ -2301,8 +2309,8 @@ read_Header(struct archive_read *a, stru

 	if (parse_7zip_uint64(a, &(zip->numFiles)) < 0)
 		return (-1);
-	if (1000000 < zip->numFiles)
-			return (-1);
+	if (UMAX_ENTRY < zip->numFiles)
+		return (-1);

 	zip->entries = calloc((size_t)zip->numFiles, sizeof(*zip->entries));
 	if (zip->entries == NULL)
@@ -2600,7 +2608,7 @@ read_Times(struct archive_read *a, struc
 	if (*p) {
 		if (parse_7zip_uint64(a, &(h->dataIndex)) < 0)
 			goto failed;
-		if (1000000 < h->dataIndex)
+		if (UMAX_ENTRY < h->dataIndex)
 			goto failed;
 	}
```

Generate a backported patch for the SUSE target version.

[Assistant]
commit e79ef306afe332faf22e9b442a2c6b59cb175573
Author: Tim Kientzle <kientzle@acm.org>
Date:   Sun Jun 19 14:14:09 2016 -0700

    Issue #718: Fix TALOS-CAN-152

    If a 7-Zip archive declares a rediculously large number of substreams,
    it can overflow an internal counter, leading a subsequent memory
    allocation to be too small for the substream data.

    Thanks to the Open Source and Threat Intelligence project at Cisco
    for reporting this issue.

Index: libarchive-3.1.2/libarchive/archive_read_support_format_7zip.c
===================================================================
--- libarchive-3.1.2.orig/libarchive/archive_read_support_format_7zip.c
+++ libarchive-3.1.2/libarchive/archive_read_support_format_7zip.c
@@ -324,6 +324,11 @@ struct _7zip {
 	char			 format_name[64];
 };

+/* Maximum entry size. This limitation prevents reading intentional
+ * corrupted 7-zip files on assuming there are not so many entries in
+ * the files. */
+#define UMAX_ENTRY     ARCHIVE_LITERAL_ULL(100000000)
+
 static int	archive_read_format_7zip_bid(struct archive_read *, int);
 static int	archive_read_format_7zip_cleanup(struct archive_read *);
 static int	archive_read_format_7zip_read_data(struct archive_read *,
@@ -1670,7 +1675,7 @@ read_PackInfo(struct archive_read *a, st
 		return (-1);
 	if (pi->numPackStreams == 0)
 		return (-1);
-	if (1000000 < pi->numPackStreams)
+	if (UMAX_ENTRY < pi->numPackStreams)
 		return (-1);

 	/*
@@ -1799,12 +1804,12 @@ read_Folder(struct archive_read *a, stru
 			if (parse_7zip_uint64(
 			    a, &(f->coders[i].numInStreams)) < 0)
 				return (-1);
-			if (1000000 < f->coders[i].numInStreams)
+			if (UMAX_ENTRY < f->coders[i].numInStreams)
 				return (-1);
 			if (parse_7zip_uint64(
 			    a, &(f->coders[i].numOutStreams)) < 0)
 				return (-1);
-			if (1000000 < f->coders[i].numOutStreams)
+			if (UMAX_ENTRY < f->coders[i].numOutStreams)
 				return (-1);
 		}

@@ -1844,11 +1849,11 @@ read_Folder(struct archive_read *a, stru
 	for (i = 0; i < f->numBindPairs; i++) {
 		if (parse_7zip_uint64(a, &(f->bindPairs[i].inIndex)) < 0)
 			return (-1);
-		if (1000000 < f->bindPairs[i].inIndex)
+		if (UMAX_ENTRY < f->bindPairs[i].inIndex)
 			return (-1);
 		if (parse_7zip_uint64(a, &(f->bindPairs[i].outIndex)) < 0)
 			return (-1);
-		if (1000000 < f->bindPairs[i].outIndex)
+		if (UMAX_ENTRY < f->bindPairs[i].outIndex)
 			return (-1);
 	}

@@ -1874,7 +1879,7 @@ read_Folder(struct archive_read *a, stru
 		for (i = 0; i < f->numPackedStreams; i++) {
 			if (parse_7zip_uint64(a, &(f->packedStreams[i])) < 0)
 				return (-1);
-			if (1000000 < f->packedStreams[i])
+			if (UMAX_ENTRY < f->packedStreams[i])
 				return (-1);
 		}
 	}
@@ -1916,8 +1921,8 @@ read_CodersInfo(struct archive_read *a,
 	 */
 	if (parse_7zip_uint64(a, &(ci->numFolders)) < 0)
 		goto failed;
-	if (1000000 < ci->numFolders)
-			return (-1);
+	if (UMAX_ENTRY < ci->numFolders)
+		return (-1);

 	/*
 	 * Read External.
@@ -1938,7 +1943,7 @@ read_CodersInfo(struct archive_read *a,
 	case 1:
 		if (parse_7zip_uint64(a, &(ci->dataStreamIndex)) < 0)
 			return (-1);
-		if (1000000 < ci->dataStreamIndex)
+		if (UMAX_ENTRY < ci->dataStreamIndex)
 			return (-1);
 		if (ci->numFolders > 0) {
 			archive_set_error(&a->archive, -1,
@@ -2052,8 +2057,11 @@ read_SubStreamsInfo(struct archive_read
 		for (i = 0; i < numFolders; i++) {
 			if (parse_7zip_uint64(a, &(f[i].numUnpackStreams)) < 0)
 				return (-1);
-			if (1000000 < f[i].numUnpackStreams)
+			if (UMAX_ENTRY < f[i].numUnpackStreams)
 				return (-1);
+			if (unpack_streams > SIZE_MAX - UMAX_ENTRY) {
+			        return (-1);
+			}
 			unpack_streams += (size_t)f[i].numUnpackStreams;
 		}
 		if ((p = header_bytes(a, 1)) == NULL)
@@ -2301,8 +2309,8 @@ read_Header(struct archive_read *a, stru

 	if (parse_7zip_uint64(a, &(zip->numFiles)) < 0)
 		return (-1);
-	if (1000000 < zip->numFiles)
-			return (-1);
+	if (UMAX_ENTRY < zip->numFiles)
+		return (-1);

 	zip->entries = calloc((size_t)zip->numFiles, sizeof(*zip->entries));
 	if (zip->entries == NULL)
@@ -2600,7 +2608,7 @@ read_Times(struct archive_read *a, struc
 	if (*p) {
 		if (parse_7zip_uint64(a, &(h->dataIndex)) < 0)
 			goto failed;
-		if (1000000 < h->dataIndex)
+		if (UMAX_ENTRY < h->dataIndex)
 			goto failed;
 	}


[System]
You are a security patch backporting assistant for SUSE/openSUSE.

Given a CVE description and an upstream fix, adapt the patch to work with
the target SUSE package version. Output the backported patch in unified
diff format. If the upstream fix applies directly, output it unchanged.

[User]
## CVE: CVE-2016-6250

Integer overflow in the ISO9660 writer in libarchive before 3.2.1 allows remote attackers to cause a denial of service (application crash) or execute arbitrary code via vectors related to verifying filename lengths when writing an ISO9660 archive, which trigger a buffer overflow.

## Package
libarchive

## Files to modify
- libarchive-3.1.2.orig/libarchive/archive_string.c
- libarchive/archive_string.c

## Target Source Code

### CMakeLists.txt

#### CHECK_FUNCTION_EXISTS() [lines 1087-194]
```c

```

### configure.ac

#### AC_CHECK_FUNCS() [lines 290-334]
```c
    AC_CHECK_HEADERS([localcharset.h])
    am_save_LIBS="$LIBS"
    LIBS="${LIBS} ${LIBICONV}"
    AC_CHECK_FUNCS([locale_charset])
    LIBS="${am_save_LIBS}"
    if test "x$ac_cv_func_locale_charset" != "xyes"; then
      # If locale_charset() is not in libiconv, we have to find libcharset.
      AC_CHECK_LIB(charset,locale_charset)
    fi
  fi
fi

AC_ARG_WITH([lzma],
  AS_HELP_STRING([--without-lzma], [Don't build support for xz through lzma]))

if test "x$with_lzma" != "xno"; then
  AC_CHECK_HEADERS([lzma.h])
  AC_CHECK_LIB(lzma,lzma_stream_decoder)
fi

AC_ARG_WITH([lzo2],
  AS_HELP_STRING([--without-lzo2], [Don't build support for lzop through liblzo2]))

if test "x$with_lzo2" != "xno"; then
  AC_CHECK_HEADERS([lzo/lzoconf.h lzo/lzo1x.h])
  AC_CHECK_LIB(lzo2,lzo1x_decompress_safe)
fi

AC_ARG_WITH([nettle],
  AS_HELP_STRING([--without-nettle], [Don't build with crypto support from Nettle]))
AC_ARG_WITH([openssl],
  AS_HELP_STRING([--without-openssl], [Don't build support for mtree and xar hashes through openssl]))
case "$host_os" in
  *darwin* ) with_openssl=no ;;
esac

AC_ARG_WITH([xml2],
  AS_HELP_STRING([--without-xml2], [Don't build support for xar through libxml2]))
AC_ARG_WITH([expat],
  AS_HELP_STRING([--without-expat], [Don't build support for xar through expat]))

if test "x$with_xml2" != "xno"; then
  AC_PATH_PROG([XML2_CONFIG], [xml2-config],, [${PATH}])
  if test "x$XML2_CONFIG" != "x"; then
    CPPFLAGS="${CPPFLAGS} `${XML2_CONFIG} --cflags`"
```

### libarchive/archive_string.c

#### __FBSDID() [lines 32-118]
```c
 * strings while minimizing heap activity.
 *
 * In particular, the buffer used by a string object is only grown, it
 * never shrinks, so you can clear and reuse the same string object
 * without incurring additional memory allocations.
 */

#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#ifdef HAVE_ICONV_H
#include <iconv.h>
#endif
#ifdef HAVE_LANGINFO_H
#include <langinfo.h>
#endif
#ifdef HAVE_LOCALCHARSET_H
#include <localcharset.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_WCHAR_H
#include <wchar.h>
#endif
#if defined(_WIN32) && !defined(__CYGWIN__)
#include <windows.h>
#include <locale.h>
#endif

#include "archive_endian.h"
#include "archive_private.h"
#include "archive_string.h"
#include "archive_string_composition.h"

#if !defined(HAVE_WMEMCPY) && !defined(wmemcpy)
#define wmemcpy(a,b,i)  (wchar_t *)memcpy((a), (b), (i) * sizeof(wchar_t))
#endif

struct archive_string_conv {
	struct archive_string_conv	*next;
	char				*from_charset;
	char				*to_charset;
	unsigned			 from_cp;
	unsigned			 to_cp;
	/* Set 1 if from_charset and to_charset are the same. */
	int				 same;
	int				 flag;
#define SCONV_TO_CHARSET	1	/* MBS is being converted to specified
					 * charset. */
#define SCONV_FROM_CHARSET	(1<<1)	/* MBS is being converted from
					 * specified charset. */
#define SCONV_BEST_EFFORT 	(1<<2)	/* Copy at least ASCII code. */
#define SCONV_WIN_CP	 	(1<<3)	/* Use Windows API for converting
					 * MBS. */
#define SCONV_UTF8_LIBARCHIVE_2 (1<<4)	/* Incorrect UTF-8 made by libarchive
					 * 2.x in the wrong assumption. */
#define SCONV_NORMALIZATION_C	(1<<6)	/* Need normalization to be Form C.
					 * Before UTF-8 characters are actually
					 * processed. */
#define SCONV_NORMALIZATION_D	(1<<7)	/* Need normalization to be Form D.
					 * Before UTF-8 characters are actually
					 * processed.
					 * Currently this only for MAC OS X. */
#define SCONV_TO_UTF8		(1<<8)	/* "to charset" side is UTF-8. */
#define SCONV_FROM_UTF8		(1<<9)	/* "from charset" side is UTF-8. */
#define SCONV_TO_UTF16BE 	(1<<10)	/* "to charset" side is UTF-16BE. */
#define SCONV_FROM_UTF16BE 	(1<<11)	/* "from charset" side is UTF-16BE. */
#define SCONV_TO_UTF16LE 	(1<<12)	/* "to charset" side is UTF-16LE. */
#define SCONV_FROM_UTF16LE 	(1<<13)	/* "from charset" side is UTF-16LE. */
#define SCONV_TO_UTF16		(SCONV_TO_UTF16BE | SCONV_TO_UTF16LE)
#define SCONV_FROM_UTF16	(SCONV_FROM_UTF16BE | SCONV_FROM_UTF16LE)

#if HAVE_ICONV
	iconv_t				 cd;
	iconv_t				 cd_w;/* Use at archive_mstring on
				 	       * Windows. */
#endif
	/* A temporary buffer for normalization. */
	struct archive_string		 utftmp;
	int (*converter[2])(struct archive_string *, const void *, size_t,
	    struct archive_string_conv *);
	int				 nconverter;
};
```

#### archive_string_append() [lines 199-212]
```c
    const void *, size_t, struct archive_string_conv *);

static struct archive_string *
archive_string_append(struct archive_string *as, const char *p, size_t s)
{
	if (archive_string_ensure(as, as->length + s + 1) == NULL)
		return (NULL);
	memcpy(as->s + as->length, p, s);
	as->length += s;
	as->s[as->length] = 0;
	return (as);
}

static struct archive_wstring *
```

#### archive_wstring_append() [lines 210-223]
```c
}

static struct archive_wstring *
archive_wstring_append(struct archive_wstring *as, const wchar_t *p, size_t s)
{
	if (archive_wstring_ensure(as, as->length + s + 1) == NULL)
		return (NULL);
	wmemcpy(as->s + as->length, p, s);
	as->length += s;
	as->s[as->length] = 0;
	return (as);
}

void
```

## Upstream Fix
```diff
commit b6ba56037f0da44efebfa271cc4b1a736a74c62f
Author: Tim Kientzle <kientzle@acm.org>
Date:   Fri Feb 6 23:00:30 2015 -0800

    Issue 398: Overlapping memcpy

    Some of the pathname edits parse a part of the pathname
    in the entry, then try to set the pathname from that part.
    This leads the text routines to memcpy() from within the
    string buffer.

    Avoid this by simply using memmove() for low-level string append
    operations.

Index: libarchive-3.1.2/CMakeLists.txt
===================================================================
--- libarchive-3.1.2.orig/CMakeLists.txt
+++ libarchive-3.1.2/CMakeLists.txt
@@ -1126,6 +1126,7 @@ CHECK_FUNCTION_EXISTS(strftime HAVE_STRF
 CHECK_FUNCTION_EXISTS(vprintf HAVE_VPRINTF)
 CHECK_FUNCTION_EXISTS(wmemcmp HAVE_WMEMCMP)
 CHECK_FUNCTION_EXISTS(wmemcpy HAVE_WMEMCPY)
+CHECK_FUNCTION_EXISTS(wmemmove HAVE_WMEMMOVE)

 CMAKE_POP_CHECK_STATE()	# Restore the state of the variables

Index: libarchive-3.1.2/configure.ac
===================================================================
--- libarchive-3.1.2.orig/configure.ac
+++ libarchive-3.1.2/configure.ac
@@ -525,7 +525,7 @@ AC_CHECK_FUNCS([nl_langinfo openat pipe
 AC_CHECK_FUNCS([select setenv setlocale sigaction statfs statvfs])
 AC_CHECK_FUNCS([strchr strdup strerror strncpy_s strrchr symlink timegm])
 AC_CHECK_FUNCS([tzset unsetenv utime utimensat utimes vfork])
-AC_CHECK_FUNCS([wcrtomb wcscmp wcscpy wcslen wctomb wmemcmp wmemcpy])
+AC_CHECK_FUNCS([wcrtomb wcscmp wcscpy wcslen wctomb wmemcmp wmemcpy wmemmove])
 AC_CHECK_FUNCS([_ctime64_s _fseeki64])
 AC_CHECK_FUNCS([_get_timezone _localtime64_s _mkgmtime64])
 # detects cygwin-1.7, as opposed to older versions
Index: libarchive-3.1.2/libarchive/archive_string.c
===================================================================
--- libarchive-3.1.2.orig/libarchive/archive_string.c
+++ libarchive-3.1.2/libarchive/archive_string.c
@@ -71,6 +71,10 @@ __FBSDID("$FreeBSD: head/lib/libarchive/
 #define wmemcpy(a,b,i)  (wchar_t *)memcpy((a), (b), (i) * sizeof(wchar_t))
 #endif

+#if !defined(HAVE_WMEMMOVE) && !defined(wmemmove)
+#define wmemmove(a,b,i)  (wchar_t *)memmove((a), (b), (i) * sizeof(wchar_t))
+#endif
+
 struct archive_string_conv {
 	struct archive_string_conv	*next;
 	char				*from_charset;
@@ -203,7 +207,7 @@ archive_string_append(struct archive_str
 {
 	if (archive_string_ensure(as, as->length + s + 1) == NULL)
 		return (NULL);
-	memcpy(as->s + as->length, p, s);
+	memmove(as->s + as->length, p, s);
 	as->length += s;
 	as->s[as->length] = 0;
 	return (as);
@@ -214,7 +218,7 @@ archive_wstring_append(struct archive_ws
 {
 	if (archive_wstring_ensure(as, as->length + s + 1) == NULL)
 		return (NULL);
-	wmemcpy(as->s + as->length, p, s);
+	wmemmove(as->s + as->length, p, s);
 	as->length += s;
 	as->s[as->length] = 0;
 	return (as);
```

Generate a backported patch for the SUSE target version.

[Assistant]
commit b6ba56037f0da44efebfa271cc4b1a736a74c62f
Author: Tim Kientzle <kientzle@acm.org>
Date:   Fri Feb 6 23:00:30 2015 -0800

    Issue 398: Overlapping memcpy

    Some of the pathname edits parse a part of the pathname
    in the entry, then try to set the pathname from that part.
    This leads the text routines to memcpy() from within the
    string buffer.

    Avoid this by simply using memmove() for low-level string append
    operations.

Index: libarchive-3.1.2/CMakeLists.txt
===================================================================
--- libarchive-3.1.2.orig/CMakeLists.txt
+++ libarchive-3.1.2/CMakeLists.txt
@@ -1126,6 +1126,7 @@ CHECK_FUNCTION_EXISTS(strftime HAVE_STRF
 CHECK_FUNCTION_EXISTS(vprintf HAVE_VPRINTF)
 CHECK_FUNCTION_EXISTS(wmemcmp HAVE_WMEMCMP)
 CHECK_FUNCTION_EXISTS(wmemcpy HAVE_WMEMCPY)
+CHECK_FUNCTION_EXISTS(wmemmove HAVE_WMEMMOVE)

 CMAKE_POP_CHECK_STATE()	# Restore the state of the variables

Index: libarchive-3.1.2/configure.ac
===================================================================
--- libarchive-3.1.2.orig/configure.ac
+++ libarchive-3.1.2/configure.ac
@@ -525,7 +525,7 @@ AC_CHECK_FUNCS([nl_langinfo openat pipe
 AC_CHECK_FUNCS([select setenv setlocale sigaction statfs statvfs])
 AC_CHECK_FUNCS([strchr strdup strerror strncpy_s strrchr symlink timegm])
 AC_CHECK_FUNCS([tzset unsetenv utime utimensat utimes vfork])
-AC_CHECK_FUNCS([wcrtomb wcscmp wcscpy wcslen wctomb wmemcmp wmemcpy])
+AC_CHECK_FUNCS([wcrtomb wcscmp wcscpy wcslen wctomb wmemcmp wmemcpy wmemmove])
 AC_CHECK_FUNCS([_ctime64_s _fseeki64])
 AC_CHECK_FUNCS([_get_timezone _localtime64_s _mkgmtime64])
 # detects cygwin-1.7, as opposed to older versions
Index: libarchive-3.1.2/libarchive/archive_string.c
===================================================================
--- libarchive-3.1.2.orig/libarchive/archive_string.c
+++ libarchive-3.1.2/libarchive/archive_string.c
@@ -71,6 +71,10 @@ __FBSDID("$FreeBSD: head/lib/libarchive/
 #define wmemcpy(a,b,i)  (wchar_t *)memcpy((a), (b), (i) * sizeof(wchar_t))
 #endif

+#if !defined(HAVE_WMEMMOVE) && !defined(wmemmove)
+#define wmemmove(a,b,i)  (wchar_t *)memmove((a), (b), (i) * sizeof(wchar_t))
+#endif
+
 struct archive_string_conv {
 	struct archive_string_conv	*next;
 	char				*from_charset;
@@ -203,7 +207,7 @@ archive_string_append(struct archive_str
 {
 	if (archive_string_ensure(as, as->length + s + 1) == NULL)
 		return (NULL);
-	memcpy(as->s + as->length, p, s);
+	memmove(as->s + as->length, p, s);
 	as->length += s;
 	as->s[as->length] = 0;
 	return (as);
@@ -214,7 +218,7 @@ archive_wstring_append(struct archive_ws
 {
 	if (archive_wstring_ensure(as, as->length + s + 1) == NULL)
 		return (NULL);
-	wmemcpy(as->s + as->length, p, s);
+	wmemmove(as->s + as->length, p, s);
 	as->length += s;
 	as->s[as->length] = 0;
 	return (as);


[System]
You are a security patch backporting assistant for SUSE/openSUSE.

Given a CVE description and an upstream fix, adapt the patch to work with
the target SUSE package version. Output the backported patch in unified
diff format. If the upstream fix applies directly, output it unchanged.

[User]
## CVE: CVE-2016-6250

Integer overflow in the ISO9660 writer in libarchive before 3.2.1 allows remote attackers to cause a denial of service (application crash) or execute arbitrary code via vectors related to verifying filename lengths when writing an ISO9660 archive, which trigger a buffer overflow.

## Package
libarchive

## Files to modify
- libarchive-3.1.2.orig/libarchive/archive_read.c
- libarchive/archive_read.c
- libarchive/test/test_read_too_many_filters.c

## Target Source Code

### Makefile.am

#### region() [lines 400-486]
```c
	libarchive/test/test_read_format_iso_xorriso.c		\
	libarchive/test/test_read_format_isojoliet_bz2.c	\
	libarchive/test/test_read_format_isojoliet_long.c	\
	libarchive/test/test_read_format_isojoliet_rr.c		\
	libarchive/test/test_read_format_isojoliet_versioned.c	\
	libarchive/test/test_read_format_isorr_bz2.c		\
	libarchive/test/test_read_format_isorr_ce.c		\
	libarchive/test/test_read_format_isorr_new_bz2.c	\
	libarchive/test/test_read_format_isorr_rr_moved.c	\
	libarchive/test/test_read_format_isozisofs_bz2.c	\
	libarchive/test/test_read_format_lha.c			\
	libarchive/test/test_read_format_lha_filename.c		\
	libarchive/test/test_read_format_mtree.c		\
	libarchive/test/test_read_format_pax_bz2.c		\
	libarchive/test/test_read_format_rar.c			\
	libarchive/test/test_read_format_raw.c			\
	libarchive/test/test_read_format_tar.c			\
	libarchive/test/test_read_format_tar_empty_filename.c	\
	libarchive/test/test_read_format_tar_filename.c		\
	libarchive/test/test_read_format_tbz.c			\
	libarchive/test/test_read_format_tgz.c			\
	libarchive/test/test_read_format_tlz.c			\
	libarchive/test/test_read_format_txz.c			\
	libarchive/test/test_read_format_tz.c			\
	libarchive/test/test_read_format_ustar_filename.c	\
	libarchive/test/test_read_format_xar.c			\
	libarchive/test/test_read_format_zip.c			\
	libarchive/test/test_read_format_zip_comment_stored.c	\
	libarchive/test/test_read_format_zip_filename.c		\
	libarchive/test/test_read_format_zip_mac_metadata.c	\
	libarchive/test/test_read_format_zip_sfx.c		\
	libarchive/test/test_read_large.c			\
	libarchive/test/test_read_pax_truncated.c		\
	libarchive/test/test_read_position.c			\
	libarchive/test/test_read_set_format.c			\
	libarchive/test/test_read_truncated.c			\
	libarchive/test/test_read_truncated_filter.c		\
	libarchive/test/test_sparse_basic.c			\
	libarchive/test/test_tar_filenames.c			\
	libarchive/test/test_tar_large.c			\
	libarchive/test/test_ustar_filenames.c			\
	libarchive/test/test_ustar_filename_encoding.c		\
	libarchive/test/test_write_disk.c			\
	libarchive/test/test_write_disk_appledouble.c		\
	libarchive/test/test_write_disk_failures.c		\
	libarchive/test/test_write_disk_hardlink.c		\
	libarchive/test/test_write_disk_hfs_compression.c	\
	libarchive/test/test_write_disk_lookup.c		\
	libarchive/test/test_write_disk_mac_metadata.c		\
	libarchive/test/test_write_disk_no_hfs_compression.c	\
	libarchive/test/test_write_disk_perms.c			\
	libarchive/test/test_write_disk_secure.c		\
	libarchive/test/test_write_disk_s
/* ... truncated ... */
```

### libarchive/archive_read.c

#### archive_read_open1() [lines 450-539]
```c
}

int
archive_read_open1(struct archive *_a)
{
	struct archive_read *a = (struct archive_read *)_a;
	struct archive_read_filter *filter, *tmp;
	int slot, e;
	unsigned int i;

	archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,
	    "archive_read_open");
	archive_clear_error(&a->archive);

	if (a->client.reader == NULL) {
		archive_set_error(&a->archive, EINVAL,
		    "No reader function provided to archive_read_open");
		a->archive.state = ARCHIVE_STATE_FATAL;
		return (ARCHIVE_FATAL);
	}

	/* Open data source. */
	if (a->client.opener != NULL) {
		e = (a->client.opener)(&a->archive, a->client.dataset[0].data);
		if (e != 0) {
			/* If the open failed, call the closer to clean up. */
			if (a->client.closer) {
				for (i = 0; i < a->client.nodes; i++)
					(a->client.closer)(&a->archive,
					    a->client.dataset[i].data);
			}
			return (e);
		}
	}

	filter = calloc(1, sizeof(*filter));
	if (filter == NULL)
		return (ARCHIVE_FATAL);
	filter->bidder = NULL;
	filter->upstream = NULL;
	filter->archive = a;
	filter->data = a->client.dataset[0].data;
	filter->open = client_open_proxy;
	filter->read = client_read_proxy;
	filter->skip = client_skip_proxy;
	filter->seek = client_seek_proxy;
	filter->close = client_close_proxy;
	filter->sswitch = client_switch_proxy;
	filter->name = "none";
	filter->code = ARCHIVE_FILTER_NONE;

	a->client.dataset[0].begin_position = 0;
	if (!a->filter || !a->bypass_filter_bidding)
	{
		a->filter = filter;
		/* Build out the input pipeline. */
		e = choose_filters(a);
		if (e < ARCHIVE_WARN) {
			a->archive.state = ARCHIVE_STATE_FATAL;
			return (ARCHIVE_FATAL);
		}
	}
	else
	{
		/* Need to add "NONE" type filter at the end of the filter chain */
		tmp = a->filter;
		while (tmp->upstream)
			tmp = tmp->upstream;
		tmp->upstream = filter;
	}

	if (!a->format)
	{
		slot = choose_format(a);
		if (slot < 0) {
			__archive_read_close_filters(a);
			a->archive.state = ARCHIVE_STATE_FATAL;
			return (ARCHIVE_FATAL);
		}
		a->format = &(a->formats[slot]);
	}

	a->archive.state = ARCHIVE_STATE_HEADER;

	/* Ensure libarchive starts from the first node in a multivolume set */
	client_switch_proxy(a->filter, 0);
	return (e);
}

/*
```

#### choose_filters() [lines 542-601]
```c
 * building the pipeline.
 */
static int
choose_filters(struct archive_read *a)
{
	int number_bidders, i, bid, best_bid;
	struct archive_read_filter_bidder *bidder, *best_bidder;
	struct archive_read_filter *filter;
	ssize_t avail;
	int r;

	for (;;) {
		n
/* ... truncated ... */
```

### libarchive/test/CMakeLists.txt

#### IF() [lines 111-197]
```c
    test_read_format_gtar_lzma.c
    test_read_format_gtar_sparse.c
    test_read_format_iso_Z.c
    test_read_format_iso_multi_extent.c
    test_read_format_iso_xorriso.c
    test_read_format_isojoliet_bz2.c
    test_read_format_isojoliet_long.c
    test_read_format_isojoliet_rr.c
    test_read_format_isojoliet_versioned.c
    test_read_format_isorr_bz2.c
    test_read_format_isorr_ce.c
    test_read_format_isorr_new_bz2.c
    test_read_format_isorr_rr_moved.c
    test_read_format_isozisofs_bz2.c
    test_read_format_lha.c
    test_read_format_lha_filename.c
    test_read_format_mtree.c
    test_read_format_pax_bz2.c
    test_read_format_rar.c
    test_read_format_raw.c
    test_read_format_tar.c
    test_read_format_tar_empty_filename.c
    test_read_format_tar_filename.c
    test_read_format_tbz.c
    test_read_format_tgz.c
    test_read_format_tlz.c
    test_read_format_txz.c
    test_read_format_tz.c
    test_read_format_ustar_filename.c
    test_read_format_xar.c
    test_read_format_zip.c
    test_read_format_zip_comment_stored.c
    test_read_format_zip_filename.c
    test_read_format_zip_mac_metadata.c
    test_read_format_zip_sfx.c
    test_read_large.c
    test_read_pax_truncated.c
    test_read_position.c
    test_read_set_format.c
    test_read_truncated.c
    test_read_truncated_filter.c
    test_sparse_basic.c
    test_tar_filenames.c
    test_tar_large.c
    test_ustar_filenames.c
    test_ustar_filename_encoding.c
    test_write_disk.c
    test_write_disk_appledouble.c
    test_write_disk_failures.c
    test_write_disk_hardlink.c
    test_write_disk_hfs_compression.c
    test_write_disk_lookup.c
    test_write_disk_mac_metadata.c
    test_write_disk_no_hfs_compression.c
    test_write_disk_perms.c
    test_write_disk_secure.c
    test_write_disk_sparse.c
    test_write_disk_symlink.c
    test_write_disk_times.c
    test_write_filter_b64encode.c
    test_write_filter_bzip2.c
    test_write_filter_compress.c
    test_write_filter_gzip.c
    test_write_filter_gzip_timestamp.c
    test_write_filter_lrzip.c
    test_write_filter_lzip.c
    test_write_filter_lzma.c
    test_write_filter_lzop.c
    test_write_filter_program.c
    test_write_filter_uuencode.c
    test_write_filter_xz.c
    test_write_format_7zip.c
    test_write_format_7zip_empty.c
    test_write_format_7zip_large.c
    test_write_format_ar.c
    test_write_format_cpio.c
    test_write_format_cpio_empty.c
    test_write_format_cpio_newc.c
    test_write_format_cpio_odc.c
    test_write_format_gn
/* ... truncated ... */
```

### Type definitions

```c
/* from archive_private.h */
struct archive {
	/*
	 * The magic/state values are used to sanity-check the
	 * client's usage.  If an API function is called at a
	 * ridiculous time, or the client passes us an invalid
	 * pointer, these values allow me to catch that.
	 */
	unsigned int	magic;
	unsigned int	state;

	/*
	 * Some public API functions depend on the "real" type of the
	 * archive object.
	 */
	struct archive_vtable *vtable;

	int		  archive_format;
	const char	 *archive_format_name;

	int	  compression_code;	/* Currently active compression. */
	const char *compression_name;

	/* Number of file entries processed. */
	int		  file_count;

	int		  archive_error_number;
	const char	 *error;
	struct archive_string	error_string;

	char *current_code;
	unsigned current_codepage; /* Current ACP(ANSI CodePage). */
	unsigned current_oemcp; /* Current OEMCP(OEM CodePage). */
	struct archive_string_conv *sconv;
};

/* from archive_read_private.h */
struct archive_read_filter_bidder {
	/* Configuration data for the bidder. */
	void *data;
	/* Name of the filter */
	const char *name;
	/* Taste the upstream filter to see if we handle this. */
	int (*bid)(struct archive_read_filter_bidder *,
	    struct archive_read_filter *);
	/* Initialize a newly-created filter. */
	int (*init)(struct archive_read_filter *);
	/* Set an option for the filter bidder. */
	int (*options)(struct archive_read_filter_bidder *,
	    const char *key, const char *value);
	/* Release the bidder's configuration data. */
	int (*free)(struct archive_read_filter_bidder *);
};

/* from archive_read_private.h */
struct archive_read_filter {
	int64_t position;
	/* Essentially all filters will need these values, so
	 * just declare them here. */
	struct archive_read_filter_bidder *bidder; /* My bidder. */
	struct archive_read_filter *upstream; /* Who I read from. */
	struct archive_read *archive; /* Associated archive. */
	/* Open a block for reading */
	int (*open)(struct archive_read_filter *self);
	/* Return next block. */
	ssize_t (*read)(struct archive_read_filter *, const void **);
	/* Skip forward this many bytes. */
	int64_t (*skip)(struct archive_read_filter *self, int64_t request);
	/* Seek to an absolute location. */
	int64_t (*seek)(struct archive_read_filter *self, int64_t offset, int whence);
	/* Close (just this filter) and free(self). */
	int (*close)(struct archive_read_filter *self);
	/* Function that handles switching from reading one block to the next/prev */
	int (*sswitch)(struct archive_read_filter *self, unsigned int iindex);
	/* My private data. */
	void *data;

	const char	*name;
	int		 code;

	/* Used by reblocking logic. */
	char		*buffer;
	size_t		 buffer_size;
	char		*next;		/* Current read location. */
	size_t		 avail;		/* Bytes in my buffer. */
	const void	*client_buff;	/* Client buffer information. */
	size_t		 client_total;
	const char	*client_next;
	size_t		 client_avail;
	char		 end_of_file;
	char		 closed;
	char		 fatal;
};
```

## Upstream Fix
```diff
commit 6e06b1c89dd0d16f74894eac4cfc1327a06ee4a0
Author: Tim Kientzle <kientzle@acm.org>
Date:   Sat Jan 10 12:24:58 2015 -0800

    Fix a potential crash issue discovered by Alexander Cherepanov:

    It seems bsdtar automatically handles stacked compression. This is a
    nice feature but it could be problematic when it's completely
    unlimited.  Most clearly it's illustrated with quines:

    $ curl -sRO http://www.maximumcompression.com/selfgz.gz
    $ (ulimit -v 10000000 && bsdtar -tvf selfgz.gz)
    bsdtar: Error opening archive: Can't allocate data for gzip decompression

    Without ulimit, bsdtar will eat all available memory. This could also
    be a problem for other applications using libarchive.

Index: libarchive-3.1.2/Makefile.am
===================================================================
--- libarchive-3.1.2.orig/Makefile.am
+++ libarchive-3.1.2/Makefile.am
@@ -439,6 +439,7 @@ libarchive_test_SOURCES=					\
 	libarchive/test/test_read_pax_truncated.c		\
 	libarchive/test/test_read_position.c			\
 	libarchive/test/test_read_set_format.c			\
+	libarchive/test/test_read_too_many_filters.c		\
 	libarchive/test/test_read_truncated.c			\
 	libarchive/test/test_read_truncated_filter.c		\
 	libarchive/test/test_sparse_basic.c			\
@@ -703,6 +704,7 @@ libarchive_test_EXTRA_DIST=\
 	libarchive/test/test_read_splitted_rar_ab.uu			\
 	libarchive/test/test_read_splitted_rar_ac.uu			\
 	libarchive/test/test_read_splitted_rar_ad.uu			\
+	libarchive/test/test_read_too_many_filters.gz.uu                \
 	libarchive/test/test_splitted_rar_seek_support_aa.uu		\
 	libarchive/test/test_splitted_rar_seek_support_ab.uu		\
 	libarchive/test/test_splitted_rar_seek_support_ac.uu		\
Index: libarchive-3.1.2/libarchive/archive_read.c
===================================================================
--- libarchive-3.1.2.orig/libarchive/archive_read.c
+++ libarchive-3.1.2/libarchive/archive_read.c
@@ -544,13 +544,13 @@ archive_read_open1(struct archive *_a)
 static int
 choose_filters(struct archive_read *a)
 {
-	int number_bidders, i, bid, best_bid;
+	int number_bidders, i, bid, best_bid, n;
 	struct archive_read_filter_bidder *bidder, *best_bidder;
 	struct archive_read_filter *filter;
 	ssize_t avail;
 	int r;

-	for (;;) {
+	for (n = 0; n < 25; ++n) {
 		number_bidders = sizeof(a->bidders) / sizeof(a->bidders[0]);

 		best_bid = 0;
@@ -596,6 +596,9 @@ choose_filters(struct archive_read *a)
 			return (ARCHIVE_FATAL);
 		}
 	}
+	archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+	    "Input requires too many filters for decoding");
+	return (ARCHIVE_FATAL);
 }

 /*
Index: libarchive-3.1.2/libarchive/test/CMakeLists.txt
===================================================================
--- libarchive-3.1.2.orig/libarchive/test/CMakeLists.txt
+++ libarchive-3.1.2/libarchive/test/CMakeLists.txt
@@ -150,6 +150,7 @@ IF(ENABLE_TEST)
     test_read_pax_truncated.c
     test_read_position.c
     test_read_set_format.c
+    test_read_too_many_filters.c
     test_read_truncated.c
     test_read_truncated_filter.c
     test_sparse_basic.c
Index: libarchive-3.1.2/libarchive/test/test_read_too_many_filters.c
===================================================================
--- /dev/null
+++ libarchive-3.1.2/libarchive/test/test_read_too_many_filters.c
@@ -0,0 +1,45 @@
+/*-
+ * Copyright (c) 2003-2008,2015 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "test.h"
+
+DEFINE_TEST(test_read_too_many_filters)
+{
+	const char *name = "test_read_too_many_filters.gz";
+	struct archive *a;
+	int r;
+
+	assert((a = archive_read_new()) != NULL);
+	r = archive_read_support_filter_gzip(a);
+	if (r == ARCHIVE_WARN) {
+		skipping("gzip reading not fully supported on this platform");
+	}
+	assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+	extract_reference_file(name);
+	assertEqualIntA(a, ARCHIVE_FATAL,
+	    archive_read_open_filename(a, name, 200));
+
+	assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+}
Index: libarchive-3.1.2/libarchive/test/test_read_too_many_filters.gz.uu
===================================================================
--- /dev/null
+++ libarchive-3.1.2/libarchive/test/test_read_too_many_filters.gz.uu
@@ -0,0 +1,15 @@
+This is a valid gzip file that decompresses to itself, from
+  http://www.maximumcompression.com/selfgz.gz
+
+This is used in test_read_too_many_filters to try to
+crash libarchive by forcing it to spawn an unending
+list of gunzip filters.
+
+begin 644 test_read_too_many_filters.gz
+M'XL(
```

Generate a backported patch for the SUSE target version.

[Assistant]
commit 6e06b1c89dd0d16f74894eac4cfc1327a06ee4a0
Author: Tim Kientzle <kientzle@acm.org>
Date:   Sat Jan 10 12:24:58 2015 -0800

    Fix a potential crash issue discovered by Alexander Cherepanov:

    It seems bsdtar automatically handles stacked compression. This is a
    nice feature but it could be problematic when it's completely
    unlimited.  Most clearly it's illustrated with quines:

    $ curl -sRO http://www.maximumcompression.com/selfgz.gz
    $ (ulimit -v 10000000 && bsdtar -tvf selfgz.gz)
    bsdtar: Error opening archive: Can't allocate data for gzip decompression

    Without ulimit, bsdtar will eat all available memory. This could also
    be a problem for other applications using libarchive.

Index: libarchive-3.1.2/Makefile.am
===================================================================
--- libarchive-3.1.2.orig/Makefile.am
+++ libarchive-3.1.2/Makefile.am
@@ -439,6 +439,7 @@ libarchive_test_SOURCES=					\
 	libarchive/test/test_read_pax_truncated.c		\
 	libarchive/test/test_read_position.c			\
 	libarchive/test/test_read_set_format.c			\
+	libarchive/test/test_read_too_many_filters.c		\
 	libarchive/test/test_read_truncated.c			\
 	libarchive/test/test_read_truncated_filter.c		\
 	libarchive/test/test_sparse_basic.c			\
@@ -703,6 +704,7 @@ libarchive_test_EXTRA_DIST=\
 	libarchive/test/test_read_splitted_rar_ab.uu			\
 	libarchive/test/test_read_splitted_rar_ac.uu			\
 	libarchive/test/test_read_splitted_rar_ad.uu			\
+	libarchive/test/test_read_too_many_filters.gz.uu                \
 	libarchive/test/test_splitted_rar_seek_support_aa.uu		\
 	libarchive/test/test_splitted_rar_seek_support_ab.uu		\
 	libarchive/test/test_splitted_rar_seek_support_ac.uu		\
Index: libarchive-3.1.2/libarchive/archive_read.c
===================================================================
--- libarchive-3.1.2.orig/libarchive/archive_read.c
+++ libarchive-3.1.2/libarchive/archive_read.c
@@ -544,13 +544,13 @@ archive_read_open1(struct archive *_a)
 static int
 choose_filters(struct archive_read *a)
 {
-	int number_bidders, i, bid, best_bid;
+	int number_bidders, i, bid, best_bid, n;
 	struct archive_read_filter_bidder *bidder, *best_bidder;
 	struct archive_read_filter *filter;
 	ssize_t avail;
 	int r;

-	for (;;) {
+	for (n = 0; n < 25; ++n) {
 		number_bidders = sizeof(a->bidders) / sizeof(a->bidders[0]);

 		best_bid = 0;
@@ -596,6 +596,9 @@ choose_filters(struct archive_read *a)
 			return (ARCHIVE_FATAL);
 		}
 	}
+	archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+	    "Input requires too many filters for decoding");
+	return (ARCHIVE_FATAL);
 }

 /*
Index: libarchive-3.1.2/libarchive/test/CMakeLists.txt
===================================================================
--- libarchive-3.1.2.orig/libarchive/test/CMakeLists.txt
+++ libarchive-3.1.2/libarchive/test/CMakeLists.txt
@@ -150,6 +150,7 @@ IF(ENABLE_TEST)
     test_read_pax_truncated.c
     test_read_position.c
     test_read_set_format.c
+    test_read_too_many_filters.c
     test_read_truncated.c
     test_read_truncated_filter.c
     test_sparse_basic.c
Index: libarchive-3.1.2/libarchive/test/test_read_too_many_filters.c
===================================================================
--- /dev/null
+++ libarchive-3.1.2/libarchive/test/test_read_too_many_filters.c
@@ -0,0 +1,45 @@
+/*-
+ * Copyright (c) 2003-2008,2015 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "test.h"
+
+DEFINE_TEST(test_read_too_many_filters)
+{
+	const char *name = "test_read_too_many_filters.gz";
+	struct archive *a;
+	int r;
+
+	assert((a = archive_read_new()) != NULL);
+	r = archive_read_support_filter_gzip(a);
+	if (r == ARCHIVE_WARN) {
+		skipping("gzip reading not fully supported on this platform");
+	}
+	assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+	extract_reference_file(name);
+	assertEqualIntA(a, ARCHIVE_FATAL,
+	    archive_read_open_filename(a, name, 200));
+
+	assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+}
Index: libarchive-3.1.2/libarchive/test/test_read_too_many_filters.gz.uu
===================================================================
--- /dev/null
+++ libarchive-3.1.2/libarchive/test/test_read_too_many_filters.gz.uu
@@ -0,0 +1,15 @@
+This is a valid gzip file that decompresses to itself, from
+  http://www.maximumcompression.com/selfgz.gz
+
+This is used in test_read_too_many_filters to try to
+crash libarchive by forcing it to spawn an unending
+list of gunzip filters.
+
+begin 644 test_read_too_many_filters.gz
+M'XL(`````````P`/`/#_'XL(`````````P`/`/#_````__\```#__X)QH5P`
+M`!X`X?\```#__P```/__@G&A7```'@#A_P```/__````__\```#__P```/__
+M````__\```#__\(FAF`!`!0`Z_\```#__P```/__PB:&8`$`%`#K_\(FAF`!
+M`!0`Z_^9(#6-B"@Q,C,T`K/`+```%`#K_P*SP"P``!0`Z_]"B"'$`````/__
+>`P!#2DTAT@```$*((<0`````__\#`$-*32'2````
+`
+end


[System]
You are a security patch backporting assistant for SUSE/openSUSE.

Given a CVE description and an upstream fix, adapt the patch to work with
the target SUSE package version. Output the backported patch in unified
diff format. If the upstream fix applies directly, output it unchanged.

[User]
## CVE: CVE-2015-7555

Security vulnerability CVE-2015-7555

## Package
giflib

## Files to modify
- giflib-5.0.5.orig/lib/egif_lib.c
- lib/egif_lib.c

## Upstream Fix
```diff
---
 lib/egif_lib.c |    6 ++++++
 1 file changed, 6 insertions(+)

Index: giflib-5.0.5/lib/egif_lib.c
===================================================================
--- giflib-5.0.5.orig/lib/egif_lib.c
+++ giflib-5.0.5/lib/egif_lib.c
@@ -376,6 +376,12 @@ EGifPutImageDesc(GifFileType *GifFile,
     GifFile->Image.Width = Width;
     GifFile->Image.Height = Height;
     GifFile->Image.Interlace = Interlace;
+
+    // We're going to overwrite the Image.ColorMap pointer next, so free it if not NULL first!
+    if (GifFile->Image.ColorMap != NULL) {
+        GifFreeMapObject(GifFile->Image.ColorMap);
+        GifFile->Image.ColorMap = NULL;
+    }
     if (ColorMap) {
         GifFile->Image.ColorMap = GifMakeMapObject(ColorMap->ColorCount,
                                                 ColorMap->Colors);
```

Generate a backported patch for the SUSE target version.

[Assistant]
---
 lib/egif_lib.c |    6 ++++++
 1 file changed, 6 insertions(+)

Index: giflib-5.0.5/lib/egif_lib.c
===================================================================
--- giflib-5.0.5.orig/lib/egif_lib.c
+++ giflib-5.0.5/lib/egif_lib.c
@@ -376,6 +376,12 @@ EGifPutImageDesc(GifFileType *GifFile,
     GifFile->Image.Width = Width;
     GifFile->Image.Height = Height;
     GifFile->Image.Interlace = Interlace;
+
+    // We're going to overwrite the Image.ColorMap pointer next, so free it if not NULL first!
+    if (GifFile->Image.ColorMap != NULL) {
+        GifFreeMapObject(GifFile->Image.ColorMap);
+        GifFile->Image.ColorMap = NULL;
+    }
     if (ColorMap) {
         GifFile->Image.ColorMap = GifMakeMapObject(ColorMap->ColorCount,
                                                 ColorMap->Colors);


[System]
You are a security patch backporting assistant for SUSE/openSUSE.

Given a CVE description and an upstream fix, adapt the patch to work with
the target SUSE package version. Output the backported patch in unified
diff format. If the upstream fix applies directly, output it unchanged.

[User]
## CVE: CVE-2014-3609

HttpHdrRange.cc in Squid 3.x before 3.3.12 and 3.4.x before 3.4.6 allows remote attackers to cause a denial of service (crash) via a request with crafted "Range headers with unidentifiable byte-range values."

## Package
squid

## Upstream Fix
```diff
------------------------------------------------------------
revno: 11826
revision-id: squid3@treenet.co.nz-20130713124108-55ve768vfrd4sbkc
parent: squid3@treenet.co.nz-20130713123806-pteg9ouzldmxpu8h
committer: Amos Jeffries <squid3@treenet.co.nz>
branch nick: 3.2
timestamp: Sat 2013-07-13 06:41:08 -0600
message:
  Better handling of strange port values in Host:

  We can do better than just producing errors about invalid port details
  and treating it as port-0.
  We can instead undo the port separation and pass it through as part of
  the host name to be verified with the default port number properly
  assumed.
------------------------------------------------------------
# Bazaar merge directive format 2 (Bazaar 0.90)
# revision_id: squid3@treenet.co.nz-20130713124108-55ve768vfrd4sbkc
# target_branch: http://bzr.squid-cache.org/bzr/squid3/branches\
#   /SQUID_3_2
# testament_sha1: a8072203e76e80d4ffb5b6a4cfe7b95f0dd30a4d
# timestamp: 2013-07-13 12:41:42 +0000
# source_branch: http://bzr.squid-cache.org/bzr/squid3/branches\
#   /SQUID_3_2
# base_revision_id: squid3@treenet.co.nz-20130713123806-\
#   pteg9ouzldmxpu8h
#
# Begin patch
=== modified file 'src/client_side_request.cc'
--- src/client_side_request.cc	2013-03-29 06:13:27 +0000
+++ src/client_side_request.cc	2013-07-13 12:41:08 +0000
@@ -641,8 +641,16 @@
     uint16_t port = 0;
     if (portStr) {
         *portStr = '\0'; // strip the ':'
-        if (*(++portStr) != '\0')
-            port = xatoi(portStr);
+        if (*(++portStr) != '\0') {
+            char *end = NULL;
+            int64_t ret = strtoll(portStr, &end, 10);
+            if (end == portStr || *end != '\0' || ret < 1 || ret > 0xFFFF) {
+                // invalid port details. Replace the ':'
+                *(--portStr) = ':';
+                portStr = NULL;
+            } else
+                port = (ret & 0xFFFF);
+        }
     }

     debugs(85, 3, HERE << "validate host=" << host << ", port=" << port << ", portStr=" << (portStr?portStr:"NULL"));
```

Generate a backported patch for the SUSE target version.

[Assistant]
------------------------------------------------------------
revno: 11826
revision-id: squid3@treenet.co.nz-20130713124108-55ve768vfrd4sbkc
parent: squid3@treenet.co.nz-20130713123806-pteg9ouzldmxpu8h
committer: Amos Jeffries <squid3@treenet.co.nz>
branch nick: 3.2
timestamp: Sat 2013-07-13 06:41:08 -0600
message:
  Better handling of strange port values in Host:

  We can do better than just producing errors about invalid port details
  and treating it as port-0.
  We can instead undo the port separation and pass it through as part of
  the host name to be verified with the default port number properly
  assumed.
------------------------------------------------------------
# Bazaar merge directive format 2 (Bazaar 0.90)
# revision_id: squid3@treenet.co.nz-20130713124108-55ve768vfrd4sbkc
# target_branch: http://bzr.squid-cache.org/bzr/squid3/branches\
#   /SQUID_3_2
# testament_sha1: a8072203e76e80d4ffb5b6a4cfe7b95f0dd30a4d
# timestamp: 2013-07-13 12:41:42 +0000
# source_branch: http://bzr.squid-cache.org/bzr/squid3/branches\
#   /SQUID_3_2
# base_revision_id: squid3@treenet.co.nz-20130713123806-\
#   pteg9ouzldmxpu8h
#
# Begin patch
=== modified file 'src/client_side_request.cc'
--- src/client_side_request.cc	2013-03-29 06:13:27 +0000
+++ src/client_side_request.cc	2013-07-13 12:41:08 +0000
@@ -641,8 +641,16 @@
     uint16_t port = 0;
     if (portStr) {
         *portStr = '\0'; // strip the ':'
-        if (*(++portStr) != '\0')
-            port = xatoi(portStr);
+        if (*(++portStr) != '\0') {
+            char *end = NULL;
+            int64_t ret = strtoll(portStr, &end, 10);
+            if (end == portStr || *end != '\0' || ret < 1 || ret > 0xFFFF) {
+                // invalid port details. Replace the ':'
+                *(--portStr) = ':';
+                portStr = NULL;
+            } else
+                port = (ret & 0xFFFF);
+        }
     }

     debugs(85, 3, HERE << "validate host=" << host << ", port=" << port << ", portStr=" << (portStr?portStr:"NULL"));


[System]
You are a security patch backporting assistant for SUSE/openSUSE.

Given a CVE description and an upstream fix, adapt the patch to work with
the target SUSE package version. Output the backported patch in unified
diff format. If the upstream fix applies directly, output it unchanged.

[User]
## CVE: CVE-2016-4658

xpointer.c in libxml2 before 2.9.5 (as used in Apple iOS before 10, OS X before 10.12, tvOS before 10, and watchOS before 3, and other products) does not forbid namespace nodes in XPointer ranges, which allows remote attackers to execute arbitrary code or cause a denial of service (use-after-free and memory corruption) via a crafted XML document.

## Package
libxml2

## Files to modify
- parser.c
- libxml2-2.9.1.orig/parser.c

## Target Source Code

### parser.c

#### xmlParseEncodingDecl() [lines 10308-7078]
```c

```

#### xmlParseEncodingDecl() [lines 10369-7078]
```c

```

## Upstream Fix
```diff
From 9aa37588ee78a06ca1379a9d9356eab16686099c Mon Sep 17 00:00:00 2001
From: Daniel Veillard <veillard@redhat.com>
Date: Mon, 29 Jun 2015 09:08:25 +0800
Subject: [PATCH] Do not process encoding values if the declaration if broken

For https://bugzilla.gnome.org/show_bug.cgi?id=751603

If the string is not properly terminated do not try to convert
to the given encoding.
---
 parser.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/parser.c b/parser.c
index fe603aca5a..a3a95681fc 100644
--- a/parser.c
+++ b/parser.c
@@ -10404,6 +10404,8 @@ xmlParseEncodingDecl(xmlParserCtxtPtr ctxt) {
 	    encoding = xmlParseEncName(ctxt);
 	    if (RAW != '"') {
 		xmlFatalErr(ctxt, XML_ERR_STRING_NOT_CLOSED, NULL);
+		xmlFree((xmlChar *) encoding);
+		return(NULL);
 	    } else
 	        NEXT;
 	} else if (RAW == '\''){
@@ -10411,6 +10413,8 @@ xmlParseEncodingDecl(xmlParserCtxtPtr ctxt) {
 	    encoding = xmlParseEncName(ctxt);
 	    if (RAW != '\'') {
 		xmlFatalErr(ctxt, XML_ERR_STRING_NOT_CLOSED, NULL);
+		xmlFree((xmlChar *) encoding);
+		return(NULL);
 	    } else
 	        NEXT;
 	} else {
```

Generate a backported patch for the SUSE target version.

[Assistant]
From 9aa37588ee78a06ca1379a9d9356eab16686099c Mon Sep 17 00:00:00 2001
From: Daniel Veillard <veillard@redhat.com>
Date: Mon, 29 Jun 2015 09:08:25 +0800
Subject: Do not process encoding values if the declaration if broken

CVE-2015-8317

For https://bugzilla.gnome.org/show_bug.cgi?id=751603

If the string is not properly terminated do not try to convert
to the given encoding.

From 709a952110e98621c9b78c4f26462a9d8333102e Mon Sep 17 00:00:00 2001
From: Daniel Veillard <veillard@redhat.com>
Date: Mon, 29 Jun 2015 16:10:26 +0800
Subject: Fail parsing early on if encoding conversion failed

For https://bugzilla.gnome.org/show_bug.cgi?id=751631

If we fail conversing the current input stream while
processing the encoding declaration of the XMLDecl
then it's safer to just abort there and not try to
report further errors.
---
 parser.c | 4 ++++
 1 file changed, 4 insertions(+)

Index: libxml2-2.9.1/parser.c
===================================================================
--- libxml2-2.9.1.orig/parser.c
+++ libxml2-2.9.1/parser.c
@@ -10347,6 +10347,8 @@ xmlParseEncodingDecl(xmlParserCtxtPtr ct
 	    encoding = xmlParseEncName(ctxt);
 	    if (RAW != '"') {
 		xmlFatalErr(ctxt, XML_ERR_STRING_NOT_CLOSED, NULL);
+		xmlFree((xmlChar *) encoding);
+		return(NULL);
 	    } else
 	        NEXT;
 	} else if (RAW == '\''){
@@ -10354,6 +10356,8 @@ xmlParseEncodingDecl(xmlParserCtxtPtr ct
 	    encoding = xmlParseEncName(ctxt);
 	    if (RAW != '\'') {
 		xmlFatalErr(ctxt, XML_ERR_STRING_NOT_CLOSED, NULL);
+		xmlFree((xmlChar *) encoding);
+		return(NULL);
 	    } else
 	        NEXT;
 	} else {
@@ -10408,7 +10412,11 @@ xmlParseEncodingDecl(xmlParserCtxtPtr ct

             handler = xmlFindCharEncodingHandler((const char *) encoding);
 	    if (handler != NULL) {
-		xmlSwitchToEncoding(ctxt, handler);
+		if (xmlSwitchToEncoding(ctxt, handler) < 0) {
+		    /* failed to convert */
+		    ctxt->errNo = XML_ERR_UNSUPPORTED_ENCODING;
+		    return(NULL);
+		}
 	    } else {
 		xmlFatalErrMsgStr(ctxt, XML_ERR_UNSUPPORTED_ENCODING,
 			"Unsupported encoding %s\n", encoding);