rsvg_defs_lookup(): Do not allow looking up extern references

This function gets called directly from the public API, and a calling
application should not be allowed to lookup an element with a name
like "some-random-file#element_id", that is, the app should not be
able to cause files to be read if they are not within the set of
resources that the SVG actually references.

The test is robust (only fragment IDs without a URL are allowed), but
will inadvertently print a g_warning if someone runs rsvg-convert like

    rsvg-convert -i 'foo#bar' -o x.png x.svg

We may be able to get rid of that g_warning once the public API is
implemented in Rust, so it can have access to the URL parsing machinery.
parent 92078565
......@@ -7,6 +7,7 @@ use std::rc::Rc;
use allowed_url::AllowedUrl;
use handle::{self, RsvgHandle};
use node::{Node, RsvgNode};
use util::rsvg_g_warning;
use util::utf8_cstr;
pub enum RsvgDefs {}
......@@ -190,10 +191,34 @@ pub extern "C" fn rsvg_defs_lookup(
match r.unwrap() {
Href::WithFragment(fragment) => match defs.lookup(handle, &fragment) {
Some(n) => n as *const RsvgNode,
None => ptr::null(),
Href::WithFragment(fragment) => {
if let Some(uri) = fragment.uri() {
// The public APIs to get geometries of individual elements, or to render
// them, should only allow referencing elements within the main handle's
// SVG file; that is, only plain "#foo" fragment IDs are allowed here.
// Otherwise, a calling program could request "another-file#foo" and cause
// another-file to be loaded, even if it is not part of the set of
// resources that the main SVG actually references. In the future we may
// relax this requirement to allow lookups within that set, but not to
// other random files.
let msg = format!(
"the public API is not allowed to look up external references: {}#{}",
rsvg_log!("{}", msg);
return ptr::null();
match defs.lookup(handle, &fragment) {
Some(n) => n as *const RsvgNode,
None => ptr::null(),
_ => unreachable!(),
......@@ -648,6 +648,37 @@ empty_write_close (void)
g_object_unref (handle);
static void
cannot_request_external_elements (void)
if (g_test_subprocess ()) {
/* We want to test that using one of the _sub() functions will fail
* if the element's id is within an external file. First, ensure
* that the main file and the external file actually exist.
char *filename = get_test_filename ("example.svg");
RsvgHandle *handle;
GError *error = NULL;
RsvgPositionData pos;
handle = rsvg_handle_new_from_file (filename, &error);
g_free (filename);
g_assert (handle != NULL);
g_assert (error == NULL);
g_assert (rsvg_handle_get_position_sub (handle, &pos, "dpi.svg#one") == FALSE);
g_object_unref (handle);
g_test_trap_subprocess (NULL, 0, 0);
g_test_trap_assert_failed ();
g_test_trap_assert_stderr ("*WARNING*the public API is not allowed to look up external references*");
main (int argc, char **argv)
......@@ -681,6 +712,7 @@ main (int argc, char **argv)
g_test_add_func ("/api/render_cairo_sub", render_cairo_sub);
g_test_add_func ("/api/no_write_before_close", no_write_before_close);
g_test_add_func ("/api/empty_write_close", empty_write_close);
g_test_add_func ("/api/cannot_request_external_elements", cannot_request_external_elements);
return g_test_run ();
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment