diff options
author | Philip Withnall <philip@tecnocode.co.uk> | 2017-01-07 16:35:54 +0000 |
---|---|---|
committer | Philip Withnall <withnall@endlessm.com> | 2017-02-17 11:21:02 +0000 |
commit | 91723d7328b128d20626731f98b414c773a98ba1 (patch) | |
tree | ce8e073e6acd938f80d73726c0f1b1bcf0a381ed | |
parent | 0f538573aca0950eac37a407aed5529f41019200 (diff) | |
download | gdk-pixbuf-91723d7328b128d20626731f98b414c773a98ba1.tar.gz |
io-ico: Fix option parsing to be locale-independent
sscanf() and strtol() are both locale-dependent. In addition, the return
value of sscanf() was not being checked (so it could fail without being
noticed), and there was no bounds checking being performed.
Bounds checking is now performed, although the bounds have been chosen
for conservative backwards-compatibility, and may not be the most
appropriate.
Coverity CID: 1388522
https://bugzilla.gnome.org/show_bug.cgi?id=776990
-rw-r--r-- | gdk-pixbuf/io-ico.c | 58 |
1 files changed, 54 insertions, 4 deletions
diff --git a/gdk-pixbuf/io-ico.c b/gdk-pixbuf/io-ico.c index 2b0441fa2..ddb804c3a 100644 --- a/gdk-pixbuf/io-ico.c +++ b/gdk-pixbuf/io-ico.c @@ -1240,6 +1240,47 @@ write_icon (FILE *f, GSList *entries) } } +/* Locale-independent signed integer string parser, base 10. + * @minimum and @maximum are valid inclusively. */ +static gboolean +ascii_strtoll (const gchar *str, + gint64 minimum, + gint64 maximum, + gint64 *out, + GError **error) +{ + gint64 retval; + const gchar *end_ptr; + + errno = 0; + retval = g_ascii_strtoll (str, (gchar **) &end_ptr, 10); + + if (errno != 0) { + g_set_error_literal (error, + G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, + g_strerror (errno)); + return FALSE; + } else if (end_ptr == str || *end_ptr != '\0') { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, + "Argument is not an integer: %s", str); + return FALSE; + } else if ((maximum < G_MAXINT64 && retval > maximum) || + (minimum > G_MININT64 && retval < minimum)) { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, + "Argument should be in range [%" G_GINT64_FORMAT + ", %" G_GINT64_FORMAT "]: %s", + minimum, maximum, str); + return FALSE; + } + + g_assert (retval >= minimum && retval <= maximum); + + if (out != NULL) + *out = retval; + + return TRUE; +} + static gboolean gdk_pixbuf__ico_image_save (FILE *f, GdkPixbuf *pixbuf, @@ -1265,15 +1306,24 @@ gdk_pixbuf__ico_image_save (FILE *f, gchar **viter; for (kiter = keys, viter = values; *kiter && *viter; kiter++, viter++) { - char *endptr; + gint64 out; if (strcmp (*kiter, "depth") == 0) { - sscanf (*viter, "%d", &icon->depth); + if (!ascii_strtoll (*viter, 1, 32, + &out, error)) + return FALSE; + icon->depth = out; } else if (strcmp (*kiter, "x_hot") == 0) { - hot_x = strtol (*viter, &endptr, 10); + if (!ascii_strtoll (*viter, G_MININT, G_MAXINT, + &out, error)) + return FALSE; + hot_x = out; } else if (strcmp (*kiter, "y_hot") == 0) { - hot_y = strtol (*viter, &endptr, 10); + if (!ascii_strtoll (*viter, G_MININT, G_MAXINT, + &out, error)) + return FALSE; + hot_y = out; } } |