$NetBSD: patch-CVE-2013-1881,v 1.1.2.2 2013/10/09 18:44:39 tron Exp $

from https://git.gnome.org/browse/librsvg/patch/?id=f01aded72c38f0e18bc7ff67dee800e380251c8e

From f01aded72c38f0e18bc7ff67dee800e380251c8e Mon Sep 17 00:00:00 2001
From: Christian Persch <chpe@gnome.org>
Date: Mon, 11 Feb 2013 21:36:58 +0000
Subject: io: Implement strict load policy

Allow any file to load from data:, and any resource to load from other
resources. Only allow file: to load other file: URIs from below the path
of the base file. Any other loads are denied.

Bug #691708.
---
diff --git a/rsvg-base.c b/rsvg-base.c
index 1f88479..9d7c1ea 100644
--- rsvg-base.c.orig	2013-10-03 07:33:50.579625000 -0500
+++ rsvg-base.c	2013-10-03 07:35:26.518496200 -0500
@@ -25,6 +25,7 @@
 */
 
 #include "config.h"
+#define _GNU_SOURCE 1
 
 #include "rsvg.h"
 #include "rsvg-private.h"
@@ -1001,6 +1002,7 @@
 rsvg_handle_set_base_uri (RsvgHandle * handle, const char *base_uri)
 {
     gchar *uri;
+    GFile *file;
 
     g_return_if_fail (handle != NULL);
 
@@ -1012,11 +1014,10 @@
     else
         uri = rsvg_get_base_uri_from_filename (base_uri);
 
-    if (uri) {
-        if (handle->priv->base_uri)
-            g_free (handle->priv->base_uri);
-        handle->priv->base_uri = uri;
-    }
+    file = g_file_new_for_uri (uri ? uri : "data:");
+    rsvg_handle_set_base_gfile (handle, file);
+    g_object_unref (file);
+    g_free (uri);
 }
 
 /**
@@ -2146,12 +2147,79 @@
                          const char *uri,
                          GError **error)
 {
-    RsvgLoadPolicy policy = handle->priv->load_policy;
+    RsvgHandlePrivate *priv = handle->priv;
+    GFile *base;
+    char *path, *dir;
+    char *scheme = NULL, *cpath = NULL, *cdir = NULL;
+    char cpath_buffer[PATH_MAX], cdir_buffer[PATH_MAX];
 
-    if (policy == RSVG_LOAD_POLICY_ALL_PERMISSIVE)
-        return TRUE;
+    g_assert (handle->priv->load_policy == RSVG_LOAD_POLICY_STRICT);
+
+    scheme = g_uri_parse_scheme (uri);
+
+    /* Not a valid URI */
+    if (scheme == NULL)
+        goto deny;
+
+    /* Allow loads of data: from any location */
+    if (g_str_equal (scheme, "data"))
+        goto allow;
+
+    /* No base to compare to? */
+    if (priv->base_gfile == NULL)
+        goto deny;
+
+    /* Deny loads from differing URI schemes */
+    if (!g_file_has_uri_scheme (priv->base_gfile, scheme))
+        goto deny;
+
+    /* resource: is allowed to load anything from other resources */
+    if (g_str_equal (scheme, "resource"))
+        goto allow;
 
+    /* Non-file: isn't allowed to load anything */
+    if (!g_str_equal (scheme, "file"))
+        goto deny;
+
+    base = g_file_get_parent (priv->base_gfile);
+    if (base == NULL)
+        goto deny;
+
+    dir = g_file_get_path (base);
+    g_object_unref (base);
+
+    cdir = realpath (dir,cdir_buffer);
+    g_free (dir);
+    if (cdir == NULL)
+        goto deny;
+
+    path = g_filename_from_uri (uri, NULL, NULL);
+    if (path == NULL)
+        goto deny;
+
+    cpath = realpath (path, cpath_buffer);
+    g_free (path);
+
+    if (cpath == NULL)
+        goto deny;
+
+    /* Now check that @cpath is below @cdir */
+    if (!g_str_has_prefix (cpath, cdir) ||
+        cpath[strlen (cdir)] != G_DIR_SEPARATOR)
+        goto deny;
+
+    /* Allow load! */
+
+ allow:
+    g_free (scheme);
     return TRUE;
+
+ deny:
+    g_free (scheme);
+
+    g_set_error (error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
+                 "File may not link to URI \"%s\"", uri);
+    return FALSE;
 }
 
 guint8* 
diff --git a/rsvg-io.c b/rsvg-io.c
index 3d6c8b5..818d2ec 100644
--- rsvg-io.c
+++ rsvg-io.c
@@ -79,7 +79,7 @@ rsvg_acquire_data_data (const char *uri,
     gboolean base64 = FALSE;
 
     g_assert (out_len != NULL);
-    g_assert (g_str_has_prefix (uri, "data:"));
+    g_assert (strncmp (uri, "data:", 5) == 0);
 
     mime_type = NULL;
     start = uri + 5;
diff --git a/rsvg-private.h b/rsvg-private.h
index 25283d4..1961eaf 100644
--- rsvg-private.h
+++ rsvg-private.h
@@ -123,10 +123,10 @@ struct RsvgSaxHandler {
 };
 
 typedef enum {
-    RSVG_LOAD_POLICY_ALL_PERMISSIVE
+    RSVG_LOAD_POLICY_STRICT
 } RsvgLoadPolicy;
 
-#define RSVG_LOAD_POLICY_DEFAULT (RSVG_LOAD_POLICY_ALL_PERMISSIVE)
+#define RSVG_LOAD_POLICY_DEFAULT (RSVG_LOAD_POLICY_STRICT)
 
 struct RsvgHandlePrivate {
     RsvgHandleFlags flags;
--
cgit v0.9.2
