Commit message: Fixed memory leak in IsOptionMember.
CVE: CVE-2016-10252
CWE: CWE-399
Vulnerability description: Memory leak in the IsOptionMember function in MagickCore/option.c in ImageMagick before 6.9.2-2, as used in ODR-PadEnc and other products, allows attackers to trigger memory consumption.

Project: ImageMagick
File: option.c

MagickExport MagickBooleanType IsOptionMember(const char *option,
  const char *options)
{
  char
    **option_list,
    *string;

  int
    number_options;

  MagickBooleanType
    member;

  register ssize_t
    i;

  /*
    Is option a member of the options list?
  */
  if (options == (const char *) NULL)
    return(MagickFalse);
  string=ConstantString(options);
  (void) SubstituteString(&string,","," ");
  option_list=StringToArgv(string,&number_options);
  string=DestroyString(string);
  if (option_list == (char **) NULL)
    return(MagickFalse);
  member=MagickFalse;
  option_list[0]=DestroyString(option_list[0]);
  for (i=1; i < (ssize_t) number_options; i++)
  {
    if ((*option_list[i] == '!') &&
        (LocaleCompare(option,option_list[i]+1) == 0))
      break;
    if (GlobExpression(option,option_list[i],MagickTrue) != MagickFalse)
      {
        member=MagickTrue;
        break;
      }
    option_list[i]=DestroyString(option_list[i]);
  }
  for ( ; i < (ssize_t) number_options; i++)
    option_list[i]=DestroyString(option_list[i]);
  option_list=(char **) RelinquishMagickMemory(option_list);
  return(member);
}

Project: ImageMagick
File: option.c

MagickExport ssize_t ParseCommandOption(const CommandOption option,
  const MagickBooleanType list,const char *options)
{
  char
    token[MagickPathExtent];

  const OptionInfo
    *command_info,
    *option_info;

  int
    sentinel;

  MagickBooleanType
    negate;

  register char
    *q;

  register const char
    *p;

  register ssize_t
    i;

  ssize_t
    option_types;

  if (options == (const char *) NULL)
    return(-1);
  option_info=GetOptionInfo(option);
  if (option_info == (const OptionInfo *) NULL)
    return(-1);
  option_types=0;
  sentinel=',';
  if (strchr(options,'|') != (char *) NULL)
    sentinel='|';
  for (p=options; p != (char *) NULL; p=strchr(p,sentinel))
  {
    while (((isspace((int) ((unsigned char) *p)) != 0) || (*p == sentinel)) &&
           (*p != '\0'))
      p++;
    negate=(*p == '!') ? MagickTrue : MagickFalse;
    if (negate != MagickFalse)
      p++;
    q=token;
    while (((isspace((int) ((unsigned char) *p)) == 0) && (*p != sentinel)) &&
           (*p != '\0'))
    {
      if ((q-token) >= (MagickPathExtent-1))
        break;
      *q++=(*p++);
    }
    *q='\0';
    for (i=0; option_info[i].mnemonic != (char *) NULL; i++)
      if (LocaleCompare(token,option_info[i].mnemonic) == 0)
        break;
    command_info=option_info+i;
    if ((command_info->mnemonic == (const char *) NULL) &&
        ((strchr(token+1,'-') != (char *) NULL) ||
         (strchr(token+1,'_') != (char *) NULL)))
        {
          while ((q=strchr(token+1,'-')) != (char *) NULL)
            (void) CopyMagickString(q,q+1,MagickPathExtent-strlen(q));
          while ((q=strchr(token+1,'_')) != (char *) NULL)
            (void) CopyMagickString(q,q+1,MagickPathExtent-strlen(q));
          for (i=0; option_info[i].mnemonic != (char *) NULL; i++)
            if (LocaleCompare(token,option_info[i].mnemonic) == 0)
              break;
          command_info=option_info+i;
        }
    if (command_info->mnemonic == (const char *) NULL)
      return(-1);
    if (negate != MagickFalse)
      option_types=option_types &~ command_info->type;
    else
      option_types=option_types | command_info->type;
    if (list == MagickFalse)
      break;
  }
  return(option_types);
}

Project: ImageMagick
File: option.c

MagickExport char *RemoveImageOption(ImageInfo *image_info,const char *option)
{
  char
    *value;

  assert(image_info != (ImageInfo *) NULL);
  assert(image_info->signature == MagickCoreSignature);
  if (image_info->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
      image_info->filename);
  if (image_info->options == (void *) NULL)
    return((char *) NULL);
  value=(char *) RemoveNodeFromSplayTree((SplayTreeInfo *)
    image_info->options,option);
  return(value);
}

Project: ImageMagick
File: option.c

MagickExport const OptionInfo *GetCommandOptionInfo(const char *option)
{
  register ssize_t
    i;

  for (i=0; CommandOptions[i].mnemonic != (char *) NULL; i++)
    if (LocaleCompare(option,CommandOptions[i].mnemonic) == 0)
      break;
  return(CommandOptions+i);
}

Project: ImageMagick
File: option.c

MagickExport ssize_t ParseChannelOption(const char *channels)
{
  register ssize_t
    i;

  ssize_t
    channel;

  channel=ParseCommandOption(MagickChannelOptions,MagickTrue,channels);
  if (channel >= 0)
    return(channel);
  channel=0;
  for (i=0; i < (ssize_t) strlen(channels); i++)
  {
    switch (channels[i])
    {
      case 'A':
      case 'a':
      {
        channel|=AlphaChannel;
        break;
      }
      case 'B':
      case 'b':
      {
        channel|=BlueChannel;
        break;
      }
      case 'C':
      case 'c':
      {
        channel|=CyanChannel;
        break;
      }
      case 'g':
      case 'G':
      {
        channel|=GreenChannel;
        break;
      }
      case 'K':
      case 'k':
      {
        channel|=BlackChannel;
        break;
      }
      case 'M':
      case 'm':
      {
        channel|=MagentaChannel;
        break;
      }
      case 'o':
      case 'O':
      {
        channel|=AlphaChannel; /* depreciate */
        break;
      }
      case 'R':
      case 'r':
      {
        channel|=RedChannel;
        break;
      }
      case 'Y':
      case 'y':
      {
        channel|=YellowChannel;
        break;
      }
      case ',':
      {
        ssize_t
          type;

        /*
          Gather the additional channel flags and merge with shorthand.
        */
        type=ParseCommandOption(MagickChannelOptions,MagickTrue,channels+i+1);
        if (type < 0)
          return(type);
        channel|=type;
        return(channel);
      }
      default:
        return(-1);
    }
  }
  return(channel);
}

Project: ImageMagick
File: option.c

MagickExport void ResetImageOptions(const ImageInfo *image_info)
{
  assert(image_info != (ImageInfo *) NULL);
  assert(image_info->signature == MagickCoreSignature);
  if (image_info->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
      image_info->filename);
  if (image_info->options == (void *) NULL)
    return;
  ResetSplayTree((SplayTreeInfo *) image_info->options);
}

Project: ImageMagick
File: option.c

MagickExport char **GetCommandOptions(const CommandOption option)
{
  char
    **options;

  const OptionInfo
    *option_info;

  register ssize_t
    i;

  option_info=GetOptionInfo(option);
  if (option_info == (const OptionInfo *) NULL)
    return((char **) NULL);
  for (i=0; option_info[i].mnemonic != (const char *) NULL; i++) ;
  options=(char **) AcquireQuantumMemory((size_t) i+1UL,sizeof(*options));
  if (options == (char **) NULL)
    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
  for (i=0; option_info[i].mnemonic != (const char *) NULL; i++)
    options[i]=AcquireString(option_info[i].mnemonic);
  options[i]=(char *) NULL;
  return(options);
}

Project: ImageMagick
File: option.c

MagickExport const char *CommandOptionToMnemonic(const CommandOption option,
  const ssize_t type)
{
  const OptionInfo
    *option_info;

  register ssize_t
    i;

  option_info=GetOptionInfo(option);
  if (option_info == (const OptionInfo *) NULL)
    return((const char *) NULL);
  for (i=0; option_info[i].mnemonic != (const char *) NULL; i++)
    if (type == option_info[i].type)
      break;
  if (option_info[i].mnemonic == (const char *) NULL)
    return("Unrecognized");
  return(option_info[i].mnemonic);
}

Project: ImageMagick
File: option.c

MagickExport MagickBooleanType DeleteImageOption(ImageInfo *image_info,
  const char *option)
{
  assert(image_info != (ImageInfo *) NULL);
  assert(image_info->signature == MagickCoreSignature);
  if (image_info->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
      image_info->filename);
  if (image_info->options == (void *) NULL)
    return(MagickFalse);
  return(DeleteNodeFromSplayTree((SplayTreeInfo *) image_info->options,option));
}

Project: ImageMagick
File: option.c

MagickExport MagickBooleanType IsCommandOption(const char *option)
{
  assert(option != (const char *) NULL);
  if ((*option != '-') && (*option != '+'))
    return(MagickFalse);
  if (strlen(option) == 1)
    return(((*option == '{') || (*option == '}') || (*option == '[') ||
      (*option == ']')) ? MagickTrue : MagickFalse);
  option++;
  if (*option == '-')
    return(MagickTrue);
  if (isalpha((int) ((unsigned char) *option)) == 0)
    return(MagickFalse);
  return(MagickTrue);
}

Project: ImageMagick
File: option.c

MagickExport char *GetNextImageOption(const ImageInfo *image_info)
{
  assert(image_info != (ImageInfo *) NULL);
  assert(image_info->signature == MagickCoreSignature);
  if (image_info->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
      image_info->filename);
  if (image_info->options == (void *) NULL)
    return((char *) NULL);
  return((char *) GetNextKeyInSplayTree((SplayTreeInfo *) image_info->options));
}

Project: ImageMagick
File: option.c

MagickExport MagickBooleanType DefineImageOption(ImageInfo *image_info,
  const char *option)
{
  char
    key[MagickPathExtent],
    value[MagickPathExtent];

  register char
    *p;

  assert(image_info != (ImageInfo *) NULL);
  assert(option != (const char *) NULL);
  (void) CopyMagickString(key,option,MagickPathExtent);
  for (p=key; *p != '\0'; p++)
    if (*p == '=')
      break;
  *value='\0';
  if (*p == '=')
    (void) CopyMagickString(value,p+1,MagickPathExtent);
  *p='\0';
  return(SetImageOption(image_info,key,value));
}

Project: ImageMagick
File: option.c

MagickExport ssize_t ParsePixelChannelOption(const char *channels)
{
  char
    *q,
    token[MagickPathExtent];

  ssize_t
    channel;

  GetMagickToken(channels,NULL,token);
  if ((*token == ';') || (*token == '|'))
    return(RedPixelChannel);
  channel=ParseCommandOption(MagickPixelChannelOptions,MagickTrue,token);
  if (channel >= 0)
    return(channel);
  q=(char *) token;
  channel=(ssize_t) InterpretLocaleValue(token,&q);
  if ((q == token) || (channel < 0) || (channel >= MaxPixelChannels))
    return(-1);
  return(channel);
}

Project: ImageMagick
File: option.c

MagickExport MagickBooleanType CloneImageOptions(ImageInfo *image_info,
  const ImageInfo *clone_info)
{
  assert(image_info != (ImageInfo *) NULL);
  assert(image_info->signature == MagickCoreSignature);
  if (image_info->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
      image_info->filename);
  assert(clone_info != (const ImageInfo *) NULL);
  assert(clone_info->signature == MagickCoreSignature);
  if (clone_info->options != (void *) NULL)
    {
      if (image_info->options != (void *) NULL)
        DestroyImageOptions(image_info);
      image_info->options=CloneSplayTree((SplayTreeInfo *) clone_info->options,
        (void *(*)(void *)) ConstantString,(void *(*)(void *)) ConstantString);
    }
  return(MagickTrue);
}

Project: ImageMagick
File: option.c

MagickExport MagickBooleanType SetImageOption(ImageInfo *image_info,
  const char *option,const char *value)
{
  assert(image_info != (ImageInfo *) NULL);
  assert(image_info->signature == MagickCoreSignature);
  if (image_info->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
      image_info->filename);
  /*
    Specific global option settings.
  */
  if (LocaleCompare(option,"size") == 0) {
    (void) CloneString(&image_info->size,value);
    return(MagickTrue);
  }
  /*
    Create tree if needed - specify how key,values are to be freed.
  */
  if (image_info->options == (void *) NULL)
    image_info->options=NewSplayTree(CompareSplayTreeString,
      RelinquishMagickMemory,RelinquishMagickMemory);
  /*
    Delete Option if NULL --  empty string values are valid!
  */
  if (value == (const char *) NULL)
    return(DeleteImageOption(image_info,option));
  /*
    Add option to splay-tree.
  */
  return(AddValueToSplayTree((SplayTreeInfo *) image_info->options,
    ConstantString(option),ConstantString(value)));
}

Project: ImageMagick
File: option.c

MagickExport ssize_t GetCommandOptionFlags(const CommandOption option,
  const MagickBooleanType list,const char *options)
{
  char
    token[MagickPathExtent];

  const OptionInfo
    *command_info,
    *option_info;

  int
    sentinel;

  MagickBooleanType
    negate;

  register char
    *q;

  register const char
    *p;

  register ssize_t
    i;

  ssize_t
    option_types;

  option_info=GetOptionInfo(option);
  if (option_info == (const OptionInfo *) NULL)
    return(UndefinedOptionFlag);
  option_types=0;
  sentinel=',';
  if (strchr(options,'|') != (char *) NULL)
    sentinel='|';
  for (p=options; p != (char *) NULL; p=strchr(p,sentinel))
  {
    while (((isspace((int) ((unsigned char) *p)) != 0) || (*p == sentinel)) &&
           (*p != '\0'))
      p++;
    negate=(*p == '!') ? MagickTrue : MagickFalse;
    if (negate != MagickFalse)
      p++;
    q=token;
    while (((isspace((int) ((unsigned char) *p)) == 0) && (*p != sentinel)) &&
           (*p != '\0'))
    {
      if ((q-token) >= (MagickPathExtent-1))
        break;
      *q++=(*p++);
    }
    *q='\0';
    for (i=0; option_info[i].mnemonic != (char *) NULL; i++)
      if (LocaleCompare(token,option_info[i].mnemonic) == 0)
        break;
    command_info=option_info+i;
    if ((command_info->mnemonic == (const char *) NULL) &&
        ((strchr(token+1,'-') != (char *) NULL) ||
         (strchr(token+1,'_') != (char *) NULL)))
      {
        while ((q=strchr(token+1,'-')) != (char *) NULL)
          (void) CopyMagickString(q,q+1,MagickPathExtent-strlen(q));
        while ((q=strchr(token+1,'_')) != (char *) NULL)
          (void) CopyMagickString(q,q+1,MagickPathExtent-strlen(q));
        for (i=0; option_info[i].mnemonic != (char *) NULL; i++)
          if (LocaleCompare(token,option_info[i].mnemonic) == 0)
            break;
        command_info=option_info+i;
      }
    if (command_info->mnemonic == (const char *) NULL)
      return(-1);
    if (negate != MagickFalse)
      option_types=option_types &~ command_info->flags;
    else
      option_types=option_types | command_info->flags;
    if (list == MagickFalse)
      break;
  }
  return(option_types);
}

Project: ImageMagick
File: option.c

MagickExport void ResetImageOptionIterator(const ImageInfo *image_info)
{
  assert(image_info != (ImageInfo *) NULL);
  assert(image_info->signature == MagickCoreSignature);
  if (image_info->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
      image_info->filename);
  if (image_info->options == (void *) NULL)
    return;
  ResetSplayTreeIterator((SplayTreeInfo *) image_info->options);
}

Project: ImageMagick
File: option.c

MagickExport const char *GetImageOption(const ImageInfo *image_info,
  const char *option)
{
  assert(image_info != (ImageInfo *) NULL);
  assert(image_info->signature == MagickCoreSignature);
  if (image_info->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
      image_info->filename);
  if (image_info->options == (void *) NULL)
    return((const char *) NULL);
  return((const char *) GetValueFromSplayTree((SplayTreeInfo *)
    image_info->options,option));
}

Project: ImageMagick
File: option.c

MagickExport void DestroyImageOptions(ImageInfo *image_info)
{
  assert(image_info != (ImageInfo *) NULL);
  assert(image_info->signature == MagickCoreSignature);
  if (image_info->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
      image_info->filename);
  if (image_info->options != (void *) NULL)
    image_info->options=DestroySplayTree((SplayTreeInfo *) image_info->options);
}

Project: ImageMagick
File: option.c

static const OptionInfo *GetOptionInfo(const CommandOption option)
{
  switch (option)
  {
    case MagickAlignOptions: return(AlignOptions);
    case MagickAlphaChannelOptions: return(AlphaChannelOptions);
    case MagickBooleanOptions: return(BooleanOptions);
    case MagickCacheOptions: return(CacheOptions);
    case MagickChannelOptions: return(ChannelOptions);
    case MagickClassOptions: return(ClassOptions);
    case MagickClipPathOptions: return(ClipPathOptions);
    case MagickColorspaceOptions: return(ColorspaceOptions);
    case MagickCommandOptions: return(CommandOptions);
    case MagickComplianceOptions: return(ComplianceOptions);
    case MagickComplexOptions: return(ComplexOptions);
    case MagickComposeOptions: return(ComposeOptions);
    case MagickCompressOptions: return(CompressOptions);
    case MagickDataTypeOptions: return(DataTypeOptions);
    case MagickDebugOptions: return(LogEventOptions);
    case MagickDecorateOptions: return(DecorateOptions);
    case MagickDirectionOptions: return(DirectionOptions);
    case MagickDisposeOptions: return(DisposeOptions);
    case MagickDistortOptions: return(DistortOptions);
    case MagickDitherOptions: return(DitherOptions);
    case MagickEndianOptions: return(EndianOptions);
    case MagickEvaluateOptions: return(EvaluateOptions);
    case MagickFillRuleOptions: return(FillRuleOptions);
    case MagickFilterOptions: return(FilterOptions);
    case MagickFunctionOptions: return(FunctionOptions);
    case MagickGradientOptions: return(GradientOptions);
    case MagickGravityOptions: return(GravityOptions);
    case MagickIntentOptions: return(IntentOptions);
    case MagickInterlaceOptions: return(InterlaceOptions);
    case MagickInterpolateOptions: return(InterpolateOptions);
    case MagickKernelOptions: return(KernelOptions);
    case MagickLayerOptions: return(LayerOptions);
    case MagickLineCapOptions: return(LineCapOptions);
    case MagickLineJoinOptions: return(LineJoinOptions);
    case MagickListOptions: return(ListOptions);
    case MagickLogEventOptions: return(LogEventOptions);
    case MagickMetricOptions: return(MetricOptions);
    case MagickMethodOptions: return(MethodOptions);
    case MagickModeOptions: return(ModeOptions);
    case MagickMorphologyOptions: return(MorphologyOptions);
    case MagickNoiseOptions: return(NoiseOptions);
    case MagickOrientationOptions: return(OrientationOptions);
    case MagickPixelChannelOptions: return(PixelChannelOptions);
    case MagickPixelIntensityOptions: return(PixelIntensityOptions);
    case MagickPixelMaskOptions: return(PixelMaskOptions);
    case MagickPixelTraitOptions: return(PixelTraitOptions);
    case MagickPolicyDomainOptions: return(PolicyDomainOptions);
    case MagickPolicyRightsOptions: return(PolicyRightsOptions);
    case MagickPreviewOptions: return(PreviewOptions);
    case MagickPrimitiveOptions: return(PrimitiveOptions);
    case MagickQuantumFormatOptions: return(QuantumFormatOptions);
    case MagickResolutionOptions: return(ResolutionOptions);
    case MagickResourceOptions: return(ResourceOptions);
    case MagickSparseColorOptions: return(SparseColorOptions);
    case MagickStatisticOptions: return(StatisticOptions);
    case MagickStorageOptions: return(StorageOptions);
    case MagickStretchOptions: return(StretchOptions);
    case MagickStyleOptions: return(StyleOptions);
    case MagickTypeOptions: return(TypeOptions);
    case MagickValidateOptions: return(ValidateOptions);
    case MagickVirtualPixelOptions: return(VirtualPixelOptions);
    case MagickWeightOptions: return(WeightOptions);
    default: break;
  }
  return((const OptionInfo *) NULL);
}

Project: ImageMagick
File: option.c

MagickExport MagickBooleanType ListCommandOptions(FILE *file,
  const CommandOption option,ExceptionInfo *magick_unused(exception))
{
  const OptionInfo
    *option_info;

  register ssize_t
    i;

  if (file == (FILE *) NULL)
    file=stdout;
  option_info=GetOptionInfo(option);
  if (option_info == (const OptionInfo *) NULL)
    return(MagickFalse);
  for (i=0; option_info[i].mnemonic != (char *) NULL; i++)
  {
    if (option_info[i].stealth != MagickFalse)
      continue;
    (void) FormatLocaleFile(file,"%s\n",option_info[i].mnemonic);
  }
  return(MagickTrue);
}