static Image *ReadDCMImage(const ImageInfo *image_info,ExceptionInfo *exception)
{
#define ThrowDCMException(exception,message) \
{ \
  if (data != (unsigned char *) NULL) \
    data=(unsigned char *) RelinquishMagickMemory(data); \
  if (stream_info != (DCMStreamInfo *) NULL) \
    stream_info=(DCMStreamInfo *) RelinquishMagickMemory(stream_info); \
  ThrowReaderException((exception),(message)); \
}

  char
    explicit_vr[MagickPathExtent],
    implicit_vr[MagickPathExtent],
    magick[MagickPathExtent],
    photometric[MagickPathExtent];

  DCMInfo
    info;

  DCMStreamInfo
    *stream_info;

  Image
    *image;

  int
    *bluemap,
    datum,
    *greenmap,
    *graymap,
    *redmap;

  MagickBooleanType
    explicit_file,
    explicit_retry,
    sequence,
    use_explicit;

  MagickOffsetType
    offset;

  register unsigned char
    *p;

  register ssize_t
    i;

  size_t
    colors,
    height,
    length,
    number_scenes,
    quantum,
    status,
    width;

  ssize_t
    count,
    scene;

  unsigned char
    *data;

  unsigned short
    group,
    element;

  /*
    Open image file.
  */
  assert(image_info != (const ImageInfo *) NULL);
  assert(image_info->signature == MagickCoreSignature);
  if (image_info->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
      image_info->filename);
  assert(exception != (ExceptionInfo *) NULL);
  assert(exception->signature == MagickCoreSignature);
  image=AcquireImage(image_info,exception);
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
  if (status == MagickFalse)
    {
      image=DestroyImageList(image);
      return((Image *) NULL);
    }
  image->depth=8UL;
  image->endian=LSBEndian;
  /*
    Read DCM preamble.
  */
  data=(unsigned char *) NULL;
  stream_info=(DCMStreamInfo *) AcquireMagickMemory(sizeof(*stream_info));
  if (stream_info == (DCMStreamInfo *) NULL)
    ThrowDCMException(ResourceLimitError,"MemoryAllocationFailed");
  (void) ResetMagickMemory(stream_info,0,sizeof(*stream_info));
  count=ReadBlob(image,128,(unsigned char *) magick);
  if (count != 128)
    ThrowDCMException(CorruptImageError,"ImproperImageHeader");
  count=ReadBlob(image,4,(unsigned char *) magick);
  if ((count != 4) || (LocaleNCompare(magick,"DICM",4) != 0))
    {
      offset=SeekBlob(image,0L,SEEK_SET);
      if (offset < 0)
        ThrowDCMException(CorruptImageError,"ImproperImageHeader");
    }
  /*
    Read DCM Medical image.
  */
  (void) CopyMagickString(photometric,"MONOCHROME1 ",MagickPathExtent);
  info.polarity=MagickFalse;
  info.scale=(Quantum *) NULL;
  info.bits_allocated=8;
  info.bytes_per_pixel=1;
  info.depth=8;
  info.mask=0xffff;
  info.max_value=255UL;
  info.samples_per_pixel=1;
  info.signed_data=(~0UL);
  info.significant_bits=0;
  info.rescale=MagickFalse;
  info.rescale_intercept=0.0;
  info.rescale_slope=1.0;
  info.window_center=0.0;
  info.window_width=0.0;
  data=(unsigned char *) NULL;
  element=0;
  explicit_vr[2]='\0';
  explicit_file=MagickFalse;
  colors=0;
  redmap=(int *) NULL;
  greenmap=(int *) NULL;
  bluemap=(int *) NULL;
  graymap=(int *) NULL;
  height=0;
  number_scenes=1;
  sequence=MagickFalse;
  use_explicit=MagickFalse;
  explicit_retry = MagickFalse;
  width=0;
  for (group=0; (group != 0x7FE0) || (element != 0x0010) ||
                (sequence != MagickFalse); )
  {
    /*
      Read a group.
    */
    image->offset=(ssize_t) TellBlob(image);
    group=ReadBlobLSBShort(image);
    element=ReadBlobLSBShort(image);
    if ((group != 0x0002) && (image->endian == MSBEndian))
      {
        group=(unsigned short) ((group << 8) | ((group >> 8) & 0xFF));
        element=(unsigned short) ((element << 8) | ((element >> 8) & 0xFF));
      }
    quantum=0;
    /*
      Find corresponding VR for this group and element.
    */
    for (i=0; dicom_info[i].group < 0xffff; i++)
      if ((group == dicom_info[i].group) && (element == dicom_info[i].element))
        break;
    (void) CopyMagickString(implicit_vr,dicom_info[i].vr,MagickPathExtent);
    count=ReadBlob(image,2,(unsigned char *) explicit_vr);
    if (count != 2)
      ThrowDCMException(CorruptImageError,"ImproperImageHeader");
    /*
      Check for "explicitness", but meta-file headers always explicit.
    */
    if ((explicit_file == MagickFalse) && (group != 0x0002))
      explicit_file=(isupper((unsigned char) *explicit_vr) != MagickFalse) &&
        (isupper((unsigned char) *(explicit_vr+1)) != MagickFalse) ?
        MagickTrue : MagickFalse;
    use_explicit=((group == 0x0002) && (explicit_retry == MagickFalse)) ||
      (explicit_file != MagickFalse) ? MagickTrue : MagickFalse;
    if ((use_explicit != MagickFalse) && (strncmp(implicit_vr,"xs",2) == 0))
      (void) CopyMagickString(implicit_vr,explicit_vr,MagickPathExtent);
    if ((use_explicit == MagickFalse) || (strncmp(implicit_vr,"!!",2) == 0))
      {
        offset=SeekBlob(image,(MagickOffsetType) -2,SEEK_CUR);
        if (offset < 0)
          ThrowDCMException(CorruptImageError,"ImproperImageHeader");
        quantum=4;
      }
    else
      {
        /*
          Assume explicit type.
        */
        quantum=2;
        if ((strncmp(explicit_vr,"OB",2) == 0) ||
            (strncmp(explicit_vr,"UN",2) == 0) ||
            (strncmp(explicit_vr,"OW",2) == 0) ||
            (strncmp(explicit_vr,"SQ",2) == 0))
          {
            (void) ReadBlobLSBShort(image);
            quantum=4;
          }
      }
    datum=0;
    if (quantum == 4)
      {
        if (group == 0x0002)
          datum=ReadBlobLSBSignedLong(image);
        else
          datum=ReadBlobSignedLong(image);
      }
    else
      if (quantum == 2)
        {
          if (group == 0x0002)
            datum=ReadBlobLSBSignedShort(image);
          else
            datum=ReadBlobSignedShort(image);
        }
    quantum=0;
    length=1;
    if (datum != 0)
      {
        if ((strncmp(implicit_vr,"SS",2) == 0) ||
            (strncmp(implicit_vr,"US",2) == 0))
          quantum=2;
        else
          if ((strncmp(implicit_vr,"UL",2) == 0) ||
              (strncmp(implicit_vr,"SL",2) == 0) ||
              (strncmp(implicit_vr,"FL",2) == 0))
            quantum=4;
          else
            if (strncmp(implicit_vr,"FD",2) != 0)
              quantum=1;
            else
              quantum=8;
        if (datum != ~0)
          length=(size_t) datum/quantum;
        else
          {
            /*
              Sequence and item of undefined length.
            */
            quantum=0;
            length=0;
          }
      }
    if (image_info->verbose != MagickFalse)
      {
        /*
          Display Dicom info.
        */
        if (use_explicit == MagickFalse)
          explicit_vr[0]='\0';
        for (i=0; dicom_info[i].description != (char *) NULL; i++)
          if ((group == dicom_info[i].group) &&
              (element == dicom_info[i].element))
            break;
        (void) FormatLocaleFile(stdout,"0x%04lX %4ld %s-%s (0x%04lx,0x%04lx)",
          (unsigned long) image->offset,(long) length,implicit_vr,explicit_vr,
          (unsigned long) group,(unsigned long) element);
        if (dicom_info[i].description != (char *) NULL)
          (void) FormatLocaleFile(stdout," %s",dicom_info[i].description);
        (void) FormatLocaleFile(stdout,": ");
      }
    if ((sequence == MagickFalse) && (group == 0x7FE0) && (element == 0x0010))
      {
        if (image_info->verbose != MagickFalse)
          (void) FormatLocaleFile(stdout,"\n");
        break;
      }
    /*
      Allocate space and read an array.
    */
    data=(unsigned char *) NULL;
    if ((length == 1) && (quantum == 1))
      datum=ReadBlobByte(image);
    else
      if ((length == 1) && (quantum == 2))
        {
          if (group == 0x0002)
            datum=ReadBlobLSBSignedShort(image);
          else
            datum=ReadBlobSignedShort(image);
        }
      else
        if ((length == 1) && (quantum == 4))
          {
            if (group == 0x0002)
              datum=ReadBlobLSBSignedLong(image);
            else
              datum=ReadBlobSignedLong(image);
          }
        else
          if ((quantum != 0) && (length != 0))
            {
              if (length > GetBlobSize(image))
                ThrowReaderException(CorruptImageError,
                  "InsufficientImageDataInFile");
              if (~length >= 1)
                data=(unsigned char *) AcquireQuantumMemory(length+1,quantum*
                  sizeof(*data));
              if (data == (unsigned char *) NULL)
                ThrowDCMException(ResourceLimitError,"MemoryAllocationFailed");
              count=ReadBlob(image,(size_t) quantum*length,data);
              if (count != (ssize_t) (quantum*length))
                {
                  if (image_info->verbose != MagickFalse)
                    (void) FormatLocaleFile(stdout,"count=%d quantum=%d "
                      "length=%d group=%d\n",(int) count,(int) quantum,(int)
                      length,(int) group);
                   ThrowDCMException(CorruptImageError,
                     "InsufficientImageDataInFile");
                }
              data[length*quantum]='\0';
            }
          else
            if ((unsigned int) datum == 0xFFFFFFFFU)
              {
                sequence=MagickTrue;
                continue;
              }

    if ((unsigned int) ((group << 16) | element) == 0xFFFEE0DD)
      {
        if (data != (unsigned char *) NULL)
          data=(unsigned char *) RelinquishMagickMemory(data);
        sequence=MagickFalse;
        continue;
      }

    if (sequence != MagickFalse)
      {
        if (data != (unsigned char *) NULL)
          data=(unsigned char *) RelinquishMagickMemory(data);
        continue;
      }

    switch (group)
    {
      case 0x0002:
      {
        switch (element)
        {
          case 0x0010:
          {
            char
              transfer_syntax[MagickPathExtent];

            /*
              Transfer Syntax.
            */
            if ((datum == 0) && (explicit_retry == MagickFalse))
              {
                explicit_retry=MagickTrue;
                (void) SeekBlob(image,(MagickOffsetType) 0,SEEK_SET);
                group=0;
                element=0;
                if (image_info->verbose != MagickFalse)
                  (void) FormatLocaleFile(stdout,
                    "Corrupted image - trying explicit format\n");
                break;
              }
            *transfer_syntax='\0';
            if (data != (unsigned char *) NULL)
              (void) CopyMagickString(transfer_syntax,(char *) data,
                MagickPathExtent);
            if (image_info->verbose != MagickFalse)
              (void) FormatLocaleFile(stdout,"transfer_syntax=%s\n",
                (const char *) transfer_syntax);
            if (strncmp(transfer_syntax,"1.2.840.10008.1.2",17) == 0)
              {
                int
                  subtype,
                  type;

                type=1;
                subtype=0;
                if (strlen(transfer_syntax) > 17)
                  {
                    count=(ssize_t) sscanf(transfer_syntax+17,".%d.%d",&type,
                      &subtype);
                    if (count < 1)
                      ThrowDCMException(CorruptImageError,
                        "ImproperImageHeader");
                  }
                switch (type)
                {
                  case 1:
                  {
                    image->endian=LSBEndian;
                    break;
                  }
                  case 2:
                  {
                    image->endian=MSBEndian;
                    break;
                  }
                  case 4:
                  {
                    if ((subtype >= 80) && (subtype <= 81))
                      image->compression=JPEGCompression;
                    else
                      if ((subtype >= 90) && (subtype <= 93))
                        image->compression=JPEG2000Compression;
                      else
                        image->compression=JPEGCompression;
                    break;
                  }
                  case 5:
                  {
                    image->compression=RLECompression;
                    break;
                  }
                }
              }
            break;
          }
          default:
            break;
        }
        break;
      }
      case 0x0028:
      {
        switch (element)
        {
          case 0x0002:
          {
            /*
              Samples per pixel.
            */
            info.samples_per_pixel=(size_t) datum;
            break;
          }
          case 0x0004:
          {
            /*
              Photometric interpretation.
            */
            if (data == (unsigned char *) NULL)
              break;
            for (i=0; i < (ssize_t) MagickMin(length,MagickPathExtent-1); i++)
              photometric[i]=(char) data[i];
            photometric[i]='\0';
            info.polarity=LocaleCompare(photometric,"MONOCHROME1 ") == 0 ?
              MagickTrue : MagickFalse;
            break;
          }
          case 0x0006:
          {
            /*
              Planar configuration.
            */
            if (datum == 1)
              image->interlace=PlaneInterlace;
            break;
          }
          case 0x0008:
          {
            /*
              Number of frames.
            */
            if (data == (unsigned char *) NULL)
              break;
            number_scenes=StringToUnsignedLong((char *) data);
            break;
          }
          case 0x0010:
          {
            /*
              Image rows.
            */
            height=(size_t) datum;
            break;
          }
          case 0x0011:
          {
            /*
              Image columns.
            */
            width=(size_t) datum;
            break;
          }
          case 0x0100:
          {
            /*
              Bits allocated.
            */
            info.bits_allocated=(size_t) datum;
            info.bytes_per_pixel=1;
            if (datum > 8)
              info.bytes_per_pixel=2;
            info.depth=info.bits_allocated;
            if (info.depth > 32)
              ThrowDCMException(CorruptImageError,"ImproperImageHeader");
            info.max_value=(1UL << info.bits_allocated)-1;
            image->depth=info.depth;
            break;
          }
          case 0x0101:
          {
            /*
              Bits stored.
            */
            info.significant_bits=(size_t) datum;
            info.bytes_per_pixel=1;
            if (info.significant_bits > 8)
              info.bytes_per_pixel=2;
            info.depth=info.significant_bits;
            if (info.depth > 32)
              ThrowDCMException(CorruptImageError,"ImproperImageHeader");
            info.max_value=(1UL << info.significant_bits)-1;
            info.mask=(size_t) GetQuantumRange(info.significant_bits);
            image->depth=info.depth;
            break;
          }
          case 0x0102:
          {
            /*
              High bit.
            */
            break;
          }
          case 0x0103:
          {
            /*
              Pixel representation.
            */
            info.signed_data=(size_t) datum;
            break;
          }
          case 0x1050:
          {
            /*
              Visible pixel range: center.
            */
            if (data != (unsigned char *) NULL)
              info.window_center=StringToDouble((char *) data, (char **) NULL);
            break;
          }
          case 0x1051:
          {
            /*
              Visible pixel range: width.
            */
            if (data != (unsigned char *) NULL)
              info.window_width=StringToDouble((char *) data, (char **) NULL);
            break;
          }
          case 0x1052:
          {
            /*
              Rescale intercept
            */
            if (data != (unsigned char *) NULL)
              info.rescale_intercept=StringToDouble((char *) data,
                (char **) NULL);
            break;
          }
          case 0x1053:
          {
            /*
              Rescale slope
            */
            if (data != (unsigned char *) NULL)
              info.rescale_slope=StringToDouble((char *) data, (char **) NULL);
            break;
          }
          case 0x1200:
          case 0x3006:
          {
            /*
              Populate graymap.
            */
            if (data == (unsigned char *) NULL)
              break;
            colors=(size_t) (length/info.bytes_per_pixel);
            datum=(int) colors;
            graymap=(int *) AcquireQuantumMemory((size_t) colors,
              sizeof(*graymap));
            if (graymap == (int *) NULL)
              ThrowDCMException(ResourceLimitError,"MemoryAllocationFailed");
            for (i=0; i < (ssize_t) colors; i++)
              if (info.bytes_per_pixel == 1)
                graymap[i]=(int) data[i];
              else
                graymap[i]=(int) ((short *) data)[i];
            break;
          }
          case 0x1201:
          {
            unsigned short
              index;

            /*
              Populate redmap.
            */
            if (data == (unsigned char *) NULL)
              break;
            colors=(size_t) (length/2);
            datum=(int) colors;
            redmap=(int *) AcquireQuantumMemory((size_t) colors,
              sizeof(*redmap));
            if (redmap == (int *) NULL)
              ThrowDCMException(ResourceLimitError,"MemoryAllocationFailed");
            p=data;
            for (i=0; i < (ssize_t) colors; i++)
            {
              if (image->endian == MSBEndian)
                index=(unsigned short) ((*p << 8) | *(p+1));
              else
                index=(unsigned short) (*p | (*(p+1) << 8));
              redmap[i]=(int) index;
              p+=2;
            }
            break;
          }
          case 0x1202:
          {
            unsigned short
              index;

            /*
              Populate greenmap.
            */
            if (data == (unsigned char *) NULL)
              break;
            colors=(size_t) (length/2);
            datum=(int) colors;
            greenmap=(int *) AcquireQuantumMemory((size_t) colors,
              sizeof(*greenmap));
            if (greenmap == (int *) NULL)
              ThrowDCMException(ResourceLimitError,"MemoryAllocationFailed");
            p=data;
            for (i=0; i < (ssize_t) colors; i++)
            {
              if (image->endian == MSBEndian)
                index=(unsigned short) ((*p << 8) | *(p+1));
              else
                index=(unsigned short) (*p | (*(p+1) << 8));
              greenmap[i]=(int) index;
              p+=2;
            }
            break;
          }
          case 0x1203:
          {
            unsigned short
              index;

            /*
              Populate bluemap.
            */
            if (data == (unsigned char *) NULL)
              break;
            colors=(size_t) (length/2);
            datum=(int) colors;
            bluemap=(int *) AcquireQuantumMemory((size_t) colors,
              sizeof(*bluemap));
            if (bluemap == (int *) NULL)
              ThrowDCMException(ResourceLimitError,"MemoryAllocationFailed");
            p=data;
            for (i=0; i < (ssize_t) colors; i++)
            {
              if (image->endian == MSBEndian)
                index=(unsigned short) ((*p << 8) | *(p+1));
              else
                index=(unsigned short) (*p | (*(p+1) << 8));
              bluemap[i]=(int) index;
              p+=2;
            }
            break;
          }
          default:
            break;
        }
        break;
      }
      case 0x2050:
      {
        switch (element)
        {
          case 0x0020:
          {
            if ((data != (unsigned char *) NULL) &&
                (strncmp((char *) data,"INVERSE",7) == 0))
              info.polarity=MagickTrue;
            break;
          }
          default:
            break;
        }
        break;
      }
      default:
        break;
    }
    if (data != (unsigned char *) NULL)
      {
        char
          *attribute;

        for (i=0; dicom_info[i].description != (char *) NULL; i++)
          if ((group == dicom_info[i].group) &&
              (element == dicom_info[i].element))
            break;
        if (dicom_info[i].description != (char *) NULL)
          {
            attribute=AcquireString("dcm:");
            (void) ConcatenateString(&attribute,dicom_info[i].description);
            for (i=0; i < (ssize_t) MagickMax(length,4); i++)
              if (isprint((int) data[i]) == MagickFalse)
                break;
            if ((i == (ssize_t) length) || (length > 4))
              {
                (void) SubstituteString(&attribute," ","");
                (void) SetImageProperty(image,attribute,(char *) data,
                  exception);
              }
            attribute=DestroyString(attribute);
          }
      }
    if (image_info->verbose != MagickFalse)
      {
        if (data == (unsigned char *) NULL)
          (void) FormatLocaleFile(stdout,"%d\n",datum);
        else
          {
            /*
              Display group data.
            */
            for (i=0; i < (ssize_t) MagickMax(length,4); i++)
              if (isprint((int) data[i]) == MagickFalse)
                break;
            if ((i != (ssize_t) length) && (length <= 4))
              {
                ssize_t
                  j;

                datum=0;
                for (j=(ssize_t) length-1; j >= 0; j--)
                  datum=(256*datum+data[j]);
                (void) FormatLocaleFile(stdout,"%d",datum);
              }
            else
              for (i=0; i < (ssize_t) length; i++)
                if (isprint((int) data[i]) != MagickFalse)
                  (void) FormatLocaleFile(stdout,"%c",data[i]);
                else
                  (void) FormatLocaleFile(stdout,"%c",'.');
            (void) FormatLocaleFile(stdout,"\n");
          }
      }
    if (data != (unsigned char *) NULL)
      data=(unsigned char *) RelinquishMagickMemory(data);
    if (EOFBlob(image) != MagickFalse)
      {
        ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
          image->filename);
        break;
      }
  }
  if ((width == 0) || (height == 0))
    ThrowDCMException(CorruptImageError,"ImproperImageHeader");
  image->columns=(size_t) width;
  image->rows=(size_t) height;
  if (info.signed_data == 0xffff)
    info.signed_data=(size_t) (info.significant_bits == 16 ? 1 : 0);
  if ((image->compression == JPEGCompression) ||
      (image->compression == JPEG2000Compression))
    {
      Image
        *images;

      ImageInfo
        *read_info;

      int
        c;

      /*
        Read offset table.
      */
      for (i=0; i < (ssize_t) stream_info->remaining; i++)
        (void) ReadBlobByte(image);
      (void)((ReadBlobLSBShort(image) << 16) | ReadBlobLSBShort(image));
      length=(size_t) ReadBlobLSBLong(image);
      stream_info->offset_count=length >> 2;
      if (stream_info->offset_count != 0)
        {
          stream_info->offsets=(ssize_t *) AcquireQuantumMemory(
            stream_info->offset_count,sizeof(*stream_info->offsets));
          if (stream_info->offsets == (ssize_t *) NULL)
            ThrowDCMException(ResourceLimitError,"MemoryAllocationFailed");
          for (i=0; i < (ssize_t) stream_info->offset_count; i++)
            stream_info->offsets[i]=(ssize_t) ReadBlobLSBSignedLong(image);
          offset=TellBlob(image);
          for (i=0; i < (ssize_t) stream_info->offset_count; i++)
            stream_info->offsets[i]+=offset;
        }
      /*
        Handle non-native image formats.
      */
      read_info=CloneImageInfo(image_info);
      SetImageInfoBlob(read_info,(void *) NULL,0);
      images=NewImageList();
      for (scene=0; scene < (ssize_t) number_scenes; scene++)
      {
        char
          filename[MagickPathExtent];

        const char
          *property;

        FILE
          *file;

        Image
          *jpeg_image;

        int
          unique_file;

        unsigned int
          tag;

        tag=(ReadBlobLSBShort(image) << 16) | ReadBlobLSBShort(image);
        length=(size_t) ReadBlobLSBLong(image);
        if (tag == 0xFFFEE0DD)
          break; /* sequence delimiter tag */
        if (tag != 0xFFFEE000)
          ThrowDCMException(CorruptImageError,"ImproperImageHeader");
        file=(FILE *) NULL;
        unique_file=AcquireUniqueFileResource(filename);
        if (unique_file != -1)
          file=fdopen(unique_file,"wb");
        if (file == (FILE *) NULL)
          {
            (void) RelinquishUniqueFileResource(filename);
            ThrowFileException(exception,FileOpenError,
              "UnableToCreateTemporaryFile",filename);
            break;
          }
        for ( ; length != 0; length--)
        {
          c=ReadBlobByte(image);
          if (c == EOF)
            {
              ThrowFileException(exception,CorruptImageError,
                "UnexpectedEndOfFile",image->filename);
              break;
            }
          (void) fputc(c,file);
        }
        (void) fclose(file);
        (void) FormatLocaleString(read_info->filename,MagickPathExtent,
          "jpeg:%s",filename);
        if (image->compression == JPEG2000Compression)
          (void) FormatLocaleString(read_info->filename,MagickPathExtent,
            "j2k:%s",filename);
        jpeg_image=ReadImage(read_info,exception);
        if (jpeg_image != (Image *) NULL)
          {
            ResetImagePropertyIterator(image);
            property=GetNextImageProperty(image);
            while (property != (const char *) NULL)
            {
              (void) SetImageProperty(jpeg_image,property,
                GetImageProperty(image,property,exception),exception);
              property=GetNextImageProperty(image);
            }
            AppendImageToList(&images,jpeg_image);
          }
        (void) RelinquishUniqueFileResource(filename);
      }
      read_info=DestroyImageInfo(read_info);
      image=DestroyImage(image);
      return(GetFirstImageInList(images));
    }
  if (info.depth != (1UL*MAGICKCORE_QUANTUM_DEPTH))
    {
      QuantumAny
        range;

      /*
        Compute pixel scaling table.
      */
      length=(size_t) (GetQuantumRange(info.depth)+1);
      info.scale=(Quantum *) AcquireQuantumMemory(length,sizeof(*info.scale));
      if (info.scale == (Quantum *) NULL)
        ThrowDCMException(ResourceLimitError,"MemoryAllocationFailed");
      range=GetQuantumRange(info.depth);
      for (i=0; i <= (ssize_t) GetQuantumRange(info.depth); i++)
        info.scale[i]=ScaleAnyToQuantum((size_t) i,range);
    }
  if (image->compression == RLECompression)
    {
      unsigned int
        tag;

      /*
        Read RLE offset table.
      */
      for (i=0; i < (ssize_t) stream_info->remaining; i++)
        (void) ReadBlobByte(image);
      tag=(ReadBlobLSBShort(image) << 16) | ReadBlobLSBShort(image);
      (void) tag;
      length=(size_t) ReadBlobLSBLong(image);
      stream_info->offset_count=length >> 2;
      if (stream_info->offset_count != 0)
        {
          stream_info->offsets=(ssize_t *) AcquireQuantumMemory(
            stream_info->offset_count,sizeof(*stream_info->offsets));
          if (stream_info->offsets == (ssize_t *) NULL)
            ThrowDCMException(ResourceLimitError,"MemoryAllocationFailed");
          for (i=0; i < (ssize_t) stream_info->offset_count; i++)
            stream_info->offsets[i]=(ssize_t) ReadBlobLSBSignedLong(image);
          offset=TellBlob(image)+8;
          for (i=0; i < (ssize_t) stream_info->offset_count; i++)
            stream_info->offsets[i]+=offset;
        }
    }
  for (scene=0; scene < (ssize_t) number_scenes; scene++)
  {
    if (image_info->ping != MagickFalse)
      break;
    image->columns=(size_t) width;
    image->rows=(size_t) height;
    image->depth=info.depth;
    status=SetImageExtent(image,image->columns,image->rows,exception);
    if (status == MagickFalse)
      break;
    image->colorspace=RGBColorspace;
    if ((image->colormap == (PixelInfo *) NULL) &&
        (info.samples_per_pixel == 1))
      {
        int
          index;

        size_t
          one;

        one=1;
        if (colors == 0)
          colors=one << info.depth;
        if (AcquireImageColormap(image,colors,exception) == MagickFalse)
          ThrowDCMException(ResourceLimitError,"MemoryAllocationFailed");
        if (redmap != (int *) NULL)
          for (i=0; i < (ssize_t) colors; i++)
          {
            index=redmap[i];
            if ((info.scale != (Quantum *) NULL) &&
                (index <= (int) info.max_value))
              index=(int) info.scale[index];
            image->colormap[i].red=(MagickRealType) index;
          }
        if (greenmap != (int *) NULL)
          for (i=0; i < (ssize_t) colors; i++)
          {
            index=greenmap[i];
            if ((info.scale != (Quantum *) NULL) &&
                (index <= (int) info.max_value))
              index=(int) info.scale[index];
            image->colormap[i].green=(MagickRealType) index;
          }
        if (bluemap != (int *) NULL)
          for (i=0; i < (ssize_t) colors; i++)
          {
            index=bluemap[i];
            if ((info.scale != (Quantum *) NULL) &&
                (index <= (int) info.max_value))
              index=(int) info.scale[index];
            image->colormap[i].blue=(MagickRealType) index;
          }
        if (graymap != (int *) NULL)
          for (i=0; i < (ssize_t) colors; i++)
          {
            index=graymap[i];
            if ((info.scale != (Quantum *) NULL) &&
                (index <= (int) info.max_value))
              index=(int) info.scale[index];
            image->colormap[i].red=(MagickRealType) index;
            image->colormap[i].green=(MagickRealType) index;
            image->colormap[i].blue=(MagickRealType) index;
          }
      }
    if (image->compression == RLECompression)
      {
        unsigned int
          tag;

        /*
          Read RLE segment table.
        */
        for (i=0; i < (ssize_t) stream_info->remaining; i++)
          (void) ReadBlobByte(image);
        tag=(ReadBlobLSBShort(image) << 16) | ReadBlobLSBShort(image);
        stream_info->remaining=(size_t) ReadBlobLSBLong(image);
        if ((tag != 0xFFFEE000) || (stream_info->remaining <= 64) ||
            (EOFBlob(image) != MagickFalse))
          ThrowDCMException(CorruptImageError,"ImproperImageHeader");
        stream_info->count=0;
        stream_info->segment_count=ReadBlobLSBLong(image);
        for (i=0; i < 15; i++)
          stream_info->segments[i]=(ssize_t) ReadBlobLSBSignedLong(image);
        stream_info->remaining-=64;
        if (stream_info->segment_count > 1)
          {
            info.bytes_per_pixel=1;
            info.depth=8;
            if (stream_info->offset_count > 0)
              (void) SeekBlob(image,(MagickOffsetType) stream_info->offsets[0]+
                stream_info->segments[0],SEEK_SET);
          }
      }
    if ((info.samples_per_pixel > 1) && (image->interlace == PlaneInterlace))
      {
        register ssize_t
          x;

        register Quantum
          *q;

        ssize_t
          y;

        /*
          Convert Planar RGB DCM Medical image to pixel packets.
        */
        for (i=0; i < (ssize_t) info.samples_per_pixel; i++)
        {
          for (y=0; y < (ssize_t) image->rows; y++)
          {
            q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
            if (q == (Quantum *) NULL)
              break;
            for (x=0; x < (ssize_t) image->columns; x++)
            {
              switch ((int) i)
              {
                case 0:
                {
                  SetPixelRed(image,ScaleCharToQuantum((unsigned char)
                    ReadDCMByte(stream_info,image)),q);
                  break;
                }
                case 1:
                {
                  SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
                    ReadDCMByte(stream_info,image)),q);
                  break;
                }
                case 2:
                {
                  SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
                    ReadDCMByte(stream_info,image)),q);
                  break;
                }
                case 3:
                {
                  SetPixelAlpha(image,ScaleCharToQuantum((unsigned char)
                    ReadDCMByte(stream_info,image)),q);
                  break;
                }
                default:
                  break;
              }
              q+=GetPixelChannels(image);
            }
            if (SyncAuthenticPixels(image,exception) == MagickFalse)
              break;
            if (image->previous == (Image *) NULL)
              {
                status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
                  image->rows);
                if (status == MagickFalse)
                  break;
              }
          }
        }
      }
    else
      {
        const char
          *option;

        /*
          Convert DCM Medical image to pixel packets.
        */
        option=GetImageOption(image_info,"dcm:display-range");
        if (option != (const char *) NULL)
          {
            if (LocaleCompare(option,"reset") == 0)
              info.window_width=0;
          }
        option=GetImageOption(image_info,"dcm:window");
        if (option != (char *) NULL)
          {
            GeometryInfo
              geometry_info;

            MagickStatusType
              flags;

            flags=ParseGeometry(option,&geometry_info);
            if (flags & RhoValue)
              info.window_center=geometry_info.rho;
            if (flags & SigmaValue)
              info.window_width=geometry_info.sigma;
            info.rescale=MagickTrue;
          }
        option=GetImageOption(image_info,"dcm:rescale");
        if (option != (char *) NULL)
          info.rescale=IsStringTrue(option);
        if ((info.window_center != 0) && (info.window_width == 0))
          info.window_width=info.window_center;
        status=ReadDCMPixels(image,&info,stream_info,MagickTrue,exception);
        if ((status != MagickFalse) && (stream_info->segment_count > 1))
          {
            if (stream_info->offset_count > 0)
              (void) SeekBlob(image,(MagickOffsetType) stream_info->offsets[0]+
                stream_info->segments[1],SEEK_SET);
            (void) ReadDCMPixels(image,&info,stream_info,MagickFalse,exception);
          }
      }
    if (SetImageGray(image,exception) != MagickFalse)
      (void) SetImageColorspace(image,GRAYColorspace,exception);
    if (EOFBlob(image) != MagickFalse)
      {
        ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
          image->filename);
        break;
      }
    /*
      Proceed to next image.
    */
    if (image_info->number_scenes != 0)
      if (image->scene >= (image_info->scene+image_info->number_scenes-1))
        break;
    if (scene < (ssize_t) (number_scenes-1))
      {
        /*
          Allocate next image structure.
        */
        AcquireNextImage(image_info,image,exception);
        if (GetNextImageInList(image) == (Image *) NULL)
          {
            image=DestroyImageList(image);
            return((Image *) NULL);
          }
        image=SyncNextImageInList(image);
        status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
          GetBlobSize(image));
        if (status == MagickFalse)
          break;
      }
  }
  /*
    Free resources.
  */
  if (stream_info->offsets != (ssize_t *) NULL)
    stream_info->offsets=(ssize_t *)
      RelinquishMagickMemory(stream_info->offsets);
  stream_info=(DCMStreamInfo *) RelinquishMagickMemory(stream_info);
  if (info.scale != (Quantum *) NULL)
    info.scale=(Quantum *) RelinquishMagickMemory(info.scale);
  if (graymap != (int *) NULL)
    graymap=(int *) RelinquishMagickMemory(graymap);
  if (bluemap != (int *) NULL)
    bluemap=(int *) RelinquishMagickMemory(bluemap);
  if (greenmap != (int *) NULL)
    greenmap=(int *) RelinquishMagickMemory(greenmap);
  if (redmap != (int *) NULL)
    redmap=(int *) RelinquishMagickMemory(redmap);
  (void) CloseBlob(image);
  return(GetFirstImageInList(image));
}

ImageMagick 7.0.6-1 has a memory leak vulnerability in ReadDCMImage in coders\dcm.c.


static Image *ReadDCMImage(const ImageInfo *image_info,ExceptionInfo *exception)
{
#define ThrowDCMException(exception,message) \
{ \
  if (data != (unsigned char *) NULL) \
    data=(unsigned char *) RelinquishMagickMemory(data); \
  if (stream_info != (DCMStreamInfo *) NULL) \
    stream_info=(DCMStreamInfo *) RelinquishMagickMemory(stream_info); \
  ThrowReaderException((exception),(message)); \
}

  char
    explicit_vr[MagickPathExtent],
    implicit_vr[MagickPathExtent],
    magick[MagickPathExtent],
    photometric[MagickPathExtent];

  DCMInfo
    info;

  DCMStreamInfo
    *stream_info;

  Image
    *image;

  int
    *bluemap,
    datum,
    *greenmap,
    *graymap,
    *redmap;

  MagickBooleanType
    explicit_file,
    explicit_retry,
    sequence,
    use_explicit;

  MagickOffsetType
    offset;

  register unsigned char
    *p;

  register ssize_t
    i;

  size_t
    colors,
    height,
    length,
    number_scenes,
    quantum,
    status,
    width;

  ssize_t
    count,
    scene;

  unsigned char
    *data;

  unsigned short
    group,
    element;

  /*
    Open image file.
  */
  assert(image_info != (const ImageInfo *) NULL);
  assert(image_info->signature == MagickCoreSignature);
  if (image_info->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
      image_info->filename);
  assert(exception != (ExceptionInfo *) NULL);
  assert(exception->signature == MagickCoreSignature);
  image=AcquireImage(image_info,exception);
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
  if (status == MagickFalse)
    {
      image=DestroyImageList(image);
      return((Image *) NULL);
    }
  image->depth=8UL;
  image->endian=LSBEndian;
  /*
    Read DCM preamble.
  */
  data=(unsigned char *) NULL;
  stream_info=(DCMStreamInfo *) AcquireMagickMemory(sizeof(*stream_info));
  if (stream_info == (DCMStreamInfo *) NULL)
    ThrowDCMException(ResourceLimitError,"MemoryAllocationFailed");
  (void) ResetMagickMemory(stream_info,0,sizeof(*stream_info));
  count=ReadBlob(image,128,(unsigned char *) magick);
  if (count != 128)
    ThrowDCMException(CorruptImageError,"ImproperImageHeader");
  count=ReadBlob(image,4,(unsigned char *) magick);
  if ((count != 4) || (LocaleNCompare(magick,"DICM",4) != 0))
    {
      offset=SeekBlob(image,0L,SEEK_SET);
      if (offset < 0)
        ThrowDCMException(CorruptImageError,"ImproperImageHeader");
    }
  /*
    Read DCM Medical image.
  */
  (void) CopyMagickString(photometric,"MONOCHROME1 ",MagickPathExtent);
  info.polarity=MagickFalse;
  info.scale=(Quantum *) NULL;
  info.bits_allocated=8;
  info.bytes_per_pixel=1;
  info.depth=8;
  info.mask=0xffff;
  info.max_value=255UL;
  info.samples_per_pixel=1;
  info.signed_data=(~0UL);
  info.significant_bits=0;
  info.rescale=MagickFalse;
  info.rescale_intercept=0.0;
  info.rescale_slope=1.0;
  info.window_center=0.0;
  info.window_width=0.0;
  data=(unsigned char *) NULL;
  element=0;
  explicit_vr[2]='\0';
  explicit_file=MagickFalse;
  colors=0;
  redmap=(int *) NULL;
  greenmap=(int *) NULL;
  bluemap=(int *) NULL;
  graymap=(int *) NULL;
  height=0;
  number_scenes=1;
  sequence=MagickFalse;
  use_explicit=MagickFalse;
  explicit_retry = MagickFalse;
  width=0;
  for (group=0; (group != 0x7FE0) || (element != 0x0010) ||
                (sequence != MagickFalse); )
  {
    /*
      Read a group.
    */
    image->offset=(ssize_t) TellBlob(image);
    group=ReadBlobLSBShort(image);
    element=ReadBlobLSBShort(image);
    if ((group != 0x0002) && (image->endian == MSBEndian))
      {
        group=(unsigned short) ((group << 8) | ((group >> 8) & 0xFF));
        element=(unsigned short) ((element << 8) | ((element >> 8) & 0xFF));
      }
    quantum=0;
    /*
      Find corresponding VR for this group and element.
    */
    for (i=0; dicom_info[i].group < 0xffff; i++)
      if ((group == dicom_info[i].group) && (element == dicom_info[i].element))
        break;
    (void) CopyMagickString(implicit_vr,dicom_info[i].vr,MagickPathExtent);
    count=ReadBlob(image,2,(unsigned char *) explicit_vr);
    if (count != 2)
      ThrowDCMException(CorruptImageError,"ImproperImageHeader");
    /*
      Check for "explicitness", but meta-file headers always explicit.
    */
    if ((explicit_file == MagickFalse) && (group != 0x0002))
      explicit_file=(isupper((unsigned char) *explicit_vr) != MagickFalse) &&
        (isupper((unsigned char) *(explicit_vr+1)) != MagickFalse) ?
        MagickTrue : MagickFalse;
    use_explicit=((group == 0x0002) && (explicit_retry == MagickFalse)) ||
      (explicit_file != MagickFalse) ? MagickTrue : MagickFalse;
    if ((use_explicit != MagickFalse) && (strncmp(implicit_vr,"xs",2) == 0))
      (void) CopyMagickString(implicit_vr,explicit_vr,MagickPathExtent);
    if ((use_explicit == MagickFalse) || (strncmp(implicit_vr,"!!",2) == 0))
      {
        offset=SeekBlob(image,(MagickOffsetType) -2,SEEK_CUR);
        if (offset < 0)
          ThrowDCMException(CorruptImageError,"ImproperImageHeader");
        quantum=4;
      }
    else
      {
        /*
          Assume explicit type.
        */
        quantum=2;
        if ((strncmp(explicit_vr,"OB",2) == 0) ||
            (strncmp(explicit_vr,"UN",2) == 0) ||
            (strncmp(explicit_vr,"OW",2) == 0) ||
            (strncmp(explicit_vr,"SQ",2) == 0))
          {
            (void) ReadBlobLSBShort(image);
            quantum=4;
          }
      }
    datum=0;
    if (quantum == 4)
      {
        if (group == 0x0002)
          datum=ReadBlobLSBSignedLong(image);
        else
          datum=ReadBlobSignedLong(image);
      }
    else
      if (quantum == 2)
        {
          if (group == 0x0002)
            datum=ReadBlobLSBSignedShort(image);
          else
            datum=ReadBlobSignedShort(image);
        }
    quantum=0;
    length=1;
    if (datum != 0)
      {
        if ((strncmp(implicit_vr,"SS",2) == 0) ||
            (strncmp(implicit_vr,"US",2) == 0))
          quantum=2;
        else
          if ((strncmp(implicit_vr,"UL",2) == 0) ||
              (strncmp(implicit_vr,"SL",2) == 0) ||
              (strncmp(implicit_vr,"FL",2) == 0))
            quantum=4;
          else
            if (strncmp(implicit_vr,"FD",2) != 0)
              quantum=1;
            else
              quantum=8;
        if (datum != ~0)
          length=(size_t) datum/quantum;
        else
          {
            /*
              Sequence and item of undefined length.
            */
            quantum=0;
            length=0;
          }
      }
    if (image_info->verbose != MagickFalse)
      {
        /*
          Display Dicom info.
        */
        if (use_explicit == MagickFalse)
          explicit_vr[0]='\0';
        for (i=0; dicom_info[i].description != (char *) NULL; i++)
          if ((group == dicom_info[i].group) &&
              (element == dicom_info[i].element))
            break;
        (void) FormatLocaleFile(stdout,"0x%04lX %4ld %s-%s (0x%04lx,0x%04lx)",
          (unsigned long) image->offset,(long) length,implicit_vr,explicit_vr,
          (unsigned long) group,(unsigned long) element);
        if (dicom_info[i].description != (char *) NULL)
          (void) FormatLocaleFile(stdout," %s",dicom_info[i].description);
        (void) FormatLocaleFile(stdout,": ");
      }
    if ((sequence == MagickFalse) && (group == 0x7FE0) && (element == 0x0010))
      {
        if (image_info->verbose != MagickFalse)
          (void) FormatLocaleFile(stdout,"\n");
        break;
      }
    /*
      Allocate space and read an array.
    */
    data=(unsigned char *) NULL;
    if ((length == 1) && (quantum == 1))
      datum=ReadBlobByte(image);
    else
      if ((length == 1) && (quantum == 2))
        {
          if (group == 0x0002)
            datum=ReadBlobLSBSignedShort(image);
          else
            datum=ReadBlobSignedShort(image);
        }
      else
        if ((length == 1) && (quantum == 4))
          {
            if (group == 0x0002)
              datum=ReadBlobLSBSignedLong(image);
            else
              datum=ReadBlobSignedLong(image);
          }
        else
          if ((quantum != 0) && (length != 0))
            {
              if (length > GetBlobSize(image))
                ThrowDCMException(CorruptImageError,
                  "InsufficientImageDataInFile");
              if (~length >= 1)
                data=(unsigned char *) AcquireQuantumMemory(length+1,quantum*
                  sizeof(*data));
              if (data == (unsigned char *) NULL)
                ThrowDCMException(ResourceLimitError,"MemoryAllocationFailed");
              count=ReadBlob(image,(size_t) quantum*length,data);
              if (count != (ssize_t) (quantum*length))
                {
                  if (image_info->verbose != MagickFalse)
                    (void) FormatLocaleFile(stdout,"count=%d quantum=%d "
                      "length=%d group=%d\n",(int) count,(int) quantum,(int)
                      length,(int) group);
                   ThrowDCMException(CorruptImageError,
                     "InsufficientImageDataInFile");
                }
              data[length*quantum]='\0';
            }
          else
            if ((unsigned int) datum == 0xFFFFFFFFU)
              {
                sequence=MagickTrue;
                continue;
              }

    if ((unsigned int) ((group << 16) | element) == 0xFFFEE0DD)
      {
        if (data != (unsigned char *) NULL)
          data=(unsigned char *) RelinquishMagickMemory(data);
        sequence=MagickFalse;
        continue;
      }

    if (sequence != MagickFalse)
      {
        if (data != (unsigned char *) NULL)
          data=(unsigned char *) RelinquishMagickMemory(data);
        continue;
      }

    switch (group)
    {
      case 0x0002:
      {
        switch (element)
        {
          case 0x0010:
          {
            char
              transfer_syntax[MagickPathExtent];

            /*
              Transfer Syntax.
            */
            if ((datum == 0) && (explicit_retry == MagickFalse))
              {
                explicit_retry=MagickTrue;
                (void) SeekBlob(image,(MagickOffsetType) 0,SEEK_SET);
                group=0;
                element=0;
                if (image_info->verbose != MagickFalse)
                  (void) FormatLocaleFile(stdout,
                    "Corrupted image - trying explicit format\n");
                break;
              }
            *transfer_syntax='\0';
            if (data != (unsigned char *) NULL)
              (void) CopyMagickString(transfer_syntax,(char *) data,
                MagickPathExtent);
            if (image_info->verbose != MagickFalse)
              (void) FormatLocaleFile(stdout,"transfer_syntax=%s\n",
                (const char *) transfer_syntax);
            if (strncmp(transfer_syntax,"1.2.840.10008.1.2",17) == 0)
              {
                int
                  subtype,
                  type;

                type=1;
                subtype=0;
                if (strlen(transfer_syntax) > 17)
                  {
                    count=(ssize_t) sscanf(transfer_syntax+17,".%d.%d",&type,
                      &subtype);
                    if (count < 1)
                      ThrowDCMException(CorruptImageError,
                        "ImproperImageHeader");
                  }
                switch (type)
                {
                  case 1:
                  {
                    image->endian=LSBEndian;
                    break;
                  }
                  case 2:
                  {
                    image->endian=MSBEndian;
                    break;
                  }
                  case 4:
                  {
                    if ((subtype >= 80) && (subtype <= 81))
                      image->compression=JPEGCompression;
                    else
                      if ((subtype >= 90) && (subtype <= 93))
                        image->compression=JPEG2000Compression;
                      else
                        image->compression=JPEGCompression;
                    break;
                  }
                  case 5:
                  {
                    image->compression=RLECompression;
                    break;
                  }
                }
              }
            break;
          }
          default:
            break;
        }
        break;
      }
      case 0x0028:
      {
        switch (element)
        {
          case 0x0002:
          {
            /*
              Samples per pixel.
            */
            info.samples_per_pixel=(size_t) datum;
            break;
          }
          case 0x0004:
          {
            /*
              Photometric interpretation.
            */
            if (data == (unsigned char *) NULL)
              break;
            for (i=0; i < (ssize_t) MagickMin(length,MagickPathExtent-1); i++)
              photometric[i]=(char) data[i];
            photometric[i]='\0';
            info.polarity=LocaleCompare(photometric,"MONOCHROME1 ") == 0 ?
              MagickTrue : MagickFalse;
            break;
          }
          case 0x0006:
          {
            /*
              Planar configuration.
            */
            if (datum == 1)
              image->interlace=PlaneInterlace;
            break;
          }
          case 0x0008:
          {
            /*
              Number of frames.
            */
            if (data == (unsigned char *) NULL)
              break;
            number_scenes=StringToUnsignedLong((char *) data);
            break;
          }
          case 0x0010:
          {
            /*
              Image rows.
            */
            height=(size_t) datum;
            break;
          }
          case 0x0011:
          {
            /*
              Image columns.
            */
            width=(size_t) datum;
            break;
          }
          case 0x0100:
          {
            /*
              Bits allocated.
            */
            info.bits_allocated=(size_t) datum;
            info.bytes_per_pixel=1;
            if (datum > 8)
              info.bytes_per_pixel=2;
            info.depth=info.bits_allocated;
            if (info.depth > 32)
              ThrowDCMException(CorruptImageError,"ImproperImageHeader");
            info.max_value=(1UL << info.bits_allocated)-1;
            image->depth=info.depth;
            break;
          }
          case 0x0101:
          {
            /*
              Bits stored.
            */
            info.significant_bits=(size_t) datum;
            info.bytes_per_pixel=1;
            if (info.significant_bits > 8)
              info.bytes_per_pixel=2;
            info.depth=info.significant_bits;
            if (info.depth > 32)
              ThrowDCMException(CorruptImageError,"ImproperImageHeader");
            info.max_value=(1UL << info.significant_bits)-1;
            info.mask=(size_t) GetQuantumRange(info.significant_bits);
            image->depth=info.depth;
            break;
          }
          case 0x0102:
          {
            /*
              High bit.
            */
            break;
          }
          case 0x0103:
          {
            /*
              Pixel representation.
            */
            info.signed_data=(size_t) datum;
            break;
          }
          case 0x1050:
          {
            /*
              Visible pixel range: center.
            */
            if (data != (unsigned char *) NULL)
              info.window_center=StringToDouble((char *) data, (char **) NULL);
            break;
          }
          case 0x1051:
          {
            /*
              Visible pixel range: width.
            */
            if (data != (unsigned char *) NULL)
              info.window_width=StringToDouble((char *) data, (char **) NULL);
            break;
          }
          case 0x1052:
          {
            /*
              Rescale intercept
            */
            if (data != (unsigned char *) NULL)
              info.rescale_intercept=StringToDouble((char *) data,
                (char **) NULL);
            break;
          }
          case 0x1053:
          {
            /*
              Rescale slope
            */
            if (data != (unsigned char *) NULL)
              info.rescale_slope=StringToDouble((char *) data, (char **) NULL);
            break;
          }
          case 0x1200:
          case 0x3006:
          {
            /*
              Populate graymap.
            */
            if (data == (unsigned char *) NULL)
              break;
            colors=(size_t) (length/info.bytes_per_pixel);
            datum=(int) colors;
            graymap=(int *) AcquireQuantumMemory((size_t) colors,
              sizeof(*graymap));
            if (graymap == (int *) NULL)
              ThrowDCMException(ResourceLimitError,"MemoryAllocationFailed");
            for (i=0; i < (ssize_t) colors; i++)
              if (info.bytes_per_pixel == 1)
                graymap[i]=(int) data[i];
              else
                graymap[i]=(int) ((short *) data)[i];
            break;
          }
          case 0x1201:
          {
            unsigned short
              index;

            /*
              Populate redmap.
            */
            if (data == (unsigned char *) NULL)
              break;
            colors=(size_t) (length/2);
            datum=(int) colors;
            redmap=(int *) AcquireQuantumMemory((size_t) colors,
              sizeof(*redmap));
            if (redmap == (int *) NULL)
              ThrowDCMException(ResourceLimitError,"MemoryAllocationFailed");
            p=data;
            for (i=0; i < (ssize_t) colors; i++)
            {
              if (image->endian == MSBEndian)
                index=(unsigned short) ((*p << 8) | *(p+1));
              else
                index=(unsigned short) (*p | (*(p+1) << 8));
              redmap[i]=(int) index;
              p+=2;
            }
            break;
          }
          case 0x1202:
          {
            unsigned short
              index;

            /*
              Populate greenmap.
            */
            if (data == (unsigned char *) NULL)
              break;
            colors=(size_t) (length/2);
            datum=(int) colors;
            greenmap=(int *) AcquireQuantumMemory((size_t) colors,
              sizeof(*greenmap));
            if (greenmap == (int *) NULL)
              ThrowDCMException(ResourceLimitError,"MemoryAllocationFailed");
            p=data;
            for (i=0; i < (ssize_t) colors; i++)
            {
              if (image->endian == MSBEndian)
                index=(unsigned short) ((*p << 8) | *(p+1));
              else
                index=(unsigned short) (*p | (*(p+1) << 8));
              greenmap[i]=(int) index;
              p+=2;
            }
            break;
          }
          case 0x1203:
          {
            unsigned short
              index;

            /*
              Populate bluemap.
            */
            if (data == (unsigned char *) NULL)
              break;
            colors=(size_t) (length/2);
            datum=(int) colors;
            bluemap=(int *) AcquireQuantumMemory((size_t) colors,
              sizeof(*bluemap));
            if (bluemap == (int *) NULL)
              ThrowDCMException(ResourceLimitError,"MemoryAllocationFailed");
            p=data;
            for (i=0; i < (ssize_t) colors; i++)
            {
              if (image->endian == MSBEndian)
                index=(unsigned short) ((*p << 8) | *(p+1));
              else
                index=(unsigned short) (*p | (*(p+1) << 8));
              bluemap[i]=(int) index;
              p+=2;
            }
            break;
          }
          default:
            break;
        }
        break;
      }
      case 0x2050:
      {
        switch (element)
        {
          case 0x0020:
          {
            if ((data != (unsigned char *) NULL) &&
                (strncmp((char *) data,"INVERSE",7) == 0))
              info.polarity=MagickTrue;
            break;
          }
          default:
            break;
        }
        break;
      }
      default:
        break;
    }
    if (data != (unsigned char *) NULL)
      {
        char
          *attribute;

        for (i=0; dicom_info[i].description != (char *) NULL; i++)
          if ((group == dicom_info[i].group) &&
              (element == dicom_info[i].element))
            break;
        if (dicom_info[i].description != (char *) NULL)
          {
            attribute=AcquireString("dcm:");
            (void) ConcatenateString(&attribute,dicom_info[i].description);
            for (i=0; i < (ssize_t) MagickMax(length,4); i++)
              if (isprint((int) data[i]) == MagickFalse)
                break;
            if ((i == (ssize_t) length) || (length > 4))
              {
                (void) SubstituteString(&attribute," ","");
                (void) SetImageProperty(image,attribute,(char *) data,
                  exception);
              }
            attribute=DestroyString(attribute);
          }
      }
    if (image_info->verbose != MagickFalse)
      {
        if (data == (unsigned char *) NULL)
          (void) FormatLocaleFile(stdout,"%d\n",datum);
        else
          {
            /*
              Display group data.
            */
            for (i=0; i < (ssize_t) MagickMax(length,4); i++)
              if (isprint((int) data[i]) == MagickFalse)
                break;
            if ((i != (ssize_t) length) && (length <= 4))
              {
                ssize_t
                  j;

                datum=0;
                for (j=(ssize_t) length-1; j >= 0; j--)
                  datum=(256*datum+data[j]);
                (void) FormatLocaleFile(stdout,"%d",datum);
              }
            else
              for (i=0; i < (ssize_t) length; i++)
                if (isprint((int) data[i]) != MagickFalse)
                  (void) FormatLocaleFile(stdout,"%c",data[i]);
                else
                  (void) FormatLocaleFile(stdout,"%c",'.');
            (void) FormatLocaleFile(stdout,"\n");
          }
      }
    if (data != (unsigned char *) NULL)
      data=(unsigned char *) RelinquishMagickMemory(data);
    if (EOFBlob(image) != MagickFalse)
      {
        ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
          image->filename);
        break;
      }
  }
  if ((width == 0) || (height == 0))
    ThrowDCMException(CorruptImageError,"ImproperImageHeader");
  image->columns=(size_t) width;
  image->rows=(size_t) height;
  if (info.signed_data == 0xffff)
    info.signed_data=(size_t) (info.significant_bits == 16 ? 1 : 0);
  if ((image->compression == JPEGCompression) ||
      (image->compression == JPEG2000Compression))
    {
      Image
        *images;

      ImageInfo
        *read_info;

      int
        c;

      /*
        Read offset table.
      */
      for (i=0; i < (ssize_t) stream_info->remaining; i++)
        (void) ReadBlobByte(image);
      (void)((ReadBlobLSBShort(image) << 16) | ReadBlobLSBShort(image));
      length=(size_t) ReadBlobLSBLong(image);
      stream_info->offset_count=length >> 2;
      if (stream_info->offset_count != 0)
        {
          stream_info->offsets=(ssize_t *) AcquireQuantumMemory(
            stream_info->offset_count,sizeof(*stream_info->offsets));
          if (stream_info->offsets == (ssize_t *) NULL)
            ThrowDCMException(ResourceLimitError,"MemoryAllocationFailed");
          for (i=0; i < (ssize_t) stream_info->offset_count; i++)
            stream_info->offsets[i]=(ssize_t) ReadBlobLSBSignedLong(image);
          offset=TellBlob(image);
          for (i=0; i < (ssize_t) stream_info->offset_count; i++)
            stream_info->offsets[i]+=offset;
        }
      /*
        Handle non-native image formats.
      */
      read_info=CloneImageInfo(image_info);
      SetImageInfoBlob(read_info,(void *) NULL,0);
      images=NewImageList();
      for (scene=0; scene < (ssize_t) number_scenes; scene++)
      {
        char
          filename[MagickPathExtent];

        const char
          *property;

        FILE
          *file;

        Image
          *jpeg_image;

        int
          unique_file;

        unsigned int
          tag;

        tag=(ReadBlobLSBShort(image) << 16) | ReadBlobLSBShort(image);
        length=(size_t) ReadBlobLSBLong(image);
        if (tag == 0xFFFEE0DD)
          break; /* sequence delimiter tag */
        if (tag != 0xFFFEE000)
          ThrowDCMException(CorruptImageError,"ImproperImageHeader");
        file=(FILE *) NULL;
        unique_file=AcquireUniqueFileResource(filename);
        if (unique_file != -1)
          file=fdopen(unique_file,"wb");
        if (file == (FILE *) NULL)
          {
            (void) RelinquishUniqueFileResource(filename);
            ThrowFileException(exception,FileOpenError,
              "UnableToCreateTemporaryFile",filename);
            break;
          }
        for ( ; length != 0; length--)
        {
          c=ReadBlobByte(image);
          if (c == EOF)
            {
              ThrowFileException(exception,CorruptImageError,
                "UnexpectedEndOfFile",image->filename);
              break;
            }
          (void) fputc(c,file);
        }
        (void) fclose(file);
        (void) FormatLocaleString(read_info->filename,MagickPathExtent,
          "jpeg:%s",filename);
        if (image->compression == JPEG2000Compression)
          (void) FormatLocaleString(read_info->filename,MagickPathExtent,
            "j2k:%s",filename);
        jpeg_image=ReadImage(read_info,exception);
        if (jpeg_image != (Image *) NULL)
          {
            ResetImagePropertyIterator(image);
            property=GetNextImageProperty(image);
            while (property != (const char *) NULL)
            {
              (void) SetImageProperty(jpeg_image,property,
                GetImageProperty(image,property,exception),exception);
              property=GetNextImageProperty(image);
            }
            AppendImageToList(&images,jpeg_image);
          }
        (void) RelinquishUniqueFileResource(filename);
      }
      read_info=DestroyImageInfo(read_info);
      image=DestroyImage(image);
      return(GetFirstImageInList(images));
    }
  if (info.depth != (1UL*MAGICKCORE_QUANTUM_DEPTH))
    {
      QuantumAny
        range;

      /*
        Compute pixel scaling table.
      */
      length=(size_t) (GetQuantumRange(info.depth)+1);
      info.scale=(Quantum *) AcquireQuantumMemory(length,sizeof(*info.scale));
      if (info.scale == (Quantum *) NULL)
        ThrowDCMException(ResourceLimitError,"MemoryAllocationFailed");
      range=GetQuantumRange(info.depth);
      for (i=0; i <= (ssize_t) GetQuantumRange(info.depth); i++)
        info.scale[i]=ScaleAnyToQuantum((size_t) i,range);
    }
  if (image->compression == RLECompression)
    {
      unsigned int
        tag;

      /*
        Read RLE offset table.
      */
      for (i=0; i < (ssize_t) stream_info->remaining; i++)
        (void) ReadBlobByte(image);
      tag=(ReadBlobLSBShort(image) << 16) | ReadBlobLSBShort(image);
      (void) tag;
      length=(size_t) ReadBlobLSBLong(image);
      stream_info->offset_count=length >> 2;
      if (stream_info->offset_count != 0)
        {
          stream_info->offsets=(ssize_t *) AcquireQuantumMemory(
            stream_info->offset_count,sizeof(*stream_info->offsets));
          if (stream_info->offsets == (ssize_t *) NULL)
            ThrowDCMException(ResourceLimitError,"MemoryAllocationFailed");
          for (i=0; i < (ssize_t) stream_info->offset_count; i++)
            stream_info->offsets[i]=(ssize_t) ReadBlobLSBSignedLong(image);
          offset=TellBlob(image)+8;
          for (i=0; i < (ssize_t) stream_info->offset_count; i++)
            stream_info->offsets[i]+=offset;
        }
    }
  for (scene=0; scene < (ssize_t) number_scenes; scene++)
  {
    if (image_info->ping != MagickFalse)
      break;
    image->columns=(size_t) width;
    image->rows=(size_t) height;
    image->depth=info.depth;
    status=SetImageExtent(image,image->columns,image->rows,exception);
    if (status == MagickFalse)
      break;
    image->colorspace=RGBColorspace;
    if ((image->colormap == (PixelInfo *) NULL) &&
        (info.samples_per_pixel == 1))
      {
        int
          index;

        size_t
          one;

        one=1;
        if (colors == 0)
          colors=one << info.depth;
        if (AcquireImageColormap(image,colors,exception) == MagickFalse)
          ThrowDCMException(ResourceLimitError,"MemoryAllocationFailed");
        if (redmap != (int *) NULL)
          for (i=0; i < (ssize_t) colors; i++)
          {
            index=redmap[i];
            if ((info.scale != (Quantum *) NULL) &&
                (index <= (int) info.max_value))
              index=(int) info.scale[index];
            image->colormap[i].red=(MagickRealType) index;
          }
        if (greenmap != (int *) NULL)
          for (i=0; i < (ssize_t) colors; i++)
          {
            index=greenmap[i];
            if ((info.scale != (Quantum *) NULL) &&
                (index <= (int) info.max_value))
              index=(int) info.scale[index];
            image->colormap[i].green=(MagickRealType) index;
          }
        if (bluemap != (int *) NULL)
          for (i=0; i < (ssize_t) colors; i++)
          {
            index=bluemap[i];
            if ((info.scale != (Quantum *) NULL) &&
                (index <= (int) info.max_value))
              index=(int) info.scale[index];
            image->colormap[i].blue=(MagickRealType) index;
          }
        if (graymap != (int *) NULL)
          for (i=0; i < (ssize_t) colors; i++)
          {
            index=graymap[i];
            if ((info.scale != (Quantum *) NULL) &&
                (index <= (int) info.max_value))
              index=(int) info.scale[index];
            image->colormap[i].red=(MagickRealType) index;
            image->colormap[i].green=(MagickRealType) index;
            image->colormap[i].blue=(MagickRealType) index;
          }
      }
    if (image->compression == RLECompression)
      {
        unsigned int
          tag;

        /*
          Read RLE segment table.
        */
        for (i=0; i < (ssize_t) stream_info->remaining; i++)
          (void) ReadBlobByte(image);
        tag=(ReadBlobLSBShort(image) << 16) | ReadBlobLSBShort(image);
        stream_info->remaining=(size_t) ReadBlobLSBLong(image);
        if ((tag != 0xFFFEE000) || (stream_info->remaining <= 64) ||
            (EOFBlob(image) != MagickFalse))
          ThrowDCMException(CorruptImageError,"ImproperImageHeader");
        stream_info->count=0;
        stream_info->segment_count=ReadBlobLSBLong(image);
        for (i=0; i < 15; i++)
          stream_info->segments[i]=(ssize_t) ReadBlobLSBSignedLong(image);
        stream_info->remaining-=64;
        if (stream_info->segment_count > 1)
          {
            info.bytes_per_pixel=1;
            info.depth=8;
            if (stream_info->offset_count > 0)
              (void) SeekBlob(image,(MagickOffsetType) stream_info->offsets[0]+
                stream_info->segments[0],SEEK_SET);
          }
      }
    if ((info.samples_per_pixel > 1) && (image->interlace == PlaneInterlace))
      {
        register ssize_t
          x;

        register Quantum
          *q;

        ssize_t
          y;

        /*
          Convert Planar RGB DCM Medical image to pixel packets.
        */
        for (i=0; i < (ssize_t) info.samples_per_pixel; i++)
        {
          for (y=0; y < (ssize_t) image->rows; y++)
          {
            q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
            if (q == (Quantum *) NULL)
              break;
            for (x=0; x < (ssize_t) image->columns; x++)
            {
              switch ((int) i)
              {
                case 0:
                {
                  SetPixelRed(image,ScaleCharToQuantum((unsigned char)
                    ReadDCMByte(stream_info,image)),q);
                  break;
                }
                case 1:
                {
                  SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
                    ReadDCMByte(stream_info,image)),q);
                  break;
                }
                case 2:
                {
                  SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
                    ReadDCMByte(stream_info,image)),q);
                  break;
                }
                case 3:
                {
                  SetPixelAlpha(image,ScaleCharToQuantum((unsigned char)
                    ReadDCMByte(stream_info,image)),q);
                  break;
                }
                default:
                  break;
              }
              q+=GetPixelChannels(image);
            }
            if (SyncAuthenticPixels(image,exception) == MagickFalse)
              break;
            if (image->previous == (Image *) NULL)
              {
                status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
                  image->rows);
                if (status == MagickFalse)
                  break;
              }
          }
        }
      }
    else
      {
        const char
          *option;

        /*
          Convert DCM Medical image to pixel packets.
        */
        option=GetImageOption(image_info,"dcm:display-range");
        if (option != (const char *) NULL)
          {
            if (LocaleCompare(option,"reset") == 0)
              info.window_width=0;
          }
        option=GetImageOption(image_info,"dcm:window");
        if (option != (char *) NULL)
          {
            GeometryInfo
              geometry_info;

            MagickStatusType
              flags;

            flags=ParseGeometry(option,&geometry_info);
            if (flags & RhoValue)
              info.window_center=geometry_info.rho;
            if (flags & SigmaValue)
              info.window_width=geometry_info.sigma;
            info.rescale=MagickTrue;
          }
        option=GetImageOption(image_info,"dcm:rescale");
        if (option != (char *) NULL)
          info.rescale=IsStringTrue(option);
        if ((info.window_center != 0) && (info.window_width == 0))
          info.window_width=info.window_center;
        status=ReadDCMPixels(image,&info,stream_info,MagickTrue,exception);
        if ((status != MagickFalse) && (stream_info->segment_count > 1))
          {
            if (stream_info->offset_count > 0)
              (void) SeekBlob(image,(MagickOffsetType) stream_info->offsets[0]+
                stream_info->segments[1],SEEK_SET);
            (void) ReadDCMPixels(image,&info,stream_info,MagickFalse,exception);
          }
      }
    if (SetImageGray(image,exception) != MagickFalse)
      (void) SetImageColorspace(image,GRAYColorspace,exception);
    if (EOFBlob(image) != MagickFalse)
      {
        ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
          image->filename);
        break;
      }
    /*
      Proceed to next image.
    */
    if (image_info->number_scenes != 0)
      if (image->scene >= (image_info->scene+image_info->number_scenes-1))
        break;
    if (scene < (ssize_t) (number_scenes-1))
      {
        /*
          Allocate next image structure.
        */
        AcquireNextImage(image_info,image,exception);
        if (GetNextImageInList(image) == (Image *) NULL)
          {
            image=DestroyImageList(image);
            return((Image *) NULL);
          }
        image=SyncNextImageInList(image);
        status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
          GetBlobSize(image));
        if (status == MagickFalse)
          break;
      }
  }
  /*
    Free resources.
  */
  if (stream_info->offsets != (ssize_t *) NULL)
    stream_info->offsets=(ssize_t *)
      RelinquishMagickMemory(stream_info->offsets);
  stream_info=(DCMStreamInfo *) RelinquishMagickMemory(stream_info);
  if (info.scale != (Quantum *) NULL)
    info.scale=(Quantum *) RelinquishMagickMemory(info.scale);
  if (graymap != (int *) NULL)
    graymap=(int *) RelinquishMagickMemory(graymap);
  if (bluemap != (int *) NULL)
    bluemap=(int *) RelinquishMagickMemory(bluemap);
  if (greenmap != (int *) NULL)
    greenmap=(int *) RelinquishMagickMemory(greenmap);
  if (redmap != (int *) NULL)
    redmap=(int *) RelinquishMagickMemory(redmap);
  (void) CloseBlob(image);
  return(GetFirstImageInList(image));
}


credential: avoid writing values with newlines

The credential protocol that we use to speak to helpers can't represent
values with newlines in them. This was an intentional design choice to
keep the protocol simple, since none of the values we pass should
generally have newlines.

However, if we _do_ encounter a newline in a value, we blindly transmit
it in credential_write(). Such values may break the protocol syntax, or
worse, inject new valid lines into the protocol stream.

The most likely way for a newline to end up in a credential struct is by
decoding a URL with a percent-encoded newline. However, since the bug
occurs at the moment we write the value to the protocol, we'll catch it
there. That should leave no possibility of accidentally missing a code
path that can trigger the problem.

At this level of the code we have little choice but to die(). However,
since we'd not ever expect to see this case outside of a malicious URL,
that's an acceptable outcome.

Reported-by: Felix Wilhelm <fwilhelm@google.com>

static void credential_write_item(FILE *fp, const char *key, const char *value)
{
	if (!value)
		return;
	fprintf(fp, "%s=%s\n", key, value);
}

Affected versions of Git have a vulnerability whereby Git can be tricked into sending private credentials to a host controlled by an attacker. Git uses external "credential helper" programs to store and retrieve passwords or other credentials from secure storage provided by the operating system. Specially-crafted URLs that contain an encoded newline can inject unintended values into the credential helper protocol stream, causing the credential helper to retrieve the password for one server (e.g., good.example.com) for an HTTP request being made to another server (e.g., evil.example.com), resulting in credentials for the former being sent to the latter. There are no restrictions on the relationship between the two, meaning that an attacker can craft a URL that will present stored credentials for any host to a host of their choosing. The vulnerability can be triggered by feeding a malicious URL to git clone. However, the affected URLs look rather suspicious; the likely vector would be through systems which automatically clone URLs not visible to the user, such as Git submodules, or package systems built around Git. The problem has been patched in the versions published on April 14th, 2020, going back to v2.17.x. Anyone wishing to backport the change further can do so by applying commit 9a6bbee (the full release includes extra checks for git fsck, but that commit is sufficient to protect clients against the vulnerability). The patched versions are: 2.17.4, 2.18.3, 2.19.4, 2.20.3, 2.21.2, 2.22.3, 2.23.2, 2.24.2, 2.25.3, 2.26.1.


static void credential_write_item(FILE *fp, const char *key, const char *value)
{
	if (!value)
		return;
	if (strchr(value, '\n'))
		die("credential value for %s contains newline", key);
	fprintf(fp, "%s=%s\n", key, value);
}


Adds bound check in oracle protocol

Found by oss-fuzz
https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=21780

void ndpi_search_oracle(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow)
{
  struct ndpi_packet_struct *packet = &flow->packet;
  u_int16_t dport = 0, sport = 0;

  NDPI_LOG_DBG(ndpi_struct, "search ORACLE\n");

  if(packet->tcp != NULL) {
    sport = ntohs(packet->tcp->source), dport = ntohs(packet->tcp->dest);
    NDPI_LOG_DBG2(ndpi_struct, "calculating ORACLE over tcp\n");
    /* Oracle Database 9g,10g,11g */
    if ((dport == 1521 || sport == 1521)
	&&  (((packet->payload[0] == 0x07) && (packet->payload[1] == 0xff) && (packet->payload[2] == 0x00))
	     || ((packet->payload_packet_len >= 232) && ((packet->payload[0] == 0x00) || (packet->payload[0] == 0x01))
	     && (packet->payload[1] != 0x00)
	     && (packet->payload[2] == 0x00)
		 && (packet->payload[3] == 0x00)))) {
      NDPI_LOG_INFO(ndpi_struct, "found oracle\n");
      ndpi_int_oracle_add_connection(ndpi_struct, flow);
    } else if (packet->payload_packet_len == 213 && packet->payload[0] == 0x00 &&
               packet->payload[1] == 0xd5 && packet->payload[2] == 0x00 &&
               packet->payload[3] == 0x00 ) {
      NDPI_LOG_INFO(ndpi_struct, "found oracle\n");
      ndpi_int_oracle_add_connection(ndpi_struct, flow);
    }
  } else {
    NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
  }
}

In nDPI through 3.2, the Oracle protocol dissector has a heap-based buffer over-read in ndpi_search_oracle in lib/protocols/oracle.c.


void ndpi_search_oracle(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow)
{
  struct ndpi_packet_struct *packet = &flow->packet;
  u_int16_t dport = 0, sport = 0;

  NDPI_LOG_DBG(ndpi_struct, "search ORACLE\n");

  if(packet->tcp != NULL) {
    sport = ntohs(packet->tcp->source), dport = ntohs(packet->tcp->dest);
    NDPI_LOG_DBG2(ndpi_struct, "calculating ORACLE over tcp\n");
    /* Oracle Database 9g,10g,11g */
    if ((dport == 1521 || sport == 1521)
	&&  (((packet->payload_packet_len >= 3 && packet->payload[0] == 0x07) && (packet->payload[1] == 0xff) && (packet->payload[2] == 0x00))
	     || ((packet->payload_packet_len >= 232) && ((packet->payload[0] == 0x00) || (packet->payload[0] == 0x01))
	     && (packet->payload[1] != 0x00)
	     && (packet->payload[2] == 0x00)
		 && (packet->payload[3] == 0x00)))) {
      NDPI_LOG_INFO(ndpi_struct, "found oracle\n");
      ndpi_int_oracle_add_connection(ndpi_struct, flow);
    } else if (packet->payload_packet_len == 213 && packet->payload[0] == 0x00 &&
               packet->payload[1] == 0xd5 && packet->payload[2] == 0x00 &&
               packet->payload[3] == 0x00 ) {
      NDPI_LOG_INFO(ndpi_struct, "found oracle\n");
      ndpi_int_oracle_add_connection(ndpi_struct, flow);
    }
  } else {
    NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
  }
}


Added missing return to avoid use after free.

void Magick::Image::read(MagickCore::Image *image,
  MagickCore::ExceptionInfo *exceptionInfo)
{
  // Ensure that multiple image frames were not read.
  if (image != (MagickCore::Image *) NULL &&
      image->next != (MagickCore::Image *) NULL)
    {
      MagickCore::Image
        *next;

      // Destroy any extra image frames
      next=image->next;
      image->next=(MagickCore::Image *) NULL;
      next->previous=(MagickCore::Image *) NULL;
      DestroyImageList(next);
    }
  replaceImage(image);
  if (exceptionInfo->severity == MagickCore::UndefinedException &&
      image == (MagickCore::Image *) NULL)
    {
      (void) MagickCore::DestroyExceptionInfo(exceptionInfo);
      if (!quiet())
        throwExceptionExplicit(MagickCore::ImageWarning,
          "No image was loaded.");
    }
  ThrowImageException;
}

ImageMagick before 6.9.9-24 and 7.x before 7.0.7-12 has a use-after-free in Magick::Image::read in Magick++/lib/Image.cpp.


void Magick::Image::read(MagickCore::Image *image,
  MagickCore::ExceptionInfo *exceptionInfo)
{
  // Ensure that multiple image frames were not read.
  if (image != (MagickCore::Image *) NULL &&
      image->next != (MagickCore::Image *) NULL)
    {
      MagickCore::Image
        *next;

      // Destroy any extra image frames
      next=image->next;
      image->next=(MagickCore::Image *) NULL;
      next->previous=(MagickCore::Image *) NULL;
      DestroyImageList(next);
    }
  replaceImage(image);
  if (exceptionInfo->severity == MagickCore::UndefinedException &&
      image == (MagickCore::Image *) NULL)
    {
      (void) MagickCore::DestroyExceptionInfo(exceptionInfo);
      if (!quiet())
        throwExceptionExplicit(MagickCore::ImageWarning,
          "No image was loaded.");
      return;
    }
  ThrowImageException;
}


secgsi: do not build/package libXrdSecgsiGMAPLDAP-4.so

The way the LDAP query is implemented may represent a security threat.
Any related building and packaging reference is removed.
The code is left in place (for the time being) to remind its functionality
in the case a sanitized version is required.

  void DefaultEnv::Initialize()
  {
    sLog           = new Log();
    SetUpLog();

    sEnv           = new DefaultEnv();
    sForkHandler   = new ForkHandler();
    sFileTimer     = new FileTimer();
    sPlugInManager = new PlugInManager();

    sPlugInManager->ProcessEnvironmentSettings();
    sForkHandler->RegisterFileTimer( sFileTimer );

    //--------------------------------------------------------------------------
    // MacOSX library loading is completely moronic. We cannot dlopen a library
    // from a thread other than a main thread, so we-pre dlopen all the
    // libraries that we may potentially want.
    //--------------------------------------------------------------------------
#ifdef __APPLE__
    char *errBuff = new char[1024];

    const char *libs[] =
    {
      "libXrdSeckrb5.so",
      "libXrdSecgsi.so",
      "libXrdSecgsiAuthzVO.so",
      "libXrdSecgsiGMAPDN.so",
      "libXrdSecgsiGMAPLDAP.so",
      "libXrdSecpwd.so",
      "libXrdSecsss.so",
      "libXrdSecunix.so",
      0
    };

    for( int i = 0; libs[i]; ++i )
    {
      sLog->Debug( UtilityMsg, "Attempting to pre-load: %s", libs[i] );
      bool ok = XrdOucPreload( libs[i], errBuff, 1024 );
      if( !ok )
        sLog->Error( UtilityMsg, "Unable to pre-load %s: %s", libs[i], errBuff );
    }
    delete [] errBuff;
#endif
  }

ROOT xrootd version 4.6.0 and below is vulnerable to an unauthenticated shell command injection resulting in remote code execution


  void DefaultEnv::Initialize()
  {
    sLog           = new Log();
    SetUpLog();

    sEnv           = new DefaultEnv();
    sForkHandler   = new ForkHandler();
    sFileTimer     = new FileTimer();
    sPlugInManager = new PlugInManager();

    sPlugInManager->ProcessEnvironmentSettings();
    sForkHandler->RegisterFileTimer( sFileTimer );

    //--------------------------------------------------------------------------
    // MacOSX library loading is completely moronic. We cannot dlopen a library
    // from a thread other than a main thread, so we-pre dlopen all the
    // libraries that we may potentially want.
    //--------------------------------------------------------------------------
#ifdef __APPLE__
    char *errBuff = new char[1024];

    const char *libs[] =
    {
      "libXrdSeckrb5.so",
      "libXrdSecgsi.so",
      "libXrdSecgsiAuthzVO.so",
      "libXrdSecgsiGMAPDN.so",
      "libXrdSecpwd.so",
      "libXrdSecsss.so",
      "libXrdSecunix.so",
      0
    };

    for( int i = 0; libs[i]; ++i )
    {
      sLog->Debug( UtilityMsg, "Attempting to pre-load: %s", libs[i] );
      bool ok = XrdOucPreload( libs[i], errBuff, 1024 );
      if( !ok )
        sLog->Error( UtilityMsg, "Unable to pre-load %s: %s", libs[i], errBuff );
    }
    delete [] errBuff;
#endif
  }


Check if output buffer is too small.

It really seems like libsodium (whose entire purpose is to make crypto
idiot-proof) making me mess with these details is a flaw in the API design.

Also, correct Hungarian.

bool AES_GCM_DecryptContext::Decrypt(
	const void *pEncryptedDataAndTag, size_t cbEncryptedDataAndTag,
	const void *pIV,
	void *pPlaintextData, uint32 *pcbPlaintextData,
	const void *pAdditionalAuthenticationData, size_t cbAuthenticationData
) {
    unsigned long long pcbPlaintextData_longlong;

    const int nDecryptResult = crypto_aead_aes256gcm_decrypt_afternm(
		static_cast<unsigned char*>( pPlaintextData ), &pcbPlaintextData_longlong,
		nullptr,
		static_cast<const unsigned char*>( pEncryptedDataAndTag ), cbEncryptedDataAndTag,
		static_cast<const unsigned char*>( pAdditionalAuthenticationData ), cbAuthenticationData,
		static_cast<const unsigned char*>( pIV ), static_cast<const crypto_aead_aes256gcm_state*>( m_ctx )
	);

    *pcbPlaintextData = pcbPlaintextData_longlong;

    return nDecryptResult == 0;
}

Valve's Game Networking Sockets prior to version v1.2.0 improperly handles long encrypted messages in function AES_GCM_DecryptContext::Decrypt() when compiled using libsodium, leading to a Stack-Based Buffer Overflow and resulting in a memory corruption and possibly even a remote code execution.


bool AES_GCM_DecryptContext::Decrypt(
	const void *pEncryptedDataAndTag, size_t cbEncryptedDataAndTag,
	const void *pIV,
	void *pPlaintextData, uint32 *pcbPlaintextData,
	const void *pAdditionalAuthenticationData, size_t cbAuthenticationData
) {
	// Make sure caller's buffer is big enough to hold the result
	if ( cbEncryptedDataAndTag > *pcbPlaintextData + crypto_aead_aes256gcm_ABYTES )
	{
		*pcbPlaintextData = 0;
		return false;
	}

    unsigned long long cbPlaintextData_longlong;
    const int nDecryptResult = crypto_aead_aes256gcm_decrypt_afternm(
		static_cast<unsigned char*>( pPlaintextData ), &cbPlaintextData_longlong,
		nullptr,
		static_cast<const unsigned char*>( pEncryptedDataAndTag ), cbEncryptedDataAndTag,
		static_cast<const unsigned char*>( pAdditionalAuthenticationData ), cbAuthenticationData,
		static_cast<const unsigned char*>( pIV ), static_cast<const crypto_aead_aes256gcm_state*>( m_ctx )
	);

    *pcbPlaintextData = cbPlaintextData_longlong;

    return nDecryptResult == 0;
}


Completely rewrite `GetMatchingPaths`.

The current parallel implementation is too complex (lambda inside lambda, two levels of parallelism) and has a read outside of bounds issue.

The new implementation cleans up artifacts from the previous implementations that were left in the code as it evolves. We add multiple helper functions, and document invariants and preconditions as well as every major step. This way, we fix the security issue and a potential new one which was not caught before

PiperOrigin-RevId: 346146220
Change-Id: Iec0f44673f43349797bf9944dffe9b2f779137d8

Status GetMatchingPaths(FileSystem* fs, Env* env, const string& pattern,
                        std::vector<string>* results) {
  results->clear();
  if (pattern.empty()) {
    return Status::OK();
  }

  string fixed_prefix = pattern.substr(0, pattern.find_first_of("*?[\\"));
  string eval_pattern = pattern;
  string dir(io::Dirname(fixed_prefix));
  // If dir is empty then we need to fix up fixed_prefix and eval_pattern to
  // include . as the top level directory.
  if (dir.empty()) {
    dir = ".";
    fixed_prefix = io::JoinPath(dir, fixed_prefix);
    eval_pattern = io::JoinPath(dir, eval_pattern);
  }
  bool is_directory = pattern[pattern.size() - 1] == '/';
#ifdef PLATFORM_WINDOWS
  is_directory = is_directory || pattern[pattern.size() - 1] == '\\';
#endif
  std::vector<string> dirs;
  if (!is_directory) {
    dirs.emplace_back(eval_pattern);
  }
  StringPiece tmp_dir(io::Dirname(eval_pattern));
  while (tmp_dir.size() > dir.size()) {
    dirs.emplace_back(string(tmp_dir));
    tmp_dir = io::Dirname(tmp_dir);
  }
  dirs.emplace_back(dir);
  std::reverse(dirs.begin(), dirs.end());
  // Setup a parallel BFS to explore everything under dir.
  std::deque<std::pair<string, int>> dir_q;
  std::deque<std::pair<string, int>> next_dir_q;
  dir_q.emplace_back(std::make_pair(dirs[0], 0));
  Status ret;  // Status to return.
  mutex results_mutex;
  condition_variable results_cond;
  mutex next_que_mutex;
  condition_variable next_que_cond;
  while (!dir_q.empty()) {
    next_dir_q.clear();
    std::vector<Status> new_rets(dir_q.size());
    auto handle_level = [fs, &results, &dir_q, &next_dir_q, &new_rets,
                         &is_directory, &dirs, &results_mutex, &results_cond,
                         &next_que_mutex, &next_que_cond](int i) {
      string current_dir = dir_q.at(i).first;
      int dir_index = dir_q.at(i).second;
      dir_index++;
      std::vector<string> children;
      Status s = fs->GetChildren(current_dir, &children);
      // In case PERMISSION_DENIED is encountered, we bail here.
      if (s.code() == tensorflow::error::PERMISSION_DENIED) {
        return;
      }
      new_rets[i] = s;
      if (children.empty()) return;

      // children_dir_status holds is_dir status for children. It can have three
      // possible values: OK for true; FAILED_PRECONDITION for false; CANCELLED
      // if we don't calculate IsDirectory (we might do that because there isn't
      // any point in exploring that child path).
      std::vector<Status> children_dir_status;

      // This IsDirectory call can be expensive for some FS. Parallelizing it.
      children_dir_status.resize(children.size());
      auto handle_children = [fs, &current_dir, &children, &dirs, dir_index,
                              is_directory, &children_dir_status](int j) {
        const string child_path = io::JoinPath(current_dir, children[j]);
        if (!fs->Match(child_path, dirs[dir_index])) {
          children_dir_status[j] =
              Status(tensorflow::error::CANCELLED, "Operation not needed");
        } else if (dir_index != dirs.size() - 1) {
          children_dir_status[j] = fs->IsDirectory(child_path);
        } else {
          children_dir_status[j] =
              is_directory ? fs->IsDirectory(child_path) : Status::OK();
        }
      };
      ForEach(0, children.size(), handle_children);

      for (size_t j = 0; j < children.size(); ++j) {
        const string child_path = io::JoinPath(current_dir, children[j]);
        // If the IsDirectory call was cancelled we bail.
        if (children_dir_status[j].code() == tensorflow::error::CANCELLED) {
          continue;
        }
        if (children_dir_status[j].ok()) {
          if (dir_index != dirs.size() - 1) {
            mutex_lock lk(next_que_mutex);
            next_dir_q.emplace_back(std::make_pair(child_path, dir_index));
            next_que_cond.notify_one();
          } else {
            mutex_lock lk(results_mutex);
            results->emplace_back(child_path);
            results_cond.notify_one();
          }
        }
      }
    };
    ForEach(0, dir_q.size(), handle_level);

    ret.Update(new_rets[dir_q.size() - 1]);
    std::swap(dir_q, next_dir_q);
  }
  return ret;
}

In TensorFlow release candidate versions 2.4.0rc*, the general implementation for matching filesystem paths to globbing pattern is vulnerable to an access out of bounds of the array holding the directories. There are multiple invariants and preconditions that are assumed by the parallel implementation of GetMatchingPaths but are not verified by the PRs introducing it (#40861 and #44310). Thus, we are completely rewriting the implementation to fully specify and validate these. This is patched in version 2.4.0. This issue only impacts master branch and the release candidates for TF version 2.4. The final release of the 2.4 release will be patched.


Status GetMatchingPaths(FileSystem* fs, Env* env, const string& pattern,
                        std::vector<string>* results) {
  // Check that `fs`, `env` and `results` are non-null.
  if (fs == nullptr || env == nullptr || results == nullptr) {
    return Status(tensorflow::error::INVALID_ARGUMENT,
                  "Filesystem calls GetMatchingPaths with nullptr arguments");
  }

  // By design, we don't match anything on empty pattern
  results->clear();
  if (pattern.empty()) {
    return Status::OK();
  }

  // The pattern can contain globbing characters at multiple levels, e.g.:
  //
  //   foo/ba?/baz/f*r
  //
  // To match the full pattern, we must match every prefix subpattern and then
  // operate on the children for each match. Thus, we separate all subpatterns
  // in the `dirs` vector below.
  std::vector<std::string> dirs = AllDirectoryPrefixes(pattern);

  // We can have patterns that have several parents where no globbing is being
  // done, for example, `foo/bar/baz/*`. We don't need to expand the directories
  // which don't contain the globbing characters.
  int matching_index = GetFirstGlobbingEntry(dirs);

  // If we don't have globbing characters in the pattern then it specifies a
  // path in the filesystem. We add it to the result set if it exists.
  if (matching_index == dirs.size()) {
    if (fs->FileExists(pattern).ok()) {
      results->emplace_back(pattern);
    }
    return Status::OK();
  }

  // To expand the globbing, we do a BFS from `dirs[matching_index-1]`.
  // At every step, we work on a pair `{dir, ix}` such that `dir` is a real
  // directory, `ix < dirs.size() - 1` and `dirs[ix+1]` is a globbing pattern.
  // To expand the pattern, we select from all the children of `dir` only those
  // that match against `dirs[ix+1]`.
  // If there are more entries in `dirs` after `dirs[ix+1]` this mean we have
  // more patterns to match. So, we add to the queue only those children that
  // are also directories, paired with `ix+1`.
  // If there are no more entries in `dirs`, we return all children as part of
  // the answer.
  // Since we can get into a combinatorial explosion issue (e.g., pattern
  // `/*/*/*`), we process the queue in parallel. Each parallel processing takes
  // elements from `expand_queue` and adds them to `next_expand_queue`, after
  // which we swap these two queues (similar to double buffering algorithms).
  // PRECONDITION: `IsGlobbingPattern(dirs[0]) == false`
  // PRECONDITION: `matching_index > 0`
  // INVARIANT: If `{d, ix}` is in queue, then `d` and `dirs[ix]` are at the
  //            same level in the filesystem tree.
  // INVARIANT: If `{d, _}` is in queue, then `IsGlobbingPattern(d) == false`.
  // INVARIANT: If `{d, _}` is in queue, then `d` is a real directory.
  // INVARIANT: If `{_, ix}` is in queue, then `ix < dirs.size() - 1`.
  // INVARIANT: If `{_, ix}` is in queue, `IsGlobbingPattern(dirs[ix + 1])`.
  std::deque<std::pair<string, int>> expand_queue;
  std::deque<std::pair<string, int>> next_expand_queue;
  expand_queue.emplace_back(dirs[matching_index - 1], matching_index - 1);

  // Adding to `result` or `new_expand_queue` need to be protected by mutexes
  // since there are multiple threads writing to these.
  mutex result_mutex;
  mutex queue_mutex;

  while (!expand_queue.empty()) {
    next_expand_queue.clear();

    // The work item for every item in `expand_queue`.
    // pattern, we process them in parallel.
    auto handle_level = [&fs, &results, &dirs, &expand_queue,
                         &next_expand_queue, &result_mutex,
                         &queue_mutex](int i) {
      // See invariants above, all of these are valid accesses.
      const auto& queue_item = expand_queue.at(i);
      const std::string& parent = queue_item.first;
      const int index = queue_item.second + 1;
      const std::string& match_pattern = dirs[index];

      // Get all children of `parent`. If this fails, return early.
      std::vector<std::string> children;
      Status s = fs->GetChildren(parent, &children);
      if (s.code() == tensorflow::error::PERMISSION_DENIED) {
        return;
      }

      // Also return early if we don't have any children
      if (children.empty()) {
        return;
      }

      // Since we can get extremely many children here and on some filesystems
      // `IsDirectory` is expensive, we process the children in parallel.
      // We also check that children match the pattern in parallel, for speedup.
      // We store the status of the match and `IsDirectory` in
      // `children_status` array, one element for each children.
      std::vector<Status> children_status(children.size());
      auto handle_children = [&fs, &match_pattern, &parent, &children,
                              &children_status](int j) {
        const std::string path = io::JoinPath(parent, children[j]);
        if (!fs->Match(path, match_pattern)) {
          children_status[j] =
              Status(tensorflow::error::CANCELLED, "Operation not needed");
        } else {
          children_status[j] = fs->IsDirectory(path);
        }
      };
      ForEach(0, children.size(), handle_children);

      // At this point, pairing `children` with `children_status` will tell us
      // if a children:
      //   * does not match the pattern
      //   * matches the pattern and is a directory
      //   * matches the pattern and is not a directory
      // We fully ignore the first case.
      // If we matched the last pattern (`index == dirs.size() - 1`) then all
      // remaining children get added to the result.
      // Otherwise, only the directories get added to the next queue.
      for (size_t j = 0; j < children.size(); j++) {
        if (children_status[j].code() == tensorflow::error::CANCELLED) {
          continue;
        }

        const std::string path = io::JoinPath(parent, children[j]);
        if (index == dirs.size() - 1) {
          mutex_lock l(result_mutex);
          results->emplace_back(path);
        } else if (children_status[j].ok()) {
          mutex_lock l(queue_mutex);
          next_expand_queue.emplace_back(path, index);
        }
      }
    };
    ForEach(0, expand_queue.size(), handle_level);

    // After evaluating one level, swap the "buffers"
    std::swap(expand_queue, next_expand_queue);
  }

  return Status::OK();
}


Fix bug#72697 - select_colors write out-of-bounds

(cherry picked from commit b6f13a5ef9d6280cf984826a5de012a32c396cd4)

Conflicts:
	ext/gd/gd.c

PHP_FUNCTION(imagetruecolortopalette)
{
	zval *IM;
	zend_bool dither;
	zend_long ncolors;
	gdImagePtr im;

	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rbl", &IM, &dither, &ncolors) == FAILURE)  {
		return;
	}

	if ((im = (gdImagePtr)zend_fetch_resource(Z_RES_P(IM), "Image", le_gd)) == NULL) {
		RETURN_FALSE;
	}

	if (ncolors <= 0) {
		php_error_docref(NULL, E_WARNING, "Number of colors has to be greater than zero");
		RETURN_FALSE;
	}
	gdImageTrueColorToPalette(im, dither, ncolors);

	RETURN_TRUE;
}

The imagetruecolortopalette function in ext/gd/gd.c in PHP before 5.6.25 and 7.x before 7.0.10 does not properly validate the number of colors, which allows remote attackers to cause a denial of service (select_colors allocation error and out-of-bounds write) or possibly have unspecified other impact via a large value in the third argument.