Commit message: https://github.com/ImageMagick/ImageMagick/issues/536
CVE: CVE-2017-12432
CWE: CWE-770
Vulnerability description: In ImageMagick 7.0.6-1, a memory exhaustion vulnerability was found in the function ReadPCXImage in coders/pcx.c, which allows attackers to cause a denial of service.

Project: ImageMagick

MagickExport MemoryInfo *AcquireVirtualMemory(const size_t count,
  const size_t quantum)
{
  MemoryInfo
    *memory_info;

  size_t
    extent;

  static ssize_t
    virtual_anonymous_memory = (-1);

  if (HeapOverflowSanityCheck(count,quantum) != MagickFalse)
    return((MemoryInfo *) NULL);
  memory_info=(MemoryInfo *) MagickAssumeAligned(AcquireAlignedMemory(1,
    sizeof(*memory_info)));
  if (memory_info == (MemoryInfo *) NULL)
    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
  (void) ResetMagickMemory(memory_info,0,sizeof(*memory_info));
  extent=count*quantum;
  memory_info->length=extent;
  memory_info->signature=MagickCoreSignature;
  if (virtual_anonymous_memory < 0)
    {
      char
        *value;

      /*
        Does the security policy require anonymous mapping for pixel cache?
      */
      virtual_anonymous_memory=0;
      value=GetPolicyValue("system:memory-map");
      if (LocaleCompare(value,"anonymous") == 0)
        {
#if defined(MAGICKCORE_HAVE_MMAP) && defined(MAP_ANONYMOUS)
          virtual_anonymous_memory=1;
#endif
        }
      value=DestroyString(value);
    }
  if (virtual_anonymous_memory <= 0)
    {
      if (AcquireMagickResource(MemoryResource,extent) != MagickFalse)
        {
          memory_info->blob=AcquireAlignedMemory(1,extent);
          if (memory_info->blob != NULL)
            {
              memory_info->type=AlignedVirtualMemory;
              return(memory_info);
            }
        }
      RelinquishMagickResource(MemoryResource,extent);
    }
  else
    {
      if (AcquireMagickResource(MapResource,extent) != MagickFalse)
        {
          /*
            Acquire anonymous memory map.
          */
          memory_info->blob=MapBlob(-1,IOMode,0,extent);
          if (memory_info->blob != NULL)
            {
              memory_info->type=MapVirtualMemory;
              return(memory_info);
            }
          if (AcquireMagickResource(DiskResource,extent) != MagickFalse)
            {
              int
                file;

              /*
                Anonymous memory mapping failed, try file-backed memory mapping.
                If the MapResource request failed, there is no point in trying
                file-backed memory mapping.
              */
              file=AcquireUniqueFileResource(memory_info->filename);
              if (file != -1)
                {
                  MagickOffsetType
                    offset;

                  offset=(MagickOffsetType) lseek(file,extent-1,SEEK_SET);
                  if ((offset == (MagickOffsetType) (extent-1)) &&
                      (write(file,"",1) == 1))
                    {
                      memory_info->blob=MapBlob(file,IOMode,0,extent);
                      if (memory_info->blob != NULL)
                        {
                          (void) close(file);
                          memory_info->type=MapVirtualMemory;
                          return(memory_info);
                        }
                    }
                  /*
                    File-backed memory mapping fail, delete the temporary file.
                  */
                  (void) close(file);
                  (void) RelinquishUniqueFileResource(memory_info->filename);
                  *memory_info->filename = '\0';
                }
            }
          RelinquishMagickResource(DiskResource,extent);
        }
      RelinquishMagickResource(MapResource,extent);
    }
  if ((memory_info->blob == NULL) &&
      (AcquireMagickResource(MemoryResource,extent) != MagickFalse))
    {
      memory_info->blob=AcquireMagickMemory(extent);
      if (memory_info->blob != NULL)
        memory_info->type=UnalignedVirtualMemory;
      RelinquishMagickResource(MemoryResource,extent);
    }
  if (memory_info->blob == NULL)
    memory_info=RelinquishVirtualMemory(memory_info);
  return(memory_info);
}

Project: ImageMagick

MagickExport void *AcquireMagickMemory(const size_t size)
{
  register void
    *memory;

#if !defined(MAGICKCORE_ANONYMOUS_MEMORY_SUPPORT)
  memory=memory_methods.acquire_memory_handler(size == 0 ? 1UL : size);
#else
  if (memory_semaphore == (SemaphoreInfo *) NULL)
    ActivateSemaphoreInfo(&memory_semaphore);
  if (free_segments == (DataSegmentInfo *) NULL)
    {
      LockSemaphoreInfo(memory_semaphore);
      if (free_segments == (DataSegmentInfo *) NULL)
        {
          register ssize_t
            i;

          assert(2*sizeof(size_t) > (size_t) (~SizeMask));
          (void) ResetMagickMemory(&memory_pool,0,sizeof(memory_pool));
          memory_pool.allocation=SegmentSize;
          memory_pool.blocks[MaxBlocks]=(void *) (-1);
          for (i=0; i < MaxSegments; i++)
          {
            if (i != 0)
              memory_pool.segment_pool[i].previous=
                (&memory_pool.segment_pool[i-1]);
            if (i != (MaxSegments-1))
              memory_pool.segment_pool[i].next=(&memory_pool.segment_pool[i+1]);
          }
          free_segments=(&memory_pool.segment_pool[0]);
        }
      UnlockSemaphoreInfo(memory_semaphore);
    }
  LockSemaphoreInfo(memory_semaphore);
  memory=AcquireBlock(size == 0 ? 1UL : size);
  if (memory == (void *) NULL)
    {
      if (ExpandHeap(size == 0 ? 1UL : size) != MagickFalse)
        memory=AcquireBlock(size == 0 ? 1UL : size);
    }
  UnlockSemaphoreInfo(memory_semaphore);
#endif
  return(memory);
}

Project: ImageMagick

MagickExport void *ResizeMagickMemory(void *memory,const size_t size)
{
  register void
    *block;

  if (memory == (void *) NULL)
    return(AcquireMagickMemory(size));
#if !defined(MAGICKCORE_ANONYMOUS_MEMORY_SUPPORT)
  block=memory_methods.resize_memory_handler(memory,size == 0 ? 1UL : size);
  if (block == (void *) NULL)
    memory=RelinquishMagickMemory(memory);
#else
  LockSemaphoreInfo(memory_semaphore);
  block=ResizeBlock(memory,size == 0 ? 1UL : size);
  if (block == (void *) NULL)
    {
      if (ExpandHeap(size == 0 ? 1UL : size) == MagickFalse)
        {
          UnlockSemaphoreInfo(memory_semaphore);
          memory=RelinquishMagickMemory(memory);
          ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
        }
      block=ResizeBlock(memory,size == 0 ? 1UL : size);
      assert(block != (void *) NULL);
    }
  UnlockSemaphoreInfo(memory_semaphore);
  memory=RelinquishMagickMemory(memory);
#endif
  return(block);
}

Project: ImageMagick

MagickExport void *AcquireAlignedMemory(const size_t count,const size_t quantum)
{
#define AlignedExtent(size,alignment) \
  (((size)+((alignment)-1)) & ~((alignment)-1))

  size_t
    alignment,
    extent,
    size;

  void
    *memory;

  if (HeapOverflowSanityCheck(count,quantum) != MagickFalse)
    return((void *) NULL);
  memory=NULL;
  size=count*quantum;
  alignment=CACHE_LINE_SIZE;
  if (size > (size_t) (GetMagickPageSize() >> 1))
    alignment=GetMagickPageSize();
  extent=AlignedExtent(size,CACHE_LINE_SIZE);
  if ((size == 0) || (extent < size))
    return((void *) NULL);
#if defined(MAGICKCORE_HAVE_POSIX_MEMALIGN)
  if (posix_memalign(&memory,alignment,extent) != 0)
    memory=NULL;
#elif defined(MAGICKCORE_HAVE__ALIGNED_MALLOC)
  memory=_aligned_malloc(extent,alignment);
#else
  {
    void
      *p;

    extent=(size+alignment-1)+sizeof(void *);
    if (extent > size)
      {
        p=malloc(extent);
        if (p != NULL)
          {
            memory=(void *) AlignedExtent((size_t) p+sizeof(void *),alignment);
            *((void **) memory-1)=p;
          }
      }
  }
#endif
  return(memory);
}

Project: ImageMagick

MagickExport void DestroyMagickMemory(void)
{
#if defined(MAGICKCORE_ANONYMOUS_MEMORY_SUPPORT)
  register ssize_t
    i;

  if (memory_semaphore == (SemaphoreInfo *) NULL)
    ActivateSemaphoreInfo(&memory_semaphore);
  LockSemaphoreInfo(memory_semaphore);
  for (i=0; i < (ssize_t) memory_pool.number_segments; i++)
    if (memory_pool.segments[i]->mapped == MagickFalse)
      memory_methods.destroy_memory_handler(
        memory_pool.segments[i]->allocation);
    else
      (void) UnmapBlob(memory_pool.segments[i]->allocation,
        memory_pool.segments[i]->length);
  free_segments=(DataSegmentInfo *) NULL;
  (void) ResetMagickMemory(&memory_pool,0,sizeof(memory_pool));
  UnlockSemaphoreInfo(memory_semaphore);
  RelinquishSemaphoreInfo(&memory_semaphore);
#endif
}