Commit message: None
CVE: CVE-2016-10068
CWE: CWE-20
Vulnerability description: The MSL interpreter in ImageMagick before 6.9.6-4 allows remote attackers to cause a denial of service (segmentation fault and application crash) via a crafted XML file.

Project: ImageMagick
File: msl.c

static inline Image *GetImageCache(const ImageInfo *image_info,const char *path,
  ExceptionInfo *exception)
{
  char
    key[MaxTextExtent];

  ExceptionInfo
    *sans_exception;

  Image
    *image;

  ImageInfo
    *read_info;

  (void) FormatLocaleString(key,MaxTextExtent,"cache:%s",path);
  sans_exception=AcquireExceptionInfo();
  image=(Image *) GetImageRegistry(ImageRegistryType,key,sans_exception);
  sans_exception=DestroyExceptionInfo(sans_exception);
  if (image != (Image *) NULL)
    return(image);
  read_info=CloneImageInfo(image_info);
  (void) CopyMagickString(read_info->filename,path,MaxTextExtent);
  image=ReadImage(read_info,exception);
  read_info=DestroyImageInfo(read_info);
  if (image != (Image *) NULL)
    (void) SetImageRegistry(ImageRegistryType,key,image,exception);
  return(image);
}

Project: ImageMagick

static void MSLCharacters(void *context,const xmlChar *c,int length)
{
  MSLInfo
    *msl_info;

  register char
    *p;

  register ssize_t
    i;

  /*
    Receiving some characters from the parser.
  */
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
    "  SAX.characters(%s,%d)",c,length);
  msl_info=(MSLInfo *) context;
  if (msl_info->content != (char *) NULL)
    msl_info->content=(char *) ResizeQuantumMemory(msl_info->content,
      strlen(msl_info->content)+length+MaxTextExtent,
      sizeof(*msl_info->content));
  else
    {
      msl_info->content=(char *) NULL;
      if (~length >= (MaxTextExtent-1))
        msl_info->content=(char *) AcquireQuantumMemory(length+MaxTextExtent,
          sizeof(*msl_info->content));
      if (msl_info->content != (char *) NULL)
        *msl_info->content='\0';
    }
  if (msl_info->content == (char *) NULL)
    return;
  p=msl_info->content+strlen(msl_info->content);
  for (i=0; i < length; i++)
    *p++=c[i];
  *p='\0';
}

Project: ImageMagick
File: msl.c

static void MSLEndElement(void *context,const xmlChar *tag)
{
  ssize_t
    n;

  MSLInfo
    *msl_info;

  /*
    Called when the end of an element has been detected.
  */
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),"  SAX.endElement(%s)",
    tag);
  msl_info=(MSLInfo *) context;
  n=msl_info->n;
  switch (*tag)
  {
    case 'C':
    case 'c':
    {
      if (LocaleCompare((const char *) tag,"comment") == 0 )
        {
          (void) DeleteImageProperty(msl_info->image[n],"comment");
          if (msl_info->content == (char *) NULL)
            break;
          StripString(msl_info->content);
          (void) SetImageProperty(msl_info->image[n],"comment",
            msl_info->content);
          break;
        }
      break;
    }
    case 'G':
    case 'g':
    {
      if (LocaleCompare((const char *) tag, "group") == 0 )
      {
        if (msl_info->group_info[msl_info->number_groups-1].numImages > 0 )
        {
          ssize_t  i = (ssize_t)
            (msl_info->group_info[msl_info->number_groups-1].numImages);
          while ( i-- )
          {
            if (msl_info->image[msl_info->n] != (Image *) NULL)
              msl_info->image[msl_info->n]=DestroyImage(msl_info->image[msl_info->n]);
            msl_info->attributes[msl_info->n]=DestroyImage(msl_info->attributes[msl_info->n]);
            msl_info->image_info[msl_info->n]=DestroyImageInfo(msl_info->image_info[msl_info->n]);
            msl_info->n--;
          }
        }
        msl_info->number_groups--;
      }
      break;
    }
    case 'I':
    case 'i':
    {
      if (LocaleCompare((const char *) tag, "image") == 0)
        MSLPopImage(msl_info);
       break;
    }
    case 'L':
    case 'l':
    {
      if (LocaleCompare((const char *) tag,"label") == 0 )
        {
          (void) DeleteImageProperty(msl_info->image[n],"label");
          if (msl_info->content == (char *) NULL)
            break;
          StripString(msl_info->content);
          (void) SetImageProperty(msl_info->image[n],"label",
            msl_info->content);
          break;
        }
      break;
    }
    case 'M':
    case 'm':
    {
      if (LocaleCompare((const char *) tag, "msl") == 0 )
      {
        /*
          This our base element.
            at the moment we don't do anything special
            but someday we might!
        */
      }
      break;
    }
    default:
      break;
  }
  if (msl_info->content != (char *) NULL)
    msl_info->content=DestroyString(msl_info->content);
}

Project: ImageMagick
File: msl.c

static void MSLError(void *context,const char *format,...)
{
  char
    reason[MaxTextExtent];

  MSLInfo
    *msl_info;

  va_list
    operands;

  /*
    Display and format a error formats, gives file, line, position and
    extra parameters.
  */
  va_start(operands,format);
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),"  SAX.error: ");
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),format,operands);
  msl_info=(MSLInfo *) context;
  (void) msl_info;
#if !defined(MAGICKCORE_HAVE_VSNPRINTF)
  (void) vsprintf(reason,format,operands);
#else
  (void) vsnprintf(reason,MaxTextExtent,format,operands);
#endif
  ThrowMSLException(DelegateFatalError,reason,"SAX error");
  va_end(operands);
}

Project: ImageMagick

static void MSLPushImage(MSLInfo *msl_info,Image *image)
{
  ssize_t
    n;

  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  assert(msl_info != (MSLInfo *) NULL);
  msl_info->n++;
  n=msl_info->n;
  msl_info->image_info=(ImageInfo **) ResizeQuantumMemory(msl_info->image_info,
    (n+1),sizeof(*msl_info->image_info));
  msl_info->draw_info=(DrawInfo **) ResizeQuantumMemory(msl_info->draw_info,
    (n+1),sizeof(*msl_info->draw_info));
  msl_info->attributes=(Image **) ResizeQuantumMemory(msl_info->attributes,
    (n+1),sizeof(*msl_info->attributes));
  msl_info->image=(Image **) ResizeQuantumMemory(msl_info->image,(n+1),
    sizeof(*msl_info->image));
  if ((msl_info->image_info == (ImageInfo **) NULL) ||
      (msl_info->draw_info == (DrawInfo **) NULL) ||
      (msl_info->attributes == (Image **) NULL) ||
      (msl_info->image == (Image **) NULL))
    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
  msl_info->image_info[n]=CloneImageInfo(msl_info->image_info[n-1]);
  msl_info->draw_info[n]=CloneDrawInfo(msl_info->image_info[n-1],
    msl_info->draw_info[n-1]);
  if (image == (Image *) NULL)
    msl_info->attributes[n]=AcquireImage(msl_info->image_info[n]);
  else
    msl_info->attributes[n]=CloneImage(image,0,0,MagickTrue,&image->exception);
  msl_info->image[n]=(Image *) image;
  if ((msl_info->image_info[n] == (ImageInfo *) NULL) ||
      (msl_info->attributes[n] == (Image *) NULL))
    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
  if (msl_info->number_groups != 0)
    msl_info->group_info[msl_info->number_groups-1].numImages++;
}

Project: ImageMagick
File: msl.c

static void MSLWarning(void *context,const char *format,...)
{
  char
    *message,
    reason[MaxTextExtent];

  MSLInfo
    *msl_info;

  va_list
    operands;

  /**
    Display and format a warning messages, gives file, line, position and
    extra parameters.
  */
  va_start(operands,format);
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),"  SAX.warning: ");
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),format,operands);
  msl_info=(MSLInfo *) context;
  (void) msl_info;
#if !defined(MAGICKCORE_HAVE_VSNPRINTF)
  (void) vsprintf(reason,format,operands);
#else
  (void) vsnprintf(reason,MaxTextExtent,format,operands);
#endif
  message=GetExceptionMessage(errno);
  ThrowMSLException(CoderError,reason,message);
  message=DestroyString(message);
  va_end(operands);
}

Project: ImageMagick

static Image *ReadMSLImage(const ImageInfo *image_info,ExceptionInfo *exception)
{
  Image
    *image;

  /*
    Open image file.
  */
  assert(image_info != (const ImageInfo *) NULL);
  assert(image_info->signature == MagickSignature);
  if (image_info->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
      image_info->filename);
  assert(exception != (ExceptionInfo *) NULL);
  assert(exception->signature == MagickSignature);
  image=(Image *) NULL;
  (void) ProcessMSLScript(image_info,&image,exception);
  return(GetFirstImageInList(image));
}

Project: ImageMagick
File: msl.c

ModuleExport size_t RegisterMSLImage(void)
{
  MagickInfo
    *entry;

#if defined(MAGICKCORE_XML_DELEGATE)
  xmlInitParser();
#endif
  entry=SetMagickInfo("MSL");
#if defined(MAGICKCORE_XML_DELEGATE)
  entry->decoder=(DecodeImageHandler *) ReadMSLImage;
  entry->encoder=(EncodeImageHandler *) WriteMSLImage;
#endif
  entry->format_type=ImplicitFormatType;
  entry->description=ConstantString("Magick Scripting Language");
  entry->module=ConstantString("MSL");
  (void) RegisterMagickInfo(entry);
  return(MagickImageCoderSignature);
}

Project: ImageMagick
File: msl.c

static MagickBooleanType SetMSLAttributes(MSLInfo *msl_info,const char *keyword,
  const char *value)
{
  Image
    *attributes;

  DrawInfo
    *draw_info;

  ExceptionInfo
    *exception;

  GeometryInfo
    geometry_info;

  Image
    *image;

  ImageInfo
    *image_info;

  int
    flags;

  ssize_t
    n;

  assert(msl_info != (MSLInfo *) NULL);
  if (keyword == (const char *) NULL)
    return(MagickTrue);
  if (value == (const char *) NULL)
    return(MagickTrue);
  exception=msl_info->exception;
  n=msl_info->n;
  attributes=msl_info->attributes[n];
  image_info=msl_info->image_info[n];
  draw_info=msl_info->draw_info[n];
  image=msl_info->image[n];
  switch (*keyword)
  {
    case 'A':
    case 'a':
    {
      if (LocaleCompare(keyword,"adjoin") == 0)
        {
          ssize_t
            adjoin;

          adjoin=ParseCommandOption(MagickBooleanOptions,MagickFalse,value);
          if (adjoin < 0)
            ThrowMSLException(OptionError,"UnrecognizedType",value);
          image_info->adjoin=(MagickBooleanType) adjoin;
          break;
        }
      if (LocaleCompare(keyword,"alpha") == 0)
        {
          ssize_t
            alpha;

          alpha=ParseCommandOption(MagickAlphaOptions,MagickFalse,value);
          if (alpha < 0)
            ThrowMSLException(OptionError,"UnrecognizedType",value);
          if (image != (Image *) NULL)
            (void) SetImageAlphaChannel(image,(AlphaChannelType) alpha);
          break;
        }
      if (LocaleCompare(keyword,"antialias") == 0)
        {
          ssize_t
            antialias;

          antialias=ParseCommandOption(MagickBooleanOptions,MagickFalse,value);
          if (antialias < 0)
            ThrowMSLException(OptionError,"UnrecognizedGravityType",value);
          image_info->antialias=(MagickBooleanType) antialias;
          break;
        }
      if (LocaleCompare(keyword,"area-limit") == 0)
        {
          MagickSizeType
            limit;

          limit=MagickResourceInfinity;
          if (LocaleCompare(value,"unlimited") != 0)
            limit=(MagickSizeType) StringToDoubleInterval(value,100.0);
          (void) SetMagickResourceLimit(AreaResource,limit);
          break;
        }
      if (LocaleCompare(keyword,"attenuate") == 0)
        {
          (void) SetImageOption(image_info,keyword,value);
          break;
        }
      if (LocaleCompare(keyword,"authenticate") == 0)
        {
          (void) CloneString(&image_info->density,value);
          break;
        }
      ThrowMSLException(OptionError,"UnrecognizedAttribute",keyword);
      break;
    }
    case 'B':
    case 'b':
    {
      if (LocaleCompare(keyword,"background") == 0)
        {
          (void) QueryColorDatabase(value,&image_info->background_color,
            exception);
          break;
        }
      if (LocaleCompare(keyword,"bias") == 0)
        {
          if (image == (Image *) NULL)
            break;
          image->bias=StringToDoubleInterval(value,(double) QuantumRange+1.0);
          break;
        }
      if (LocaleCompare(keyword,"blue-primary") == 0)
        {
          if (image == (Image *) NULL)
            break;
          flags=ParseGeometry(value,&geometry_info);
          image->chromaticity.blue_primary.x=geometry_info.rho;
          image->chromaticity.blue_primary.y=geometry_info.sigma;
          if ((flags & SigmaValue) == 0)
            image->chromaticity.blue_primary.y=
              image->chromaticity.blue_primary.x;
          break;
        }
      if (LocaleCompare(keyword,"bordercolor") == 0)
        {
          (void) QueryColorDatabase(value,&image_info->border_color,
            exception);
          break;
        }
      ThrowMSLException(OptionError,"UnrecognizedAttribute",keyword);
      break;
    }
    case 'D':
    case 'd':
    {
      if (LocaleCompare(keyword,"density") == 0)
        {
          (void) CloneString(&image_info->density,value);
          (void) CloneString(&draw_info->density,value);
          break;
        }
      ThrowMSLException(OptionError,"UnrecognizedAttribute",keyword);
      break;
    }
    case 'F':
    case 'f':
    {
      if (LocaleCompare(keyword,"fill") == 0)
        {
          (void) QueryColorDatabase(value,&draw_info->fill,exception);
          (void) SetImageOption(image_info,keyword,value);
          break;
        }
      if (LocaleCompare(keyword,"filename") == 0)
        {
          (void) CopyMagickString(image_info->filename,value,MaxTextExtent);
          break;
        }
      ThrowMSLException(OptionError,"UnrecognizedAttribute",keyword);
      break;
    }
    case 'G':
    case 'g':
    {
      if (LocaleCompare(keyword,"gravity") == 0)
        {
          ssize_t
            gravity;

          gravity=ParseCommandOption(MagickGravityOptions,MagickFalse,value);
          if (gravity < 0)
            ThrowMSLException(OptionError,"UnrecognizedGravityType",value);
          (void) SetImageOption(image_info,keyword,value);
          break;
        }
      ThrowMSLException(OptionError,"UnrecognizedAttribute",keyword);
      break;
    }
    case 'I':
    case 'i':
    {
      if (LocaleCompare(keyword,"id") == 0)
        {
          (void) SetImageProperty(attributes,keyword,value);
          break;
        }
      ThrowMSLException(OptionError,"UnrecognizedAttribute",keyword);
      break;
    }
    case 'M':
    case 'm':
    {
      if (LocaleCompare(keyword,"magick") == 0)
        {
          (void) CopyMagickString(image_info->magick,value,MaxTextExtent);
          break;
        }
      if (LocaleCompare(keyword,"mattecolor") == 0)
        {
          (void) QueryColorDatabase(value,&image_info->matte_color,
            exception);
          break;
        }
      ThrowMSLException(OptionError,"UnrecognizedAttribute",keyword);
      break;
    }
    case 'P':
    case 'p':
    {
      if (LocaleCompare(keyword,"pointsize") == 0)
        {
          image_info->pointsize=StringToDouble(value,(char **) NULL);
          draw_info->pointsize=StringToDouble(value,(char **) NULL);
          break;
        }
      ThrowMSLException(OptionError,"UnrecognizedAttribute",keyword);
      break;
    }
    case 'Q':
    case 'q':
    {
      if (LocaleCompare(keyword,"quality") == 0)
        {
          image_info->quality=StringToLong(value);
          if (image == (Image *) NULL)
            break;
          image->quality=StringToLong(value);
          break;
        }
      break;
    }
    case 'S':
    case 's':
    {
      if (LocaleCompare(keyword,"size") == 0)
        {
          (void) CloneString(&image_info->size,value);
          break;
        }
      if (LocaleCompare(keyword,"stroke") == 0)
        {
          (void) QueryColorDatabase(value,&draw_info->stroke,exception);
          (void) SetImageOption(image_info,keyword,value);
          break;
        }
      ThrowMSLException(OptionError,"UnrecognizedAttribute",keyword);
      break;
    }
    default:
    {
      ThrowMSLException(OptionError,"UnrecognizedAttribute",keyword);
      break;
    }
  }
  return(MagickTrue);
}

Project: ImageMagick

static MagickBooleanType WriteMSLImage(const ImageInfo *image_info,Image *image)
{
  assert(image_info != (const ImageInfo *) NULL);
  assert(image_info->signature == MagickSignature);
  assert(image != (Image *) NULL);
  assert(image->signature == MagickSignature);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  (void) ReferenceImage(image);
  (void) ProcessMSLScript(image_info,&image,&image->exception);
  return(MagickTrue);
}