plug-ins: fix crash when reading corrupt flame settings file

Thanks to a report by Stefan Cornelius, we became aware that the flame
plug-in does no checking for correct input when loading a pre-saved
settings file.

I reworked the parser to read one or more values based on the type of
token, making sure we also don't read past the end of our token buffer.

All int values have a min and max value set. If any unexpected input is
encountered, we will give a warning.

(cherry picked from commit 89c83ef4c7)
This commit is contained in:
Jacob Boerema
2022-10-31 14:22:44 -04:00
parent b36cc3ab3f
commit 5481b110f9

View File

@ -911,8 +911,6 @@ compare_xforms (const void *va,
/*
* given a pointer to a string SS, fill fields of a control point CP.
* return a pointer to the first unused char in SS. totally barfucious,
* must integrate with tcl soon...
*/
void
@ -921,10 +919,9 @@ parse_control_point (char **ss,
{
char *argv[MAXARGS];
int argc, i, j;
int set_cm = 0, set_image_size = 0, set_nbatches = 0, set_white_level = 0, set_cmap_inter = 0;
int set_spatial_oversample = 0;
double *slot = NULL, xf, cm, t, nbatches, white_level, spatial_oversample, cmap_inter;
double image_size[2];
gint64 xf_index = 0;
gint parse_errors = 0;
double *slot = NULL, t;
for (i = 0; i < NXFORMS; i++)
{
@ -949,94 +946,258 @@ parse_control_point (char **ss,
}
tokenize (ss, argv, &argc);
for (i = 0; i < argc; i++)
i = 0;
while (i < argc)
{
if (streql("xform", argv[i]))
slot = &xf;
else if (streql("time", argv[i]))
slot = &cp->time;
else if (streql("brightness", argv[i]))
slot = &cp->brightness;
else if (streql("contrast", argv[i]))
slot = &cp->contrast;
else if (streql("gamma", argv[i]))
slot = &cp->gamma;
else if (streql("zoom", argv[i]))
slot = &cp->zoom;
else if (streql("image_size", argv[i]))
gint itoken;
itoken = i;
if (i < argc)
{
slot = image_size;
set_image_size = 1;
}
else if (streql("center", argv[i]))
slot = cp->center;
else if (streql("pulse", argv[i]))
slot = (double *) cp->pulse;
else if (streql("wiggle", argv[i]))
slot = (double *) cp->wiggle;
else if (streql("pixels_per_unit", argv[i]))
slot = &cp->pixels_per_unit;
else if (streql("spatial_filter_radius", argv[i]))
slot = &cp->spatial_filter_radius;
else if (streql("sample_density", argv[i]))
slot = &cp->sample_density;
else if (streql("nbatches", argv[i]))
{
slot = &nbatches;
set_nbatches = 1;
}
else if (streql("white_level", argv[i]))
{
slot = &white_level;
set_white_level = 1;
}
else if (streql("spatial_oversample", argv[i]))
{
slot = &spatial_oversample;
set_spatial_oversample = 1;
}
else if (streql("cmap", argv[i]))
{
slot = &cm;
set_cm = 1;
}
else if (streql("density", argv[i]))
slot = &cp->xform[(int)xf].density;
else if (streql("color", argv[i]))
slot = &cp->xform[(int)xf].color;
else if (streql("coefs", argv[i]))
{
slot = cp->xform[(int)xf].c[0];
cp->xform[(int)xf].density = 1.0;
}
else if (streql("var", argv[i]))
slot = cp->xform[(int)xf].var;
else if (streql("cmap_inter", argv[i]))
{
slot = &cmap_inter;
set_cmap_inter = 1;
/* First value belonging to token. */
i++;
}
else
*slot++ = g_strtod(argv[i], NULL);
{
g_printerr ("Not enough parameters. File may be corrupt!\n");
parse_errors++;
break;
}
if (streql ("xform", argv[itoken]))
{
if (! g_ascii_string_to_signed (argv[i++], 10, 0, NXFORMS-1, &xf_index, NULL))
{
g_printerr ("Invalid xform index '%s'\n", argv[i-1]);
parse_errors++;
xf_index = 0;
}
}
else if (streql ("density", argv[itoken]))
{
cp->xform[xf_index].density = g_strtod (argv[i++], NULL);
}
else if (streql ("color", argv[itoken]))
{
cp->xform[xf_index].color = g_strtod (argv[i++], NULL);
}
else if (streql ("coefs", argv[itoken]))
{
/* We need 6 coef values and we know are at the first */
if (i + 5 >= argc)
{
g_printerr ("Not enough parameters. File may be corrupt!\n");
parse_errors++;
break;
}
slot = cp->xform[xf_index].c[0];
for (j = 0; j < 6; j++)
{
*slot++ = g_strtod (argv[i++], NULL);
}
cp->xform[xf_index].density = 1.0;
}
else if (streql ("var", argv[itoken]))
{
/* We need NVARS var values and we know are at the first */
if (i + NVARS > argc)
{
g_printerr ("Not enough parameters. File may be corrupt!\n");
parse_errors++;
break;
}
slot = cp->xform[xf_index].var;
for (j = 0; j < NVARS; j++)
{
*slot++ = g_strtod (argv[i++], NULL);
}
}
else if (streql ("time", argv[itoken]))
{
cp->time = g_strtod (argv[i++], NULL);
}
else if (streql ("brightness", argv[itoken]))
{
cp->brightness = g_strtod (argv[i++], NULL);
}
else if (streql ("contrast", argv[itoken]))
{
cp->contrast = g_strtod (argv[i++], NULL);
}
else if (streql ("gamma", argv[itoken]))
{
cp->gamma = g_strtod (argv[i++], NULL);
}
else if (streql ("zoom", argv[itoken]))
{
cp->zoom = g_strtod (argv[i++], NULL);
}
else if (streql ("image_size", argv[itoken]))
{
gint64 w, h;
/* We need 2 values and we know are at the first */
if (i + 1 >= argc)
{
g_printerr ("Not enough parameters. File may be corrupt!\n");
parse_errors++;
break;
}
if (! g_ascii_string_to_signed (argv[i++], 10, 1, GIMP_MAX_IMAGE_SIZE, &w, NULL))
{
g_printerr ("Ignoring invalid image width '%s'\n", argv[i-1]);
parse_errors++;
}
else if (! g_ascii_string_to_signed (argv[i++], 10, 1, GIMP_MAX_IMAGE_SIZE, &h, NULL))
{
g_printerr ("Ignoring invalid image_size heigth '%s'\n", argv[i-1]);
parse_errors++;
}
else
{
cp->width = w;
cp->height = h;
}
}
else if (streql ("center", argv[itoken]))
{
/* We need 2 values and we know are at the first */
if (i + 1 >= argc)
{
g_printerr ("Not enough parameters. File may be corrupt!\n");
parse_errors++;
break;
}
cp->center[0] = g_strtod (argv[i++], NULL);
cp->center[1] = g_strtod (argv[i++], NULL);
}
else if (streql ("pixels_per_unit", argv[itoken]))
{
cp->pixels_per_unit = g_strtod (argv[i++], NULL);
}
else if (streql ("pulse", argv[itoken]))
{
/* We need 4 values and we know are at the first */
if (i + 3 >= argc)
{
g_printerr ("Not enough parameters. File may be corrupt!\n");
parse_errors++;
break;
}
slot = &cp->pulse[0][0];
for (j = 0; j < 4; j++)
{
*slot++ = g_strtod (argv[i++], NULL);
}
}
else if (streql ("wiggle", argv[itoken]))
{
/* We need 4 values and we know are at the first */
if (i + 3 >= argc)
{
g_printerr ("Not enough parameters. File may be corrupt!\n");
parse_errors++;
break;
}
slot = &cp->wiggle[0][0];
for (j = 0; j < 4; j++)
{
*slot++ = g_strtod (argv[i++], NULL);
}
}
else if (streql ("spatial_oversample", argv[itoken]))
{
gint64 oversample;
/* Values in the gui seem to be between 1 and 4 */
if (! g_ascii_string_to_signed (argv[i++], 10, 1, 4, &oversample, NULL))
{
g_printerr ("Ignoring invalid spatial oversample value '%s'\n", argv[i-1]);
parse_errors++;
}
else
{
cp->spatial_oversample = oversample;
}
}
else if (streql ("spatial_filter_radius", argv[itoken]))
{
cp->spatial_filter_radius = g_strtod (argv[i++], NULL);
}
else if (streql ("sample_density", argv[itoken]))
{
cp->sample_density = g_strtod (argv[i++], NULL);
}
else if (streql ("nbatches", argv[itoken]))
{
gint64 nbatches;
/* Not sure what the maximum should be. It always seems to be set to 1. */
if (! g_ascii_string_to_signed (argv[i++], 10, 0, 2, &nbatches, NULL))
{
g_printerr ("Ignoring invalid nbatches value '%s'\n", argv[i-1]);
parse_errors++;
}
else
{
cp->nbatches = nbatches;
}
}
else if (streql ("white_level", argv[itoken]))
{
gint64 wl;
if (! g_ascii_string_to_signed (argv[i++], 10, 0, 255, &wl, NULL))
{
g_printerr ("Ignoring invalid white level value '%s'\n", argv[i-1]);
parse_errors++;
}
else
{
cp->white_level = wl;
}
}
else if (streql ("cmap", argv[itoken]))
{
gint64 cmi;
/* -1 = random */
if (! g_ascii_string_to_signed (argv[i++], 10, -1, 255, &cmi, NULL))
{
g_printerr ("Ignoring invalid color map value '%s'\n", argv[i-1]);
parse_errors++;
}
else
{
cp->cmap_index = cmi;
}
}
else if (streql ("cmap_inter", argv[itoken]))
{
gint64 cmi;
/* 0 or 1 */
if (! g_ascii_string_to_signed (argv[i++], 10, 0, 1, &cmi, NULL))
{
g_printerr ("Ignoring invalid color interpolate value '%s'\n", argv[i-1]);
parse_errors++;
}
else
{
cp->cmap_inter = cmi;
}
}
else
{
g_printerr ("Invalid token '%s'. File may be corrupt!\n", argv[itoken]);
parse_errors++;
}
}
if (set_cm)
{
cp->cmap_index = (int) cm;
get_cmap(cp->cmap_index, cp->cmap, 256);
}
if (set_image_size)
{
cp->width = (int) image_size[0];
cp->height = (int) image_size[1];
}
if (set_cmap_inter)
cp->cmap_inter = (int) cmap_inter;
if (set_nbatches)
cp->nbatches = (int) nbatches;
if (set_spatial_oversample)
cp->spatial_oversample = (int) spatial_oversample;
if (set_white_level)
cp->white_level = (int) white_level;
if (parse_errors > 0)
g_warning ("Input file contains %d errors. File may be corrupt!", parse_errors);
for (i = 0; i < NXFORMS; i++)
{
t = 0.0;