[librsvg] io: Implement strict load policy



commit f01aded72c38f0e18bc7ff67dee800e380251c8e
Author: Christian Persch <chpe gnome org>
Date:   Mon Feb 11 22:36:58 2013 +0100

    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.

 rsvg-base.c    |   89 +++++++++++++++++++++++++++++++++++++++++++++++++++-----
 rsvg-io.c      |    2 +-
 rsvg-private.h |    4 +-
 3 files changed, 84 insertions(+), 11 deletions(-)
---
diff --git a/rsvg-base.c b/rsvg-base.c
index 1f88479..9d7c1ea 100644
--- a/rsvg-base.c
+++ b/rsvg-base.c
@@ -25,6 +25,7 @@
 */
 
 #include "config.h"
+#define _GNU_SOURCE 1
 
 #include "rsvg.h"
 #include "rsvg-private.h"
@@ -1002,6 +1003,7 @@ void
 rsvg_handle_set_base_uri (RsvgHandle * handle, const char *base_uri)
 {
     gchar *uri;
+    GFile *file;
 
     g_return_if_fail (handle != NULL);
 
@@ -1013,11 +1015,10 @@ rsvg_handle_set_base_uri (RsvgHandle * handle, const char *base_uri)
     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);
 }
 
 /**
@@ -2149,12 +2150,84 @@ _rsvg_handle_allow_load (RsvgHandle *handle,
                          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;
 
-    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);
+
+    /* FIXME portability */
+    cdir = canonicalize_file_name (dir);
+    g_free (dir);
+    if (cdir == NULL)
+        goto deny;
+
+    path = g_filename_from_uri (uri, NULL, NULL);
+    if (path == NULL)
+        goto deny;
+
+    /* FIXME portability */
+    cpath = canonicalize_file_name (path);
+    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);
+    free (cpath);
+    free (cdir);
     return TRUE;
+
+ deny:
+    g_free (scheme);
+    free (cpath);
+    free (cdir);
+
+    g_set_error (error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
+                 "File may not link to URI \"%s\"", uri);
+    return FALSE;
 }
 
 static char *
diff --git a/rsvg-io.c b/rsvg-io.c
index 3d6c8b5..818d2ec 100644
--- a/rsvg-io.c
+++ b/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
--- a/rsvg-private.h
+++ b/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;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]