x86/acpi: Prevent out of bound access caused by broken ACPI tables

The bus_irq argument of mp_override_legacy_irq() is used as the index into
the isa_irq_to_gsi[] array. The bus_irq argument originates from
ACPI_MADT_TYPE_IO_APIC and ACPI_MADT_TYPE_INTERRUPT items in the ACPI
tables, but is nowhere sanity checked.

That allows broken or malicious ACPI tables to overwrite memory, which
might cause malfunction, panic or arbitrary code execution.

Add a sanity check and emit a warning when that triggers.

[ tglx: Added warning and rewrote changelog ]

Signed-off-by: Seunghun Han <kkamagui@gmail.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: security@kernel.org
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: stable@vger.kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>

static void __init mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger,
					  u32 gsi)
{
	int ioapic;
	int pin;
	struct mpc_intsrc mp_irq;

	/*
	 * Convert 'gsi' to 'ioapic.pin'.
	 */
	ioapic = mp_find_ioapic(gsi);
	if (ioapic < 0)
		return;
	pin = mp_find_ioapic_pin(ioapic, gsi);

	/*
	 * TBD: This check is for faulty timer entries, where the override
	 *      erroneously sets the trigger to level, resulting in a HUGE
	 *      increase of timer interrupts!
	 */
	if ((bus_irq == 0) && (trigger == 3))
		trigger = 1;

	mp_irq.type = MP_INTSRC;
	mp_irq.irqtype = mp_INT;
	mp_irq.irqflag = (trigger << 2) | polarity;
	mp_irq.srcbus = MP_ISA_BUS;
	mp_irq.srcbusirq = bus_irq;	/* IRQ */
	mp_irq.dstapic = mpc_ioapic_id(ioapic); /* APIC ID */
	mp_irq.dstirq = pin;	/* INTIN# */

	mp_save_irq(&mp_irq);

	/*
	 * Reset default identity mapping if gsi is also an legacy IRQ,
	 * otherwise there will be more than one entry with the same GSI
	 * and acpi_isa_irq_to_gsi() may give wrong result.
	 */
	if (gsi < nr_legacy_irqs() && isa_irq_to_gsi[gsi] == gsi)
		isa_irq_to_gsi[gsi] = ACPI_INVALID_GSI;
	isa_irq_to_gsi[bus_irq] = gsi;
}

Buffer overflow in the mp_override_legacy_irq() function in arch/x86/kernel/acpi/boot.c in the Linux kernel through 3.2 allows local users to gain privileges via a crafted ACPI table.


static void __init mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger,
					  u32 gsi)
{
	int ioapic;
	int pin;
	struct mpc_intsrc mp_irq;

	/*
	 * Check bus_irq boundary.
	 */
	if (bus_irq >= NR_IRQS_LEGACY) {
		pr_warn("Invalid bus_irq %u for legacy override\n", bus_irq);
		return;
	}

	/*
	 * Convert 'gsi' to 'ioapic.pin'.
	 */
	ioapic = mp_find_ioapic(gsi);
	if (ioapic < 0)
		return;
	pin = mp_find_ioapic_pin(ioapic, gsi);

	/*
	 * TBD: This check is for faulty timer entries, where the override
	 *      erroneously sets the trigger to level, resulting in a HUGE
	 *      increase of timer interrupts!
	 */
	if ((bus_irq == 0) && (trigger == 3))
		trigger = 1;

	mp_irq.type = MP_INTSRC;
	mp_irq.irqtype = mp_INT;
	mp_irq.irqflag = (trigger << 2) | polarity;
	mp_irq.srcbus = MP_ISA_BUS;
	mp_irq.srcbusirq = bus_irq;	/* IRQ */
	mp_irq.dstapic = mpc_ioapic_id(ioapic); /* APIC ID */
	mp_irq.dstirq = pin;	/* INTIN# */

	mp_save_irq(&mp_irq);

	/*
	 * Reset default identity mapping if gsi is also an legacy IRQ,
	 * otherwise there will be more than one entry with the same GSI
	 * and acpi_isa_irq_to_gsi() may give wrong result.
	 */
	if (gsi < nr_legacy_irqs() && isa_irq_to_gsi[gsi] == gsi)
		isa_irq_to_gsi[gsi] = ACPI_INVALID_GSI;
	isa_irq_to_gsi[bus_irq] = gsi;
}


rsa: Add exponent blinding.

* cipher/rsa.c (secret_core_crt): Blind secret D with randomized
nonce R for mpi_powm computation.

--

Co-authored-by: Werner Koch <wk@gnupg.org>
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>

The paper describing attack: https://eprint.iacr.org/2017/627

Sliding right into disaster: Left-to-right sliding windows leak
by Daniel J. Bernstein and Joachim Breitner and Daniel Genkin and
Leon Groot Bruinderink and Nadia Heninger and Tanja Lange and
Christine van Vredendaal and Yuval Yarom

  It is well known that constant-time implementations of modular
  exponentiation cannot use sliding windows. However, software
  libraries such as Libgcrypt, used by GnuPG, continue to use sliding
  windows. It is widely believed that, even if the complete pattern of
  squarings and multiplications is observed through a side-channel
  attack, the number of exponent bits leaked is not sufficient to
  carry out a full key-recovery attack against RSA. Specifically,
  4-bit sliding windows leak only 40% of the bits, and 5-bit sliding
  windows leak only 33% of the bits.

  In this paper we demonstrate a complete break of RSA-1024 as
  implemented in Libgcrypt. Our attack makes essential use of the fact
  that Libgcrypt uses the left-to-right method for computing the
  sliding-window expansion. We show for the first time that the
  direction of the encoding matters: the pattern of squarings and
  multiplications in left-to-right sliding windows leaks significantly
  more information about exponent bits than for right-to-left. We show
  how to incorporate this additional information into the
  Heninger-Shacham algorithm for partial key reconstruction, and use
  it to obtain very efficient full key recovery for RSA-1024. We also
  provide strong evidence that the same attack works for RSA-2048 with
  only moderately more computation.

Exponent blinding is a kind of workaround to add noise.  Signal (leak)
is still there for non-constant-time implementation.

secret_core_crt (gcry_mpi_t M, gcry_mpi_t C,
                 gcry_mpi_t D, unsigned int Nlimbs,
                 gcry_mpi_t P, gcry_mpi_t Q, gcry_mpi_t U)
{
  gcry_mpi_t m1 = mpi_alloc_secure ( Nlimbs + 1 );
  gcry_mpi_t m2 = mpi_alloc_secure ( Nlimbs + 1 );
  gcry_mpi_t h  = mpi_alloc_secure ( Nlimbs + 1 );

  /* m1 = c ^ (d mod (p-1)) mod p */
  mpi_sub_ui ( h, P, 1 );
  mpi_fdiv_r ( h, D, h );
  mpi_powm ( m1, C, h, P );

  /* m2 = c ^ (d mod (q-1)) mod q */
  mpi_sub_ui ( h, Q, 1  );
  mpi_fdiv_r ( h, D, h );
  mpi_powm ( m2, C, h, Q );

  /* h = u * ( m2 - m1 ) mod q */
  mpi_sub ( h, m2, m1 );
  if ( mpi_has_sign ( h ) )
    mpi_add ( h, h, Q );
  mpi_mulm ( h, U, h, Q );

  /* m = m1 + h * p */
  mpi_mul ( h, h, P );
  mpi_add ( M, m1, h );

  mpi_free ( h );
  mpi_free ( m1 );
  mpi_free ( m2 );
}

libgcrypt before version 1.7.8 is vulnerable to a cache side-channel attack resulting into a complete break of RSA-1024 while using the left-to-right method for computing the sliding-window expansion. The same attack is believed to work on RSA-2048 with moderately more computation. This side-channel requires that attacker can run arbitrary software on the hardware where the private RSA key is used.


secret_core_crt (gcry_mpi_t M, gcry_mpi_t C,
                 gcry_mpi_t D, unsigned int Nlimbs,
                 gcry_mpi_t P, gcry_mpi_t Q, gcry_mpi_t U)
{
  gcry_mpi_t m1 = mpi_alloc_secure ( Nlimbs + 1 );
  gcry_mpi_t m2 = mpi_alloc_secure ( Nlimbs + 1 );
  gcry_mpi_t h  = mpi_alloc_secure ( Nlimbs + 1 );
  gcry_mpi_t D_blind = mpi_alloc_secure ( Nlimbs + 1 );
  gcry_mpi_t r;
  unsigned int r_nbits;

  r_nbits = mpi_get_nbits (P) / 4;
  if (r_nbits < 96)
    r_nbits = 96;
  r = mpi_alloc_secure ( (r_nbits + BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB );

  /* d_blind = (d mod (p-1)) + (p-1) * r            */
  /* m1 = c ^ d_blind mod p */
  _gcry_mpi_randomize (r, r_nbits, GCRY_WEAK_RANDOM);
  mpi_set_highbit (r, r_nbits - 1);
  mpi_sub_ui ( h, P, 1 );
  mpi_mul ( D_blind, h, r );
  mpi_fdiv_r ( h, D, h );
  mpi_add ( D_blind, D_blind, h );
  mpi_powm ( m1, C, D_blind, P );

  /* d_blind = (d mod (q-1)) + (q-1) * r            */
  /* m2 = c ^ d_blind mod q */
  _gcry_mpi_randomize (r, r_nbits, GCRY_WEAK_RANDOM);
  mpi_set_highbit (r, r_nbits - 1);
  mpi_sub_ui ( h, Q, 1  );
  mpi_mul ( D_blind, h, r );
  mpi_fdiv_r ( h, D, h );
  mpi_add ( D_blind, D_blind, h );
  mpi_powm ( m2, C, D_blind, Q );

  mpi_free ( r );
  mpi_free ( D_blind );

  /* h = u * ( m2 - m1 ) mod q */
  mpi_sub ( h, m2, m1 );
  if ( mpi_has_sign ( h ) )
    mpi_add ( h, h, Q );
  mpi_mulm ( h, U, h, Q );

  /* m = m1 + h * p */
  mpi_mul ( h, h, P );
  mpi_add ( M, m1, h );

  mpi_free ( h );
  mpi_free ( m1 );
  mpi_free ( m2 );
}


static MagickBooleanType WriteDPXImage(const ImageInfo *image_info,Image *image,
  ExceptionInfo *exception)
{
  const char
    *value;

  const StringInfo
    *profile;

  DPXInfo
    dpx;

  GeometryInfo
    geometry_info;

  MagickBooleanType
    status;

  MagickOffsetType
    offset;

  MagickStatusType
    flags;

  QuantumInfo
    *quantum_info;

  QuantumType
    quantum_type;

  register const Quantum
    *p;

  register ssize_t
    i;

  size_t
    channels,
    extent;

  ssize_t
    count,
    horizontal_factor,
    vertical_factor,
    y;

  time_t
    seconds;

  unsigned char
    *pixels;

  /*
    Open output image file.
  */
  assert(image_info != (const ImageInfo *) NULL);
  assert(image_info->signature == MagickCoreSignature);
  assert(image != (Image *) NULL);
  assert(image->signature == MagickCoreSignature);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  horizontal_factor=4;
  vertical_factor=4;
  if (image_info->sampling_factor != (char *) NULL)
    {
      flags=ParseGeometry(image_info->sampling_factor,&geometry_info);
      horizontal_factor=(ssize_t) geometry_info.rho;
      vertical_factor=(ssize_t) geometry_info.sigma;
      if ((flags & SigmaValue) == 0)
        vertical_factor=horizontal_factor;
      if ((horizontal_factor != 1) && (horizontal_factor != 2) &&
          (horizontal_factor != 4) && (vertical_factor != 1) &&
          (vertical_factor != 2) && (vertical_factor != 4))
        ThrowWriterException(CorruptImageError,"UnexpectedSamplingFactor");
    }
  if ((image->colorspace == YCbCrColorspace) &&
      ((horizontal_factor == 2) || (vertical_factor == 2)))
    if ((image->columns % 2) != 0)
      image->columns++;
  assert(exception != (ExceptionInfo *) NULL);
  assert(exception->signature == MagickCoreSignature);
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
  if (status == MagickFalse)
    return(status);
  /*
    Write file header.
  */
  (void) memset(&dpx,0,sizeof(dpx));
  offset=0;
  dpx.file.magic=0x53445058U;
  offset+=WriteBlobLong(image,dpx.file.magic);
  dpx.file.image_offset=0x2000U;
  profile=GetImageProfile(image,"dpx:user-data");
  if (profile != (StringInfo *) NULL)
    {
      if (GetStringInfoLength(profile) > 1048576)
        ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
      dpx.file.image_offset+=(unsigned int) GetStringInfoLength(profile);
      dpx.file.image_offset=(((dpx.file.image_offset+0x2000-1)/0x2000)*0x2000);
    }
  offset+=WriteBlobLong(image,dpx.file.image_offset);
  (void) strncpy(dpx.file.version,"V2.0",sizeof(dpx.file.version)-1);
  offset+=WriteBlob(image,8,(unsigned char *) &dpx.file.version);
  channels=1;
  if (IsImageGray(image) == MagickFalse)
    channels=3;
  if (image->alpha_trait != UndefinedPixelTrait)
    channels++;
  dpx.file.file_size=(unsigned int) (channels*image->columns*image->rows+
    dpx.file.image_offset);
  offset+=WriteBlobLong(image,dpx.file.file_size);
  dpx.file.ditto_key=1U;  /* new frame */
  offset+=WriteBlobLong(image,dpx.file.ditto_key);
  dpx.file.generic_size=0x00000680U;
  offset+=WriteBlobLong(image,dpx.file.generic_size);
  dpx.file.industry_size=0x00000180U;
  offset+=WriteBlobLong(image,dpx.file.industry_size);
  dpx.file.user_size=0;
  if (profile != (StringInfo *) NULL)
    {
      dpx.file.user_size+=(unsigned int) GetStringInfoLength(profile);
      dpx.file.user_size=(((dpx.file.user_size+0x2000-1)/0x2000)*0x2000);
    }
  offset+=WriteBlobLong(image,dpx.file.user_size);
  value=GetDPXProperty(image,"dpx:file.filename",exception);
  if (value != (const char *) NULL)
    (void) strncpy(dpx.file.filename,value,sizeof(dpx.file.filename)-1);
  offset+=WriteBlob(image,sizeof(dpx.file.filename),(unsigned char *)
    dpx.file.filename);
  seconds=time((time_t *) NULL);
  (void) FormatMagickTime(seconds,sizeof(dpx.file.timestamp),
    dpx.file.timestamp);
  offset+=WriteBlob(image,sizeof(dpx.file.timestamp),(unsigned char *)
    dpx.file.timestamp);
  (void) strncpy(dpx.file.creator,MagickAuthoritativeURL,
    sizeof(dpx.file.creator)-1);
  value=GetDPXProperty(image,"dpx:file.creator",exception);
  if (value != (const char *) NULL)
    (void) strncpy(dpx.file.creator,value,sizeof(dpx.file.creator)-1);
  offset+=WriteBlob(image,sizeof(dpx.file.creator),(unsigned char *)
    dpx.file.creator);
  value=GetDPXProperty(image,"dpx:file.project",exception);
  if (value != (const char *) NULL)
    (void) strncpy(dpx.file.project,value,sizeof(dpx.file.project)-1);
  offset+=WriteBlob(image,sizeof(dpx.file.project),(unsigned char *)
    dpx.file.project);
  value=GetDPXProperty(image,"dpx:file.copyright",exception);
  if (value != (const char *) NULL)
    (void) strncpy(dpx.file.copyright,value,sizeof(dpx.file.copyright)-1);
  offset+=WriteBlob(image,sizeof(dpx.file.copyright),(unsigned char *)
    dpx.file.copyright);
  dpx.file.encrypt_key=(~0U);
  offset+=WriteBlobLong(image,dpx.file.encrypt_key);
  offset+=WriteBlob(image,sizeof(dpx.file.reserve),(unsigned char *)
    dpx.file.reserve);
  /*
    Write image header.
  */
  switch (image->orientation)
  {
    default:
    case TopLeftOrientation: dpx.image.orientation=0; break;
    case TopRightOrientation: dpx.image.orientation=1; break;
    case BottomLeftOrientation: dpx.image.orientation=2; break;
    case BottomRightOrientation: dpx.image.orientation=3; break;
    case LeftTopOrientation: dpx.image.orientation=4; break;
    case RightTopOrientation: dpx.image.orientation=5; break;
    case LeftBottomOrientation: dpx.image.orientation=6; break;
    case RightBottomOrientation: dpx.image.orientation=7; break;
  }
  offset+=WriteBlobShort(image,dpx.image.orientation);
  dpx.image.number_elements=1;
  offset+=WriteBlobShort(image,dpx.image.number_elements);
  if ((image->columns != (unsigned int) image->columns) ||
      (image->rows != (unsigned int) image->rows))
    ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
  offset+=WriteBlobLong(image,(unsigned int) image->columns);
  offset+=WriteBlobLong(image,(unsigned int) image->rows);
  for (i=0; i < 8; i++)
  {
    dpx.image.image_element[i].data_sign=0U;
    offset+=WriteBlobLong(image,dpx.image.image_element[i].data_sign);
    dpx.image.image_element[i].low_data=0U;
    offset+=WriteBlobLong(image,dpx.image.image_element[i].low_data);
    dpx.image.image_element[i].low_quantity=0.0f;
    offset+=WriteBlobFloat(image,dpx.image.image_element[i].low_quantity);
    dpx.image.image_element[i].high_data=0U;
    offset+=WriteBlobLong(image,dpx.image.image_element[i].high_data);
    dpx.image.image_element[i].high_quantity=0.0f;
    offset+=WriteBlobFloat(image,dpx.image.image_element[i].high_quantity);
    dpx.image.image_element[i].descriptor=0;
    if (i == 0)
      switch (image->colorspace)
      {
        case Rec601YCbCrColorspace:
        case Rec709YCbCrColorspace:
        case YCbCrColorspace:
        {
          dpx.image.image_element[i].descriptor=CbYCr444ComponentType;
          if (image->alpha_trait != UndefinedPixelTrait)
            dpx.image.image_element[i].descriptor=CbYCrA4444ComponentType;
          break;
        }
        default:
        {
          dpx.image.image_element[i].descriptor=RGBComponentType;
          if (image->alpha_trait != UndefinedPixelTrait)
            dpx.image.image_element[i].descriptor=RGBAComponentType;
          if ((image_info->type != TrueColorType) &&
              (image->alpha_trait == UndefinedPixelTrait) &&
              (SetImageGray(image,exception) != MagickFalse))
            dpx.image.image_element[i].descriptor=LumaComponentType;
          break;
        }
      }
    offset+=WriteBlobByte(image,dpx.image.image_element[i].descriptor);
    dpx.image.image_element[i].transfer_characteristic=0;
    if (image->colorspace == LogColorspace)
      dpx.image.image_element[0].transfer_characteristic=
        PrintingDensityColorimetric;
    offset+=WriteBlobByte(image,
      dpx.image.image_element[i].transfer_characteristic);
    dpx.image.image_element[i].colorimetric=0;
    offset+=WriteBlobByte(image,dpx.image.image_element[i].colorimetric);
    dpx.image.image_element[i].bit_size=0;
    if (i == 0)
      dpx.image.image_element[i].bit_size=(unsigned char) image->depth;
    offset+=WriteBlobByte(image,dpx.image.image_element[i].bit_size);
    dpx.image.image_element[i].packing=0;
    if ((image->depth == 10) || (image->depth == 12))
      dpx.image.image_element[i].packing=1;
    offset+=WriteBlobShort(image,dpx.image.image_element[i].packing);
    dpx.image.image_element[i].encoding=0;
    offset+=WriteBlobShort(image,dpx.image.image_element[i].encoding);
    dpx.image.image_element[i].data_offset=0U;
    if (i == 0)
      dpx.image.image_element[i].data_offset=dpx.file.image_offset;
    offset+=WriteBlobLong(image,dpx.image.image_element[i].data_offset);
    dpx.image.image_element[i].end_of_line_padding=0U;
    offset+=WriteBlobLong(image,dpx.image.image_element[i].end_of_line_padding);
    offset+=WriteBlobLong(image,
      dpx.image.image_element[i].end_of_image_padding);
    offset+=WriteBlob(image,sizeof(dpx.image.image_element[i].description),
      (unsigned char *) dpx.image.image_element[i].description);
  }
  offset+=WriteBlob(image,sizeof(dpx.image.reserve),(unsigned char *)
    dpx.image.reserve);
  /*
    Write orientation header.
  */
  if ((image->rows != image->magick_rows) ||
      (image->columns != image->magick_columns))
    {
      /*
        These properties are not valid if image size changed.
      */
      (void) DeleteImageProperty(image,"dpx:orientation.x_offset");
      (void) DeleteImageProperty(image,"dpx:orientation.y_offset");
      (void) DeleteImageProperty(image,"dpx:orientation.x_center");
      (void) DeleteImageProperty(image,"dpx:orientation.y_center");
      (void) DeleteImageProperty(image,"dpx:orientation.x_size");
      (void) DeleteImageProperty(image,"dpx:orientation.y_size");
    }
  dpx.orientation.x_offset=0U;
  value=GetDPXProperty(image,"dpx:orientation.x_offset",exception);
  if (value != (const char *) NULL)
    dpx.orientation.x_offset=(unsigned int) StringToUnsignedLong(value);
  offset+=WriteBlobLong(image,dpx.orientation.x_offset);
  dpx.orientation.y_offset=0U;
  value=GetDPXProperty(image,"dpx:orientation.y_offset",exception);
  if (value != (const char *) NULL)
    dpx.orientation.y_offset=(unsigned int) StringToUnsignedLong(value);
  offset+=WriteBlobLong(image,dpx.orientation.y_offset);
  dpx.orientation.x_center=0.0f;
  value=GetDPXProperty(image,"dpx:orientation.x_center",exception);
  if (value != (const char *) NULL)
    dpx.orientation.x_center=StringToDouble(value,(char **) NULL);
  offset+=WriteBlobFloat(image,dpx.orientation.x_center);
  dpx.orientation.y_center=0.0f;
  value=GetDPXProperty(image,"dpx:orientation.y_center",exception);
  if (value != (const char *) NULL)
    dpx.orientation.y_center=StringToDouble(value,(char **) NULL);
  offset+=WriteBlobFloat(image,dpx.orientation.y_center);
  dpx.orientation.x_size=0U;
  value=GetDPXProperty(image,"dpx:orientation.x_size",exception);
  if (value != (const char *) NULL)
    dpx.orientation.x_size=(unsigned int) StringToUnsignedLong(value);
  offset+=WriteBlobLong(image,dpx.orientation.x_size);
  dpx.orientation.y_size=0U;
  value=GetDPXProperty(image,"dpx:orientation.y_size",exception);
  if (value != (const char *) NULL)
    dpx.orientation.y_size=(unsigned int) StringToUnsignedLong(value);
  offset+=WriteBlobLong(image,dpx.orientation.y_size);
  value=GetDPXProperty(image,"dpx:orientation.filename",exception);
  if (value != (const char *) NULL)
    (void) strncpy(dpx.orientation.filename,value,
      sizeof(dpx.orientation.filename)-1);
  offset+=WriteBlob(image,sizeof(dpx.orientation.filename),(unsigned char *)
    dpx.orientation.filename);
  offset+=WriteBlob(image,sizeof(dpx.orientation.timestamp),(unsigned char *)
    dpx.orientation.timestamp);
  value=GetDPXProperty(image,"dpx:orientation.device",exception);
  if (value != (const char *) NULL)
    (void) strncpy(dpx.orientation.device,value,
      sizeof(dpx.orientation.device)-1);
  offset+=WriteBlob(image,sizeof(dpx.orientation.device),(unsigned char *)
    dpx.orientation.device);
  value=GetDPXProperty(image,"dpx:orientation.serial",exception);
  if (value != (const char *) NULL)
    (void) strncpy(dpx.orientation.serial,value,
      sizeof(dpx.orientation.serial)-1);
  offset+=WriteBlob(image,sizeof(dpx.orientation.serial),(unsigned char *)
    dpx.orientation.serial);
  for (i=0; i < 4; i++)
    dpx.orientation.border[i]=0;
  value=GetDPXProperty(image,"dpx:orientation.border",exception);
  if (value != (const char *) NULL)
    {
      flags=ParseGeometry(value,&geometry_info);
      if ((flags & SigmaValue) == 0)
        geometry_info.sigma=geometry_info.rho;
      dpx.orientation.border[0]=(unsigned short) (geometry_info.rho+0.5);
      dpx.orientation.border[1]=(unsigned short) (geometry_info.sigma+0.5);
      dpx.orientation.border[2]=(unsigned short) (geometry_info.xi+0.5);
      dpx.orientation.border[3]=(unsigned short) (geometry_info.psi+0.5);
    }
  for (i=0; i < 4; i++)
    offset+=WriteBlobShort(image,dpx.orientation.border[i]);
  for (i=0; i < 2; i++)
    dpx.orientation.aspect_ratio[i]=0U;
  value=GetDPXProperty(image,"dpx:orientation.aspect_ratio",exception);
  if (value != (const char *) NULL)
    {
      flags=ParseGeometry(value,&geometry_info);
      if ((flags & SigmaValue) == 0)
        geometry_info.sigma=geometry_info.rho;
      dpx.orientation.aspect_ratio[0]=(unsigned int) (geometry_info.rho+0.5);
      dpx.orientation.aspect_ratio[1]=(unsigned int) (geometry_info.sigma+0.5);
    }
  for (i=0; i < 2; i++)
    offset+=WriteBlobLong(image,dpx.orientation.aspect_ratio[i]);
  offset+=WriteBlob(image,sizeof(dpx.orientation.reserve),(unsigned char *)
    dpx.orientation.reserve);
  /*
    Write film header.
  */
  (void) memset(dpx.film.id,0,sizeof(dpx.film.id));
  value=GetDPXProperty(image,"dpx:film.id",exception);
  if (value != (const char *) NULL)
    (void) strncpy(dpx.film.id,value,sizeof(dpx.film.id)-1);
  offset+=WriteBlob(image,sizeof(dpx.film.id),(unsigned char *) dpx.film.id);
  (void) memset(dpx.film.type,0,sizeof(dpx.film.type));
  value=GetDPXProperty(image,"dpx:film.type",exception);
  if (value != (const char *) NULL)
    (void) strncpy(dpx.film.type,value,sizeof(dpx.film.type)-1);
  offset+=WriteBlob(image,sizeof(dpx.film.type),(unsigned char *)
    dpx.film.type);
  (void) memset(dpx.film.offset,0,sizeof(dpx.film.offset));
  value=GetDPXProperty(image,"dpx:film.offset",exception);
  if (value != (const char *) NULL)
    (void) strncpy(dpx.film.offset,value,sizeof(dpx.film.offset)-1);
  offset+=WriteBlob(image,sizeof(dpx.film.offset),(unsigned char *)
    dpx.film.offset);
  (void) memset(dpx.film.prefix,0,sizeof(dpx.film.prefix));
  value=GetDPXProperty(image,"dpx:film.prefix",exception);
  if (value != (const char *) NULL)
    (void) strncpy(dpx.film.prefix,value,sizeof(dpx.film.prefix)-1);
  offset+=WriteBlob(image,sizeof(dpx.film.prefix),(unsigned char *)
    dpx.film.prefix);
  (void) memset(dpx.film.count,0,sizeof(dpx.film.count));
  value=GetDPXProperty(image,"dpx:film.count",exception);
  if (value != (const char *) NULL)
    (void) strncpy(dpx.film.count,value,sizeof(dpx.film.count)-1);
  offset+=WriteBlob(image,sizeof(dpx.film.count),(unsigned char *)
    dpx.film.count);
  (void) memset(dpx.film.format,0,sizeof(dpx.film.format));
  value=GetDPXProperty(image,"dpx:film.format",exception);
  if (value != (const char *) NULL)
    (void) strncpy(dpx.film.format,value,sizeof(dpx.film.format)-1);
  offset+=WriteBlob(image,sizeof(dpx.film.format),(unsigned char *)
    dpx.film.format);
  dpx.film.frame_position=0U;
  value=GetDPXProperty(image,"dpx:film.frame_position",exception);
  if (value != (const char *) NULL)
    dpx.film.frame_position=(unsigned int) StringToUnsignedLong(value);
  offset+=WriteBlobLong(image,dpx.film.frame_position);
  dpx.film.sequence_extent=0U;
  value=GetDPXProperty(image,"dpx:film.sequence_extent",exception);
  if (value != (const char *) NULL)
    dpx.film.sequence_extent=(unsigned int) StringToUnsignedLong(value);
  offset+=WriteBlobLong(image,dpx.film.sequence_extent);
  dpx.film.held_count=0U;
  value=GetDPXProperty(image,"dpx:film.held_count",exception);
  if (value != (const char *) NULL)
    dpx.film.held_count=(unsigned int) StringToUnsignedLong(value);
  offset+=WriteBlobLong(image,dpx.film.held_count);
  dpx.film.frame_rate=0.0f;
  value=GetDPXProperty(image,"dpx:film.frame_rate",exception);
  if (value != (const char *) NULL)
    dpx.film.frame_rate=StringToDouble(value,(char **) NULL);
  offset+=WriteBlobFloat(image,dpx.film.frame_rate);
  dpx.film.shutter_angle=0.0f;
  value=GetDPXProperty(image,"dpx:film.shutter_angle",exception);
  if (value != (const char *) NULL)
    dpx.film.shutter_angle=StringToDouble(value,(char **) NULL);
  offset+=WriteBlobFloat(image,dpx.film.shutter_angle);
  (void) memset(dpx.film.frame_id,0,sizeof(dpx.film.frame_id));
  value=GetDPXProperty(image,"dpx:film.frame_id",exception);
  if (value != (const char *) NULL)
    (void) strncpy(dpx.film.frame_id,value,sizeof(dpx.film.frame_id)-1);
  offset+=WriteBlob(image,sizeof(dpx.film.frame_id),(unsigned char *)
    dpx.film.frame_id);
  value=GetDPXProperty(image,"dpx:film.slate",exception);
  if (value != (const char *) NULL)
    (void) strncpy(dpx.film.slate,value,sizeof(dpx.film.slate)-1);
  offset+=WriteBlob(image,sizeof(dpx.film.slate),(unsigned char *)
    dpx.film.slate);
  offset+=WriteBlob(image,sizeof(dpx.film.reserve),(unsigned char *)
    dpx.film.reserve);
  /*
    Write television header.
  */
  value=GetDPXProperty(image,"dpx:television.time.code",exception);
  if (value != (const char *) NULL)
    dpx.television.time_code=StringToTimeCode(value);
  offset+=WriteBlobLong(image,dpx.television.time_code);
  value=GetDPXProperty(image,"dpx:television.user.bits",exception);
  if (value != (const char *) NULL)
    dpx.television.user_bits=StringToTimeCode(value);
  offset+=WriteBlobLong(image,dpx.television.user_bits);
  value=GetDPXProperty(image,"dpx:television.interlace",exception);
  if (value != (const char *) NULL)
    dpx.television.interlace=(unsigned char) StringToLong(value);
  offset+=WriteBlobByte(image,dpx.television.interlace);
  value=GetDPXProperty(image,"dpx:television.field_number",exception);
  if (value != (const char *) NULL)
    dpx.television.field_number=(unsigned char) StringToLong(value);
  offset+=WriteBlobByte(image,dpx.television.field_number);
  dpx.television.video_signal=0;
  value=GetDPXProperty(image,"dpx:television.video_signal",exception);
  if (value != (const char *) NULL)
    dpx.television.video_signal=(unsigned char) StringToLong(value);
  offset+=WriteBlobByte(image,dpx.television.video_signal);
  dpx.television.padding=0;
  value=GetDPXProperty(image,"dpx:television.padding",exception);
  if (value != (const char *) NULL)
    dpx.television.padding=(unsigned char) StringToLong(value);
  offset+=WriteBlobByte(image,dpx.television.padding);
  dpx.television.horizontal_sample_rate=0.0f;
  value=GetDPXProperty(image,"dpx:television.horizontal_sample_rate",
    exception);
  if (value != (const char *) NULL)
    dpx.television.horizontal_sample_rate=StringToDouble(value,(char **) NULL);
  offset+=WriteBlobFloat(image,dpx.television.horizontal_sample_rate);
  dpx.television.vertical_sample_rate=0.0f;
  value=GetDPXProperty(image,"dpx:television.vertical_sample_rate",exception);
  if (value != (const char *) NULL)
    dpx.television.vertical_sample_rate=StringToDouble(value,(char **) NULL);
  offset+=WriteBlobFloat(image,dpx.television.vertical_sample_rate);
  dpx.television.frame_rate=0.0f;
  value=GetDPXProperty(image,"dpx:television.frame_rate",exception);
  if (value != (const char *) NULL)
    dpx.television.frame_rate=StringToDouble(value,(char **) NULL);
  offset+=WriteBlobFloat(image,dpx.television.frame_rate);
  dpx.television.time_offset=0.0f;
  value=GetDPXProperty(image,"dpx:television.time_offset",exception);
  if (value != (const char *) NULL)
    dpx.television.time_offset=StringToDouble(value,(char **) NULL);
  offset+=WriteBlobFloat(image,dpx.television.time_offset);
  dpx.television.gamma=0.0f;
  value=GetDPXProperty(image,"dpx:television.gamma",exception);
  if (value != (const char *) NULL)
    dpx.television.gamma=StringToDouble(value,(char **) NULL);
  offset+=WriteBlobFloat(image,dpx.television.gamma);
  dpx.television.black_level=0.0f;
  value=GetDPXProperty(image,"dpx:television.black_level",exception);
  if (value != (const char *) NULL)
    dpx.television.black_level=StringToDouble(value,(char **) NULL);
  offset+=WriteBlobFloat(image,dpx.television.black_level);
  dpx.television.black_gain=0.0f;
  value=GetDPXProperty(image,"dpx:television.black_gain",exception);
  if (value != (const char *) NULL)
    dpx.television.black_gain=StringToDouble(value,(char **) NULL);
  offset+=WriteBlobFloat(image,dpx.television.black_gain);
  dpx.television.break_point=0.0f;
  value=GetDPXProperty(image,"dpx:television.break_point",exception);
  if (value != (const char *) NULL)
    dpx.television.break_point=StringToDouble(value,(char **) NULL);
  offset+=WriteBlobFloat(image,dpx.television.break_point);
  dpx.television.white_level=0.0f;
  value=GetDPXProperty(image,"dpx:television.white_level",exception);
  if (value != (const char *) NULL)
    dpx.television.white_level=StringToDouble(value,(char **) NULL);
  offset+=WriteBlobFloat(image,dpx.television.white_level);
  dpx.television.integration_times=0.0f;
  value=GetDPXProperty(image,"dpx:television.integration_times",exception);
  if (value != (const char *) NULL)
    dpx.television.integration_times=StringToDouble(value,(char **) NULL);
  offset+=WriteBlobFloat(image,dpx.television.integration_times);
  offset+=WriteBlob(image,sizeof(dpx.television.reserve),(unsigned char *)
    dpx.television.reserve);
  /*
    Write user header.
  */
  value=GetDPXProperty(image,"dpx:user.id",exception);
  if (value != (const char *) NULL)
    (void) strncpy(dpx.user.id,value,sizeof(dpx.user.id)-1);
  offset+=WriteBlob(image,sizeof(dpx.user.id),(unsigned char *) dpx.user.id);
  if (profile != (StringInfo *) NULL)
    offset+=WriteBlob(image,GetStringInfoLength(profile),
      GetStringInfoDatum(profile));
  while (offset < (MagickOffsetType) dpx.image.image_element[0].data_offset)
  {
    count=WriteBlobByte(image,0x00);
    if (count != 1)
      {
        ThrowFileException(exception,FileOpenError,"UnableToWriteFile",
          image->filename);
        break;
      }
    offset+=count;
  }
  /*
    Convert pixel packets to DPX raster image.
  */
  quantum_info=AcquireQuantumInfo(image_info,image);
  if (quantum_info == (QuantumInfo *) NULL)
    ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
  SetQuantumQuantum(quantum_info,32);
  SetQuantumPack(quantum_info,dpx.image.image_element[0].packing == 0 ?
    MagickTrue : MagickFalse);
  quantum_type=RGBQuantum;
  if (image->alpha_trait != UndefinedPixelTrait)
    quantum_type=RGBAQuantum;
  if (image->colorspace == YCbCrColorspace)
    {
      quantum_type=CbYCrQuantum;
      if (image->alpha_trait != UndefinedPixelTrait)
        quantum_type=CbYCrAQuantum;
      if ((horizontal_factor == 2) || (vertical_factor == 2))
        quantum_type=CbYCrYQuantum;
    }
  extent=GetBytesPerRow(image->columns,
    image->alpha_trait != UndefinedPixelTrait ? 4UL : 3UL,image->depth,
    dpx.image.image_element[0].packing == 0 ? MagickFalse : MagickTrue);
  if ((image_info->type != TrueColorType) &&
      (image->alpha_trait == UndefinedPixelTrait) &&
      (SetImageGray(image,exception) != MagickFalse))
    {
      quantum_type=GrayQuantum;
      extent=GetBytesPerRow(image->columns,1UL,image->depth,
        dpx.image.image_element[0].packing == 0 ? MagickFalse : MagickTrue);
    }
  pixels=(unsigned char *) GetQuantumPixels(quantum_info);
  for (y=0; y < (ssize_t) image->rows; y++)
  {
    size_t
      length;

    p=GetVirtualPixels(image,0,y,image->columns,1,exception);
    if (p == (const Quantum *) NULL)
      break;
    length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
      quantum_type,pixels,exception);
    count=WriteBlob(image,extent,pixels);
    if (count != (ssize_t) length)
      break;
    status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
      image->rows);
    if (status == MagickFalse)
      break;
  }
  quantum_info=DestroyQuantumInfo(quantum_info);
  if (y < (ssize_t) image->rows)
    ThrowWriterException(CorruptImageError,"UnableToWriteImageData");
  (void) CloseBlob(image);
  return(status);
}

ImageMagick 7.0.8-34 has a memory leak vulnerability in the WriteDPXImage function in coders/dpx.c.


static MagickBooleanType WriteDPXImage(const ImageInfo *image_info,Image *image,
  ExceptionInfo *exception)
{
  const char
    *value;

  const StringInfo
    *profile;

  DPXInfo
    dpx;

  GeometryInfo
    geometry_info;

  MagickBooleanType
    status;

  MagickOffsetType
    offset;

  MagickStatusType
    flags;

  QuantumInfo
    *quantum_info;

  QuantumType
    quantum_type;

  register const Quantum
    *p;

  register ssize_t
    i;

  size_t
    channels,
    extent;

  ssize_t
    count,
    horizontal_factor,
    vertical_factor,
    y;

  time_t
    seconds;

  unsigned char
    *pixels;

  /*
    Open output image file.
  */
  assert(image_info != (const ImageInfo *) NULL);
  assert(image_info->signature == MagickCoreSignature);
  assert(image != (Image *) NULL);
  assert(image->signature == MagickCoreSignature);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  horizontal_factor=4;
  vertical_factor=4;
  if (image_info->sampling_factor != (char *) NULL)
    {
      flags=ParseGeometry(image_info->sampling_factor,&geometry_info);
      horizontal_factor=(ssize_t) geometry_info.rho;
      vertical_factor=(ssize_t) geometry_info.sigma;
      if ((flags & SigmaValue) == 0)
        vertical_factor=horizontal_factor;
      if ((horizontal_factor != 1) && (horizontal_factor != 2) &&
          (horizontal_factor != 4) && (vertical_factor != 1) &&
          (vertical_factor != 2) && (vertical_factor != 4))
        ThrowWriterException(CorruptImageError,"UnexpectedSamplingFactor");
    }
  if ((image->colorspace == YCbCrColorspace) &&
      ((horizontal_factor == 2) || (vertical_factor == 2)))
    if ((image->columns % 2) != 0)
      image->columns++;
  assert(exception != (ExceptionInfo *) NULL);
  assert(exception->signature == MagickCoreSignature);
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
  if (status == MagickFalse)
    return(status);
  /*
    Write file header.
  */
  (void) memset(&dpx,0,sizeof(dpx));
  offset=0;
  dpx.file.magic=0x53445058U;
  offset+=WriteBlobLong(image,dpx.file.magic);
  dpx.file.image_offset=0x2000U;
  profile=GetImageProfile(image,"dpx:user-data");
  if (profile != (StringInfo *) NULL)
    {
      if (GetStringInfoLength(profile) > 1048576)
        ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
      dpx.file.image_offset+=(unsigned int) GetStringInfoLength(profile);
      dpx.file.image_offset=(((dpx.file.image_offset+0x2000-1)/0x2000)*0x2000);
    }
  offset+=WriteBlobLong(image,dpx.file.image_offset);
  (void) strncpy(dpx.file.version,"V2.0",sizeof(dpx.file.version)-1);
  offset+=WriteBlob(image,8,(unsigned char *) &dpx.file.version);
  channels=1;
  if (IsImageGray(image) == MagickFalse)
    channels=3;
  if (image->alpha_trait != UndefinedPixelTrait)
    channels++;
  dpx.file.file_size=(unsigned int) (channels*image->columns*image->rows+
    dpx.file.image_offset);
  offset+=WriteBlobLong(image,dpx.file.file_size);
  dpx.file.ditto_key=1U;  /* new frame */
  offset+=WriteBlobLong(image,dpx.file.ditto_key);
  dpx.file.generic_size=0x00000680U;
  offset+=WriteBlobLong(image,dpx.file.generic_size);
  dpx.file.industry_size=0x00000180U;
  offset+=WriteBlobLong(image,dpx.file.industry_size);
  dpx.file.user_size=0;
  if (profile != (StringInfo *) NULL)
    {
      dpx.file.user_size+=(unsigned int) GetStringInfoLength(profile);
      dpx.file.user_size=(((dpx.file.user_size+0x2000-1)/0x2000)*0x2000);
    }
  offset+=WriteBlobLong(image,dpx.file.user_size);
  value=GetDPXProperty(image,"dpx:file.filename",exception);
  if (value != (const char *) NULL)
    (void) strncpy(dpx.file.filename,value,sizeof(dpx.file.filename)-1);
  offset+=WriteBlob(image,sizeof(dpx.file.filename),(unsigned char *)
    dpx.file.filename);
  seconds=time((time_t *) NULL);
  (void) FormatMagickTime(seconds,sizeof(dpx.file.timestamp),
    dpx.file.timestamp);
  offset+=WriteBlob(image,sizeof(dpx.file.timestamp),(unsigned char *)
    dpx.file.timestamp);
  (void) strncpy(dpx.file.creator,MagickAuthoritativeURL,
    sizeof(dpx.file.creator)-1);
  value=GetDPXProperty(image,"dpx:file.creator",exception);
  if (value != (const char *) NULL)
    (void) strncpy(dpx.file.creator,value,sizeof(dpx.file.creator)-1);
  offset+=WriteBlob(image,sizeof(dpx.file.creator),(unsigned char *)
    dpx.file.creator);
  value=GetDPXProperty(image,"dpx:file.project",exception);
  if (value != (const char *) NULL)
    (void) strncpy(dpx.file.project,value,sizeof(dpx.file.project)-1);
  offset+=WriteBlob(image,sizeof(dpx.file.project),(unsigned char *)
    dpx.file.project);
  value=GetDPXProperty(image,"dpx:file.copyright",exception);
  if (value != (const char *) NULL)
    (void) strncpy(dpx.file.copyright,value,sizeof(dpx.file.copyright)-1);
  offset+=WriteBlob(image,sizeof(dpx.file.copyright),(unsigned char *)
    dpx.file.copyright);
  dpx.file.encrypt_key=(~0U);
  offset+=WriteBlobLong(image,dpx.file.encrypt_key);
  offset+=WriteBlob(image,sizeof(dpx.file.reserve),(unsigned char *)
    dpx.file.reserve);
  /*
    Write image header.
  */
  switch (image->orientation)
  {
    default:
    case TopLeftOrientation: dpx.image.orientation=0; break;
    case TopRightOrientation: dpx.image.orientation=1; break;
    case BottomLeftOrientation: dpx.image.orientation=2; break;
    case BottomRightOrientation: dpx.image.orientation=3; break;
    case LeftTopOrientation: dpx.image.orientation=4; break;
    case RightTopOrientation: dpx.image.orientation=5; break;
    case LeftBottomOrientation: dpx.image.orientation=6; break;
    case RightBottomOrientation: dpx.image.orientation=7; break;
  }
  offset+=WriteBlobShort(image,dpx.image.orientation);
  dpx.image.number_elements=1;
  offset+=WriteBlobShort(image,dpx.image.number_elements);
  if ((image->columns != (unsigned int) image->columns) ||
      (image->rows != (unsigned int) image->rows))
    ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
  offset+=WriteBlobLong(image,(unsigned int) image->columns);
  offset+=WriteBlobLong(image,(unsigned int) image->rows);
  for (i=0; i < 8; i++)
  {
    dpx.image.image_element[i].data_sign=0U;
    offset+=WriteBlobLong(image,dpx.image.image_element[i].data_sign);
    dpx.image.image_element[i].low_data=0U;
    offset+=WriteBlobLong(image,dpx.image.image_element[i].low_data);
    dpx.image.image_element[i].low_quantity=0.0f;
    offset+=WriteBlobFloat(image,dpx.image.image_element[i].low_quantity);
    dpx.image.image_element[i].high_data=0U;
    offset+=WriteBlobLong(image,dpx.image.image_element[i].high_data);
    dpx.image.image_element[i].high_quantity=0.0f;
    offset+=WriteBlobFloat(image,dpx.image.image_element[i].high_quantity);
    dpx.image.image_element[i].descriptor=0;
    if (i == 0)
      switch (image->colorspace)
      {
        case Rec601YCbCrColorspace:
        case Rec709YCbCrColorspace:
        case YCbCrColorspace:
        {
          dpx.image.image_element[i].descriptor=CbYCr444ComponentType;
          if (image->alpha_trait != UndefinedPixelTrait)
            dpx.image.image_element[i].descriptor=CbYCrA4444ComponentType;
          break;
        }
        default:
        {
          dpx.image.image_element[i].descriptor=RGBComponentType;
          if (image->alpha_trait != UndefinedPixelTrait)
            dpx.image.image_element[i].descriptor=RGBAComponentType;
          if ((image_info->type != TrueColorType) &&
              (image->alpha_trait == UndefinedPixelTrait) &&
              (SetImageGray(image,exception) != MagickFalse))
            dpx.image.image_element[i].descriptor=LumaComponentType;
          break;
        }
      }
    offset+=WriteBlobByte(image,dpx.image.image_element[i].descriptor);
    dpx.image.image_element[i].transfer_characteristic=0;
    if (image->colorspace == LogColorspace)
      dpx.image.image_element[0].transfer_characteristic=
        PrintingDensityColorimetric;
    offset+=WriteBlobByte(image,
      dpx.image.image_element[i].transfer_characteristic);
    dpx.image.image_element[i].colorimetric=0;
    offset+=WriteBlobByte(image,dpx.image.image_element[i].colorimetric);
    dpx.image.image_element[i].bit_size=0;
    if (i == 0)
      dpx.image.image_element[i].bit_size=(unsigned char) image->depth;
    offset+=WriteBlobByte(image,dpx.image.image_element[i].bit_size);
    dpx.image.image_element[i].packing=0;
    if ((image->depth == 10) || (image->depth == 12))
      dpx.image.image_element[i].packing=1;
    offset+=WriteBlobShort(image,dpx.image.image_element[i].packing);
    dpx.image.image_element[i].encoding=0;
    offset+=WriteBlobShort(image,dpx.image.image_element[i].encoding);
    dpx.image.image_element[i].data_offset=0U;
    if (i == 0)
      dpx.image.image_element[i].data_offset=dpx.file.image_offset;
    offset+=WriteBlobLong(image,dpx.image.image_element[i].data_offset);
    dpx.image.image_element[i].end_of_line_padding=0U;
    offset+=WriteBlobLong(image,dpx.image.image_element[i].end_of_line_padding);
    offset+=WriteBlobLong(image,
      dpx.image.image_element[i].end_of_image_padding);
    offset+=WriteBlob(image,sizeof(dpx.image.image_element[i].description),
      (unsigned char *) dpx.image.image_element[i].description);
  }
  offset+=WriteBlob(image,sizeof(dpx.image.reserve),(unsigned char *)
    dpx.image.reserve);
  /*
    Write orientation header.
  */
  if ((image->rows != image->magick_rows) ||
      (image->columns != image->magick_columns))
    {
      /*
        These properties are not valid if image size changed.
      */
      (void) DeleteImageProperty(image,"dpx:orientation.x_offset");
      (void) DeleteImageProperty(image,"dpx:orientation.y_offset");
      (void) DeleteImageProperty(image,"dpx:orientation.x_center");
      (void) DeleteImageProperty(image,"dpx:orientation.y_center");
      (void) DeleteImageProperty(image,"dpx:orientation.x_size");
      (void) DeleteImageProperty(image,"dpx:orientation.y_size");
    }
  dpx.orientation.x_offset=0U;
  value=GetDPXProperty(image,"dpx:orientation.x_offset",exception);
  if (value != (const char *) NULL)
    dpx.orientation.x_offset=(unsigned int) StringToUnsignedLong(value);
  offset+=WriteBlobLong(image,dpx.orientation.x_offset);
  dpx.orientation.y_offset=0U;
  value=GetDPXProperty(image,"dpx:orientation.y_offset",exception);
  if (value != (const char *) NULL)
    dpx.orientation.y_offset=(unsigned int) StringToUnsignedLong(value);
  offset+=WriteBlobLong(image,dpx.orientation.y_offset);
  dpx.orientation.x_center=0.0f;
  value=GetDPXProperty(image,"dpx:orientation.x_center",exception);
  if (value != (const char *) NULL)
    dpx.orientation.x_center=StringToDouble(value,(char **) NULL);
  offset+=WriteBlobFloat(image,dpx.orientation.x_center);
  dpx.orientation.y_center=0.0f;
  value=GetDPXProperty(image,"dpx:orientation.y_center",exception);
  if (value != (const char *) NULL)
    dpx.orientation.y_center=StringToDouble(value,(char **) NULL);
  offset+=WriteBlobFloat(image,dpx.orientation.y_center);
  dpx.orientation.x_size=0U;
  value=GetDPXProperty(image,"dpx:orientation.x_size",exception);
  if (value != (const char *) NULL)
    dpx.orientation.x_size=(unsigned int) StringToUnsignedLong(value);
  offset+=WriteBlobLong(image,dpx.orientation.x_size);
  dpx.orientation.y_size=0U;
  value=GetDPXProperty(image,"dpx:orientation.y_size",exception);
  if (value != (const char *) NULL)
    dpx.orientation.y_size=(unsigned int) StringToUnsignedLong(value);
  offset+=WriteBlobLong(image,dpx.orientation.y_size);
  value=GetDPXProperty(image,"dpx:orientation.filename",exception);
  if (value != (const char *) NULL)
    (void) strncpy(dpx.orientation.filename,value,
      sizeof(dpx.orientation.filename)-1);
  offset+=WriteBlob(image,sizeof(dpx.orientation.filename),(unsigned char *)
    dpx.orientation.filename);
  offset+=WriteBlob(image,sizeof(dpx.orientation.timestamp),(unsigned char *)
    dpx.orientation.timestamp);
  value=GetDPXProperty(image,"dpx:orientation.device",exception);
  if (value != (const char *) NULL)
    (void) strncpy(dpx.orientation.device,value,
      sizeof(dpx.orientation.device)-1);
  offset+=WriteBlob(image,sizeof(dpx.orientation.device),(unsigned char *)
    dpx.orientation.device);
  value=GetDPXProperty(image,"dpx:orientation.serial",exception);
  if (value != (const char *) NULL)
    (void) strncpy(dpx.orientation.serial,value,
      sizeof(dpx.orientation.serial)-1);
  offset+=WriteBlob(image,sizeof(dpx.orientation.serial),(unsigned char *)
    dpx.orientation.serial);
  for (i=0; i < 4; i++)
    dpx.orientation.border[i]=0;
  value=GetDPXProperty(image,"dpx:orientation.border",exception);
  if (value != (const char *) NULL)
    {
      flags=ParseGeometry(value,&geometry_info);
      if ((flags & SigmaValue) == 0)
        geometry_info.sigma=geometry_info.rho;
      dpx.orientation.border[0]=(unsigned short) (geometry_info.rho+0.5);
      dpx.orientation.border[1]=(unsigned short) (geometry_info.sigma+0.5);
      dpx.orientation.border[2]=(unsigned short) (geometry_info.xi+0.5);
      dpx.orientation.border[3]=(unsigned short) (geometry_info.psi+0.5);
    }
  for (i=0; i < 4; i++)
    offset+=WriteBlobShort(image,dpx.orientation.border[i]);
  for (i=0; i < 2; i++)
    dpx.orientation.aspect_ratio[i]=0U;
  value=GetDPXProperty(image,"dpx:orientation.aspect_ratio",exception);
  if (value != (const char *) NULL)
    {
      flags=ParseGeometry(value,&geometry_info);
      if ((flags & SigmaValue) == 0)
        geometry_info.sigma=geometry_info.rho;
      dpx.orientation.aspect_ratio[0]=(unsigned int) (geometry_info.rho+0.5);
      dpx.orientation.aspect_ratio[1]=(unsigned int) (geometry_info.sigma+0.5);
    }
  for (i=0; i < 2; i++)
    offset+=WriteBlobLong(image,dpx.orientation.aspect_ratio[i]);
  offset+=WriteBlob(image,sizeof(dpx.orientation.reserve),(unsigned char *)
    dpx.orientation.reserve);
  /*
    Write film header.
  */
  (void) memset(dpx.film.id,0,sizeof(dpx.film.id));
  value=GetDPXProperty(image,"dpx:film.id",exception);
  if (value != (const char *) NULL)
    (void) strncpy(dpx.film.id,value,sizeof(dpx.film.id)-1);
  offset+=WriteBlob(image,sizeof(dpx.film.id),(unsigned char *) dpx.film.id);
  (void) memset(dpx.film.type,0,sizeof(dpx.film.type));
  value=GetDPXProperty(image,"dpx:film.type",exception);
  if (value != (const char *) NULL)
    (void) strncpy(dpx.film.type,value,sizeof(dpx.film.type)-1);
  offset+=WriteBlob(image,sizeof(dpx.film.type),(unsigned char *)
    dpx.film.type);
  (void) memset(dpx.film.offset,0,sizeof(dpx.film.offset));
  value=GetDPXProperty(image,"dpx:film.offset",exception);
  if (value != (const char *) NULL)
    (void) strncpy(dpx.film.offset,value,sizeof(dpx.film.offset)-1);
  offset+=WriteBlob(image,sizeof(dpx.film.offset),(unsigned char *)
    dpx.film.offset);
  (void) memset(dpx.film.prefix,0,sizeof(dpx.film.prefix));
  value=GetDPXProperty(image,"dpx:film.prefix",exception);
  if (value != (const char *) NULL)
    (void) strncpy(dpx.film.prefix,value,sizeof(dpx.film.prefix)-1);
  offset+=WriteBlob(image,sizeof(dpx.film.prefix),(unsigned char *)
    dpx.film.prefix);
  (void) memset(dpx.film.count,0,sizeof(dpx.film.count));
  value=GetDPXProperty(image,"dpx:film.count",exception);
  if (value != (const char *) NULL)
    (void) strncpy(dpx.film.count,value,sizeof(dpx.film.count)-1);
  offset+=WriteBlob(image,sizeof(dpx.film.count),(unsigned char *)
    dpx.film.count);
  (void) memset(dpx.film.format,0,sizeof(dpx.film.format));
  value=GetDPXProperty(image,"dpx:film.format",exception);
  if (value != (const char *) NULL)
    (void) strncpy(dpx.film.format,value,sizeof(dpx.film.format)-1);
  offset+=WriteBlob(image,sizeof(dpx.film.format),(unsigned char *)
    dpx.film.format);
  dpx.film.frame_position=0U;
  value=GetDPXProperty(image,"dpx:film.frame_position",exception);
  if (value != (const char *) NULL)
    dpx.film.frame_position=(unsigned int) StringToUnsignedLong(value);
  offset+=WriteBlobLong(image,dpx.film.frame_position);
  dpx.film.sequence_extent=0U;
  value=GetDPXProperty(image,"dpx:film.sequence_extent",exception);
  if (value != (const char *) NULL)
    dpx.film.sequence_extent=(unsigned int) StringToUnsignedLong(value);
  offset+=WriteBlobLong(image,dpx.film.sequence_extent);
  dpx.film.held_count=0U;
  value=GetDPXProperty(image,"dpx:film.held_count",exception);
  if (value != (const char *) NULL)
    dpx.film.held_count=(unsigned int) StringToUnsignedLong(value);
  offset+=WriteBlobLong(image,dpx.film.held_count);
  dpx.film.frame_rate=0.0f;
  value=GetDPXProperty(image,"dpx:film.frame_rate",exception);
  if (value != (const char *) NULL)
    dpx.film.frame_rate=StringToDouble(value,(char **) NULL);
  offset+=WriteBlobFloat(image,dpx.film.frame_rate);
  dpx.film.shutter_angle=0.0f;
  value=GetDPXProperty(image,"dpx:film.shutter_angle",exception);
  if (value != (const char *) NULL)
    dpx.film.shutter_angle=StringToDouble(value,(char **) NULL);
  offset+=WriteBlobFloat(image,dpx.film.shutter_angle);
  (void) memset(dpx.film.frame_id,0,sizeof(dpx.film.frame_id));
  value=GetDPXProperty(image,"dpx:film.frame_id",exception);
  if (value != (const char *) NULL)
    (void) strncpy(dpx.film.frame_id,value,sizeof(dpx.film.frame_id)-1);
  offset+=WriteBlob(image,sizeof(dpx.film.frame_id),(unsigned char *)
    dpx.film.frame_id);
  value=GetDPXProperty(image,"dpx:film.slate",exception);
  if (value != (const char *) NULL)
    (void) strncpy(dpx.film.slate,value,sizeof(dpx.film.slate)-1);
  offset+=WriteBlob(image,sizeof(dpx.film.slate),(unsigned char *)
    dpx.film.slate);
  offset+=WriteBlob(image,sizeof(dpx.film.reserve),(unsigned char *)
    dpx.film.reserve);
  /*
    Write television header.
  */
  value=GetDPXProperty(image,"dpx:television.time.code",exception);
  if (value != (const char *) NULL)
    dpx.television.time_code=StringToTimeCode(value);
  offset+=WriteBlobLong(image,dpx.television.time_code);
  value=GetDPXProperty(image,"dpx:television.user.bits",exception);
  if (value != (const char *) NULL)
    dpx.television.user_bits=StringToTimeCode(value);
  offset+=WriteBlobLong(image,dpx.television.user_bits);
  value=GetDPXProperty(image,"dpx:television.interlace",exception);
  if (value != (const char *) NULL)
    dpx.television.interlace=(unsigned char) StringToLong(value);
  offset+=WriteBlobByte(image,dpx.television.interlace);
  value=GetDPXProperty(image,"dpx:television.field_number",exception);
  if (value != (const char *) NULL)
    dpx.television.field_number=(unsigned char) StringToLong(value);
  offset+=WriteBlobByte(image,dpx.television.field_number);
  dpx.television.video_signal=0;
  value=GetDPXProperty(image,"dpx:television.video_signal",exception);
  if (value != (const char *) NULL)
    dpx.television.video_signal=(unsigned char) StringToLong(value);
  offset+=WriteBlobByte(image,dpx.television.video_signal);
  dpx.television.padding=0;
  value=GetDPXProperty(image,"dpx:television.padding",exception);
  if (value != (const char *) NULL)
    dpx.television.padding=(unsigned char) StringToLong(value);
  offset+=WriteBlobByte(image,dpx.television.padding);
  dpx.television.horizontal_sample_rate=0.0f;
  value=GetDPXProperty(image,"dpx:television.horizontal_sample_rate",
    exception);
  if (value != (const char *) NULL)
    dpx.television.horizontal_sample_rate=StringToDouble(value,(char **) NULL);
  offset+=WriteBlobFloat(image,dpx.television.horizontal_sample_rate);
  dpx.television.vertical_sample_rate=0.0f;
  value=GetDPXProperty(image,"dpx:television.vertical_sample_rate",exception);
  if (value != (const char *) NULL)
    dpx.television.vertical_sample_rate=StringToDouble(value,(char **) NULL);
  offset+=WriteBlobFloat(image,dpx.television.vertical_sample_rate);
  dpx.television.frame_rate=0.0f;
  value=GetDPXProperty(image,"dpx:television.frame_rate",exception);
  if (value != (const char *) NULL)
    dpx.television.frame_rate=StringToDouble(value,(char **) NULL);
  offset+=WriteBlobFloat(image,dpx.television.frame_rate);
  dpx.television.time_offset=0.0f;
  value=GetDPXProperty(image,"dpx:television.time_offset",exception);
  if (value != (const char *) NULL)
    dpx.television.time_offset=StringToDouble(value,(char **) NULL);
  offset+=WriteBlobFloat(image,dpx.television.time_offset);
  dpx.television.gamma=0.0f;
  value=GetDPXProperty(image,"dpx:television.gamma",exception);
  if (value != (const char *) NULL)
    dpx.television.gamma=StringToDouble(value,(char **) NULL);
  offset+=WriteBlobFloat(image,dpx.television.gamma);
  dpx.television.black_level=0.0f;
  value=GetDPXProperty(image,"dpx:television.black_level",exception);
  if (value != (const char *) NULL)
    dpx.television.black_level=StringToDouble(value,(char **) NULL);
  offset+=WriteBlobFloat(image,dpx.television.black_level);
  dpx.television.black_gain=0.0f;
  value=GetDPXProperty(image,"dpx:television.black_gain",exception);
  if (value != (const char *) NULL)
    dpx.television.black_gain=StringToDouble(value,(char **) NULL);
  offset+=WriteBlobFloat(image,dpx.television.black_gain);
  dpx.television.break_point=0.0f;
  value=GetDPXProperty(image,"dpx:television.break_point",exception);
  if (value != (const char *) NULL)
    dpx.television.break_point=StringToDouble(value,(char **) NULL);
  offset+=WriteBlobFloat(image,dpx.television.break_point);
  dpx.television.white_level=0.0f;
  value=GetDPXProperty(image,"dpx:television.white_level",exception);
  if (value != (const char *) NULL)
    dpx.television.white_level=StringToDouble(value,(char **) NULL);
  offset+=WriteBlobFloat(image,dpx.television.white_level);
  dpx.television.integration_times=0.0f;
  value=GetDPXProperty(image,"dpx:television.integration_times",exception);
  if (value != (const char *) NULL)
    dpx.television.integration_times=StringToDouble(value,(char **) NULL);
  offset+=WriteBlobFloat(image,dpx.television.integration_times);
  offset+=WriteBlob(image,sizeof(dpx.television.reserve),(unsigned char *)
    dpx.television.reserve);
  /*
    Write user header.
  */
  value=GetDPXProperty(image,"dpx:user.id",exception);
  if (value != (const char *) NULL)
    (void) strncpy(dpx.user.id,value,sizeof(dpx.user.id)-1);
  offset+=WriteBlob(image,sizeof(dpx.user.id),(unsigned char *) dpx.user.id);
  if (profile != (StringInfo *) NULL)
    offset+=WriteBlob(image,GetStringInfoLength(profile),
      GetStringInfoDatum(profile));
  while (offset < (MagickOffsetType) dpx.image.image_element[0].data_offset)
  {
    count=WriteBlobByte(image,0x00);
    if (count != 1)
      {
        ThrowFileException(exception,FileOpenError,"UnableToWriteFile",
          image->filename);
        break;
      }
    offset+=count;
  }
  /*
    Convert pixel packets to DPX raster image.
  */
  quantum_info=AcquireQuantumInfo(image_info,image);
  if (quantum_info == (QuantumInfo *) NULL)
    ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
  SetQuantumQuantum(quantum_info,32);
  SetQuantumPack(quantum_info,dpx.image.image_element[0].packing == 0 ?
    MagickTrue : MagickFalse);
  quantum_type=RGBQuantum;
  if (image->alpha_trait != UndefinedPixelTrait)
    quantum_type=RGBAQuantum;
  if (image->colorspace == YCbCrColorspace)
    {
      quantum_type=CbYCrQuantum;
      if (image->alpha_trait != UndefinedPixelTrait)
        quantum_type=CbYCrAQuantum;
      if ((horizontal_factor == 2) || (vertical_factor == 2))
        quantum_type=CbYCrYQuantum;
    }
  extent=GetBytesPerRow(image->columns,
    image->alpha_trait != UndefinedPixelTrait ? 4UL : 3UL,image->depth,
    dpx.image.image_element[0].packing == 0 ? MagickFalse : MagickTrue);
  if ((image_info->type != TrueColorType) &&
      (image->alpha_trait == UndefinedPixelTrait) &&
      (SetImageGray(image,exception) != MagickFalse))
    {
      quantum_type=GrayQuantum;
      extent=GetBytesPerRow(image->columns,1UL,image->depth,
        dpx.image.image_element[0].packing == 0 ? MagickFalse : MagickTrue);
    }
  pixels=(unsigned char *) GetQuantumPixels(quantum_info);
  for (y=0; y < (ssize_t) image->rows; y++)
  {
    size_t
      length;

    p=GetVirtualPixels(image,0,y,image->columns,1,exception);
    if (p == (const Quantum *) NULL)
      break;
    length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
      quantum_type,pixels,exception);
    if (length == 0)
      break;
    count=WriteBlob(image,extent,pixels);
    if (count != (ssize_t) extent)
      break;
    status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
      image->rows);
    if (status == MagickFalse)
      break;
  }
  quantum_info=DestroyQuantumInfo(quantum_info);
  if (y < (ssize_t) image->rows)
    ThrowWriterException(CorruptImageError,"UnableToWriteImageData");
  (void) CloseBlob(image);
  return(status);
}


SECURITY: Prevent compiler from eliding bounds checks.

Details: https://github.com/sandstorm-io/capnproto/blob/master/security-advisories/2017-04-17-0-apple-32bit-elides-bounds-check.md

inline bool SegmentReader::containsInterval(const void* from, const void* to) {
  return from >= this->ptr.begin() && to <= this->ptr.end() && from <= to &&
      readLimiter->canRead(
          intervalLength(reinterpret_cast<const byte*>(from),
                         reinterpret_cast<const byte*>(to),
                         MAX_SEGMENT_WORDS * BYTES_PER_WORD)
              / BYTES_PER_WORD,
          arena);
}

Sandstorm Cap'n Proto before 0.5.3.1 allows remote crashes related to a compiler optimization. A remote attacker can trigger a segfault in a 32-bit libcapnp application because Cap'n Proto relies on pointer arithmetic calculations that overflow. An example compiler with optimization that elides a bounds check in such calculations is Apple LLVM version 8.1.0 (clang-802.0.41). The attack vector is a crafted far pointer within a message.


inline bool SegmentReader::containsInterval(const void* from, const void* to) {
  uintptr_t start = reinterpret_cast<uintptr_t>(from) - reinterpret_cast<uintptr_t>(ptr.begin());
  uintptr_t end = reinterpret_cast<uintptr_t>(to) - reinterpret_cast<uintptr_t>(ptr.begin());
  uintptr_t bound = ptr.size() * sizeof(capnp::word);

  return start <= bound && end <= bound && start <= end &&
      readLimiter->canRead(
          intervalLength(reinterpret_cast<const byte*>(from),
                         reinterpret_cast<const byte*>(to),
                         MAX_SEGMENT_WORDS * BYTES_PER_WORD)
              / BYTES_PER_WORD,
          arena);
}


Reject string longer than USHRT_MAX before sending them on the wire

The X protocol uses CARD16 values to represent the length so
this would overflow.

CVE-2021-31535

Signed-off-by: Matthieu Herrb <matthieu@herrb.eu>

XLookupColor (
	register Display *dpy,
        Colormap cmap,
	_Xconst char *spec,
	XColor *def,
	XColor *scr)
{
	register int n;
	xLookupColorReply reply;
	register xLookupColorReq *req;
	XcmsCCC ccc;
	XcmsColor cmsColor_exact;

#ifdef XCMS
	/*
	 * Let's Attempt to use Xcms and i18n approach to Parse Color
	 */
	if ((ccc = XcmsCCCOfColormap(dpy, cmap)) != (XcmsCCC)NULL) {
	    const char *tmpName = spec;

	    switch (_XcmsResolveColorString(ccc, &tmpName, &cmsColor_exact,
					    XcmsRGBFormat)) {
	    case XcmsSuccess:
	    case XcmsSuccessWithCompression:
		_XcmsRGB_to_XColor(&cmsColor_exact, def, 1);
		memcpy((char *)scr, (char *)def, sizeof(XColor));
		_XUnresolveColor(ccc, scr);
		return(1);
	    case XcmsFailure:
	    case _XCMS_NEWNAME:
		/*
		 * if the result was _XCMS_NEWNAME tmpName points to
		 * a string in cmsColNm.c:pairs table, for example,
		 * gray70 would become tekhvc:0.0/70.0/0.0
		 */
		break;
	    }
	}
#endif

	/*
	 * Xcms and i18n methods failed, so lets pass it to the server
	 * for parsing.
	 */

	n = (int) strlen (spec);
	LockDisplay(dpy);
	GetReq (LookupColor, req);
	req->cmap = cmap;
	req->nbytes = n;
	req->length += (n + 3) >> 2;
	Data (dpy, spec, (long)n);
	if (!_XReply (dpy, (xReply *) &reply, 0, xTrue)) {
	    UnlockDisplay(dpy);
	    SyncHandle();
	    return (0);
	    }
	def->red   = reply.exactRed;
	def->green = reply.exactGreen;
	def->blue  = reply.exactBlue;

	scr->red   = reply.screenRed;
	scr->green = reply.screenGreen;
	scr->blue  = reply.screenBlue;

	UnlockDisplay(dpy);
	SyncHandle();
	return (1);
}

LookupCol.c in X.Org X through X11R7.7 and libX11 before 1.7.1 might allow remote attackers to execute arbitrary code. The libX11 XLookupColor request (intended for server-side color lookup) contains a flaw allowing a client to send color-name requests with a name longer than the maximum size allowed by the protocol (and also longer than the maximum packet size for normal-sized packets). The user-controlled data exceeding the maximum size is then interpreted by the server as additional X protocol requests and executed, e.g., to disable X server authorization completely. For example, if the victim encounters malicious terminal control sequences for color codes, then the attacker may be able to take full control of the running graphical session.


XLookupColor (
	register Display *dpy,
        Colormap cmap,
	_Xconst char *spec,
	XColor *def,
	XColor *scr)
{
	register int n;
	xLookupColorReply reply;
	register xLookupColorReq *req;
	XcmsCCC ccc;
	XcmsColor cmsColor_exact;

	n = (int) strlen (spec);
	if (n >= USHRT_MAX)
            return 0;
#ifdef XCMS
	/*
	 * Let's Attempt to use Xcms and i18n approach to Parse Color
	 */
	if ((ccc = XcmsCCCOfColormap(dpy, cmap)) != (XcmsCCC)NULL) {
	    const char *tmpName = spec;

	    switch (_XcmsResolveColorString(ccc, &tmpName, &cmsColor_exact,
					    XcmsRGBFormat)) {
	    case XcmsSuccess:
	    case XcmsSuccessWithCompression:
		_XcmsRGB_to_XColor(&cmsColor_exact, def, 1);
		memcpy((char *)scr, (char *)def, sizeof(XColor));
		_XUnresolveColor(ccc, scr);
		return(1);
	    case XcmsFailure:
	    case _XCMS_NEWNAME:
		/*
		 * if the result was _XCMS_NEWNAME tmpName points to
		 * a string in cmsColNm.c:pairs table, for example,
		 * gray70 would become tekhvc:0.0/70.0/0.0
		 */
		break;
	    }
	}
#endif

	/*
	 * Xcms and i18n methods failed, so lets pass it to the server
	 * for parsing.
	 */
	LockDisplay(dpy);
	GetReq (LookupColor, req);
	req->cmap = cmap;
	req->nbytes = n;
	req->length += (n + 3) >> 2;
	Data (dpy, spec, (long)n);
	if (!_XReply (dpy, (xReply *) &reply, 0, xTrue)) {
	    UnlockDisplay(dpy);
	    SyncHandle();
	    return (0);
	    }
	def->red   = reply.exactRed;
	def->green = reply.exactGreen;
	def->blue  = reply.exactBlue;

	scr->red   = reply.screenRed;
	scr->green = reply.screenGreen;
	scr->blue  = reply.screenBlue;

	UnlockDisplay(dpy);
	SyncHandle();
	return (1);
}


Fixed plugin load

I have no idea when I broke this...

plugin_init (Ekiga::KickStart& kickstart)
{
#ifdef DEBUG
  // should make it easier to test ekiga without installing
  gchar* path = g_build_path (G_DIR_SEPARATOR_S,
			      g_get_tmp_dir (), "ekiga_debug_plugins", NULL);
  plugin_parse_directory (kickstart, path);
  g_free (path);
#else
  plugin_parse_directory (kickstart,
			  EKIGA_PLUGIN_DIR);
#endif
}

Ekiga versions before 3.3.0 attempted to load a module from /tmp/ekiga_test.so.


plugin_init (Ekiga::KickStart& kickstart)
{
#if DEBUG
  // should make it easier to test ekiga without installing
  gchar* path = g_build_path (G_DIR_SEPARATOR_S,
			      g_get_tmp_dir (), "ekiga_debug_plugins", NULL);
  plugin_parse_directory (kickstart, path);
  g_free (path);
#else
  plugin_parse_directory (kickstart,
			  EKIGA_PLUGIN_DIR);
#endif
}


ASoC: SOF: ipc: Fix memory leak in sof_set_get_large_ctrl_data

In the implementation of sof_set_get_large_ctrl_data() there is a memory
leak in case an error. Release partdata if sof_get_ctrl_copy_params()
fails.

Fixes: 54d198d5019d ("ASoC: SOF: Propagate sof_get_ctrl_copy_params() error properly")
Signed-off-by: Navid Emamdoost <navid.emamdoost@gmail.com>
Link: https://lore.kernel.org/r/20191027215330.12729-1-navid.emamdoost@gmail.com
Signed-off-by: Mark Brown <broonie@kernel.org>

static int sof_set_get_large_ctrl_data(struct snd_sof_dev *sdev,
				       struct sof_ipc_ctrl_data *cdata,
				       struct sof_ipc_ctrl_data_params *sparams,
				       bool send)
{
	struct sof_ipc_ctrl_data *partdata;
	size_t send_bytes;
	size_t offset = 0;
	size_t msg_bytes;
	size_t pl_size;
	int err;
	int i;

	/* allocate max ipc size because we have at least one */
	partdata = kzalloc(SOF_IPC_MSG_MAX_SIZE, GFP_KERNEL);
	if (!partdata)
		return -ENOMEM;

	if (send)
		err = sof_get_ctrl_copy_params(cdata->type, cdata, partdata,
					       sparams);
	else
		err = sof_get_ctrl_copy_params(cdata->type, partdata, cdata,
					       sparams);
	if (err < 0)
		return err;

	msg_bytes = sparams->msg_bytes;
	pl_size = sparams->pl_size;

	/* copy the header data */
	memcpy(partdata, cdata, sparams->hdr_bytes);

	/* Serialise IPC TX */
	mutex_lock(&sdev->ipc->tx_mutex);

	/* copy the payload data in a loop */
	for (i = 0; i < sparams->num_msg; i++) {
		send_bytes = min(msg_bytes, pl_size);
		partdata->num_elems = send_bytes;
		partdata->rhdr.hdr.size = sparams->hdr_bytes + send_bytes;
		partdata->msg_index = i;
		msg_bytes -= send_bytes;
		partdata->elems_remaining = msg_bytes;

		if (send)
			memcpy(sparams->dst, sparams->src + offset, send_bytes);

		err = sof_ipc_tx_message_unlocked(sdev->ipc,
						  partdata->rhdr.hdr.cmd,
						  partdata,
						  partdata->rhdr.hdr.size,
						  partdata,
						  partdata->rhdr.hdr.size);
		if (err < 0)
			break;

		if (!send)
			memcpy(sparams->dst + offset, sparams->src, send_bytes);

		offset += pl_size;
	}

	mutex_unlock(&sdev->ipc->tx_mutex);

	kfree(partdata);
	return err;
}

A memory leak in the sof_set_get_large_ctrl_data() function in sound/soc/sof/ipc.c in the Linux kernel through 5.3.9 allows attackers to cause a denial of service (memory consumption) by triggering sof_get_ctrl_copy_params() failures, aka CID-45c1380358b1.


static int sof_set_get_large_ctrl_data(struct snd_sof_dev *sdev,
				       struct sof_ipc_ctrl_data *cdata,
				       struct sof_ipc_ctrl_data_params *sparams,
				       bool send)
{
	struct sof_ipc_ctrl_data *partdata;
	size_t send_bytes;
	size_t offset = 0;
	size_t msg_bytes;
	size_t pl_size;
	int err;
	int i;

	/* allocate max ipc size because we have at least one */
	partdata = kzalloc(SOF_IPC_MSG_MAX_SIZE, GFP_KERNEL);
	if (!partdata)
		return -ENOMEM;

	if (send)
		err = sof_get_ctrl_copy_params(cdata->type, cdata, partdata,
					       sparams);
	else
		err = sof_get_ctrl_copy_params(cdata->type, partdata, cdata,
					       sparams);
	if (err < 0) {
		kfree(partdata);
		return err;
	}

	msg_bytes = sparams->msg_bytes;
	pl_size = sparams->pl_size;

	/* copy the header data */
	memcpy(partdata, cdata, sparams->hdr_bytes);

	/* Serialise IPC TX */
	mutex_lock(&sdev->ipc->tx_mutex);

	/* copy the payload data in a loop */
	for (i = 0; i < sparams->num_msg; i++) {
		send_bytes = min(msg_bytes, pl_size);
		partdata->num_elems = send_bytes;
		partdata->rhdr.hdr.size = sparams->hdr_bytes + send_bytes;
		partdata->msg_index = i;
		msg_bytes -= send_bytes;
		partdata->elems_remaining = msg_bytes;

		if (send)
			memcpy(sparams->dst, sparams->src + offset, send_bytes);

		err = sof_ipc_tx_message_unlocked(sdev->ipc,
						  partdata->rhdr.hdr.cmd,
						  partdata,
						  partdata->rhdr.hdr.size,
						  partdata,
						  partdata->rhdr.hdr.size);
		if (err < 0)
			break;

		if (!send)
			memcpy(sparams->dst + offset, sparams->src, send_bytes);

		offset += pl_size;
	}

	mutex_unlock(&sdev->ipc->tx_mutex);

	kfree(partdata);
	return err;
}


A heap-based-buffer-over-read flaw was found in ImageMagick's GetPixelAlpha() function of 'pixel-accessor.h'. This vulnerability is triggered when an attacker passes a specially crafted Tagged Image File Format (TIFF) image to convert it into a PICON file format. This issue can potentially lead to a denial of service and information disclosure.


crypto_recv(
	struct peer *peer,	/* peer structure pointer */
	struct recvbuf *rbufp	/* packet buffer pointer */
	)
{
	const EVP_MD *dp;	/* message digest algorithm */
	u_int32	*pkt;		/* receive packet pointer */
	struct autokey *ap, *bp; /* autokey pointer */
	struct exten *ep, *fp;	/* extension pointers */
	struct cert_info *xinfo; /* certificate info pointer */
	int	has_mac;	/* length of MAC field */
	int	authlen;	/* offset of MAC field */
	associd_t associd;	/* association ID */
	tstamp_t fstamp = 0;	/* filestamp */
	u_int	len;		/* extension field length */
	u_int	code;		/* extension field opcode */
	u_int	vallen = 0;	/* value length */
	X509	*cert;		/* X509 certificate */
	char	statstr[NTP_MAXSTRLEN]; /* statistics for filegen */
	keyid_t	cookie;		/* crumbles */
	int	hismode;	/* packet mode */
	int	rval = XEVNT_OK;
	const u_char *puch;
	u_int32 temp32;

	/*
	 * Initialize. Note that the packet has already been checked for
	 * valid format and extension field lengths. First extract the
	 * field length, command code and association ID in host byte
	 * order. These are used with all commands and modes. Then check
	 * the version number, which must be 2, and length, which must
	 * be at least 8 for requests and VALUE_LEN (24) for responses.
	 * Packets that fail either test sink without a trace. The
	 * association ID is saved only if nonzero.
	 */
	authlen = LEN_PKT_NOMAC;
	hismode = (int)PKT_MODE((&rbufp->recv_pkt)->li_vn_mode);
	while ((has_mac = rbufp->recv_length - authlen) > (int)MAX_MAC_LEN) {
		pkt = (u_int32 *)&rbufp->recv_pkt + authlen / 4;
		ep = (struct exten *)pkt;
		code = ntohl(ep->opcode) & 0xffff0000;
		len = ntohl(ep->opcode) & 0x0000ffff;
		// HMS: Why pkt[1] instead of ep->associd ?
		associd = (associd_t)ntohl(pkt[1]);
		rval = XEVNT_OK;
		DPRINTF(1, ("crypto_recv: flags 0x%x ext offset %d len %u code 0x%x associd %d\n",
			    peer->crypto, authlen, len, code >> 16,
			    associd));

		/*
		 * Check version number and field length. If bad,
		 * quietly ignore the packet.
		 */
		if (((code >> 24) & 0x3f) != CRYPTO_VN || len < 8) {
			sys_badlength++;
			code |= CRYPTO_ERROR;
		}

		if (len >= VALUE_LEN) {
			fstamp = ntohl(ep->fstamp);
			vallen = ntohl(ep->vallen);
			/*
			 * Bug 2761: I hope this isn't too early...
			 */
			if (   vallen == 0
			    || len - VALUE_LEN < vallen)
				return XEVNT_LEN;
		}
		switch (code) {

		/*
		 * Install status word, host name, signature scheme and
		 * association ID. In OpenSSL the signature algorithm is
		 * bound to the digest algorithm, so the NID completely
		 * defines the signature scheme. Note the request and
		 * response are identical, but neither is validated by
		 * signature. The request is processed here only in
		 * symmetric modes. The server name field might be
		 * useful to implement access controls in future.
		 */
		case CRYPTO_ASSOC:

			/*
			 * If our state machine is running when this
			 * message arrives, the other fellow might have
			 * restarted. However, this could be an
			 * intruder, so just clamp the poll interval and
			 * find out for ourselves. Otherwise, pass the
			 * extension field to the transmit side.
			 */
			if (peer->crypto & CRYPTO_FLAG_CERT) {
				rval = XEVNT_ERR;
				break;
			}
			if (peer->cmmd) {
				if (peer->assoc != associd) {
					rval = XEVNT_ERR;
					break;
				}
			}
			fp = emalloc(len);
			memcpy(fp, ep, len);
			fp->associd = htonl(peer->associd);
			peer->cmmd = fp;
			/* fall through */

		case CRYPTO_ASSOC | CRYPTO_RESP:

			/*
			 * Discard the message if it has already been
			 * stored or the message has been amputated.
			 */
			if (peer->crypto) {
				if (peer->assoc != associd)
					rval = XEVNT_ERR;
				break;
			}
			INSIST(len >= VALUE_LEN);
			if (vallen == 0 || vallen > MAXHOSTNAME ||
			    len - VALUE_LEN < vallen) {
				rval = XEVNT_LEN;
				break;
			}
			DPRINTF(1, ("crypto_recv: ident host 0x%x %d server 0x%x %d\n",
				    crypto_flags, peer->associd, fstamp,
				    peer->assoc));
			temp32 = crypto_flags & CRYPTO_FLAG_MASK;

			/*
			 * If the client scheme is PC, the server scheme
			 * must be PC. The public key and identity are
			 * presumed valid, so we skip the certificate
			 * and identity exchanges and move immediately
			 * to the cookie exchange which confirms the
			 * server signature.
			 */
			if (crypto_flags & CRYPTO_FLAG_PRIV) {
				if (!(fstamp & CRYPTO_FLAG_PRIV)) {
					rval = XEVNT_KEY;
					break;
				}
				fstamp |= CRYPTO_FLAG_CERT |
				    CRYPTO_FLAG_VRFY | CRYPTO_FLAG_SIGN;

			/*
			 * It is an error if either peer supports
			 * identity, but the other does not.
			 */
			} else if (hismode == MODE_ACTIVE || hismode ==
			    MODE_PASSIVE) {
				if ((temp32 && !(fstamp &
				    CRYPTO_FLAG_MASK)) ||
				    (!temp32 && (fstamp &
				    CRYPTO_FLAG_MASK))) {
					rval = XEVNT_KEY;
					break;
				}
			}

			/*
			 * Discard the message if the signature digest
			 * NID is not supported.
			 */
			temp32 = (fstamp >> 16) & 0xffff;
			dp =
			    (const EVP_MD *)EVP_get_digestbynid(temp32);
			if (dp == NULL) {
				rval = XEVNT_MD;
				break;
			}

			/*
			 * Save status word, host name and message
			 * digest/signature type. If this is from a
			 * broadcast and the association ID has changed,
			 * request the autokey values.
			 */
			peer->assoc = associd;
			if (hismode == MODE_SERVER)
				fstamp |= CRYPTO_FLAG_AUTO;
			if (!(fstamp & CRYPTO_FLAG_TAI))
				fstamp |= CRYPTO_FLAG_LEAP;
			RAND_bytes((u_char *)&peer->hcookie, 4);
			peer->crypto = fstamp;
			peer->digest = dp;
			if (peer->subject != NULL)
				free(peer->subject);
			peer->subject = emalloc(vallen + 1);
			memcpy(peer->subject, ep->pkt, vallen);
			peer->subject[vallen] = '\0';
			if (peer->issuer != NULL)
				free(peer->issuer);
			peer->issuer = estrdup(peer->subject);
			snprintf(statstr, sizeof(statstr),
			    "assoc %d %d host %s %s", peer->associd,
			    peer->assoc, peer->subject,
			    OBJ_nid2ln(temp32));
			record_crypto_stats(&peer->srcadr, statstr);
			DPRINTF(1, ("crypto_recv: %s\n", statstr));
			break;

		/*
		 * Decode X509 certificate in ASN.1 format and extract
		 * the data containing, among other things, subject
		 * name and public key. In the default identification
		 * scheme, the certificate trail is followed to a self
		 * signed trusted certificate.
		 */
		case CRYPTO_CERT | CRYPTO_RESP:

			/*
			 * Discard the message if empty or invalid.
			 */
			if (len < VALUE_LEN)
				break;

			if ((rval = crypto_verify(ep, NULL, peer)) !=
			    XEVNT_OK)
				break;

			/*
			 * Scan the certificate list to delete old
			 * versions and link the newest version first on
			 * the list. Then, verify the signature. If the
			 * certificate is bad or missing, just ignore
			 * it.
			 */
			if ((xinfo = cert_install(ep, peer)) == NULL) {
				rval = XEVNT_CRT;
				break;
			}
			if ((rval = cert_hike(peer, xinfo)) != XEVNT_OK)
				break;

			/*
			 * We plug in the public key and lifetime from
			 * the first certificate received. However, note
			 * that this certificate might not be signed by
			 * the server, so we can't check the
			 * signature/digest NID.
			 */
			if (peer->pkey == NULL) {
				puch = xinfo->cert.ptr;
				cert = d2i_X509(NULL, &puch,
				    ntohl(xinfo->cert.vallen));
				peer->pkey = X509_get_pubkey(cert);
				X509_free(cert);
			}
			peer->flash &= ~TEST8;
			temp32 = xinfo->nid;
			snprintf(statstr, sizeof(statstr),
			    "cert %s %s 0x%x %s (%u) fs %u",
			    xinfo->subject, xinfo->issuer, xinfo->flags,
			    OBJ_nid2ln(temp32), temp32,
			    ntohl(ep->fstamp));
			record_crypto_stats(&peer->srcadr, statstr);
			DPRINTF(1, ("crypto_recv: %s\n", statstr));
			break;

		/*
		 * Schnorr (IFF) identity scheme. This scheme is
		 * designed for use with shared secret server group keys
		 * and where the certificate may be generated by a third
		 * party. The client sends a challenge to the server,
		 * which performs a calculation and returns the result.
		 * A positive result is possible only if both client and
		 * server contain the same secret group key.
		 */
		case CRYPTO_IFF | CRYPTO_RESP:

			/*
			 * Discard the message if invalid.
			 */
			if ((rval = crypto_verify(ep, NULL, peer)) !=
			    XEVNT_OK)
				break;

			/*
			 * If the challenge matches the response, the
			 * server public key, signature and identity are
			 * all verified at the same time. The server is
			 * declared trusted, so we skip further
			 * certificate exchanges and move immediately to
			 * the cookie exchange.
			 */
			if ((rval = crypto_iff(ep, peer)) != XEVNT_OK)
				break;

			peer->crypto |= CRYPTO_FLAG_VRFY;
			peer->flash &= ~TEST8;
			snprintf(statstr, sizeof(statstr), "iff %s fs %u",
			    peer->issuer, ntohl(ep->fstamp));
			record_crypto_stats(&peer->srcadr, statstr);
			DPRINTF(1, ("crypto_recv: %s\n", statstr));
			break;

		/*
		 * Guillou-Quisquater (GQ) identity scheme. This scheme
		 * is designed for use with public certificates carrying
		 * the GQ public key in an extension field. The client
		 * sends a challenge to the server, which performs a
		 * calculation and returns the result. A positive result
		 * is possible only if both client and server contain
		 * the same group key and the server has the matching GQ
		 * private key.
		 */
		case CRYPTO_GQ | CRYPTO_RESP:

			/*
			 * Discard the message if invalid
			 */
			if ((rval = crypto_verify(ep, NULL, peer)) !=
			    XEVNT_OK)
				break;

			/*
			 * If the challenge matches the response, the
			 * server public key, signature and identity are
			 * all verified at the same time. The server is
			 * declared trusted, so we skip further
			 * certificate exchanges and move immediately to
			 * the cookie exchange.
			 */
			if ((rval = crypto_gq(ep, peer)) != XEVNT_OK)
				break;

			peer->crypto |= CRYPTO_FLAG_VRFY;
			peer->flash &= ~TEST8;
			snprintf(statstr, sizeof(statstr), "gq %s fs %u",
			    peer->issuer, ntohl(ep->fstamp));
			record_crypto_stats(&peer->srcadr, statstr);
			DPRINTF(1, ("crypto_recv: %s\n", statstr));
			break;

		/*
		 * Mu-Varadharajan (MV) identity scheme. This scheme is
		 * designed for use with three levels of trust, trusted
		 * host, server and client. The trusted host key is
		 * opaque to servers and clients; the server keys are
		 * opaque to clients and each client key is different.
		 * Client keys can be revoked without requiring new key
		 * generations.
		 */
		case CRYPTO_MV | CRYPTO_RESP:

			/*
			 * Discard the message if invalid.
			 */
			if ((rval = crypto_verify(ep, NULL, peer)) !=
			    XEVNT_OK)
				break;

			/*
			 * If the challenge matches the response, the
			 * server public key, signature and identity are
			 * all verified at the same time. The server is
			 * declared trusted, so we skip further
			 * certificate exchanges and move immediately to
			 * the cookie exchange.
			 */
			if ((rval = crypto_mv(ep, peer)) != XEVNT_OK)
				break;

			peer->crypto |= CRYPTO_FLAG_VRFY;
			peer->flash &= ~TEST8;
			snprintf(statstr, sizeof(statstr), "mv %s fs %u",
			    peer->issuer, ntohl(ep->fstamp));
			record_crypto_stats(&peer->srcadr, statstr);
			DPRINTF(1, ("crypto_recv: %s\n", statstr));
			break;

		/*
		 * Cookie response in client and symmetric modes. If the
		 * cookie bit is set, the working cookie is the EXOR of
		 * the current and new values.
		 */
		case CRYPTO_COOK | CRYPTO_RESP:

			/*
			 * Discard the message if invalid or signature
			 * not verified with respect to the cookie
			 * values.
			 */
			if ((rval = crypto_verify(ep, &peer->cookval,
			    peer)) != XEVNT_OK)
				break;

			/*
			 * Decrypt the cookie, hunting all the time for
			 * errors.
			 */
			if (vallen == (u_int)EVP_PKEY_size(host_pkey)) {
				u_int32 *cookiebuf = malloc(
				    RSA_size(host_pkey->pkey.rsa));
				if (!cookiebuf) {
					rval = XEVNT_CKY;
					break;
				}

				if (RSA_private_decrypt(vallen,
				    (u_char *)ep->pkt,
				    (u_char *)cookiebuf,
				    host_pkey->pkey.rsa,
				    RSA_PKCS1_OAEP_PADDING) != 4) {
					rval = XEVNT_CKY;
					free(cookiebuf);
					break;
				} else {
					cookie = ntohl(*cookiebuf);
					free(cookiebuf);
				}
			} else {
				rval = XEVNT_CKY;
				break;
			}

			/*
			 * Install cookie values and light the cookie
			 * bit. If this is not broadcast client mode, we
			 * are done here.
			 */
			key_expire(peer);
			if (hismode == MODE_ACTIVE || hismode ==
			    MODE_PASSIVE)
				peer->pcookie = peer->hcookie ^ cookie;
			else
				peer->pcookie = cookie;
			peer->crypto |= CRYPTO_FLAG_COOK;
			peer->flash &= ~TEST8;
			snprintf(statstr, sizeof(statstr),
			    "cook %x ts %u fs %u", peer->pcookie,
			    ntohl(ep->tstamp), ntohl(ep->fstamp));
			record_crypto_stats(&peer->srcadr, statstr);
			DPRINTF(1, ("crypto_recv: %s\n", statstr));
			break;

		/*
		 * Install autokey values in broadcast client and
		 * symmetric modes. We have to do this every time the
		 * sever/peer cookie changes or a new keylist is
		 * rolled. Ordinarily, this is automatic as this message
		 * is piggybacked on the first NTP packet sent upon
		 * either of these events. Note that a broadcast client
		 * or symmetric peer can receive this response without a
		 * matching request.
		 */
		case CRYPTO_AUTO | CRYPTO_RESP:

			/*
			 * Discard the message if invalid or signature
			 * not verified with respect to the receive
			 * autokey values.
			 */
			if ((rval = crypto_verify(ep, &peer->recval,
			    peer)) != XEVNT_OK)
				break;

			/*
			 * Discard the message if a broadcast client and
			 * the association ID does not match. This might
			 * happen if a broacast server restarts the
			 * protocol. A protocol restart will occur at
			 * the next ASSOC message.
			 */
			if ((peer->cast_flags & MDF_BCLNT) &&
			    peer->assoc != associd)
				break;

			/*
			 * Install autokey values and light the
			 * autokey bit. This is not hard.
			 */
			if (ep->tstamp == 0)
				break;

			if (peer->recval.ptr == NULL)
				peer->recval.ptr =
				    emalloc(sizeof(struct autokey));
			bp = (struct autokey *)peer->recval.ptr;
			peer->recval.tstamp = ep->tstamp;
			peer->recval.fstamp = ep->fstamp;
			ap = (struct autokey *)ep->pkt;
			bp->seq = ntohl(ap->seq);
			bp->key = ntohl(ap->key);
			peer->pkeyid = bp->key;
			peer->crypto |= CRYPTO_FLAG_AUTO;
			peer->flash &= ~TEST8;
			snprintf(statstr, sizeof(statstr),
			    "auto seq %d key %x ts %u fs %u", bp->seq,
			    bp->key, ntohl(ep->tstamp),
			    ntohl(ep->fstamp));
			record_crypto_stats(&peer->srcadr, statstr);
			DPRINTF(1, ("crypto_recv: %s\n", statstr));
			break;

		/*
		 * X509 certificate sign response. Validate the
		 * certificate signed by the server and install. Later
		 * this can be provided to clients of this server in
		 * lieu of the self signed certificate in order to
		 * validate the public key.
		 */
		case CRYPTO_SIGN | CRYPTO_RESP:

			/*
			 * Discard the message if invalid.
			 */
			if ((rval = crypto_verify(ep, NULL, peer)) !=
			    XEVNT_OK)
				break;

			/*
			 * Scan the certificate list to delete old
			 * versions and link the newest version first on
			 * the list.
			 */
			if ((xinfo = cert_install(ep, peer)) == NULL) {
				rval = XEVNT_CRT;
				break;
			}
			peer->crypto |= CRYPTO_FLAG_SIGN;
			peer->flash &= ~TEST8;
			temp32 = xinfo->nid;
			snprintf(statstr, sizeof(statstr),
			    "sign %s %s 0x%x %s (%u) fs %u",
			    xinfo->subject, xinfo->issuer, xinfo->flags,
			    OBJ_nid2ln(temp32), temp32,
			    ntohl(ep->fstamp));
			record_crypto_stats(&peer->srcadr, statstr);
			DPRINTF(1, ("crypto_recv: %s\n", statstr));
			break;

		/*
		 * Install leapseconds values. While the leapsecond
		 * values epoch, TAI offset and values expiration epoch
		 * are retained, only the current TAI offset is provided
		 * via the kernel to other applications.
		 */
		case CRYPTO_LEAP | CRYPTO_RESP:
			/*
			 * Discard the message if invalid. We can't
			 * compare the value timestamps here, as they
			 * can be updated by different servers.
			 */
			rval = crypto_verify(ep, NULL, peer);
			if ((rval   != XEVNT_OK          ) ||
			    (vallen != 3*sizeof(uint32_t))  )
				break;

			/* Check if we can update the basic TAI offset
			 * for our current leap frame. This is a hack
			 * and ignores the time stamps in the autokey
			 * message.
			 */
			if (sys_leap != LEAP_NOTINSYNC)
				leapsec_autokey_tai(ntohl(ep->pkt[0]),
						    rbufp->recv_time.l_ui, NULL);
			tai_leap.tstamp = ep->tstamp;
			tai_leap.fstamp = ep->fstamp;
			crypto_update();
			mprintf_event(EVNT_TAI, peer,
				      "%d seconds", ntohl(ep->pkt[0]));
			peer->crypto |= CRYPTO_FLAG_LEAP;
			peer->flash &= ~TEST8;
			snprintf(statstr, sizeof(statstr),
				 "leap TAI offset %d at %u expire %u fs %u",
				 ntohl(ep->pkt[0]), ntohl(ep->pkt[1]),
				 ntohl(ep->pkt[2]), ntohl(ep->fstamp));
			record_crypto_stats(&peer->srcadr, statstr);
			DPRINTF(1, ("crypto_recv: %s\n", statstr));
			break;

		/*
		 * We come here in symmetric modes for miscellaneous
		 * commands that have value fields but are processed on
		 * the transmit side. All we need do here is check for
		 * valid field length. Note that ASSOC is handled
		 * separately.
		 */
		case CRYPTO_CERT:
		case CRYPTO_IFF:
		case CRYPTO_GQ:
		case CRYPTO_MV:
		case CRYPTO_COOK:
		case CRYPTO_SIGN:
			if (len < VALUE_LEN) {
				rval = XEVNT_LEN;
				break;
			}
			/* fall through */

		/*
		 * We come here in symmetric modes for requests
		 * requiring a response (above plus AUTO and LEAP) and
		 * for responses. If a request, save the extension field
		 * for later; invalid requests will be caught on the
		 * transmit side. If an error or invalid response,
		 * declare a protocol error.
		 */
		default:
			if (code & (CRYPTO_RESP | CRYPTO_ERROR)) {
				rval = XEVNT_ERR;
			} else if (peer->cmmd == NULL) {
				fp = emalloc(len);
				memcpy(fp, ep, len);
				peer->cmmd = fp;
			}
		}

		/*
		 * The first error found terminates the extension field
		 * scan and we return the laundry to the caller.
		 */
		if (rval != XEVNT_OK) {
			snprintf(statstr, sizeof(statstr),
			    "%04x %d %02x %s", htonl(ep->opcode),
			    associd, rval, eventstr(rval));
			record_crypto_stats(&peer->srcadr, statstr);
			DPRINTF(1, ("crypto_recv: %s\n", statstr));
			return (rval);
		}
		authlen += (len + 3) / 4 * 4;
	}
	return (rval);
}

The crypto_xmit function in ntpd in NTP 4.2.x before 4.2.8p4, and 4.3.x before 4.3.77 allows remote attackers to cause a denial of service (crash) via crafted packets containing particular autokey operations.  NOTE: This vulnerability exists due to an incomplete fix for CVE-2014-9750.