[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

#### region() [lines 9371-7078]
```c

```

#### region() [lines 9444-7078]
```c

```

## Upstream Fix
```diff
From 38eae571111db3b43ffdeb05487c9f60551906fb Mon Sep 17 00:00:00 2001
From: Pranjal Jumde <pjumde@apple.com>
Date: Mon, 7 Mar 2016 14:04:08 -0800
Subject: Heap use-after-free in xmlSAX2AttributeNs

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

* parser.c:
(xmlParseStartTag2): Attribute strings are only valid if the
base does not change, so add another check where the base may
change.  Make sure to set 'attvalue' to NULL after freeing it.
* result/errors/759020.xml: Added.
* result/errors/759020.xml.err: Added.
* result/errors/759020.xml.str: Added.
* test/errors/759020.xml: Added test case.
---
 parser.c                     | 12 ++++++++++--
 result/errors/759020.xml     |  0
 result/errors/759020.xml.err |  6 ++++++
 result/errors/759020.xml.str |  7 +++++++
 test/errors/759020.xml       | 46 ++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 69 insertions(+), 2 deletions(-)
 create mode 100644 result/errors/759020.xml
 create mode 100644 result/errors/759020.xml.err
 create mode 100644 result/errors/759020.xml.str
 create mode 100644 test/errors/759020.xml

Index: libxml2-2.9.1/parser.c
===================================================================
--- libxml2-2.9.1.orig/parser.c
+++ libxml2-2.9.1/parser.c
@@ -9410,8 +9410,13 @@ reparse:
 		else
 		    if (nsPush(ctxt, NULL, URL) > 0) nbNs++;
 skip_default_ns:
-		if (alloc != 0) xmlFree(attvalue);
+		if ((attvalue != NULL) && (alloc != 0)) {
+		    xmlFree(attvalue);
+		    attvalue = NULL;
+		}
 		SKIP_BLANKS;
+		if ((ctxt->input->base != base) || (inputNr != ctxt->inputNr))
+		    goto base_changed;
 		continue;
 	    }
             if (aprefix == ctxt->str_xmlns) {
@@ -9483,7 +9488,10 @@ skip_default_ns:
 		else
 		    if (nsPush(ctxt, attname, URL) > 0) nbNs++;
 skip_ns:
-		if (alloc != 0) xmlFree(attvalue);
+		if ((attvalue != NULL) && (alloc != 0)) {
+		    xmlFree(attvalue);
+		    attvalue = NULL;
+		}
 		SKIP_BLANKS;
 		if ((ctxt->input->base != base) || (inputNr != ctxt->inputNr))
 		    goto base_changed;
Index: libxml2-2.9.1/result/errors/759020.xml.err
===================================================================
--- /dev/null
+++ libxml2-2.9.1/result/errors/759020.xml.err
@@ -0,0 +1,6 @@
+./test/errors/759020.xml:3: namespace warning : xmlns: URI 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 is not absolute
+0000000000000000000000000000000000000000000000000000000000000000000000000000000'
+                                                                               ^
+./test/errors/759020.xml:46: parser error : Couldn't find end of Start Tag s00 line 2
+
+                                                                   ^
Index: libxml2-2.9.1/result/errors/759020.xml.str
===================================================================
--- /dev/null
+++ libxml2-2.9.1/result/errors/759020.xml.str
@@ -0,0 +1,7 @@
+./test/errors/759020.xml:3: namespace warning : xmlns: URI 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 is not absolute
+0000000000000000000000000000000000000000000000000000000000000000000000000000000'
+                                                                               ^
+./test/errors/759020.xml:46: parser error : Couldn't find end of Start Tag s00
+
+                                                                   ^
+./test/errors/759020.xml : failed to parse
Index: libxml2-2.9.1/test/errors/759020.xml
===================================================================
--- /dev/null
+++ libxml2-2.9.1/test/errors/759020.xml
@@ -0,0 +1,46 @@
+<?l 00000000000000000000000000000?>
+<s00 w0000="000" h00000="000"
+ xmlns = '00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
... (truncated)
```

Generate a backported patch for the SUSE target version.

[Assistant]
From 38eae571111db3b43ffdeb05487c9f60551906fb Mon Sep 17 00:00:00 2001
From: Pranjal Jumde <pjumde@apple.com>
Date: Mon, 7 Mar 2016 14:04:08 -0800
Subject: Heap use-after-free in xmlSAX2AttributeNs

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

* parser.c:
(xmlParseStartTag2): Attribute strings are only valid if the
base does not change, so add another check where the base may
change.  Make sure to set 'attvalue' to NULL after freeing it.
* result/errors/759020.xml: Added.
* result/errors/759020.xml.err: Added.
* result/errors/759020.xml.str: Added.
* test/errors/759020.xml: Added test case.
---
 parser.c                     | 12 ++++++++++--
 result/errors/759020.xml     |  0
 result/errors/759020.xml.err |  6 ++++++
 result/errors/759020.xml.str |  7 +++++++
 test/errors/759020.xml       | 46 ++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 69 insertions(+), 2 deletions(-)
 create mode 100644 result/errors/759020.xml
 create mode 100644 result/errors/759020.xml.err
 create mode 100644 result/errors/759020.xml.str
 create mode 100644 test/errors/759020.xml

Index: libxml2-2.9.1/parser.c
===================================================================
--- libxml2-2.9.1.orig/parser.c
+++ libxml2-2.9.1/parser.c
@@ -9410,8 +9410,13 @@ reparse:
 		else
 		    if (nsPush(ctxt, NULL, URL) > 0) nbNs++;
 skip_default_ns:
-		if (alloc != 0) xmlFree(attvalue);
+		if ((attvalue != NULL) && (alloc != 0)) {
+		    xmlFree(attvalue);
+		    attvalue = NULL;
+		}
 		SKIP_BLANKS;
+		if ((ctxt->input->base != base) || (inputNr != ctxt->inputNr))
+		    goto base_changed;
 		continue;
 	    }
             if (aprefix == ctxt->str_xmlns) {
@@ -9483,7 +9488,10 @@ skip_default_ns:
 		else
 		    if (nsPush(ctxt, attname, URL) > 0) nbNs++;
 skip_ns:
-		if (alloc != 0) xmlFree(attvalue);
+		if ((attvalue != NULL) && (alloc != 0)) {
+		    xmlFree(attvalue);
+		    attvalue = NULL;
+		}
 		SKIP_BLANKS;
 		if ((ctxt->input->base != base) || (inputNr != ctxt->inputNr))
 		    goto base_changed;
Index: libxml2-2.9.1/result/errors/759020.xml.err
===================================================================
--- /dev/null
+++ libxml2-2.9.1/result/errors/759020.xml.err
@@ -0,0 +1,6 @@
+./test/errors/759020.xml:3: namespace warning : xmlns: URI 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 is not absolute
+0000000000000000000000000000000000000000000000000000000000000000000000000000000'
+                                                                               ^
+./test/errors/759020.xml:46: parser error : Couldn't find end of Start Tag s00 line 2
+
+                                                                   ^
Index: libxml2-2.9.1/result/errors/759020.xml.str
===================================================================
--- /dev/null
+++ libxml2-2.9.1/result/errors/759020.xml.str
@@ -0,0 +1,7 @@
+./test/errors/759020.xml:3: namespace warning : xmlns: URI 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 is not absolute
+0000000000000000000000000000000000000000000000000000000000000000000000000000000'
+                                                                               ^
+./test/errors/759020.xml:46: parser error : Couldn't find end of Start Tag s00
+
+                                                                   ^
+./test/errors/759020.xml : failed to parse
Index: libxml2-2.9.1/test/errors/759020.xml
===================================================================
--- /dev/null
+++ libxml2-2.9.1/test/errors/759020.xml
@@ -0,0 +1,46 @@
+<?l 00000000000000000000000000000?>
+<s00 w0000="000" h00000="000"
+ xmlns = '00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file


[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-2012-0113

Unspecified vulnerability in the MySQL Server component in Oracle MySQL 5.1.x and 5.5.x allows remote authenticated users to affect confidentiality and availability via unknown vectors, a different vulnerability than CVE-2012-0118.

## Package
mariadb

## Files to modify
- client/mysql_upgrade.c

## Upstream Fix
```diff
PATCH-P0-FEATURE-SUSE: Returning 0 when already upgraded.

Returning non-zero exit status in this case is not nice to scripts using
mysql_upgrade (eg. our init script)

Maintainer: Michal Hrusecky <mhrusecky@suse.cz>

Index: client/mysql_upgrade.c
===================================================================
--- client/mysql_upgrade.c.orig
+++ client/mysql_upgrade.c
@@ -878,7 +878,9 @@ int main(int argc, char **argv)
     printf("This installation of MySQL is already upgraded to %s, "
            "use --force if you still need to run mysql_upgrade\n",
            MYSQL_SERVER_VERSION);
-    die(NULL);
+    free_used_memory();
+    my_end(MY_CHECK_ERROR);
+    exit(0);
   }

   /*
Index: mysql-test/t/mysql_upgrade.test
===================================================================
--- mysql-test/t/mysql_upgrade.test.orig
+++ mysql-test/t/mysql_upgrade.test
@@ -41,7 +41,7 @@ file_exists $MYSQLD_DATADIR/mysql_upgrad

 --echo Run it again - should say already completed
 --replace_result $MYSQL_SERVER_VERSION VERSION
---error 1
+--error 0
 --exec $MYSQL_UPGRADE 2>&1

 # It should have created a file in the MySQL Servers datadir
```

Generate a backported patch for the SUSE target version.

[Assistant]
PATCH-P0-FEATURE-SUSE: Returning 0 when already upgraded.

Returning non-zero exit status in this case is not nice to scripts using
mysql_upgrade (eg. our init script)

Maintainer: Michal Hrusecky <mhrusecky@suse.cz>

Index: client/mysql_upgrade.c
===================================================================
--- client/mysql_upgrade.c.orig
+++ client/mysql_upgrade.c
@@ -878,7 +878,9 @@ int main(int argc, char **argv)
     printf("This installation of MySQL is already upgraded to %s, "
            "use --force if you still need to run mysql_upgrade\n",
            MYSQL_SERVER_VERSION);
-    die(NULL);
+    free_used_memory();
+    my_end(MY_CHECK_ERROR);
+    exit(0);
   }

   /*
Index: mysql-test/t/mysql_upgrade.test
===================================================================
--- mysql-test/t/mysql_upgrade.test.orig
+++ mysql-test/t/mysql_upgrade.test
@@ -41,7 +41,7 @@ file_exists $MYSQLD_DATADIR/mysql_upgrad

 --echo Run it again - should say already completed
 --replace_result $MYSQL_SERVER_VERSION VERSION
---error 1
+--error 0
 --exec $MYSQL_UPGRADE 2>&1

 # It should have created a file in the MySQL Servers datadir


[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

Heap-based buffer overflow in giffix.c in giffix in giflib 5.1.1 allows attackers to cause a denial of service (program crash) via crafted image and logical screen width fields in a GIF file.

## 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-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
- parserInternals.c

## Target Source Code

### parser.c

#### xmlParseXMLDecl() [lines 10626-7078]
```c

```

#### xmlParseDocument() [lines 10750-7078]
```c

```

#### xmlParseDocument() [lines 10767-7078]
```c

```

## Upstream Fix
```diff
From afd27c21f6b36e22682b7da20d726bce2dcb2f43 Mon Sep 17 00:00:00 2001
From: Daniel Veillard <veillard@redhat.com>
Date: Mon, 9 Nov 2015 18:07:18 +0800
Subject: [PATCH] Avoid processing entities after encoding conversion failures

For https://bugzilla.gnome.org/show_bug.cgi?id=756527
and was also raised by Chromium team in the past

When we hit a convwersion failure when switching encoding
it is bestter to stop parsing there, this was treated as a
fatal error but the parser was continuing to process to extract
more errors, unfortunately that makes little sense as the data
is obviously corrupt and can potentially lead to unexpected behaviour.
---
 parser.c          |  7 +++++--
 parserInternals.c | 11 ++++++++++-
 2 files changed, 15 insertions(+), 3 deletions(-)

diff --git a/parser.c b/parser.c
index 134afe7055..c79b4e85de 100644
--- a/parser.c
+++ b/parser.c
@@ -10665,7 +10665,8 @@ xmlParseXMLDecl(xmlParserCtxtPtr ctxt) {
 	xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Blank needed here\n");
     }
     xmlParseEncodingDecl(ctxt);
-    if (ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) {
+    if ((ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) ||
+         (ctxt->instate == XML_PARSER_EOF)) {
 	/*
 	 * The XML REC instructs us to stop parsing right here
 	 */
@@ -10789,6 +10790,7 @@ xmlParseDocument(xmlParserCtxtPtr ctxt) {

     if (CUR == 0) {
 	xmlFatalErr(ctxt, XML_ERR_DOCUMENT_EMPTY, NULL);
+	return(-1);
     }

     /*
@@ -10806,7 +10808,8 @@ xmlParseDocument(xmlParserCtxtPtr ctxt) {
 	 * Note that we will switch encoding on the fly.
 	 */
 	xmlParseXMLDecl(ctxt);
-	if (ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) {
+	if ((ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) ||
+	    (ctxt->instate == XML_PARSER_EOF)) {
 	    /*
 	     * The XML REC instructs us to stop parsing right here
 	     */
diff --git a/parserInternals.c b/parserInternals.c
index df204fde63..c8230c1c64 100644
--- a/parserInternals.c
+++ b/parserInternals.c
@@ -937,6 +937,7 @@ xmlSwitchEncoding(xmlParserCtxtPtr ctxt, xmlCharEncoding enc)
 {
     xmlCharEncodingHandlerPtr handler;
     int len = -1;
+    int ret;

     if (ctxt == NULL) return(-1);
     switch (enc) {
@@ -1097,7 +1098,15 @@ xmlSwitchEncoding(xmlParserCtxtPtr ctxt, xmlCharEncoding enc)
     if (handler == NULL)
 	return(-1);
     ctxt->charset = XML_CHAR_ENCODING_UTF8;
-    return(xmlSwitchToEncodingInt(ctxt, handler, len));
+    ret = xmlSwitchToEncodingInt(ctxt, handler, len);
+    if ((ret < 0) || (ctxt->errNo == XML_I18N_CONV_FAILED)) {
+        /*
+	 * on encoding conversion errors, stop the parser
+	 */
+        xmlStopParser(ctxt);
+	ctxt->errNo = XML_I18N_CONV_FAILED;
+    }
+    return(ret);
 }

 /**
```

Generate a backported patch for the SUSE target version.

[Assistant]
From afd27c21f6b36e22682b7da20d726bce2dcb2f43 Mon Sep 17 00:00:00 2001
From: Daniel Veillard <veillard@redhat.com>
Date: Mon, 9 Nov 2015 18:07:18 +0800
Subject: Avoid processing entities after encoding conversion failures

For https://bugzilla.gnome.org/show_bug.cgi?id=756527
and was also raised by Chromium team in the past

When we hit a convwersion failure when switching encoding
it is bestter to stop parsing there, this was treated as a
fatal error but the parser was continuing to process to extract
more errors, unfortunately that makes little sense as the data
is obviously corrupt and can potentially lead to unexpected behaviour.
---
 parser.c          |  7 +++++--
 parserInternals.c | 11 ++++++++++-
 2 files changed, 15 insertions(+), 3 deletions(-)

diff --git a/parser.c b/parser.c
index 134afe7..c79b4e8 100644
--- a/parser.c
+++ b/parser.c
@@ -10665,7 +10665,8 @@ xmlParseXMLDecl(xmlParserCtxtPtr ctxt) {
 	xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Blank needed here\n");
     }
     xmlParseEncodingDecl(ctxt);
-    if (ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) {
+    if ((ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) ||
+         (ctxt->instate == XML_PARSER_EOF)) {
 	/*
 	 * The XML REC instructs us to stop parsing right here
 	 */
@@ -10789,6 +10790,7 @@ xmlParseDocument(xmlParserCtxtPtr ctxt) {

     if (CUR == 0) {
 	xmlFatalErr(ctxt, XML_ERR_DOCUMENT_EMPTY, NULL);
+	return(-1);
     }

     /*
@@ -10806,7 +10808,8 @@ xmlParseDocument(xmlParserCtxtPtr ctxt) {
 	 * Note that we will switch encoding on the fly.
 	 */
 	xmlParseXMLDecl(ctxt);
-	if (ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) {
+	if ((ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) ||
+	    (ctxt->instate == XML_PARSER_EOF)) {
 	    /*
 	     * The XML REC instructs us to stop parsing right here
 	     */
diff --git a/parserInternals.c b/parserInternals.c
index df204fd..c8230c1 100644
--- a/parserInternals.c
+++ b/parserInternals.c
@@ -937,6 +937,7 @@ xmlSwitchEncoding(xmlParserCtxtPtr ctxt, xmlCharEncoding enc)
 {
     xmlCharEncodingHandlerPtr handler;
     int len = -1;
+    int ret;

     if (ctxt == NULL) return(-1);
     switch (enc) {
@@ -1097,7 +1098,15 @@ xmlSwitchEncoding(xmlParserCtxtPtr ctxt, xmlCharEncoding enc)
     if (handler == NULL)
 	return(-1);
     ctxt->charset = XML_CHAR_ENCODING_UTF8;
-    return(xmlSwitchToEncodingInt(ctxt, handler, len));
+    ret = xmlSwitchToEncodingInt(ctxt, handler, len);
+    if ((ret < 0) || (ctxt->errNo == XML_I18N_CONV_FAILED)) {
+        /*
+	 * on encoding conversion errors, stop the parser
+	 */
+        xmlStopParser(ctxt);
+	ctxt->errNo = XML_I18N_CONV_FAILED;
+    }
+    return(ret);
 }

 /**
--
cgit v0.11.2


[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-9556

The IsPixelGray function in MagickCore/pixel-accessor.h in ImageMagick 7.0.3-8 allows remote attackers to cause a denial of service (out-of-bounds heap read) via a crafted image file.

## Package
GraphicsMagick

## Files to modify
- GraphicsMagick-1.3.20.orig/coders/meta.c
- coders/meta.c

## Upstream Fix
```diff
ff -r 4f748e625c82 -r 8da95e3e5e81 coders/meta.c
Index: GraphicsMagick-1.3.20/coders/meta.c
===================================================================
--- GraphicsMagick-1.3.20.orig/coders/meta.c	2013-03-10 00:19:31.000000000 +0100
+++ GraphicsMagick-1.3.20/coders/meta.c	2016-10-06 15:21:19.580881195 +0200
@@ -129,14 +129,16 @@ static unsigned int IsMETA(const unsigne

 typedef struct _html_code
 {
-  short
+  unsigned short
     len;
+
   const char
     *code,
     val;
+
 } html_code;

-static html_code html_codes[] = {
+static html_code const html_codes[] = {
 #ifdef HANDLE_GT_LT
   { 4,"<",'<' },
   { 4,">",'>' },
@@ -179,29 +181,36 @@ static int stringnicmp(const char *p,con
   return(toupper((int) *p)-toupper((int) *q));
 }

-static int convertHTMLcodes(char *s, int len)
+static size_t convertHTMLcodes(char *s, const size_t len)
 {
-  if (len <=0 || s==(char*)NULL || *s=='\0')
+  int val;
+
+  if ((len == 0) || (s == (char*) NULL) || (*s=='\0'))
     return 0;

-  if (s[1] == '#')
-    {
-      int val, o;
+  /*
+    Check for hex or decimal character escape.

-      if (sscanf(s,"&#%d;",&val) == 1)
-      {
-        o = 3;
-        while (s[o] != ';')
+    e.g. hex: " ", decimal " "
+
+    Note that scanf is expected to parse the number in hex or decimal
+    and that it does not require the terminating ';' to appear in
+    order to parse the numeric argument.
+  */
+  if ((len > 3) && (s[1] == '#') && (strchr(s,';') != (char *) NULL) &&
+      (sscanf(s,"&#%d;",&val) == 1))
+    {
+      size_t o = 3;
+      while (s[o] != ';')
         {
           o++;
           if (o > 5)
             break;
         }
-        if (o < 6)
-          (void) strcpy(s+1, s+1+o);
-        *s = val;
-        return o;
-      }
+      if (o < 6)
+        (void) memmove(s+1,s+1+o,strlen(s+1+o)+1);
+      *s = val;
+      return o;
     }
   else
     {
@@ -214,7 +223,7 @@ static int convertHTMLcodes(char *s, int
         if (html_codes[i].len <= len)
           if (stringnicmp(s, html_codes[i].code, (size_t) (html_codes[i].len)) == 0)
             {
-              (void) strcpy(s+1, s+html_codes[i].len);
+              (void) memmove(s+1, s+html_codes[i].len, strlen(s+html_codes[i].len)+1);
               *s = html_codes[i].val;
               return html_codes[i].len-1;
             }
@@ -281,10 +290,10 @@ static long parse8BIM(Image *ifile, Imag
   char
     brkused,
     quoted,
-    *line,
-    *token,
-    *newstr,
-    *name;
+    *line = (char *) NULL,
+    *token = (char *) NULL,
+    *newstr = (char *) NULL,
+    *name = (char *) NULL;

   int
     state,
@@ -299,7 +308,7 @@ static long parse8BIM(Image *ifile, Imag
   size_t
     inputlen = BUFFER_SZ;

-  long
+  ssize_t
     savedolen = 0L,
     outputlen = 0L;

@@ -313,7 +322,8 @@ static long parse8BIM(Image *ifile, Imag
   dataset = 0;
   recnum = 0;
   line = MagickAllocateMemory(char *,inputlen);
-  name = token = (char *)NULL;
+  if (line == (char *) NULL)
+    goto parse8BIM_failure;
   savedpos = 0;
   while(super_fgets(&line,&inputlen,ifile)!=NULL)
   {
@@ -321,7 +331,11 @@ static long parse8BIM(Image *ifile, Imag
     next=0;

     token = MagickAllocateMemory(char *,inputlen);
+    if (token == (char *) NULL)
+      goto parse8BIM_failure;
     newstr = MagickAllocateMemory(char *,inputlen);
+    if (newstr == (char *) NULL)
+      goto parse8BIM_failure;
     while (Tokenizer(&token_info, 0, token, inputlen, line,
           (char *) "", (char *) "=",
       (char *) "\"", 0, &brkused,&next,&quoted)==0)
@@ -354,8 +368,9 @@ static long parse8BIM(Image *ifile, Imag
                 break;
               case 2:
                 name = MagickAllocateMemory(char *,strlen(newstr)+1);
-                if (name)
-                  (void) strcpy(name,newstr);
+                if (name == (char *) NULL)
+                  goto parse8BIM_failure;
+                (void) strcpy(name,newstr);
                 break;
             }
             state++;
@@ -367,7 +382,7 @@ static long parse8BIM(Image *ifile, Imag
             int
               next;

-            unsigned long
+            size_t
               len;

             char
@@ -384,7 +399,7 @@ static long parse8BIM(Image *ifile, Imag
                   char
                     *s = &token[next-1];

-                  len -= convertHTMLcodes(s, (int) strlen(s));
+                  len -= convertHTMLcodes(s, strlen(s));
                 }
             }

@@ -400,6 +415,8 @@ static long parse8BIM(Image *ifile, Imag
                   {
                     long diff = outputlen - savedolen;
                     currentpos = TellBlob(ofile);
+                    if (currentpos < 0)
+                      goto parse8BIM_failure;
                     (void) SeekBlob(ofile,savedpos,SEEK_SET);
                     (void) WriteBlobMSBLong(ofile,diff);
                     (void) SeekBlob(ofile,currentpos,SEEK_SET);
@@ -433,7 +450,7 @@ static long parse8BIM(Image *ifile, Imag
                     next=0;
                     outputlen += len;
                     while (len--)
-                      (void) WriteBlobByte(ofile,token[next++]);
+                      (void) WriteBlobByte(ofile,token[next++]); /* boom */

                     if (outputlen & 1)
                       {
@@ -445,6 +462,8 @@ static long parse8BIM(Image *ifile, Imag
                   {
                     /* patch in a fake length for now and fix it later */
                     savedpos = TellBlob(ofile);
+                    if (savedpos < 0)
+                      goto parse8BIM_failure;
                     (void) WriteBlobMSBLong(ofile,0xFFFFFFFFUL);
                     outputlen += 4;
                     savedolen = outputlen;
@@ -478,12 +497,22 @@ static long parse8BIM(Image *ifile, Imag
       long diff = outputlen - savedolen;

       currentpos = TellBlob(ofile);
+      if (currentpos < 0)
+        goto parse8BIM_failure;
+
       (void) SeekBlob(ofile,savedpos,SEEK_SET);
       (void) WriteBlobMSBLong(ofile,diff);
       (void) SeekBlob(ofile,currentpos,SEEK_SET);
       savedolen = 0L;
     }
   return outputlen;
+
+ parse8BIM_failure:
+  MagickFreeMemory(token);
+  MagickFreeMemory(newstr);
+  MagickFreeMemory(name);
+  MagickFreeMemory(line);
+  return 0L;
 }

 static char *super_fgets_w(char **b, size_t *blen, Image *file)
@@ -542,10 +571,10 @@ static long parse8BIMW(Image *ifile, Ima
   char
     brkused,
     quoted,
-    *line,
-    *token,
-    *newstr,
-    *name;
+    *line = (char *) NULL,
+    *token = (char *) NULL,
+    *newstr = (char *) NULL,
+    *name = (char *) NULL;

   int
     state,
@@ -560,7 +589,7 @@ static long parse8BIMW(Image *ifile, Ima
   size_t
     inputlen = BUFFER_SZ;

-  long
+  ssize_t
     savedolen = 0L,
     outputlen = 0L;

@@ -574,6 +603,8 @@ static long parse8BIMW(Image *ifile, Ima
   dataset = 0;
   recnum = 0;
   line = MagickAllocateMemory(char *,inputlen);
+  if (line == (char *) NULL)
+    goto parse8BIMW_failure;
   name = token = (char *)NULL;
   savedpos = 0;
   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
@@ -586,7 +617,11 @@ static long parse8BIMW(Image *ifile, Ima
     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
                           "META CODER Parse8BIM: %s (%lu)",line, (unsigned long) inputlen);
     token = MagickAllocateMemory(char *,inputlen);
+    if (token == (char *) NULL)
+      goto parse8BIMW_failure;
     newstr = MagickAllocateMemory(char *,inputlen);
+    if (newstr == (char *) NULL)
+      goto parse8BIMW_failure;
     while (Tokenizer(&token_info, 0, token, inputlen, line,
           (char *) "", (char *) "=",
       (char *) "\"", 0, &brkused,&next,&quoted)==0)
@@ -619,8 +654,9 @@ static long parse8BIMW(Image *ifile, Ima
                 break;
               case 2:
                 name = MagickAllocateMemory(char *,strlen(newstr)+1);
-                if (name)
-                  (void) strcpy(name,newstr);
+
... (truncated)
```

Generate a backported patch for the SUSE target version.

[Assistant]
ff -r 4f748e625c82 -r 8da95e3e5e81 coders/meta.c
Index: GraphicsMagick-1.3.20/coders/meta.c
===================================================================
--- GraphicsMagick-1.3.20.orig/coders/meta.c	2013-03-10 00:19:31.000000000 +0100
+++ GraphicsMagick-1.3.20/coders/meta.c	2016-10-06 15:21:19.580881195 +0200
@@ -129,14 +129,16 @@ static unsigned int IsMETA(const unsigne

 typedef struct _html_code
 {
-  short
+  unsigned short
     len;
+
   const char
     *code,
     val;
+
 } html_code;

-static html_code html_codes[] = {
+static html_code const html_codes[] = {
 #ifdef HANDLE_GT_LT
   { 4,"<",'<' },
   { 4,">",'>' },
@@ -179,29 +181,36 @@ static int stringnicmp(const char *p,con
   return(toupper((int) *p)-toupper((int) *q));
 }

-static int convertHTMLcodes(char *s, int len)
+static size_t convertHTMLcodes(char *s, const size_t len)
 {
-  if (len <=0 || s==(char*)NULL || *s=='\0')
+  int val;
+
+  if ((len == 0) || (s == (char*) NULL) || (*s=='\0'))
     return 0;

-  if (s[1] == '#')
-    {
-      int val, o;
+  /*
+    Check for hex or decimal character escape.

-      if (sscanf(s,"&#%d;",&val) == 1)
-      {
-        o = 3;
-        while (s[o] != ';')
+    e.g. hex: " ", decimal " "
+
+    Note that scanf is expected to parse the number in hex or decimal
+    and that it does not require the terminating ';' to appear in
+    order to parse the numeric argument.
+  */
+  if ((len > 3) && (s[1] == '#') && (strchr(s,';') != (char *) NULL) &&
+      (sscanf(s,"&#%d;",&val) == 1))
+    {
+      size_t o = 3;
+      while (s[o] != ';')
         {
           o++;
           if (o > 5)
             break;
         }
-        if (o < 6)
-          (void) strcpy(s+1, s+1+o);
-        *s = val;
-        return o;
-      }
+      if (o < 6)
+        (void) memmove(s+1,s+1+o,strlen(s+1+o)+1);
+      *s = val;
+      return o;
     }
   else
     {
@@ -214,7 +223,7 @@ static int convertHTMLcodes(char *s, int
         if (html_codes[i].len <= len)
           if (stringnicmp(s, html_codes[i].code, (size_t) (html_codes[i].len)) == 0)
             {
-              (void) strcpy(s+1, s+html_codes[i].len);
+              (void) memmove(s+1, s+html_codes[i].len, strlen(s+html_codes[i].len)+1);
               *s = html_codes[i].val;
               return html_codes[i].len-1;
             }
@@ -281,10 +290,10 @@ static long parse8BIM(Image *ifile, Imag
   char
     brkused,
     quoted,
-    *line,
-    *token,
-    *newstr,
-    *name;
+    *line = (char *) NULL,
+    *token = (char *) NULL,
+    *newstr = (char *) NULL,
+    *name = (char *) NULL;

   int
     state,
@@ -299,7 +308,7 @@ static long parse8BIM(Image *ifile, Imag
   size_t
     inputlen = BUFFER_SZ;

-  long
+  ssize_t
     savedolen = 0L,
     outputlen = 0L;

@@ -313,7 +322,8 @@ static long parse8BIM(Image *ifile, Imag
   dataset = 0;
   recnum = 0;
   line = MagickAllocateMemory(char *,inputlen);
-  name = token = (char *)NULL;
+  if (line == (char *) NULL)
+    goto parse8BIM_failure;
   savedpos = 0;
   while(super_fgets(&line,&inputlen,ifile)!=NULL)
   {
@@ -321,7 +331,11 @@ static long parse8BIM(Image *ifile, Imag
     next=0;

     token = MagickAllocateMemory(char *,inputlen);
+    if (token == (char *) NULL)
+      goto parse8BIM_failure;
     newstr = MagickAllocateMemory(char *,inputlen);
+    if (newstr == (char *) NULL)
+      goto parse8BIM_failure;
     while (Tokenizer(&token_info, 0, token, inputlen, line,
           (char *) "", (char *) "=",
       (char *) "\"", 0, &brkused,&next,&quoted)==0)
@@ -354,8 +368,9 @@ static long parse8BIM(Image *ifile, Imag
                 break;
               case 2:
                 name = MagickAllocateMemory(char *,strlen(newstr)+1);
-                if (name)
-                  (void) strcpy(name,newstr);
+                if (name == (char *) NULL)
+                  goto parse8BIM_failure;
+                (void) strcpy(name,newstr);
                 break;
             }
             state++;
@@ -367,7 +382,7 @@ static long parse8BIM(Image *ifile, Imag
             int
               next;

-            unsigned long
+            size_t
               len;

             char
@@ -384,7 +399,7 @@ static long parse8BIM(Image *ifile, Imag
                   char
                     *s = &token[next-1];

-                  len -= convertHTMLcodes(s, (int) strlen(s));
+                  len -= convertHTMLcodes(s, strlen(s));
                 }
             }

@@ -400,6 +415,8 @@ static long parse8BIM(Image *ifile, Imag
                   {
                     long diff = outputlen - savedolen;
                     currentpos = TellBlob(ofile);
+                    if (currentpos < 0)
+                      goto parse8BIM_failure;
                     (void) SeekBlob(ofile,savedpos,SEEK_SET);
                     (void) WriteBlobMSBLong(ofile,diff);
                     (void) SeekBlob(ofile,currentpos,SEEK_SET);
@@ -433,7 +450,7 @@ static long parse8BIM(Image *ifile, Imag
                     next=0;
                     outputlen += len;
                     while (len--)
-                      (void) WriteBlobByte(ofile,token[next++]);
+                      (void) WriteBlobByte(ofile,token[next++]); /* boom */

                     if (outputlen & 1)
                       {
@@ -445,6 +462,8 @@ static long parse8BIM(Image *ifile, Imag
                   {
                     /* patch in a fake length for now and fix it later */
                     savedpos = TellBlob(ofile);
+                    if (savedpos < 0)
+                      goto parse8BIM_failure;
                     (void) WriteBlobMSBLong(ofile,0xFFFFFFFFUL);
                     outputlen += 4;
                     savedolen = outputlen;
@@ -478,12 +497,22 @@ static long parse8BIM(Image *ifile, Imag
       long diff = outputlen - savedolen;

       currentpos = TellBlob(ofile);
+      if (currentpos < 0)
+        goto parse8BIM_failure;
+
       (void) SeekBlob(ofile,savedpos,SEEK_SET);
       (void) WriteBlobMSBLong(ofile,diff);
       (void) SeekBlob(ofile,currentpos,SEEK_SET);
       savedolen = 0L;
     }
   return outputlen;
+
+ parse8BIM_failure:
+  MagickFreeMemory(token);
+  MagickFreeMemory(newstr);
+  MagickFreeMemory(name);
+  MagickFreeMemory(line);
+  return 0L;
 }

 static char *super_fgets_w(char **b, size_t *blen, Image *file)
@@ -542,10 +571,10 @@ static long parse8BIMW(Image *ifile, Ima
   char
     brkused,
     quoted,
-    *line,
-    *token,
-    *newstr,
-    *name;
+    *line = (char *) NULL,
+    *token = (char *) NULL,
+    *newstr = (char *) NULL,
+    *name = (char *) NULL;

   int
     state,
@@ -560,7 +589,7 @@ static long parse8BIMW(Image *ifile, Ima
   size_t
     inputlen = BUFFER_SZ;

-  long
+  ssize_t
     savedolen = 0L,
     outputlen = 0L;

@@ -574,6 +603,8 @@ static long parse8BIMW(Image *ifile, Ima
   dataset = 0;
   recnum = 0;
   line = MagickAllocateMemory(char *,inputlen);
+  if (line == (char *) NULL)
+    goto parse8BIMW_failure;
   name = token = (char *)NULL;
   savedpos = 0;
   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
@@ -586,7 +617,11 @@ static long parse8BIMW(Image *ifile, Ima
     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
                           "META CODER Parse8BIM: %s (%lu)",line, (unsigned long) inputlen);
     token = MagickAllocateMemory(char *,inputlen);
+    if (token == (char *) NULL)
+      goto parse8BIMW_failure;
     newstr = MagickAllocateMemory(char *,inputlen);
+    if (newstr == (char *) NULL)
+      goto parse8BIMW_failure;
     while (Tokenizer(&token_info, 0, token, inputlen, line,
           (char *) "", (char *) "=",
       (char *) "\"", 0, &brkused,&next,&quoted)==0)
@@ -619,8 +654,9 @@ static long parse8BIMW(Image *ifile, Ima
                 break;
               case 2:
                 name = MagickAllocateMemory(char *,strlen(newstr)+1);
-                if (name)
-                  (void) strcpy(name,newstr);
+                if (name == (char *) NULL)
+                  goto parse8BIMW_failure;
+                (void) strcpy(name,newstr);
                 break;
             }
             state++;
@@ -632,7 +668,7 @@ static long parse8BIMW(Image *ifile, Ima
             int
               next;

-            unsigned long
+            size_t
               len;

             char
@@ -649,7 +685,7 @@ static long parse8BIMW(Image *ifile, Ima
                   char
                     *s = &token[next-1];

-                  len -= convertHTMLcodes(s, (int) strlen(s));
+                  len -= convertHTMLcodes(s, strlen(s));
                 }
             }

@@ -665,6 +701,8 @@ static long parse8BIMW(Image *ifile, Ima
                   {
                     long diff = outputlen - savedolen;
                     currentpos = TellBlob(ofile);
+                    if (currentpos < 0)
+                      goto parse8BIMW_failure;
                     (void) SeekBlob(ofile,savedpos,SEEK_SET);
                     (void) WriteBlobMSBLong(ofile,diff);
                     (void) SeekBlob(ofile,currentpos,SEEK_SET);
@@ -710,6 +748,8 @@ static long parse8BIMW(Image *ifile, Ima
                   {
                     /* patch in a fake length for now and fix it later */
                     savedpos = TellBlob(ofile);
+                    if (savedpos < 0)
+                      goto parse8BIMW_failure;
                     (void) WriteBlobMSBLong(ofile,0xFFFFFFFFUL);
                     outputlen += 4;
                     savedolen = outputlen;
@@ -743,12 +783,21 @@ static long parse8BIMW(Image *ifile, Ima
       long diff = outputlen - savedolen;

       currentpos = TellBlob(ofile);
+      if (currentpos < 0)
+        goto parse8BIMW_failure;
       (void) SeekBlob(ofile,savedpos,SEEK_SET);
       (void) WriteBlobMSBLong(ofile,diff);
       (void) SeekBlob(ofile,currentpos,SEEK_SET);
       savedolen = 0L;
     }
   return outputlen;
+
+ parse8BIMW_failure:
+  MagickFreeMemory(token);
+  MagickFreeMemory(newstr);
+  MagickFreeMemory(name);
+  MagickFreeMemory(line);
+  return 0L;
 }

 /* some defines for the different JPEG block types */
@@ -835,11 +884,12 @@ static int jpeg_skip_variable(Image *ifi
   return 0;
 }

-static int jpeg_skip_variable2(Image *ifile, Image *ARGUNUSED(ofile))
+static int jpeg_skip_variable2(Image *ifile, Image *ofile)
 {
   unsigned int  length;
   int c1,c2;

+  ARG_NOT_USED(ofile);
   if ((c1 = ReadBlobByte(ifile)) == EOF) return M_EOI;
   if ((c2 = ReadBlobByte(ifile)) == EOF) return M_EOI;

@@ -908,8 +958,6 @@ static int jpeg_skip_till_marker(Image *
 }
 #endif

-static char psheader[] = "\xFF\xED\0\0Photoshop 3.0\08BIM\x04\x04\0\0\0\0";
-
 /* Embed binary IPTC data into a JPEG image. */
 static int jpeg_embed(Image *ifile, Image *ofile, Image *iptc)
 {
@@ -952,9 +1000,12 @@ static int jpeg_embed(Image *ifile, Imag

         if (iptc != (Image *)NULL)
           {
+            static const char psheader_base[] = "\xFF\xED\0\0Photoshop 3.0\08BIM\x04\x04\0\0\0\0";
+            char psheader[sizeof(psheader_base)];
             len=GetBlobSize(iptc);
             if (len & 1)
               len++; /* make the length even */
+            (void) strlcpy(psheader,psheader_base,sizeof(psheader));
             psheader[ 2 ] = (len+16)>>8;
             psheader[ 3 ] = (len+16)&0xff;
             for (inx = 0; inx < 18; inx++)
@@ -1250,7 +1301,7 @@ static Image *ReadMETAImage(const ImageI

       DestroyImage(buff);
     }
-  if (LocaleCompare(image_info->magick,"IPTC") == 0)
+  if (LocaleNCompare(image_info->magick,"IPTC",4) == 0)
     {
       buff=AllocateImage((ImageInfo *) NULL);
       if (buff == (Image *) NULL)
@@ -1260,7 +1311,7 @@ static Image *ReadMETAImage(const ImageI
         {
           DestroyImage(buff);
           ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,
-            image)
+                               image);
         }
       AttachBlob(buff->blob,blob,length);
       /* write out the header - length field patched below */
@@ -1286,14 +1337,21 @@ static Image *ReadMETAImage(const ImageI
         }

       /* subtract off the length of the 8BIM stuff */
+      blob=GetBlobStreamData(buff); /* blob may be realloced */
+      if ((blob == (const unsigned char *) NULL) || (GetBlobSize(buff) < 12))
+        {
+          DestroyImage(buff);
+          ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,
+                               image);
+        }
       length=GetBlobSize(buff)-12;
       blob[10]=(unsigned char) ((length >> 8) & 0xff);
       blob[11]=(unsigned char) (length & 0xff);
       blob=GetBlobStreamData(buff);
       length=GetBlobSize(buff);
       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                            "Store IPTC profile, size %lu bytes",
-                            (unsigned long) length);
+                            "Store IPTC profile, size %" MAGICK_SIZE_T_F
+                            "u bytes",(MAGICK_SIZE_T) length);
       (void) SetImageProfile(image,"IPTC",blob,length);
       DetachBlob(buff->blob);
       MagickFreeMemory(blob)
@@ -1840,9 +1898,14 @@ static int formatIPTC(Image *ifile, Imag
     else
       {
         if (foundiptc)
-          return -1;
+          {
+            return -1;
+          }
         else
-          continue;
+          {
+            c = ReadBlobByte(ifile);
+            continue;
+          }
       }

     /* we found the 0x1c tag and now grab the dataset and record number tags */
@@ -1888,7 +1951,11 @@ static int formatIPTC(Image *ifile, Imag
     for (tagindx=0; tagindx<taglen; tagindx++)
     {
       c=ReadBlobByte(ifile);
-      if (c == EOF) return -1;
+      if (c == EOF)
+        {
+          MagickFreeMemory(str);
+          return -1;
+        }
       str[tagindx] = (unsigned char) c;
     }
     str[taglen] = 0;
@@ -2011,7 +2078,11 @@ static int formatIPTCfromBuffer(Image *o
     for (tagindx=0; tagindx<taglen; tagindx++)
     {
       c = *s++; len--;
-      if (len < 0) return -1;
+      if (len < 0)
+        {
+          MagickFreeMemory(str);
+          return -1;
+        }
       str[tagindx] = (unsigned char) c;
     }
     str[ taglen ] = 0;
@@ -2030,6 +2101,13 @@ static int formatIPTCfromBuffer(Image *o
   return tagsfound;
 }

+#define Format8BIMLiberate()                    \
+  do                                            \
+    {                                           \
+      MagickFreeMemory(PString);                \
+      MagickFreeMemory(str);                    \
+    } while(0);
+
 static int format8BIM(Image *ifile, Image *ofile)
 {
   char
@@ -2045,109 +2123,138 @@ static int format8BIM(Image *ifile, Imag
     c;

   unsigned char
-    *PString,
-    *str;
+    *PString=0,
+    *str=0;

   resCount = 0;

   c =ReadBlobByte(ifile);
   while (c != EOF)
-  {
-    if (c == '8')
-      {
-        unsigned char
-          buffer[5];
+    {
+      if (c == '8')
+        {
+          unsigned char
+            buffer[5];

-        buffer[0] = (unsigned char) c;
-        for (i=1; i<4; i++)
+          buffer[0] = (unsigned char) c;
+          for (i=1; i<4; i++)
+            {
+              c=ReadBlobByte(ifile);
+              if (c == EOF)
+                {
+                  Format8BIMLiberate();
+                  return -1;
+                }
+              buffer[i] = (unsigned char) c;
+            }
+          buffer[4] = 0;
+          if (strcmp((const char *)buffer, "8BIM") != 0)
+            continue;
+        }
+      else
         {
           c=ReadBlobByte(ifile);
-          if (c == EOF) return -1;
-          buffer[i] = (unsigned char) c;
-        }
-        buffer[4] = 0;
-        if (strcmp((const char *)buffer, "8BIM") != 0)
           continue;
-      }
-    else
-      {
-        c=ReadBlobByte(ifile);
-        continue;
-      }
-
-    /* we found the OSType (8BIM) and now grab the ID, PString, and Size fields */
-    ID = ReadBlobMSBShort(ifile);
-    if (ID < 0) return -1;
-    {
-      unsigned char
-        plen;
+        }

-      c=ReadBlobByte(ifile);
-      if (c == EOF) return -1;
-      plen = (unsigned char) c;
-      PString=MagickAllocateMemory(unsigned char *,(unsigned int) (plen+1));
-      if (PString == (unsigned char *) NULL)
-      {
-        (void) printf("MemoryAllocationFailed");
-        return 0;
-      }
-      for (i=0; i<plen; i++)
-      {
-        c=ReadBlobByte(ifile);
-        if (c == EOF) return -1;
-        PString[i] = (unsigned char) c;
-      }
-      PString[ plen ] = 0;
-      if (!(plen&1))
-      {
-        c=ReadBlobByte(ifile);
-        if (c == EOF) return -1;
-      }
-    }
-    Size = ReadBlobMSBLong(ifile);
-    if (Size < 0) return -1;
-    /* make a buffer to hold the data and snag it from the input stream */
-    str=MagickAllocateMemory(unsigned char *,(size_t) Size);
-    if (str == (unsigned char *) NULL)
+      /* we found the OSType (8BIM) and now grab the ID, PString, and Size fields */
+      ID = ReadBlobMSBShort(ifile);
+      if (ID < 0)
+        {
+          Format8BIMLiberate();
+          return -1;
+        }
       {
-        (void) printf("MemoryAllocationFailed");
-        return 0;
-      }
-    for (i=0; i<Size; i++)
-    {
-      c=ReadBlobByte(ifile);
-      if (c == EOF) return -1;
-      str[i] = (unsigned char) c;
-    }
+        unsigned char
+          plen;

-    /* we currently skip thumbnails, since it does not make
-     * any sense preserving them in a real world application
-     */
-    if (ID != THUMBNAIL_ID)
-      {
-        /* now finish up by formatting this binary data into
-         * ASCII equivalent
-         */
-        if (strlen((const char *) PString) != 0)
-          FormatString(temp, "8BIM#%d#%s=", ID, PString);
-        else
-          FormatString(temp, "8BIM#%d=", ID);
-        (void) WriteBlobString(ofile,temp);
-        if (ID == IPTC_ID)
+        c=ReadBlobByte(ifile);
+        if (c == EOF)
           {
-            formatString(ofile, "IPTC", 4);
-            (void) formatIPTCfromBuffer(ofile, (char *)str, (long) Size);
+            Format8BIMLiberate();
+            return -1;
+          }
+        plen = (unsigned char) c;
+        PString=MagickAllocateMemory(unsigned char *,(unsigned int) (plen+1));
+        if (PString == (unsigned char *) NULL)
+          {
+            (void) printf("MemoryAllocationFailed");
+            Format8BIMLiberate();
+            return 0;
+          }
+        for (i=0; i<plen; i++)
+          {
+            c=ReadBlobByte(ifile);
+            if (c == EOF)
+              {
+                Format8BIMLiberate();
+                return -1;
+              }
+            PString[i] = (unsigned char) c;
+          }
+        PString[ plen ] = 0;
+        if (!(plen&1))
+          {
+            c=ReadBlobByte(ifile);
+            if (c == EOF)
+              {
+                Format8BIMLiberate();
+                return -1;
+              }
           }
-        else
-          formatString(ofile, (char *)str, (long) Size);
       }
-    MagickFreeMemory(str);
-    MagickFreeMemory(PString);
+      Size = ReadBlobMSBLong(ifile);
+      if (Size < 0)
+        {
+          Format8BIMLiberate();
+          return -1;
+        }
+      /* make a buffer to hold the data and snag it from the input stream */
+      str=MagickAllocateMemory(unsigned char *,(size_t) Size);
+      if (str == (unsigned char *) NULL)
+        {
+          (void) printf("MemoryAllocationFailed");
+          Format8BIMLiberate();
+          return 0;
+        }
+      for (i=0; i<Size; i++)
+        {
+          c=ReadBlobByte(ifile);
+          if (c == EOF)
+            {
+              Format8BIMLiberate();
+              return -1;
+            }
+          str[i] = (unsigned char) c;
+        }
+
+      /* we currently skip thumbnails, since it does not make
+       * any sense preserving them in a real world application
+       */
+      if (ID != THUMBNAIL_ID)
+        {
+          /* now finish up by formatting this binary data into
+           * ASCII equivalent
+           */
+          if (strlen((const char *) PString) != 0)
+            FormatString(temp, "8BIM#%d#%s=", ID, PString);
+          else
+            FormatString(temp, "8BIM#%d=", ID);
+          (void) WriteBlobString(ofile,temp);
+          if (ID == IPTC_ID)
+            {
+              formatString(ofile, "IPTC", 4);
+              (void) formatIPTCfromBuffer(ofile, (char *)str, (long) Size);
+            }
+          else
+            formatString(ofile, (char *)str, (long) Size);
+        }
+      Format8BIMLiberate();

-    resCount++;
+      resCount++;

-    c=ReadBlobByte(ifile);
-  }
+      c=ReadBlobByte(ifile);
+    }
   return resCount;
 }


[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-5118

The OpenBlob function in blob.c in GraphicsMagick before 1.3.24 and ImageMagick allows remote attackers to execute arbitrary code via a | (pipe) character at the start of a filename.

## Package
GraphicsMagick

## Files to modify
- GraphicsMagick-1.3.18.orig/magick/utility.c
- magick/tempfile.h
- GraphicsMagick-1.3.18.orig/magick/tempfile.c
- GraphicsMagick-1.3.18.orig/magick/symbols.h
- magick/utility.h

## Upstream Fix
```diff
Index: GraphicsMagick-1.3.18/magick/delegate.c
===================================================================
--- GraphicsMagick-1.3.18.orig/magick/delegate.c
+++ GraphicsMagick-1.3.18/magick/delegate.c
@@ -539,7 +539,10 @@ MagickExport unsigned int InvokeDelegate
   char
     *command,
     **commands,
-    filename[MaxTextExtent];
+    linkedname[MaxTextExtent],
+    linkedinfoname[MaxTextExtent],
+    filename[MaxTextExtent],
+    safechars[]="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.,-_+ /";

   const DelegateInfo
     *delegate_info;
@@ -559,6 +562,10 @@ MagickExport unsigned int InvokeDelegate
   assert(image != (Image *) NULL);
   assert(image->signature == MagickSignature);
   temporary_image_filename=(*image->filename == '\0');
+  linkedname[0]='\0';
+  linkedname[MaxTextExtent-1]='\0';
+  linkedinfoname[0]='\0';
+  linkedinfoname[MaxTextExtent-1]='\0';
   if (temporary_image_filename)
     {
       /* Allocate a temporary filename if image is unnamed.  */
@@ -568,12 +575,24 @@ MagickExport unsigned int InvokeDelegate
           return(False);
         }
     }
+  else if (strspn(image->filename, safechars) != strlen(image->filename))
+    {
+      strncpy(linkedname,image->filename,MaxTextExtent-1);
+      if (!AcquireTemporarySymlink(image->filename,linkedname))
+	{
+          (void) ThrowException(exception,FileOpenError,UnableToCreateTemporaryFile,image->filename);
+	  return (False);
+	}
+    }
+
   (void) strlcpy(filename,image->filename,MaxTextExtent);
   delegate_info=GetDelegateInfo(decode,encode,exception);
   if (delegate_info == (DelegateInfo *) NULL)
     {
       if (temporary_image_filename)
         (void) LiberateTemporaryFile(image->filename);
+      if (*linkedname)
+	strncpy(image->filename,linkedname,MaxTextExtent-1);
       (void) ThrowException(exception,DelegateError,NoTagFound,
         decode ? decode : encode);
       return(False);
@@ -594,6 +613,18 @@ MagickExport unsigned int InvokeDelegate
         }
       image_info->temporary=True;
     }
+  else if (strspn(image_info->filename, safechars) != strlen(image_info->filename))
+    {
+      strncpy(linkedinfoname,image_info->filename,MaxTextExtent-1);
+      if (!AcquireTemporarySymlink(image_info->filename,linkedinfoname))
+	{
+          if (temporary_image_filename)
+            LiberateTemporaryFile(image->filename);
+          (void) ThrowException(exception,FileOpenError,UnableToCreateTemporaryFile,image_info->filename);
+          return(False);
+        }
+      temporary_image_filename=True;
+    }

   if (delegate_info->mode != 0)
     if ((decode && (delegate_info->encode != (char *) NULL)) ||
@@ -617,6 +648,13 @@ MagickExport unsigned int InvokeDelegate
         {
           if (temporary_image_filename)
             (void) LiberateTemporaryFile(image->filename);
+	  if (*linkedname)
+            strncpy(image->filename,linkedname,MaxTextExtent-1);
+	  if (*linkedinfoname)
+            {
+              LiberateTemporaryFile(linkedinfoname);
+              strncpy(image_info->filename,linkedinfoname,MaxTextExtent-1);
+	    }
           (void) ThrowException(exception,FileOpenError,UnableToCreateTemporaryFile,image_info->unique);
           return(False);
         }
@@ -625,6 +663,13 @@ MagickExport unsigned int InvokeDelegate
         {
           if (temporary_image_filename)
             (void) LiberateTemporaryFile(image->filename);
+	  if (*linkedname)
+            strncpy(image->filename,linkedname,MaxTextExtent-1);
+	  if (*linkedinfoname)
+            {
+              LiberateTemporaryFile(linkedinfoname);
+              strncpy(image_info->filename,linkedinfoname,MaxTextExtent-1);
+	    }
           (void) LiberateTemporaryFile(image_info->unique);
           (void) ThrowException(exception,FileOpenError,UnableToCreateTemporaryFile,image_info->zero);
           return(False);
@@ -638,6 +683,13 @@ MagickExport unsigned int InvokeDelegate
             (void) LiberateTemporaryFile(image_info->zero);
             if (temporary_image_filename)
               (void) LiberateTemporaryFile(image->filename);
+	    if (*linkedname)
+              strncpy(image->filename,linkedname,MaxTextExtent-1);
+	    if (*linkedinfoname)
+              {
+                LiberateTemporaryFile(linkedinfoname);
+                strncpy(image_info->filename,linkedinfoname,MaxTextExtent-1);
+	      }
             (void) ThrowException(exception,DelegateError,DelegateFailed,
               decode ? decode : encode);
             return(False);
@@ -663,6 +715,13 @@ MagickExport unsigned int InvokeDelegate
               (void) LiberateTemporaryFile(image_info->zero);
               if (temporary_image_filename)
                 (void) LiberateTemporaryFile(image->filename);
+	      if (*linkedname)
+                strncpy(image->filename,linkedname,MaxTextExtent-1);
+	      if (*linkedinfoname)
+                {
+                  LiberateTemporaryFile(linkedinfoname);
+                  strncpy(image_info->filename,linkedinfoname,MaxTextExtent-1);
+	        }
               DestroyImageInfo(clone_info);
               (void) ThrowException(exception,DelegateError,DelegateFailed,
                 decode ? decode : encode);
@@ -684,6 +743,13 @@ MagickExport unsigned int InvokeDelegate
     {
       if (temporary_image_filename)
         (void) LiberateTemporaryFile(image->filename);
+      if (*linkedname)
+        strncpy(image->filename,linkedname,MaxTextExtent-1);
+      if (*linkedinfoname)
+        {
+          LiberateTemporaryFile(linkedinfoname);
+          strncpy(image_info->filename,linkedinfoname,MaxTextExtent-1);
+        }
       (void) ThrowException(exception,ResourceLimitError,MemoryAllocationFailed,decode ? decode : encode);
       return(False);
     }
@@ -810,6 +876,13 @@ MagickExport unsigned int InvokeDelegate
  error_exit:
   if (temporary_image_filename)
     (void) LiberateTemporaryFile(image->filename);
+  if (*linkedname)
+    strncpy(image->filename,linkedname,MaxTextExtent-1);
+  if (*linkedinfoname)
+    {
+      LiberateTemporaryFile(linkedinfoname);
+      strncpy(image_info->filename,linkedinfoname,MaxTextExtent-1);
+    }
   for ( ; commands[i] != (char *) NULL; i++)
     MagickFreeMemory(commands[i]);
   MagickFreeMemory(commands);
Index: GraphicsMagick-1.3.18/magick/symbols.h
===================================================================
--- GraphicsMagick-1.3.18.orig/magick/symbols.h
+++ GraphicsMagick-1.3.18/magick/symbols.h
@@ -43,6 +43,7 @@
 #define AcquireTemporaryFileDescriptor GmAcquireTemporaryFileDescriptor
 #define AcquireTemporaryFileName GmAcquireTemporaryFileName
 #define AcquireTemporaryFileStream GmAcquireTemporaryFileStream
+#define AcquireTemporarySymlink GmAcquireTemporarySymlink
 #define AdaptiveThresholdImage GmAdaptiveThresholdImage
 #define AddDefinition GmAddDefinition
 #define AddDefinitions GmAddDefinitions
Index: GraphicsMagick-1.3.18/magick/tempfile.c
===================================================================
--- GraphicsMagick-1.3.18.orig/magick/tempfile.c
+++ GraphicsMagick-1.3.18/magick/tempfile.c
@@ -192,6 +192,93 @@ MagickExport MagickPassFail AcquireTempo
 %                                                                             %
 %                                                                             %
 %                                                                             %
++   A c q u i r e T e m p o r a r y S y m l i n k                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% AcquireTemporarySymlink replaces the contents of the string buffer pointed
+% to by filename with the unique name of a symbolic link.  True is returned
+% if a symlink
... (truncated)
```

Generate a backported patch for the SUSE target version.

[Assistant]
Index: GraphicsMagick-1.3.18/magick/delegate.c
===================================================================
--- GraphicsMagick-1.3.18.orig/magick/delegate.c
+++ GraphicsMagick-1.3.18/magick/delegate.c
@@ -539,7 +539,10 @@ MagickExport unsigned int InvokeDelegate
   char
     *command,
     **commands,
-    filename[MaxTextExtent];
+    linkedname[MaxTextExtent],
+    linkedinfoname[MaxTextExtent],
+    filename[MaxTextExtent],
+    safechars[]="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.,-_+ /";

   const DelegateInfo
     *delegate_info;
@@ -559,6 +562,10 @@ MagickExport unsigned int InvokeDelegate
   assert(image != (Image *) NULL);
   assert(image->signature == MagickSignature);
   temporary_image_filename=(*image->filename == '\0');
+  linkedname[0]='\0';
+  linkedname[MaxTextExtent-1]='\0';
+  linkedinfoname[0]='\0';
+  linkedinfoname[MaxTextExtent-1]='\0';
   if (temporary_image_filename)
     {
       /* Allocate a temporary filename if image is unnamed.  */
@@ -568,12 +575,24 @@ MagickExport unsigned int InvokeDelegate
           return(False);
         }
     }
+  else if (strspn(image->filename, safechars) != strlen(image->filename))
+    {
+      strncpy(linkedname,image->filename,MaxTextExtent-1);
+      if (!AcquireTemporarySymlink(image->filename,linkedname))
+	{
+          (void) ThrowException(exception,FileOpenError,UnableToCreateTemporaryFile,image->filename);
+	  return (False);
+	}
+    }
+
   (void) strlcpy(filename,image->filename,MaxTextExtent);
   delegate_info=GetDelegateInfo(decode,encode,exception);
   if (delegate_info == (DelegateInfo *) NULL)
     {
       if (temporary_image_filename)
         (void) LiberateTemporaryFile(image->filename);
+      if (*linkedname)
+	strncpy(image->filename,linkedname,MaxTextExtent-1);
       (void) ThrowException(exception,DelegateError,NoTagFound,
         decode ? decode : encode);
       return(False);
@@ -594,6 +613,18 @@ MagickExport unsigned int InvokeDelegate
         }
       image_info->temporary=True;
     }
+  else if (strspn(image_info->filename, safechars) != strlen(image_info->filename))
+    {
+      strncpy(linkedinfoname,image_info->filename,MaxTextExtent-1);
+      if (!AcquireTemporarySymlink(image_info->filename,linkedinfoname))
+	{
+          if (temporary_image_filename)
+            LiberateTemporaryFile(image->filename);
+          (void) ThrowException(exception,FileOpenError,UnableToCreateTemporaryFile,image_info->filename);
+          return(False);
+        }
+      temporary_image_filename=True;
+    }

   if (delegate_info->mode != 0)
     if ((decode && (delegate_info->encode != (char *) NULL)) ||
@@ -617,6 +648,13 @@ MagickExport unsigned int InvokeDelegate
         {
           if (temporary_image_filename)
             (void) LiberateTemporaryFile(image->filename);
+	  if (*linkedname)
+            strncpy(image->filename,linkedname,MaxTextExtent-1);
+	  if (*linkedinfoname)
+            {
+              LiberateTemporaryFile(linkedinfoname);
+              strncpy(image_info->filename,linkedinfoname,MaxTextExtent-1);
+	    }
           (void) ThrowException(exception,FileOpenError,UnableToCreateTemporaryFile,image_info->unique);
           return(False);
         }
@@ -625,6 +663,13 @@ MagickExport unsigned int InvokeDelegate
         {
           if (temporary_image_filename)
             (void) LiberateTemporaryFile(image->filename);
+	  if (*linkedname)
+            strncpy(image->filename,linkedname,MaxTextExtent-1);
+	  if (*linkedinfoname)
+            {
+              LiberateTemporaryFile(linkedinfoname);
+              strncpy(image_info->filename,linkedinfoname,MaxTextExtent-1);
+	    }
           (void) LiberateTemporaryFile(image_info->unique);
           (void) ThrowException(exception,FileOpenError,UnableToCreateTemporaryFile,image_info->zero);
           return(False);
@@ -638,6 +683,13 @@ MagickExport unsigned int InvokeDelegate
             (void) LiberateTemporaryFile(image_info->zero);
             if (temporary_image_filename)
               (void) LiberateTemporaryFile(image->filename);
+	    if (*linkedname)
+              strncpy(image->filename,linkedname,MaxTextExtent-1);
+	    if (*linkedinfoname)
+              {
+                LiberateTemporaryFile(linkedinfoname);
+                strncpy(image_info->filename,linkedinfoname,MaxTextExtent-1);
+	      }
             (void) ThrowException(exception,DelegateError,DelegateFailed,
               decode ? decode : encode);
             return(False);
@@ -663,6 +715,13 @@ MagickExport unsigned int InvokeDelegate
               (void) LiberateTemporaryFile(image_info->zero);
               if (temporary_image_filename)
                 (void) LiberateTemporaryFile(image->filename);
+	      if (*linkedname)
+                strncpy(image->filename,linkedname,MaxTextExtent-1);
+	      if (*linkedinfoname)
+                {
+                  LiberateTemporaryFile(linkedinfoname);
+                  strncpy(image_info->filename,linkedinfoname,MaxTextExtent-1);
+	        }
               DestroyImageInfo(clone_info);
               (void) ThrowException(exception,DelegateError,DelegateFailed,
                 decode ? decode : encode);
@@ -684,6 +743,13 @@ MagickExport unsigned int InvokeDelegate
     {
       if (temporary_image_filename)
         (void) LiberateTemporaryFile(image->filename);
+      if (*linkedname)
+        strncpy(image->filename,linkedname,MaxTextExtent-1);
+      if (*linkedinfoname)
+        {
+          LiberateTemporaryFile(linkedinfoname);
+          strncpy(image_info->filename,linkedinfoname,MaxTextExtent-1);
+        }
       (void) ThrowException(exception,ResourceLimitError,MemoryAllocationFailed,decode ? decode : encode);
       return(False);
     }
@@ -810,6 +876,13 @@ MagickExport unsigned int InvokeDelegate
  error_exit:
   if (temporary_image_filename)
     (void) LiberateTemporaryFile(image->filename);
+  if (*linkedname)
+    strncpy(image->filename,linkedname,MaxTextExtent-1);
+  if (*linkedinfoname)
+    {
+      LiberateTemporaryFile(linkedinfoname);
+      strncpy(image_info->filename,linkedinfoname,MaxTextExtent-1);
+    }
   for ( ; commands[i] != (char *) NULL; i++)
     MagickFreeMemory(commands[i]);
   MagickFreeMemory(commands);
Index: GraphicsMagick-1.3.18/magick/symbols.h
===================================================================
--- GraphicsMagick-1.3.18.orig/magick/symbols.h
+++ GraphicsMagick-1.3.18/magick/symbols.h
@@ -43,6 +43,7 @@
 #define AcquireTemporaryFileDescriptor GmAcquireTemporaryFileDescriptor
 #define AcquireTemporaryFileName GmAcquireTemporaryFileName
 #define AcquireTemporaryFileStream GmAcquireTemporaryFileStream
+#define AcquireTemporarySymlink GmAcquireTemporarySymlink
 #define AdaptiveThresholdImage GmAdaptiveThresholdImage
 #define AddDefinition GmAddDefinition
 #define AddDefinitions GmAddDefinitions
Index: GraphicsMagick-1.3.18/magick/tempfile.c
===================================================================
--- GraphicsMagick-1.3.18.orig/magick/tempfile.c
+++ GraphicsMagick-1.3.18/magick/tempfile.c
@@ -192,6 +192,93 @@ MagickExport MagickPassFail AcquireTempo
 %                                                                             %
 %                                                                             %
 %                                                                             %
++   A c q u i r e T e m p o r a r y S y m l i n k                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% AcquireTemporarySymlink replaces the contents of the string buffer pointed
+% to by filename with the unique name of a symbolic link.  True is returned
+% if a symlink waas created, or False is returned if there is a failure.
+% The allocated symlink should be recovered via the LiberateTemporaryFile()
+% function once it is no longer required.
+%
+% The format of the AcquireTemporarySymlink method is:
+%
+%     unsigned int AcquireTemporarySymlink(char *linkname, const char *name,
+%                                          ExceptionInfo *exception)
+%
+%  A description of each parameter follows.
+%
+%   o linkname: Specifies a pointer to an array of characters that must be
+%               MaxTextExtent characters of size.  The unique
+%               name of the symlink is returned in this array.
+%   o name: Specifies a file name the symlink should point to.
+*/
+MagickExport unsigned int AcquireTemporarySymlink(char *linkname, const char *name)
+{
+  char
+    *tempdir,
+    tempname[MaxTextExtent];
+
+  int
+    fd,
+    tries;
+
+  assert(linkname != (char *)NULL);
+  linkname[0]='\0';
+  tempname[MaxTextExtent-1]='\0';
+
+  tempdir=getenv("MAGICK_TMPDIR");
+#if defined(POSIX)
+  if (!tempdir)
+    tempdir=getenv("TMPDIR");
+#endif /* POSIX */
+#if defined(WIN32)
+  if (!tempdir)
+    tempdir=getenv("TMP");
+  if (!tempdir)
+    tempdir=getenv("TEMP");
+#endif /* WIN32 */
+#if defined(P_tmpdir)
+  if (!tempdir)
+    tempdir=P_tmpdir;
+#endif
+
+  for (tries=0; tries < 15; tries++)
+    {
+      strncpy(tempname,"gmXXXXXX",MaxTextExtent-1);
+      ComposeTemporaryFileName(tempname);
+      strncpy(linkname,tempdir,MaxTextExtent-1);
+      if (tempdir[strlen(tempdir)-1] != DirectorySeparator[0])
+	strncat(linkname,DirectorySeparator,MaxTextExtent-1);
+      strncat(linkname,tempname,MaxTextExtent-1);
+      if (*name == '/')
+        fd=symlink(name, linkname);
+      else
+        {
+          char cname[MaxTextExtent];
+	  if (!getcwd(cname,(size_t)MaxTextExtent))
+	    return (False);
+	  strncat(cname,DirectorySeparator,MaxTextExtent-1);
+	  strncat(cname,name,MaxTextExtent-1);
+	  fd=symlink(cname,linkname);
+	}
+      if (fd != -1)
+	{
+	  AddTemporaryFileToList(linkname);
+	  return (True);
+	}
+    }
+  return (False);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
 +   A c q u i r e T e m p o r a r y F i l e D e s c r i p t o r               %
 %                                                                             %
 %                                                                             %
Index: GraphicsMagick-1.3.18/magick/tempfile.h
===================================================================
--- GraphicsMagick-1.3.18.orig/magick/tempfile.h
+++ GraphicsMagick-1.3.18/magick/tempfile.h
@@ -24,6 +24,7 @@ typedef enum

 MagickExport MagickPassFail
   AcquireTemporaryFileName(char *filename),
+  AcquireTemporarySymlink(char *linkname, const char *name),
   LiberateTemporaryFile(char *filename);

 MagickExport int
Index: GraphicsMagick-1.3.18/magick/utility.c
===================================================================
--- GraphicsMagick-1.3.18.orig/magick/utility.c
+++ GraphicsMagick-1.3.18/magick/utility.c
@@ -1253,6 +1253,72 @@ MagickExport void FormatString(char *str
 %                                                                             %
 %                                                                             %
 %                                                                             %
+%  F o r m a t S t r i n g N u m e r i c                                      %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  Method FormatStringNumeric formats output for a single numeric argument.
+%  It takes into account that the format string given might be untrusted
+%  user input, and returns a pointer to the formatted string.
+%
+%  The format of the FormatStringNumeric method is:
+%
+%      char * FormatStringNumeric(char *string,const char *format,int value)
+%
+%  A description of each parameter follows.
+%
+%   o  format:  A string describing the format to use to write the numeric
+%      argument. Only the first numeric format identifier is replaced.
+%
+%   o  value:  Numeric value to substitute into format string.
+%
+%
+*/
+MagickExport char *FormatStringNumeric(const char *format,int value)
+{
+  char
+    *p,
+    *string;
+
+  string = NULL;
+
+  (void) CloneString(&string, format);
+
+  for (p=strchr(format,'%'); p != (char *) NULL; p=strchr(p+1,'%'))
+  {
+    char
+      *q;
+
+    q=(char *) p+1;
+    if (*q == '0')
+      (void) strtol(q,&q,10);
+    if ((*q == '%') || (*q == 'd') || (*q == 'o') || (*q == 'x'))
+    {
+      char
+        c;
+
+      q++;
+      c=*q;
+      *q='\0';
+      (void) snprintf(string+(p-format),MaxTextExtent-(p-format),p,value);
+      *q=c;
+      (void) ConcatenateString(&string,q);
+      if (*(q-1) == '%')
+        p++;
+      else
+        break;
+    }
+  }
+  return string;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
 %   G e t E x e c u t i o n P a t h                                           %
 %                                                                             %
 %                                                                             %
Index: GraphicsMagick-1.3.18/magick/utility.h
===================================================================
--- GraphicsMagick-1.3.18.orig/magick/utility.h
+++ GraphicsMagick-1.3.18/magick/utility.h
@@ -72,6 +72,7 @@ extern MagickExport char
   *AllocateString(const char *),
   *Base64Encode(const unsigned char *,const size_t,size_t *),
   *EscapeString(const char *,const char),
+  *FormatStringNumeric(const char *,int),
   *GetPageGeometry(const char *),
   **ListFiles(const char *,const char *,long *),
   **StringToArgv(const char *,int *),