Control: tag 732144 patch Attached patch should correctly handle URIs and non-URIs.
I've tested it with a few applications using relative and absolute paths, and URIs. Cheers, -- Raphael Geissert - Debian Developer www.debian.org - get.debian.net
Index: librsvg-2.26.3/rsvg-image.c =================================================================== --- librsvg-2.26.3.orig/rsvg-image.c 2013-12-19 11:47:57.499003067 +0100 +++ librsvg-2.26.3/rsvg-image.c 2013-12-19 12:20:32.046140515 +0100 @@ -325,22 +325,7 @@ rsvg_acquire_vfs_resource (const char *f file = g_file_new_for_uri (filename); - if (!(res = g_file_load_contents (file, NULL, &data, &size, NULL, error))) { - if (base_uri != NULL) { - GFile *base; - - rsvg_free_error (error); - - g_object_unref (file); - - base = g_file_new_for_uri (base_uri); - file = g_file_resolve_relative_path (base, filename); - g_object_unref (base); - - res = g_file_load_contents (file, NULL, &data, &size, NULL, error); - } - } - + res = g_file_load_contents (file, NULL, &data, &size, NULL, error); g_object_unref (file); if (res) { @@ -356,23 +341,137 @@ rsvg_acquire_vfs_resource (const char *f } #endif +/* Partial origin-based policy, based on the one implemented in f01aded72c38f0e1 */ +gboolean +_rsvg_acquire_xlink_allow_load (const char *href, const char *base_uri, GError ** err) +{ + char *base_scheme = NULL, *href_scheme = NULL; + + if (base_uri) + base_scheme = g_uri_parse_scheme (base_uri); + if (href) + href_scheme = g_uri_parse_scheme (href); + + /* Not a valid URI */ + if (href_scheme == NULL) + goto deny; + + /* Allow loads of data: from any location */ + if (g_str_equal (href_scheme, "data")) + goto allow; + + /* no valid base URI */ + if (base_scheme == NULL) + goto deny; + + /* Deny loads from differing URI schemes */ + if (href_scheme == NULL || !g_str_equal (href_scheme, base_scheme)) + goto deny; + + /* resource: is allowed to load anything from other resources */ + if (g_str_equal (href_scheme, "resource")) + goto allow; + + /* Non-file: isn't allowed to load anything */ + if (!g_str_equal (href_scheme, "file")) + goto deny; + + /* no local-file policy is applied here */ + +allow: + free(base_scheme); + free(href_scheme); + return TRUE; + +deny: + free(base_scheme); + free(href_scheme); + g_set_error (err, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED, + "File may not link to URI \"%s\"", href); + return FALSE; +} + GByteArray * _rsvg_acquire_xlink_href_resource (const char *href, const char *base_uri, GError ** err) { GByteArray *arr = NULL; + char *base_scheme = NULL, *href_scheme = NULL; + char *href_uri = NULL; +#ifndef HAVE_GIO + /* to be used ONLY for the policy check */ + GString *href_uri_str = NULL; +#endif if (!(href && *href)) return NULL; - if (!strncmp (href, "data:", 5)) + if (base_uri) + base_scheme = g_uri_parse_scheme (base_uri); + if (href) + href_scheme = g_uri_parse_scheme (href); + + if (href_scheme && g_str_equal (href_scheme, "data")) arr = rsvg_acquire_base64_resource (href, NULL); + if (arr) + goto done; - if (!arr) +#ifdef HAVE_GIO + /* if href is not a URI already, turn it into one based on base_uri */ + if (href_scheme == NULL) { + GFile *file, *base, *parentless_base; + base = g_file_new_for_uri (base_uri); + /* now strip the file name: */ + parentless_base = g_file_get_parent (base); + base = g_file_new_for_uri (base_uri); + file = g_file_resolve_relative_path (parentless_base, href); + + g_object_unref (base); + g_object_unref (parentless_base); + href_uri = g_file_get_uri(file); + g_object_unref (file); + } else { + href_uri = strdup (href); + if (!href_uri) /* FIXME: better handling failure */ + goto done; + } +#else + if (href_scheme == NULL) { + href_uri_str = g_string_new(href); + if (base_scheme) { + /* try to turn href into a uri */ + g_string_prepend (href_uri_str, "://"); + g_string_prepend (href_uri_str, base_scheme); + /* no need to free, as href_scheme is NULL, remember? */ + href_scheme = strdup (base_scheme); + if (!href_scheme) /* FIXME: better handling failure */ + goto done; + } else + goto done; + } else { + href_uri_str = g_string_new(href); + } + href_uri = href_uri_str->str; +#endif + + if (!_rsvg_acquire_xlink_allow_load(href_uri, base_uri, err)) + goto done; + +#ifdef HAVE_GIO + arr = rsvg_acquire_vfs_resource (href_uri, base_uri, NULL); +#else + /* href must be a path for fopen() to work */ + if (g_str_equal (href_scheme, "file")) arr = rsvg_acquire_file_resource (href, base_uri, NULL); +#endif + +done: + free(href_scheme); + free(base_scheme); #ifdef HAVE_GIO - if (!arr) - arr = rsvg_acquire_vfs_resource (href, base_uri, NULL); + g_free(href_uri); +#else + g_string_free (href_uri_str, TRUE); #endif return arr; Index: librsvg-2.26.3/rsvg-base.c =================================================================== --- librsvg-2.26.3.orig/rsvg-base.c 2013-12-19 11:47:57.499003067 +0100 +++ librsvg-2.26.3/rsvg-base.c 2013-12-19 12:18:45.573322740 +0100 @@ -1049,12 +1049,13 @@ rsvg_handle_set_base_uri (RsvgHandle * h 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; - rsvg_defs_set_base_uri (handle->priv->defs, handle->priv->base_uri); - } + if (!uri) + uri = g_strdup("data:"); + + if (handle->priv->base_uri) + g_free (handle->priv->base_uri); + handle->priv->base_uri = uri; + rsvg_defs_set_base_uri (handle->priv->defs, handle->priv->base_uri); } /** Index: librsvg-2.26.3/rsvg-base-file-util.c =================================================================== --- librsvg-2.26.3.orig/rsvg-base-file-util.c 2013-12-19 11:47:57.499003067 +0100 +++ librsvg-2.26.3/rsvg-base-file-util.c 2013-12-19 12:19:06.249481571 +0100 @@ -87,10 +87,20 @@ rsvg_handle_new_from_file (const gchar * gchar *base_uri; GByteArray *f; RsvgHandle *handle = NULL; + char *base_scheme; rsvg_return_val_if_fail (file_name != NULL, NULL, error); - base_uri = rsvg_get_base_uri_from_filename (file_name); + /* turn the file name/path into a URI if it is not one already */ + base_scheme = g_uri_parse_scheme (file_name); + if (base_scheme) { + free (base_scheme); + base_scheme = 0; + base_uri = g_strdup(file_name); + } else { + base_uri = rsvg_get_base_uri_from_filename (file_name); + } + base_file_name = g_filename_from_uri (base_uri, NULL, error); f = _rsvg_acquire_xlink_href_resource (file_name, base_uri, error); if (f) {