Commit aa1f447e authored by Christian Persch's avatar Christian Persch

all: Add option to parse huge SVG XML files

For security reasons, newer libxml versions applies limits that huge
SVG files exceed and thus fail parsing. Add an RSVG_HANDLE_FLAG_UNLIMITED
flag that uses XML_PARSE_HUGE to allow parsing these files again.

Note: for security reasons, this flag should ONLY be used on trusted input!

https://bugzilla.gnome.org/show_bug.cgi?id=710310
parent bed3f143
......@@ -119,15 +119,14 @@ rsvg_convert_CPPFLAGS = \
$(AM_CPPFLAGS)
rsvg_convert_CFLAGS =\
$(LIBRSVG_CFLAGS) \
$(RSVG_CONVERT_CFLAGS) \
$(AM_CFLAGS)
rsvg_convert_LDFLAGS = $(AM_LDFLAGS)
rsvg_convert_LDADD = \
$(top_builddir)/librsvg-@RSVG_API_MAJOR_VERSION@.la \
$(LIBRSVG_LIBS) \
$(GTHREAD_LIBS) \
$(RSVG_CONVERT_LIBS) \
$(LIBM)
rsvg_view_3_SOURCES = \
......
......@@ -111,6 +111,8 @@ PKG_CHECK_MODULES([GTHREAD],[gthread-2.0 >= $GLIB_REQUIRED])
PKG_CHECK_MODULES([GMODULE],[gmodule-2.0])
PKG_CHECK_MODULES([RSVG_CONVERT],[gio-2.0 gio-unix-2.0 gdk-pixbuf-2.0 cairo pangocairo])
dnl ===========================================================================
AC_CHECK_FUNCS(strtok_r)
......
......@@ -523,6 +523,23 @@ rsvg_xinclude_handler_end (RsvgSaxHandler * self, const char *name)
}
}
static void
_rsvg_set_xml_parse_options(xmlParserCtxtPtr xml_parser,
RsvgHandle *ctx)
{
xml_parser->options |= XML_PARSE_NONET;
if (ctx->priv->flags & RSVG_HANDLE_FLAG_UNLIMITED) {
#if LIBXML_VERSION > 20632
xml_parser->options |= XML_PARSE_HUGE;
#endif
}
#if LIBXML_VERSION > 20800
xml_parser->options |= XML_PARSE_BIG_LINES;
#endif
}
/* http://www.w3.org/TR/xinclude/ */
static void
rsvg_start_xinclude (RsvgHandle * ctx, RsvgPropertyBag * atts)
......@@ -575,7 +592,7 @@ rsvg_start_xinclude (RsvgHandle * ctx, RsvgPropertyBag * atts)
goto fallback;
xml_parser = xmlCreatePushParserCtxt (&rsvgSAXHandlerStruct, ctx, NULL, 0, NULL);
xml_parser->options |= XML_PARSE_NONET;
_rsvg_set_xml_parse_options(xml_parser, ctx);
buffer = _rsvg_xml_input_buffer_new_from_stream (stream, NULL /* cancellable */, XML_CHAR_ENCODING_NONE, &err);
g_object_unref (stream);
......@@ -1115,7 +1132,7 @@ rsvg_handle_write_impl (RsvgHandle * handle, const guchar * buf, gsize count, GE
if (handle->priv->ctxt == NULL) {
handle->priv->ctxt = xmlCreatePushParserCtxt (&rsvgSAXHandlerStruct, handle, NULL, 0,
rsvg_handle_get_base_uri (handle));
handle->priv->ctxt->options |= XML_PARSE_NONET;
_rsvg_set_xml_parse_options(handle->priv->ctxt, handle);
/* if false, external entities work, but internal ones don't. if true, internal entities
work, but external ones don't. favor internal entities, in order to not cause a
......@@ -1773,7 +1790,7 @@ rsvg_handle_read_stream_sync (RsvgHandle *handle,
if (priv->ctxt == NULL) {
priv->ctxt = xmlCreatePushParserCtxt (&rsvgSAXHandlerStruct, handle, NULL, 0,
rsvg_handle_get_base_uri (handle));
priv->ctxt->options |= XML_PARSE_NONET;
_rsvg_set_xml_parse_options(priv->ctxt, handle);
/* if false, external entities work, but internal ones don't. if true, internal entities
work, but external ones don't. favor internal entities, in order to not cause a
......
......@@ -34,10 +34,12 @@
#include <stdlib.h>
#include <string.h>
#include <locale.h>
#include <glib/gi18n.h>
#include <gio/gio.h>
#include <gio/gunixinputstream.h>
#include "rsvg-css.h"
#include "rsvg.h"
#include "rsvg-private.h"
#include "rsvg-size-callback.h"
#ifdef CAIRO_HAS_PS_SURFACE
......@@ -65,44 +67,6 @@ display_error (GError * err)
}
}
static RsvgHandle *
rsvg_handle_new_from_stdio_file (FILE * f, GError ** error)
{
RsvgHandle *handle;
gchar *current_dir;
gchar *base_uri;
handle = rsvg_handle_new ();
while (!feof (f)) {
guchar buffer[4096];
gsize length = fread (buffer, 1, sizeof (buffer), f);
if (length > 0) {
if (!rsvg_handle_write (handle, buffer, length, error)) {
g_object_unref (handle);
return NULL;
}
} else if (ferror (f)) {
g_object_unref (handle);
return NULL;
}
}
if (!rsvg_handle_close (handle, error)) {
g_object_unref (handle);
return NULL;
}
current_dir = g_get_current_dir ();
base_uri = g_build_filename (current_dir, "file.svg", NULL);
rsvg_handle_set_base_uri (handle, base_uri);
g_free (base_uri);
g_free (current_dir);
return handle;
}
static void
rsvg_cairo_size_callback (int *width, int *height, gpointer data)
{
......@@ -136,8 +100,8 @@ main (int argc, char **argv)
int keep_aspect_ratio = FALSE;
guint32 background_color = 0;
char *background_color_str = NULL;
char *base_uri = NULL;
gboolean using_stdin = FALSE;
gboolean unlimited = FALSE;
GError *error = NULL;
int i;
......@@ -146,6 +110,7 @@ main (int argc, char **argv)
RsvgHandle *rsvg;
cairo_surface_t *surface = NULL;
cairo_t *cr = NULL;
RsvgHandleFlags flags = RSVG_HANDLE_FLAGS_NONE;
RsvgDimensionData dimensions;
FILE *output_file = stdout;
......@@ -172,8 +137,8 @@ main (int argc, char **argv)
N_("whether to preserve the aspect ratio [optional; defaults to FALSE]"), NULL},
{"background-color", 'b', 0, G_OPTION_ARG_STRING, &background_color_str,
N_("set the background color [optional; defaults to None]"), N_("[black, white, #abccee, #aaa...]")},
{"unlimited", 'u', 0, G_OPTION_ARG_NONE, &unlimited, N_("Allow huge SVG files"), NULL},
{"version", 'v', 0, G_OPTION_ARG_NONE, &bVersion, N_("show version information"), NULL},
{"base-uri", 'b', 0, G_OPTION_ARG_STRING, &base_uri, N_("base uri"), NULL},
{G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &args, NULL, N_("[FILE...]")},
{NULL}
};
......@@ -227,23 +192,36 @@ main (int argc, char **argv)
rsvg_set_default_dpi_x_y (dpi_x, dpi_y);
if (unlimited)
flags |= RSVG_HANDLE_FLAG_UNLIMITED;
for (i = 0; i < n_args; i++) {
GFile *file;
GInputStream *stream;
if (using_stdin)
rsvg = rsvg_handle_new_from_stdio_file (stdin, &error);
else
rsvg = rsvg_handle_new_from_file (args[i], &error);
if (using_stdin) {
file = NULL;
stream = g_unix_input_stream_new (STDIN_FILENO, FALSE);
} else {
file = g_file_new_for_commandline_arg (args[i]);
stream = (GInputStream *) g_file_read (file, NULL, &error);
if (stream == NULL)
goto done;
}
rsvg = rsvg_handle_new_from_stream_sync (stream, file, flags, NULL, &error);
if (!rsvg) {
done:
g_clear_object (&stream);
g_clear_object (&file);
if (error != NULL) {
fprintf (stderr, _("Error reading SVG:"));
display_error (error);
fprintf (stderr, "\n");
exit (1);
}
if (base_uri)
rsvg_handle_set_base_uri (rsvg, base_uri);
/* in the case of multi-page output, all subsequent SVGs are scaled to the first's size */
rsvg_handle_set_size_callback (rsvg, rsvg_cairo_size_callback, &dimensions, NULL);
......
......@@ -27,8 +27,11 @@
#define RSVG_CSS_H
#include <glib.h>
#ifdef RSVG_COMPILATION
#include <pango/pango.h>
#include "rsvg-private.h"
#endif
G_BEGIN_DECLS
......@@ -44,10 +47,13 @@ G_BEGIN_DECLS
#define RSVG_ASPECT_RATIO_XMAX_YMAX (1 << 8)
#define RSVG_ASPECT_RATIO_SLICE (1 << 31)
/* This one is semi-public for mis-use in rsvg-convert */
guint32 rsvg_css_parse_color (const char *str, gboolean * inherit);
#ifdef RSVG_COMPILATION
G_GNUC_INTERNAL
int rsvg_css_parse_aspect_ratio (const char *str);
/* for some reason this one's public... */
guint32 rsvg_css_parse_color (const char *str, gboolean * inherit);
G_GNUC_INTERNAL
guint rsvg_css_parse_opacity (const char *str);
G_GNUC_INTERNAL
......@@ -79,6 +85,8 @@ gboolean rsvg_css_parse_overflow (const char *str, gboolean * inherit
G_GNUC_INTERNAL
char **rsvg_css_parse_xml_attribute_string (const char *attribute_string);
#endif /* RSVG_COMPILATION */
G_END_DECLS
#endif
......@@ -155,10 +155,14 @@ gboolean rsvg_handle_has_sub (RsvgHandle * handle, const char *id);
/**
* RsvgHandleFlags:
* @RSVG_HANDLE_FLAGS_NONE: none
* @RSVG_HANDLE_FLAG_UNLIMITED: Allow any SVG XML without size limitations.
* For security reasons, this should only be used for trusted input!
* Since: 2.40.3
*/
typedef enum /*< flags >*/
{
RSVG_HANDLE_FLAGS_NONE = 0
RSVG_HANDLE_FLAGS_NONE = 0,
RSVG_HANDLE_FLAG_UNLIMITED = 1 << 0
} RsvgHandleFlags;
RsvgHandle *rsvg_handle_new_with_flags (RsvgHandleFlags flags);
......
......@@ -612,6 +612,7 @@ main (int argc, char **argv)
char *bg_color = NULL;
char *base_uri = NULL;
gboolean keep_aspect_ratio = FALSE;
gboolean unlimited = FALSE;
char *id = NULL;
GInputStream *input;
GFileInfo *file_info;
......@@ -622,6 +623,8 @@ main (int argc, char **argv)
int from_stdin = 0;
ViewerCbInfo info;
RsvgHandleFlags flags = RSVG_HANDLE_FLAGS_NONE;
char **args = NULL;
gint n_args = 0;
......@@ -646,6 +649,8 @@ main (int argc, char **argv)
N_("<string>")},
{"keep-aspect", 'k', 0, G_OPTION_ARG_NONE, &keep_aspect_ratio,
N_("Preserve the image's aspect ratio"), NULL},
{"unlimited", 'u', 0, G_OPTION_ARG_NONE, &unlimited,
N_("Allow huge SVG files"), NULL},
{"version", 'v', 0, G_OPTION_ARG_NONE, &bVersion, N_("Show version information"), NULL},
{G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &args, NULL, N_("[FILE...]")},
{NULL}
......@@ -688,6 +693,9 @@ main (int argc, char **argv)
compressed = FALSE;
if (unlimited)
flags |= RSVG_HANDLE_FLAG_UNLIMITED;
if (from_stdin) {
#if 0 // defined (G_OS_UNIX)
input = g_unix_input_stream_new (STDIN_FILENO, FALSE);
......@@ -749,7 +757,7 @@ main (int argc, char **argv)
info.handle = rsvg_handle_new_from_stream_sync (input,
base_file,
RSVG_HANDLE_FLAGS_NONE,
flags,
NULL /* cancellable */,
&err);
if (base_file != NULL)
......
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