static Image *ReadDCMImage(const ImageInfo *image_info,ExceptionInfo *exception)
{
  char
    explicit_vr[MagickPathExtent],
    implicit_vr[MagickPathExtent],
    magick[MagickPathExtent],
    photometric[MagickPathExtent];

  DCMStreamInfo
    *stream_info;

  Image
    *image;

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

  MagickBooleanType
    explicit_file,
    explicit_retry,
    polarity,
    sequence,
    use_explicit;

  MagickOffsetType
    offset;

  Quantum
    *scale;

  register ssize_t
    i,
    x;

  register Quantum
    *q;

  register unsigned char
    *p;

  size_t
    bits_allocated,
    bytes_per_pixel,
    colors,
    depth,
    height,
    length,
    mask,
    max_value,
    number_scenes,
    quantum,
    samples_per_pixel,
    signed_data,
    significant_bits,
    status,
    width,
    window_width;

  ssize_t
    count,
    rescale_intercept,
    rescale_slope,
    scene,
    window_center,
    y;

  unsigned char
    *data;

  unsigned short
    group,
    element;

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

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

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

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

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

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

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

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

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

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

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

      ImageInfo
        *read_info;

      int
        c;

      size_t
        length;

      unsigned int
        tag;

      /*
        Read offset table.
      */
      for (i=0; i < (ssize_t) stream_info->remaining; i++)
        (void) ReadBlobByte(image);
      tag=(ReadBlobLSBShort(image) << 16) | ReadBlobLSBShort(image);
      (void) tag;
      length=(size_t) ReadBlobLSBLong(image);
      stream_info->offset_count=length >> 2;
      if (stream_info->offset_count != 0)
        {
          MagickOffsetType
            offset;

          stream_info->offsets=(ssize_t *) AcquireQuantumMemory(
            stream_info->offset_count,sizeof(*stream_info->offsets));
          if (stream_info->offsets == (ssize_t *) NULL)
            ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
          for (i=0; i < (ssize_t) stream_info->offset_count; i++)
            stream_info->offsets[i]=(ssize_t) ReadBlobLSBSignedLong(image);
          offset=TellBlob(image);
          for (i=0; i < (ssize_t) stream_info->offset_count; i++)
            stream_info->offsets[i]+=offset;
        }
      /*
        Handle non-native image formats.
      */
      read_info=CloneImageInfo(image_info);
      SetImageInfoBlob(read_info,(void *) NULL,0);
      images=NewImageList();
      for (scene=0; scene < (ssize_t) number_scenes; scene++)
      {
        char
          filename[MagickPathExtent];

        const char
          *property;

        FILE
          *file;

        Image
          *jpeg_image;

        int
          unique_file;

        unsigned int
          tag;

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

      size_t
        length;

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

      unsigned int
        tag;

      /*
        Read RLE offset table.
      */
      for (i=0; i < (ssize_t) stream_info->remaining; i++)
        (void) ReadBlobByte(image);
      tag=(ReadBlobLSBShort(image) << 16) | ReadBlobLSBShort(image);
      (void) tag;
      length=(size_t) ReadBlobLSBLong(image);
      stream_info->offset_count=length >> 2;
      if (stream_info->offset_count != 0)
        {
          MagickOffsetType
            offset;

          stream_info->offsets=(ssize_t *) AcquireQuantumMemory(
            stream_info->offset_count,sizeof(*stream_info->offsets));
          if (stream_info->offsets == (ssize_t *) NULL)
            ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
          for (i=0; i < (ssize_t) stream_info->offset_count; i++)
            stream_info->offsets[i]=(ssize_t) ReadBlobLSBSignedLong(image);
          offset=TellBlob(image);
          for (i=0; i < (ssize_t) stream_info->offset_count; i++)
            stream_info->offsets[i]+=offset;
        }
    }
  for (scene=0; scene < (ssize_t) number_scenes; scene++)
  {
    if (image_info->ping != MagickFalse)
      break;
    image->columns=(size_t) width;
    image->rows=(size_t) height;
    image->depth=depth;
    status=SetImageExtent(image,image->columns,image->rows,exception);
    if (status == MagickFalse)
      break;
    image->colorspace=RGBColorspace;
    if ((image->colormap == (PixelInfo *) NULL) && (samples_per_pixel == 1))
      {
        size_t
          one;

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

        /*
          Read RLE segment table.
        */
        for (i=0; i < (ssize_t) stream_info->remaining; i++)
          (void) ReadBlobByte(image);
        tag=(ReadBlobLSBShort(image) << 16) | ReadBlobLSBShort(image);
        stream_info->remaining=(size_t) ReadBlobLSBLong(image);
        if ((tag != 0xFFFEE000) || (stream_info->remaining <= 64) ||
            (EOFBlob(image) != MagickFalse))
          ThrowReaderException(CorruptImageError,"ImproperImageHeader");
        stream_info->count=0;
        stream_info->segment_count=ReadBlobLSBLong(image);
        if (stream_info->segment_count > 1)
          {
            bytes_per_pixel=1;
            depth=8;
          }
        for (i=0; i < 15; i++)
          stream_info->segments[i]=(ssize_t) ReadBlobLSBSignedLong(image);
        stream_info->remaining-=64;
      }
    if ((samples_per_pixel > 1) && (image->interlace == PlaneInterlace))
      {
        /*
          Convert Planar RGB DCM Medical image to pixel packets.
        */
        for (i=0; i < (ssize_t) samples_per_pixel; i++)
        {
          for (y=0; y < (ssize_t) image->rows; y++)
          {
            q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
            if (q == (Quantum *) NULL)
              break;
            for (x=0; x < (ssize_t) image->columns; x++)
            {
              switch ((int) i)
              {
                case 0:
                {
                  SetPixelRed(image,ScaleCharToQuantum((unsigned char)
                    ReadDCMByte(stream_info,image)),q);
                  break;
                }
                case 1:
                {
                  SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
                    ReadDCMByte(stream_info,image)),q);
                  break;
                }
                case 2:
                {
                  SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
                    ReadDCMByte(stream_info,image)),q);
                  break;
                }
                case 3:
                {
                  SetPixelAlpha(image,ScaleCharToQuantum((unsigned char)
                    ReadDCMByte(stream_info,image)),q);
                  break;
                }
                default:
                  break;
              }
              q+=GetPixelChannels(image);
            }
            if (SyncAuthenticPixels(image,exception) == MagickFalse)
              break;
            if (image->previous == (Image *) NULL)
              {
                status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
                  image->rows);
                if (status == MagickFalse)
                  break;
              }
          }
        }
      }
    else
      {
        const char
          *option;

        int
          byte;

        PixelPacket
          pixel;

        /*
          Convert DCM Medical image to pixel packets.
        */
        byte=0;
        i=0;
        if ((window_center != 0) && (window_width == 0))
          window_width=(size_t) window_center;
        option=GetImageOption(image_info,"dcm:display-range");
        if (option != (const char *) NULL)
          {
            if (LocaleCompare(option,"reset") == 0)
              window_width=0;
          }
        (void) ResetMagickMemory(&pixel,0,sizeof(pixel));
        for (y=0; y < (ssize_t) image->rows; y++)
        {
          q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
          if (q == (Quantum *) NULL)
            break;
          for (x=0; x < (ssize_t) image->columns; x++)
          {
            if (samples_per_pixel == 1)
              {
                int
                  pixel_value;

                if (bytes_per_pixel == 1)
                  pixel_value=polarity != MagickFalse ?
                    ((int) max_value-ReadDCMByte(stream_info,image)) :
                    ReadDCMByte(stream_info,image);
                else
                  if ((bits_allocated != 12) || (significant_bits != 12))
                    {
                      if (signed_data)
                        pixel_value=ReadDCMSignedShort(stream_info,image);
                      else
                        pixel_value=ReadDCMShort(stream_info,image);
                      if (polarity != MagickFalse)
                        pixel_value=(int)max_value-pixel_value;
                    }
                  else
                    {
                      if ((i & 0x01) != 0)
                        pixel_value=(ReadDCMByte(stream_info,image) << 8) |
                          byte;
                      else
                        {
                          pixel_value=ReadDCMSignedShort(stream_info,image);
                          byte=(int) (pixel_value & 0x0f);
                          pixel_value>>=4;
                        }
                      i++;
                    }
                index=(pixel_value*rescale_slope)+rescale_intercept;
                if (window_width == 0)
                  {
                    if (signed_data == 1)
                      index-=32767;
                  }
                else
                  {
                    ssize_t
                      window_max,
                      window_min;

                    window_min=(ssize_t) ceil((double) window_center-
                      (window_width-1.0)/2.0-0.5);
                    window_max=(ssize_t) floor((double) window_center+
                      (window_width-1.0)/2.0+0.5);
                    if ((ssize_t)index <= window_min)
                      index=0;
                    else
                      if ((ssize_t)index > window_max)
                        index=(int) max_value;
                      else
                        index=(int) (max_value*(((index-window_center-
                          0.5)/(window_width-1))+0.5));
                  }
                index&=mask;
                index=(int) ConstrainColormapIndex(image,(size_t) index,
                  exception);
                SetPixelIndex(image,(Quantum) index,q);
                pixel.red=(unsigned int) image->colormap[index].red;
                pixel.green=(unsigned int) image->colormap[index].green;
                pixel.blue=(unsigned int) image->colormap[index].blue;
              }
            else
              {
                if (bytes_per_pixel == 1)
                  {
                    pixel.red=(unsigned int) ReadDCMByte(stream_info,image);
                    pixel.green=(unsigned int) ReadDCMByte(stream_info,image);
                    pixel.blue=(unsigned int) ReadDCMByte(stream_info,image);
                  }
                else
                  {
                    pixel.red=ReadDCMShort(stream_info,image);
                    pixel.green=ReadDCMShort(stream_info,image);
                    pixel.blue=ReadDCMShort(stream_info,image);
                  }
                pixel.red&=mask;
                pixel.green&=mask;
                 pixel.blue&=mask;
                 if (scale != (Quantum *) NULL)
                   {
                    if (pixel.red <= GetQuantumRange(depth))
                      pixel.red=scale[pixel.red];
                    if (pixel.green <= GetQuantumRange(depth))
                      pixel.green=scale[pixel.green];
                    if (pixel.blue <= GetQuantumRange(depth))
                      pixel.blue=scale[pixel.blue];
                   }
               }
             SetPixelRed(image,(Quantum) pixel.red,q);
            SetPixelGreen(image,(Quantum) pixel.green,q);
            SetPixelBlue(image,(Quantum) pixel.blue,q);
            q+=GetPixelChannels(image);
          }
          if (SyncAuthenticPixels(image,exception) == MagickFalse)
            break;
          if (image->previous == (Image *) NULL)
            {
              status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
                image->rows);
              if (status == MagickFalse)
                break;
            }
        }
        if (stream_info->segment_count > 1)
          for (y=0; y < (ssize_t) image->rows; y++)
          {
            q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
            if (q == (Quantum *) NULL)
              break;
            for (x=0; x < (ssize_t) image->columns; x++)
            {
              if (samples_per_pixel == 1)
                {
                  int
                    pixel_value;

                  if (bytes_per_pixel == 1)
                    pixel_value=polarity != MagickFalse ?
                      ((int) max_value-ReadDCMByte(stream_info,image)) :
                      ReadDCMByte(stream_info,image);
                  else
                    if ((bits_allocated != 12) || (significant_bits != 12))
                      {
                        pixel_value=(int) (polarity != MagickFalse ?
                          (max_value-ReadDCMShort(stream_info,image)) :
                          ReadDCMShort(stream_info,image));
                        if (signed_data == 1)
                          pixel_value=((signed short) pixel_value);
                      }
                    else
                      {
                        if ((i & 0x01) != 0)
                          pixel_value=(ReadDCMByte(stream_info,image) << 8) |
                            byte;
                        else
                          {
                            pixel_value=ReadDCMShort(stream_info,image);
                            byte=(int) (pixel_value & 0x0f);
                            pixel_value>>=4;
                          }
                        i++;
                      }
                  index=(pixel_value*rescale_slope)+rescale_intercept;
                  if (window_width == 0)
                    {
                      if (signed_data == 1)
                        index-=32767;
                    }
                  else
                    {
                      ssize_t
                        window_max,
                        window_min;

                      window_min=(ssize_t) ceil((double) window_center-
                        (window_width-1.0)/2.0-0.5);
                      window_max=(ssize_t) floor((double) window_center+
                        (window_width-1.0)/2.0+0.5);
                      if ((ssize_t)index <= window_min)
                        index=0;
                      else
                        if ((ssize_t)index > window_max)
                          index=(int) max_value;
                        else
                          index=(int) (max_value*(((index-window_center-
                            0.5)/(window_width-1))+0.5));
                    }
                  index&=mask;
                  index=(int) ConstrainColormapIndex(image,(size_t) index,
                    exception);
                  SetPixelIndex(image,(Quantum) (((size_t)
                    GetPixelIndex(image,q)) | (((size_t) index) << 8)),q);
                  pixel.red=(unsigned int) image->colormap[index].red;
                  pixel.green=(unsigned int) image->colormap[index].green;
                  pixel.blue=(unsigned int) image->colormap[index].blue;
                }
              else
                {
                  if (bytes_per_pixel == 1)
                    {
                      pixel.red=(unsigned int) ReadDCMByte(stream_info,image);
                      pixel.green=(unsigned int) ReadDCMByte(stream_info,image);
                      pixel.blue=(unsigned int) ReadDCMByte(stream_info,image);
                    }
                  else
                    {
                      pixel.red=ReadDCMShort(stream_info,image);
                      pixel.green=ReadDCMShort(stream_info,image);
                      pixel.blue=ReadDCMShort(stream_info,image);
                    }
                  pixel.red&=mask;
                  pixel.green&=mask;
                  pixel.blue&=mask;
                  if (scale != (Quantum *) NULL)
                    {
                      pixel.red=scale[pixel.red];
                      pixel.green=scale[pixel.green];
                      pixel.blue=scale[pixel.blue];
                    }
                }
              SetPixelRed(image,(Quantum) (((size_t) GetPixelRed(image,q)) |
                (((size_t) pixel.red) << 8)),q);
              SetPixelGreen(image,(Quantum) (((size_t) GetPixelGreen(image,q)) |
                (((size_t) pixel.green) << 8)),q);
              SetPixelBlue(image,(Quantum) (((size_t) GetPixelBlue(image,q)) |
                (((size_t) pixel.blue) << 8)),q);
              q+=GetPixelChannels(image);
            }
            if (SyncAuthenticPixels(image,exception) == MagickFalse)
              break;
            if (image->previous == (Image *) NULL)
              {
                status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
                  image->rows);
                if (status == MagickFalse)
                  break;
              }
          }
      }
    if (SetImageGray(image,exception) != MagickFalse)
      (void) SetImageColorspace(image,GRAYColorspace,exception);
    if (EOFBlob(image) != MagickFalse)
      {
        ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
          image->filename);
        break;
      }
    /*
      Proceed to next image.
    */
    if (image_info->number_scenes != 0)
      if (image->scene >= (image_info->scene+image_info->number_scenes-1))
        break;
    if (scene < (ssize_t) (number_scenes-1))
      {
        /*
          Allocate next image structure.
        */
        AcquireNextImage(image_info,image,exception);
        if (GetNextImageInList(image) == (Image *) NULL)
          {
            image=DestroyImageList(image);
            return((Image *) NULL);
          }
        image=SyncNextImageInList(image);
        status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
          GetBlobSize(image));
        if (status == MagickFalse)
          break;
      }
  }
  /*
    Free resources.
  */
  if (stream_info->offsets != (ssize_t *) NULL)
    stream_info->offsets=(ssize_t *)
      RelinquishMagickMemory(stream_info->offsets);
  stream_info=(DCMStreamInfo *) RelinquishMagickMemory(stream_info);
  if (scale != (Quantum *) NULL)
    scale=(Quantum *) RelinquishMagickMemory(scale);
  if (graymap != (int *) NULL)
    graymap=(int *) RelinquishMagickMemory(graymap);
  if (bluemap != (int *) NULL)
    bluemap=(int *) RelinquishMagickMemory(bluemap);
  if (greenmap != (int *) NULL)
    greenmap=(int *) RelinquishMagickMemory(greenmap);
  if (redmap != (int *) NULL)
    redmap=(int *) RelinquishMagickMemory(redmap);
  (void) CloseBlob(image);
  return(GetFirstImageInList(image));
}


media: fix airspy usb probe error path

Fix a memory leak on probe error of the airspy usb device driver.

The problem is triggered when more than 64 usb devices register with
v4l2 of type VFL_TYPE_SDR or VFL_TYPE_SUBDEV.

The memory leak is caused by the probe function of the airspy driver
mishandeling errors and not freeing the corresponding control structures
when an error occours registering the device to v4l2 core.

A badusb device can emulate 64 of these devices, and then through
continual emulated connect/disconnect of the 65th device, cause the
kernel to run out of RAM and crash the kernel, thus causing a local DOS
vulnerability.

Fixes CVE-2016-5400

Signed-off-by: James Patrick-Evans <james@jmp-e.com>
Reviewed-by: Kees Cook <keescook@chromium.org>
Cc: stable@vger.kernel.org # 3.17+
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

static int airspy_probe(struct usb_interface *intf,
		const struct usb_device_id *id)
{
	struct airspy *s;
	int ret;
	u8 u8tmp, buf[BUF_SIZE];

	s = kzalloc(sizeof(struct airspy), GFP_KERNEL);
	if (s == NULL) {
		dev_err(&intf->dev, "Could not allocate memory for state\n");
		return -ENOMEM;
	}

	mutex_init(&s->v4l2_lock);
	mutex_init(&s->vb_queue_lock);
	spin_lock_init(&s->queued_bufs_lock);
	INIT_LIST_HEAD(&s->queued_bufs);
	s->dev = &intf->dev;
	s->udev = interface_to_usbdev(intf);
	s->f_adc = bands[0].rangelow;
	s->f_rf = bands_rf[0].rangelow;
	s->pixelformat = formats[0].pixelformat;
	s->buffersize = formats[0].buffersize;

	/* Detect device */
	ret = airspy_ctrl_msg(s, CMD_BOARD_ID_READ, 0, 0, &u8tmp, 1);
	if (ret == 0)
		ret = airspy_ctrl_msg(s, CMD_VERSION_STRING_READ, 0, 0,
				buf, BUF_SIZE);
	if (ret) {
		dev_err(s->dev, "Could not detect board\n");
		goto err_free_mem;
	}

	buf[BUF_SIZE - 1] = '\0';

	dev_info(s->dev, "Board ID: %02x\n", u8tmp);
	dev_info(s->dev, "Firmware version: %s\n", buf);

	/* Init videobuf2 queue structure */
	s->vb_queue.type = V4L2_BUF_TYPE_SDR_CAPTURE;
	s->vb_queue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
	s->vb_queue.drv_priv = s;
	s->vb_queue.buf_struct_size = sizeof(struct airspy_frame_buf);
	s->vb_queue.ops = &airspy_vb2_ops;
	s->vb_queue.mem_ops = &vb2_vmalloc_memops;
	s->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
	ret = vb2_queue_init(&s->vb_queue);
	if (ret) {
		dev_err(s->dev, "Could not initialize vb2 queue\n");
		goto err_free_mem;
	}

	/* Init video_device structure */
	s->vdev = airspy_template;
	s->vdev.queue = &s->vb_queue;
	s->vdev.queue->lock = &s->vb_queue_lock;
	video_set_drvdata(&s->vdev, s);

	/* Register the v4l2_device structure */
	s->v4l2_dev.release = airspy_video_release;
	ret = v4l2_device_register(&intf->dev, &s->v4l2_dev);
	if (ret) {
		dev_err(s->dev, "Failed to register v4l2-device (%d)\n", ret);
		goto err_free_mem;
	}

	/* Register controls */
	v4l2_ctrl_handler_init(&s->hdl, 5);
	s->lna_gain_auto = v4l2_ctrl_new_std(&s->hdl, &airspy_ctrl_ops,
			V4L2_CID_RF_TUNER_LNA_GAIN_AUTO, 0, 1, 1, 0);
	s->lna_gain = v4l2_ctrl_new_std(&s->hdl, &airspy_ctrl_ops,
			V4L2_CID_RF_TUNER_LNA_GAIN, 0, 14, 1, 8);
	v4l2_ctrl_auto_cluster(2, &s->lna_gain_auto, 0, false);
	s->mixer_gain_auto = v4l2_ctrl_new_std(&s->hdl, &airspy_ctrl_ops,
			V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO, 0, 1, 1, 0);
	s->mixer_gain = v4l2_ctrl_new_std(&s->hdl, &airspy_ctrl_ops,
			V4L2_CID_RF_TUNER_MIXER_GAIN, 0, 15, 1, 8);
	v4l2_ctrl_auto_cluster(2, &s->mixer_gain_auto, 0, false);
	s->if_gain = v4l2_ctrl_new_std(&s->hdl, &airspy_ctrl_ops,
			V4L2_CID_RF_TUNER_IF_GAIN, 0, 15, 1, 0);
	if (s->hdl.error) {
		ret = s->hdl.error;
		dev_err(s->dev, "Could not initialize controls\n");
		goto err_free_controls;
	}

	v4l2_ctrl_handler_setup(&s->hdl);

	s->v4l2_dev.ctrl_handler = &s->hdl;
	s->vdev.v4l2_dev = &s->v4l2_dev;
	s->vdev.lock = &s->v4l2_lock;

	ret = video_register_device(&s->vdev, VFL_TYPE_SDR, -1);
 	if (ret) {
 		dev_err(s->dev, "Failed to register as video device (%d)\n",
 				ret);
		goto err_unregister_v4l2_dev;
 	}
 	dev_info(s->dev, "Registered as %s\n",
 			video_device_node_name(&s->vdev));
	dev_notice(s->dev, "SDR API is still slightly experimental and functionality changes may follow\n");
	return 0;

 err_free_controls:
 	v4l2_ctrl_handler_free(&s->hdl);
err_unregister_v4l2_dev:
 	v4l2_device_unregister(&s->v4l2_dev);
 err_free_mem:
 	kfree(s);
	return ret;
}

Memory leak in the airspy_probe function in drivers/media/usb/airspy/airspy.c in the airspy USB driver in the Linux kernel before 4.7 allows local users to cause a denial of service (memory consumption) via a crafted USB device that emulates many VFL_TYPE_SDR or VFL_TYPE_SUBDEV devices and performs many connect and disconnect operations.


static int airspy_probe(struct usb_interface *intf,
		const struct usb_device_id *id)
{
	struct airspy *s;
	int ret;
	u8 u8tmp, buf[BUF_SIZE];

	s = kzalloc(sizeof(struct airspy), GFP_KERNEL);
	if (s == NULL) {
		dev_err(&intf->dev, "Could not allocate memory for state\n");
		return -ENOMEM;
	}

	mutex_init(&s->v4l2_lock);
	mutex_init(&s->vb_queue_lock);
	spin_lock_init(&s->queued_bufs_lock);
	INIT_LIST_HEAD(&s->queued_bufs);
	s->dev = &intf->dev;
	s->udev = interface_to_usbdev(intf);
	s->f_adc = bands[0].rangelow;
	s->f_rf = bands_rf[0].rangelow;
	s->pixelformat = formats[0].pixelformat;
	s->buffersize = formats[0].buffersize;

	/* Detect device */
	ret = airspy_ctrl_msg(s, CMD_BOARD_ID_READ, 0, 0, &u8tmp, 1);
	if (ret == 0)
		ret = airspy_ctrl_msg(s, CMD_VERSION_STRING_READ, 0, 0,
				buf, BUF_SIZE);
	if (ret) {
		dev_err(s->dev, "Could not detect board\n");
		goto err_free_mem;
	}

	buf[BUF_SIZE - 1] = '\0';

	dev_info(s->dev, "Board ID: %02x\n", u8tmp);
	dev_info(s->dev, "Firmware version: %s\n", buf);

	/* Init videobuf2 queue structure */
	s->vb_queue.type = V4L2_BUF_TYPE_SDR_CAPTURE;
	s->vb_queue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
	s->vb_queue.drv_priv = s;
	s->vb_queue.buf_struct_size = sizeof(struct airspy_frame_buf);
	s->vb_queue.ops = &airspy_vb2_ops;
	s->vb_queue.mem_ops = &vb2_vmalloc_memops;
	s->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
	ret = vb2_queue_init(&s->vb_queue);
	if (ret) {
		dev_err(s->dev, "Could not initialize vb2 queue\n");
		goto err_free_mem;
	}

	/* Init video_device structure */
	s->vdev = airspy_template;
	s->vdev.queue = &s->vb_queue;
	s->vdev.queue->lock = &s->vb_queue_lock;
	video_set_drvdata(&s->vdev, s);

	/* Register the v4l2_device structure */
	s->v4l2_dev.release = airspy_video_release;
	ret = v4l2_device_register(&intf->dev, &s->v4l2_dev);
	if (ret) {
		dev_err(s->dev, "Failed to register v4l2-device (%d)\n", ret);
		goto err_free_mem;
	}

	/* Register controls */
	v4l2_ctrl_handler_init(&s->hdl, 5);
	s->lna_gain_auto = v4l2_ctrl_new_std(&s->hdl, &airspy_ctrl_ops,
			V4L2_CID_RF_TUNER_LNA_GAIN_AUTO, 0, 1, 1, 0);
	s->lna_gain = v4l2_ctrl_new_std(&s->hdl, &airspy_ctrl_ops,
			V4L2_CID_RF_TUNER_LNA_GAIN, 0, 14, 1, 8);
	v4l2_ctrl_auto_cluster(2, &s->lna_gain_auto, 0, false);
	s->mixer_gain_auto = v4l2_ctrl_new_std(&s->hdl, &airspy_ctrl_ops,
			V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO, 0, 1, 1, 0);
	s->mixer_gain = v4l2_ctrl_new_std(&s->hdl, &airspy_ctrl_ops,
			V4L2_CID_RF_TUNER_MIXER_GAIN, 0, 15, 1, 8);
	v4l2_ctrl_auto_cluster(2, &s->mixer_gain_auto, 0, false);
	s->if_gain = v4l2_ctrl_new_std(&s->hdl, &airspy_ctrl_ops,
			V4L2_CID_RF_TUNER_IF_GAIN, 0, 15, 1, 0);
	if (s->hdl.error) {
		ret = s->hdl.error;
		dev_err(s->dev, "Could not initialize controls\n");
		goto err_free_controls;
	}

	v4l2_ctrl_handler_setup(&s->hdl);

	s->v4l2_dev.ctrl_handler = &s->hdl;
	s->vdev.v4l2_dev = &s->v4l2_dev;
	s->vdev.lock = &s->v4l2_lock;

	ret = video_register_device(&s->vdev, VFL_TYPE_SDR, -1);
 	if (ret) {
 		dev_err(s->dev, "Failed to register as video device (%d)\n",
 				ret);
		goto err_free_controls;
 	}
 	dev_info(s->dev, "Registered as %s\n",
 			video_device_node_name(&s->vdev));
	dev_notice(s->dev, "SDR API is still slightly experimental and functionality changes may follow\n");
	return 0;

 err_free_controls:
 	v4l2_ctrl_handler_free(&s->hdl);
 	v4l2_device_unregister(&s->v4l2_dev);
 err_free_mem:
 	kfree(s);
	return ret;
}


The WTAP_ENCAP_ETHERNET dissector needs to be passed a struct eth_phdr.

We now require that.  Make it so.

Bug: 12440
Change-Id: Iffee520976b013800699bde3c6092a3e86be0d76
Reviewed-on: https://code.wireshark.org/review/15424
Reviewed-by: Guy Harris <guy@alum.mit.edu>

dissect_pktap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
	proto_tree *pktap_tree = NULL;
	proto_item *ti = NULL;
 	tvbuff_t *next_tvb;
 	int offset = 0;
 	guint32 pkt_len, rectype, dlt;

 	col_set_str(pinfo->cinfo, COL_PROTOCOL, "PKTAP");
 	col_clear(pinfo->cinfo, COL_INFO);

	pkt_len = tvb_get_letohl(tvb, offset);
	col_add_fstr(pinfo->cinfo, COL_INFO, "PKTAP, %u byte header", pkt_len);

	/* Dissect the packet */
	ti = proto_tree_add_item(tree, proto_pktap, tvb, offset, pkt_len, ENC_NA);
	pktap_tree = proto_item_add_subtree(ti, ett_pktap);

	proto_tree_add_item(pktap_tree, hf_pktap_hdrlen, tvb, offset, 4,
	    ENC_LITTLE_ENDIAN);
	if (pkt_len < MIN_PKTAP_HDR_LEN) {
		proto_tree_add_expert(tree, pinfo, &ei_pktap_hdrlen_too_short,
		    tvb, offset, 4);
		return;
	}
	offset += 4;

	proto_tree_add_item(pktap_tree, hf_pktap_rectype, tvb, offset, 4,
	    ENC_LITTLE_ENDIAN);
	rectype = tvb_get_letohl(tvb, offset);
	offset += 4;
	proto_tree_add_item(pktap_tree, hf_pktap_dlt, tvb, offset, 4,
	    ENC_LITTLE_ENDIAN);
	dlt = tvb_get_letohl(tvb, offset);
	offset += 4;
	proto_tree_add_item(pktap_tree, hf_pktap_ifname, tvb, offset, 24,
	    ENC_ASCII|ENC_NA);
	offset += 24;
	proto_tree_add_item(pktap_tree, hf_pktap_flags, tvb, offset, 4,
	    ENC_LITTLE_ENDIAN);
	offset += 4;
	proto_tree_add_item(pktap_tree, hf_pktap_pfamily, tvb, offset, 4,
	    ENC_LITTLE_ENDIAN);
	offset += 4;
	proto_tree_add_item(pktap_tree, hf_pktap_llhdrlen, tvb, offset, 4,
	    ENC_LITTLE_ENDIAN);
	offset += 4;
	proto_tree_add_item(pktap_tree, hf_pktap_lltrlrlen, tvb, offset, 4,
	    ENC_LITTLE_ENDIAN);
	offset += 4;
	proto_tree_add_item(pktap_tree, hf_pktap_pid, tvb, offset, 4,
	    ENC_LITTLE_ENDIAN);
	offset += 4;
	proto_tree_add_item(pktap_tree, hf_pktap_cmdname, tvb, offset, 20,
	    ENC_UTF_8|ENC_NA);
	offset += 20;
	proto_tree_add_item(pktap_tree, hf_pktap_svc_class, tvb, offset, 4,
	    ENC_LITTLE_ENDIAN);
	offset += 4;
	proto_tree_add_item(pktap_tree, hf_pktap_iftype, tvb, offset, 2,
	    ENC_LITTLE_ENDIAN);
	offset += 2;
	proto_tree_add_item(pktap_tree, hf_pktap_ifunit, tvb, offset, 2,
	    ENC_LITTLE_ENDIAN);
	offset += 2;
	proto_tree_add_item(pktap_tree, hf_pktap_epid, tvb, offset, 4,
	    ENC_LITTLE_ENDIAN);
	offset += 4;
	proto_tree_add_item(pktap_tree, hf_pktap_ecmdname, tvb, offset, 20,
	    ENC_UTF_8|ENC_NA);
	/*offset += 20;*/

 	if (rectype == PKT_REC_PACKET) {
 		next_tvb = tvb_new_subset_remaining(tvb, pkt_len);
		dissector_try_uint(wtap_encap_dissector_table,
		    wtap_pcap_encap_to_wtap_encap(dlt), next_tvb, pinfo, tree);
 	}
 }

epan/dissectors/packet-pktap.c in the Ethernet dissector in Wireshark 2.x before 2.0.4 mishandles the packet-header data type, which allows remote attackers to cause a denial of service (application crash) via a crafted packet.


dissect_pktap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
	proto_tree *pktap_tree = NULL;
	proto_item *ti = NULL;
 	tvbuff_t *next_tvb;
 	int offset = 0;
 	guint32 pkt_len, rectype, dlt;
	int wtap_encap;
	struct eth_phdr eth;
	void *phdr;

 	col_set_str(pinfo->cinfo, COL_PROTOCOL, "PKTAP");
 	col_clear(pinfo->cinfo, COL_INFO);

	pkt_len = tvb_get_letohl(tvb, offset);
	col_add_fstr(pinfo->cinfo, COL_INFO, "PKTAP, %u byte header", pkt_len);

	/* Dissect the packet */
	ti = proto_tree_add_item(tree, proto_pktap, tvb, offset, pkt_len, ENC_NA);
	pktap_tree = proto_item_add_subtree(ti, ett_pktap);

	proto_tree_add_item(pktap_tree, hf_pktap_hdrlen, tvb, offset, 4,
	    ENC_LITTLE_ENDIAN);
	if (pkt_len < MIN_PKTAP_HDR_LEN) {
		proto_tree_add_expert(tree, pinfo, &ei_pktap_hdrlen_too_short,
		    tvb, offset, 4);
		return;
	}
	offset += 4;

	proto_tree_add_item(pktap_tree, hf_pktap_rectype, tvb, offset, 4,
	    ENC_LITTLE_ENDIAN);
	rectype = tvb_get_letohl(tvb, offset);
	offset += 4;
	proto_tree_add_item(pktap_tree, hf_pktap_dlt, tvb, offset, 4,
	    ENC_LITTLE_ENDIAN);
	dlt = tvb_get_letohl(tvb, offset);
	offset += 4;
	proto_tree_add_item(pktap_tree, hf_pktap_ifname, tvb, offset, 24,
	    ENC_ASCII|ENC_NA);
	offset += 24;
	proto_tree_add_item(pktap_tree, hf_pktap_flags, tvb, offset, 4,
	    ENC_LITTLE_ENDIAN);
	offset += 4;
	proto_tree_add_item(pktap_tree, hf_pktap_pfamily, tvb, offset, 4,
	    ENC_LITTLE_ENDIAN);
	offset += 4;
	proto_tree_add_item(pktap_tree, hf_pktap_llhdrlen, tvb, offset, 4,
	    ENC_LITTLE_ENDIAN);
	offset += 4;
	proto_tree_add_item(pktap_tree, hf_pktap_lltrlrlen, tvb, offset, 4,
	    ENC_LITTLE_ENDIAN);
	offset += 4;
	proto_tree_add_item(pktap_tree, hf_pktap_pid, tvb, offset, 4,
	    ENC_LITTLE_ENDIAN);
	offset += 4;
	proto_tree_add_item(pktap_tree, hf_pktap_cmdname, tvb, offset, 20,
	    ENC_UTF_8|ENC_NA);
	offset += 20;
	proto_tree_add_item(pktap_tree, hf_pktap_svc_class, tvb, offset, 4,
	    ENC_LITTLE_ENDIAN);
	offset += 4;
	proto_tree_add_item(pktap_tree, hf_pktap_iftype, tvb, offset, 2,
	    ENC_LITTLE_ENDIAN);
	offset += 2;
	proto_tree_add_item(pktap_tree, hf_pktap_ifunit, tvb, offset, 2,
	    ENC_LITTLE_ENDIAN);
	offset += 2;
	proto_tree_add_item(pktap_tree, hf_pktap_epid, tvb, offset, 4,
	    ENC_LITTLE_ENDIAN);
	offset += 4;
	proto_tree_add_item(pktap_tree, hf_pktap_ecmdname, tvb, offset, 20,
	    ENC_UTF_8|ENC_NA);
	/*offset += 20;*/

 	if (rectype == PKT_REC_PACKET) {
 		next_tvb = tvb_new_subset_remaining(tvb, pkt_len);
		wtap_encap = wtap_pcap_encap_to_wtap_encap(dlt);
		switch (wtap_encap) {

		case WTAP_ENCAP_ETHERNET:
			eth.fcs_len = -1;    /* Unknown whether we have an FCS */
			phdr = ð
			break;

		default:
			phdr = NULL;
			break;
		}
		dissector_try_uint_new(wtap_encap_dissector_table,
		    wtap_encap, next_tvb, pinfo, tree, TRUE, phdr);
 	}
 }


Don't treat the packet length as unsigned.

The scanf family of functions are as annoyingly bad at handling unsigned
numbers as strtoul() is - both of them are perfectly willing to accept a
value beginning with a negative sign as an unsigned value.  When using
strtoul(), you can compensate for this by explicitly checking for a '-'
as the first character of the string, but you can't do that with
sscanf().

So revert to having pkt_len be signed, and scanning it with %d, but
check for a negative value and fail if we see a negative value.

Bug: 12395
Change-Id: I43b458a73b0934e9a5c2c89d34eac5a8f21a7455
Reviewed-on: https://code.wireshark.org/review/15223
Reviewed-by: Guy Harris <guy@alum.mit.edu>

parse_cosine_packet(FILE_T fh, struct wtap_pkthdr *phdr, Buffer *buf,
    char *line, int *err, gchar **err_info)
 {
 	union wtap_pseudo_header *pseudo_header = &phdr->pseudo_header;
 	int	num_items_scanned;
	int	yy, mm, dd, hr, min, sec, csec;
	guint	pkt_len;
 	int	pro, off, pri, rm, error;
 	guint	code1, code2;
 	char	if_name[COSINE_MAX_IF_NAME_LEN] = "", direction[6] = "";
	struct	tm tm;
	guint8 *pd;
	int	i, hex_lines, n, caplen = 0;

	if (sscanf(line, "%4d-%2d-%2d,%2d:%2d:%2d.%9d:",
 		   &yy, &mm, &dd, &hr, &min, &sec, &csec) == 7) {
 		/* appears to be output to a control blade */
 		num_items_scanned = sscanf(line,
		   "%4d-%2d-%2d,%2d:%2d:%2d.%9d: %5s (%127[A-Za-z0-9/:]), Length:%9u, Pro:%9d, Off:%9d, Pri:%9d, RM:%9d, Err:%9d [%8x, %8x]",
 			&yy, &mm, &dd, &hr, &min, &sec, &csec,
 				   direction, if_name, &pkt_len,
 				   &pro, &off, &pri, &rm, &error,
				   &code1, &code2);

		if (num_items_scanned != 17) {
			*err = WTAP_ERR_BAD_FILE;
			*err_info = g_strdup("cosine: purported control blade line doesn't have code values");
			return FALSE;
		}
 	} else {
 		/* appears to be output to PE */
 		num_items_scanned = sscanf(line,
		   "%5s (%127[A-Za-z0-9/:]), Length:%9u, Pro:%9d, Off:%9d, Pri:%9d, RM:%9d, Err:%9d [%8x, %8x]",
 				   direction, if_name, &pkt_len,
 				   &pro, &off, &pri, &rm, &error,
 				   &code1, &code2);

		if (num_items_scanned != 10) {
			*err = WTAP_ERR_BAD_FILE;
			*err_info = g_strdup("cosine: header line is neither control blade nor PE output");
			return FALSE;
 		}
 		yy = mm = dd = hr = min = sec = csec = 0;
 	}
 	if (pkt_len > WTAP_MAX_PACKET_SIZE) {
 		/*
 		 * Probably a corrupt capture file; don't blow up trying
		 * to allocate space for an immensely-large packet.
		 */
		*err = WTAP_ERR_BAD_FILE;
		*err_info = g_strdup_printf("cosine: File has %u-byte packet, bigger than maximum of %u",
		    pkt_len, WTAP_MAX_PACKET_SIZE);
		return FALSE;
	}

	phdr->rec_type = REC_TYPE_PACKET;
	phdr->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
	tm.tm_year = yy - 1900;
	tm.tm_mon = mm - 1;
	tm.tm_mday = dd;
	tm.tm_hour = hr;
	tm.tm_min = min;
	tm.tm_sec = sec;
	tm.tm_isdst = -1;
	phdr->ts.secs = mktime(&tm);
	phdr->ts.nsecs = csec * 10000000;
	phdr->len = pkt_len;

	/* XXX need to handle other encapsulations like Cisco HDLC,
	   Frame Relay and ATM */
	if (strncmp(if_name, "TEST:", 5) == 0) {
		pseudo_header->cosine.encap = COSINE_ENCAP_TEST;
	} else if (strncmp(if_name, "PPoATM:", 7) == 0) {
		pseudo_header->cosine.encap = COSINE_ENCAP_PPoATM;
	} else if (strncmp(if_name, "PPoFR:", 6) == 0) {
		pseudo_header->cosine.encap = COSINE_ENCAP_PPoFR;
	} else if (strncmp(if_name, "ATM:", 4) == 0) {
		pseudo_header->cosine.encap = COSINE_ENCAP_ATM;
	} else if (strncmp(if_name, "FR:", 3) == 0) {
		pseudo_header->cosine.encap = COSINE_ENCAP_FR;
	} else if (strncmp(if_name, "HDLC:", 5) == 0) {
		pseudo_header->cosine.encap = COSINE_ENCAP_HDLC;
	} else if (strncmp(if_name, "PPP:", 4) == 0) {
		pseudo_header->cosine.encap = COSINE_ENCAP_PPP;
	} else if (strncmp(if_name, "ETH:", 4) == 0) {
		pseudo_header->cosine.encap = COSINE_ENCAP_ETH;
	} else {
		pseudo_header->cosine.encap = COSINE_ENCAP_UNKNOWN;
	}
	if (strncmp(direction, "l2-tx", 5) == 0) {
		pseudo_header->cosine.direction = COSINE_DIR_TX;
	} else if (strncmp(direction, "l2-rx", 5) == 0) {
		pseudo_header->cosine.direction = COSINE_DIR_RX;
	}
	g_strlcpy(pseudo_header->cosine.if_name, if_name,
		COSINE_MAX_IF_NAME_LEN);
	pseudo_header->cosine.pro = pro;
	pseudo_header->cosine.off = off;
	pseudo_header->cosine.pri = pri;
	pseudo_header->cosine.rm = rm;
	pseudo_header->cosine.err = error;

	/* Make sure we have enough room for the packet */
	ws_buffer_assure_space(buf, pkt_len);
	pd = ws_buffer_start_ptr(buf);

	/* Calculate the number of hex dump lines, each
	 * containing 16 bytes of data */
	hex_lines = pkt_len / 16 + ((pkt_len % 16) ? 1 : 0);

	for (i = 0; i < hex_lines; i++) {
		if (file_gets(line, COSINE_LINE_LENGTH, fh) == NULL) {
			*err = file_error(fh, err_info);
			if (*err == 0) {
				*err = WTAP_ERR_SHORT_READ;
			}
			return FALSE;
		}
		if (empty_line(line)) {
			break;
		}
		if ((n = parse_single_hex_dump_line(line, pd, i*16)) == -1) {
			*err = WTAP_ERR_BAD_FILE;
			*err_info = g_strdup("cosine: hex dump line doesn't have 16 numbers");
			return FALSE;
		}
		caplen += n;
	}
	phdr->caplen = caplen;
	return TRUE;
}

wiretap/cosine.c in the CoSine file parser in Wireshark 1.12.x before 1.12.12 and 2.x before 2.0.4 mishandles sscanf unsigned-integer processing, which allows remote attackers to cause a denial of service (application crash) via a crafted file.


parse_cosine_packet(FILE_T fh, struct wtap_pkthdr *phdr, Buffer *buf,
    char *line, int *err, gchar **err_info)
 {
 	union wtap_pseudo_header *pseudo_header = &phdr->pseudo_header;
 	int	num_items_scanned;
	int	yy, mm, dd, hr, min, sec, csec, pkt_len;
 	int	pro, off, pri, rm, error;
 	guint	code1, code2;
 	char	if_name[COSINE_MAX_IF_NAME_LEN] = "", direction[6] = "";
	struct	tm tm;
	guint8 *pd;
	int	i, hex_lines, n, caplen = 0;

	if (sscanf(line, "%4d-%2d-%2d,%2d:%2d:%2d.%9d:",
 		   &yy, &mm, &dd, &hr, &min, &sec, &csec) == 7) {
 		/* appears to be output to a control blade */
 		num_items_scanned = sscanf(line,
		   "%4d-%2d-%2d,%2d:%2d:%2d.%9d: %5s (%127[A-Za-z0-9/:]), Length:%9d, Pro:%9d, Off:%9d, Pri:%9d, RM:%9d, Err:%9d [%8x, %8x]",
 			&yy, &mm, &dd, &hr, &min, &sec, &csec,
 				   direction, if_name, &pkt_len,
 				   &pro, &off, &pri, &rm, &error,
				   &code1, &code2);

		if (num_items_scanned != 17) {
			*err = WTAP_ERR_BAD_FILE;
			*err_info = g_strdup("cosine: purported control blade line doesn't have code values");
			return FALSE;
		}
 	} else {
 		/* appears to be output to PE */
 		num_items_scanned = sscanf(line,
		   "%5s (%127[A-Za-z0-9/:]), Length:%9d, Pro:%9d, Off:%9d, Pri:%9d, RM:%9d, Err:%9d [%8x, %8x]",
 				   direction, if_name, &pkt_len,
 				   &pro, &off, &pri, &rm, &error,
 				   &code1, &code2);

		if (num_items_scanned != 10) {
			*err = WTAP_ERR_BAD_FILE;
			*err_info = g_strdup("cosine: header line is neither control blade nor PE output");
			return FALSE;
 		}
 		yy = mm = dd = hr = min = sec = csec = 0;
 	}
	if (pkt_len < 0) {
		*err = WTAP_ERR_BAD_FILE;
		*err_info = g_strdup("cosine: packet header has a negative packet length");
		return FALSE;
	}
 	if (pkt_len > WTAP_MAX_PACKET_SIZE) {
 		/*
 		 * Probably a corrupt capture file; don't blow up trying
		 * to allocate space for an immensely-large packet.
		 */
		*err = WTAP_ERR_BAD_FILE;
		*err_info = g_strdup_printf("cosine: File has %u-byte packet, bigger than maximum of %u",
		    pkt_len, WTAP_MAX_PACKET_SIZE);
		return FALSE;
	}

	phdr->rec_type = REC_TYPE_PACKET;
	phdr->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
	tm.tm_year = yy - 1900;
	tm.tm_mon = mm - 1;
	tm.tm_mday = dd;
	tm.tm_hour = hr;
	tm.tm_min = min;
	tm.tm_sec = sec;
	tm.tm_isdst = -1;
	phdr->ts.secs = mktime(&tm);
	phdr->ts.nsecs = csec * 10000000;
	phdr->len = pkt_len;

	/* XXX need to handle other encapsulations like Cisco HDLC,
	   Frame Relay and ATM */
	if (strncmp(if_name, "TEST:", 5) == 0) {
		pseudo_header->cosine.encap = COSINE_ENCAP_TEST;
	} else if (strncmp(if_name, "PPoATM:", 7) == 0) {
		pseudo_header->cosine.encap = COSINE_ENCAP_PPoATM;
	} else if (strncmp(if_name, "PPoFR:", 6) == 0) {
		pseudo_header->cosine.encap = COSINE_ENCAP_PPoFR;
	} else if (strncmp(if_name, "ATM:", 4) == 0) {
		pseudo_header->cosine.encap = COSINE_ENCAP_ATM;
	} else if (strncmp(if_name, "FR:", 3) == 0) {
		pseudo_header->cosine.encap = COSINE_ENCAP_FR;
	} else if (strncmp(if_name, "HDLC:", 5) == 0) {
		pseudo_header->cosine.encap = COSINE_ENCAP_HDLC;
	} else if (strncmp(if_name, "PPP:", 4) == 0) {
		pseudo_header->cosine.encap = COSINE_ENCAP_PPP;
	} else if (strncmp(if_name, "ETH:", 4) == 0) {
		pseudo_header->cosine.encap = COSINE_ENCAP_ETH;
	} else {
		pseudo_header->cosine.encap = COSINE_ENCAP_UNKNOWN;
	}
	if (strncmp(direction, "l2-tx", 5) == 0) {
		pseudo_header->cosine.direction = COSINE_DIR_TX;
	} else if (strncmp(direction, "l2-rx", 5) == 0) {
		pseudo_header->cosine.direction = COSINE_DIR_RX;
	}
	g_strlcpy(pseudo_header->cosine.if_name, if_name,
		COSINE_MAX_IF_NAME_LEN);
	pseudo_header->cosine.pro = pro;
	pseudo_header->cosine.off = off;
	pseudo_header->cosine.pri = pri;
	pseudo_header->cosine.rm = rm;
	pseudo_header->cosine.err = error;

	/* Make sure we have enough room for the packet */
	ws_buffer_assure_space(buf, pkt_len);
	pd = ws_buffer_start_ptr(buf);

	/* Calculate the number of hex dump lines, each
	 * containing 16 bytes of data */
	hex_lines = pkt_len / 16 + ((pkt_len % 16) ? 1 : 0);

	for (i = 0; i < hex_lines; i++) {
		if (file_gets(line, COSINE_LINE_LENGTH, fh) == NULL) {
			*err = file_error(fh, err_info);
			if (*err == 0) {
				*err = WTAP_ERR_SHORT_READ;
			}
			return FALSE;
		}
		if (empty_line(line)) {
			break;
		}
		if ((n = parse_single_hex_dump_line(line, pd, i*16)) == -1) {
			*err = WTAP_ERR_BAD_FILE;
			*err_info = g_strdup("cosine: hex dump line doesn't have 16 numbers");
			return FALSE;
		}
		caplen += n;
	}
	phdr->caplen = caplen;
	return TRUE;
}


Don't treat the packet length as unsigned.

The scanf family of functions are as annoyingly bad at handling unsigned
numbers as strtoul() is - both of them are perfectly willing to accept a
value beginning with a negative sign as an unsigned value.  When using
strtoul(), you can compensate for this by explicitly checking for a '-'
as the first character of the string, but you can't do that with
sscanf().

So revert to having pkt_len be signed, and scanning it with %d, but
check for a negative value and fail if we see a negative value.

Bug: 12394
Change-Id: I4b19b95f2e1ffc96dac5c91bff6698c246f52007
Reviewed-on: https://code.wireshark.org/review/15230
Reviewed-by: Guy Harris <guy@alum.mit.edu>

parse_toshiba_packet(FILE_T fh, struct wtap_pkthdr *phdr, Buffer *buf,
    int *err, gchar **err_info)
{
 	union wtap_pseudo_header *pseudo_header = &phdr->pseudo_header;
 	char	line[TOSHIBA_LINE_LENGTH];
 	int	num_items_scanned;
	guint	pkt_len;
	int	pktnum, hr, min, sec, csec;
 	char	channel[10], direction[10];
 	int	i, hex_lines;
 	guint8	*pd;

	/* Our file pointer should be on the line containing the
	 * summary information for a packet. Read in that line and
	 * extract the useful information
	 */
	if (file_gets(line, TOSHIBA_LINE_LENGTH, fh) == NULL) {
		*err = file_error(fh, err_info);
		if (*err == 0) {
			*err = WTAP_ERR_SHORT_READ;
		}
		return FALSE;
	}

	/* Find text in line after "[No.". Limit the length of the
	 * two strings since we have fixed buffers for channel[] and
	 * direction[] */
	num_items_scanned = sscanf(line, "%9d] %2d:%2d:%2d.%9d %9s %9s",
			&pktnum, &hr, &min, &sec, &csec, channel, direction);

	if (num_items_scanned != 7) {
		*err = WTAP_ERR_BAD_FILE;
		*err_info = g_strdup("toshiba: record header isn't valid");
		return FALSE;
	}

	/* Scan lines until we find the OFFSET line. In a "telnet" trace,
	 * this will be the next line. But if you save your telnet session
	 * to a file from within a Windows-based telnet client, it may
	 * put in line breaks at 80 columns (or however big your "telnet" box
	 * is). CRT (a Windows telnet app from VanDyke) does this.
	 * Here we assume that 80 columns will be the minimum size, and that
	 * the OFFSET line is not broken in the middle. It's the previous
	 * line that is normally long and can thus be broken at column 80.
	 */
	do {
		if (file_gets(line, TOSHIBA_LINE_LENGTH, fh) == NULL) {
			*err = file_error(fh, err_info);
			if (*err == 0) {
				*err = WTAP_ERR_SHORT_READ;
			}
			return FALSE;
		}

		/* Check for "OFFSET 0001-0203" at beginning of line */
		line[16] = '\0';

 	} while (strcmp(line, "OFFSET 0001-0203") != 0);

	num_items_scanned = sscanf(line+64, "LEN=%9u", &pkt_len);
 	if (num_items_scanned != 1) {
 		*err = WTAP_ERR_BAD_FILE;
 		*err_info = g_strdup("toshiba: OFFSET line doesn't have valid LEN item");
 		return FALSE;
 	}
 	if (pkt_len > WTAP_MAX_PACKET_SIZE) {
 		/*
 		 * Probably a corrupt capture file; don't blow up trying
		 * to allocate space for an immensely-large packet.
		 */
		*err = WTAP_ERR_BAD_FILE;
		*err_info = g_strdup_printf("toshiba: File has %u-byte packet, bigger than maximum of %u",
		    pkt_len, WTAP_MAX_PACKET_SIZE);
		return FALSE;
	}

	phdr->rec_type = REC_TYPE_PACKET;
	phdr->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
	phdr->ts.secs = hr * 3600 + min * 60 + sec;
	phdr->ts.nsecs = csec * 10000000;
	phdr->caplen = pkt_len;
	phdr->len = pkt_len;

	switch (channel[0]) {
		case 'B':
			phdr->pkt_encap = WTAP_ENCAP_ISDN;
			pseudo_header->isdn.uton = (direction[0] == 'T');
			pseudo_header->isdn.channel = (guint8)
			    strtol(&channel[1], NULL, 10);
			break;

		case 'D':
			phdr->pkt_encap = WTAP_ENCAP_ISDN;
			pseudo_header->isdn.uton = (direction[0] == 'T');
			pseudo_header->isdn.channel = 0;
			break;

		default:
			phdr->pkt_encap = WTAP_ENCAP_ETHERNET;
			/* XXX - is there an FCS in the frame? */
			pseudo_header->eth.fcs_len = -1;
			break;
	}

	/* Make sure we have enough room for the packet */
	ws_buffer_assure_space(buf, pkt_len);
	pd = ws_buffer_start_ptr(buf);

	/* Calculate the number of hex dump lines, each
	 * containing 16 bytes of data */
	hex_lines = pkt_len / 16 + ((pkt_len % 16) ? 1 : 0);

	for (i = 0; i < hex_lines; i++) {
		if (file_gets(line, TOSHIBA_LINE_LENGTH, fh) == NULL) {
			*err = file_error(fh, err_info);
			if (*err == 0) {
				*err = WTAP_ERR_SHORT_READ;
			}
			return FALSE;
		}
		if (!parse_single_hex_dump_line(line, pd, i * 16)) {
			*err = WTAP_ERR_BAD_FILE;
			*err_info = g_strdup("toshiba: hex dump not valid");
			return FALSE;
		}
	}
	return TRUE;
}

wiretap/toshiba.c in the Toshiba file parser in Wireshark 1.12.x before 1.12.12 and 2.x before 2.0.4 mishandles sscanf unsigned-integer processing, which allows remote attackers to cause a denial of service (application crash) via a crafted file.


parse_toshiba_packet(FILE_T fh, struct wtap_pkthdr *phdr, Buffer *buf,
    int *err, gchar **err_info)
{
 	union wtap_pseudo_header *pseudo_header = &phdr->pseudo_header;
 	char	line[TOSHIBA_LINE_LENGTH];
 	int	num_items_scanned;
	int	pkt_len, pktnum, hr, min, sec, csec;
 	char	channel[10], direction[10];
 	int	i, hex_lines;
 	guint8	*pd;

	/* Our file pointer should be on the line containing the
	 * summary information for a packet. Read in that line and
	 * extract the useful information
	 */
	if (file_gets(line, TOSHIBA_LINE_LENGTH, fh) == NULL) {
		*err = file_error(fh, err_info);
		if (*err == 0) {
			*err = WTAP_ERR_SHORT_READ;
		}
		return FALSE;
	}

	/* Find text in line after "[No.". Limit the length of the
	 * two strings since we have fixed buffers for channel[] and
	 * direction[] */
	num_items_scanned = sscanf(line, "%9d] %2d:%2d:%2d.%9d %9s %9s",
			&pktnum, &hr, &min, &sec, &csec, channel, direction);

	if (num_items_scanned != 7) {
		*err = WTAP_ERR_BAD_FILE;
		*err_info = g_strdup("toshiba: record header isn't valid");
		return FALSE;
	}

	/* Scan lines until we find the OFFSET line. In a "telnet" trace,
	 * this will be the next line. But if you save your telnet session
	 * to a file from within a Windows-based telnet client, it may
	 * put in line breaks at 80 columns (or however big your "telnet" box
	 * is). CRT (a Windows telnet app from VanDyke) does this.
	 * Here we assume that 80 columns will be the minimum size, and that
	 * the OFFSET line is not broken in the middle. It's the previous
	 * line that is normally long and can thus be broken at column 80.
	 */
	do {
		if (file_gets(line, TOSHIBA_LINE_LENGTH, fh) == NULL) {
			*err = file_error(fh, err_info);
			if (*err == 0) {
				*err = WTAP_ERR_SHORT_READ;
			}
			return FALSE;
		}

		/* Check for "OFFSET 0001-0203" at beginning of line */
		line[16] = '\0';

 	} while (strcmp(line, "OFFSET 0001-0203") != 0);

	num_items_scanned = sscanf(line+64, "LEN=%9d", &pkt_len);
 	if (num_items_scanned != 1) {
 		*err = WTAP_ERR_BAD_FILE;
 		*err_info = g_strdup("toshiba: OFFSET line doesn't have valid LEN item");
 		return FALSE;
 	}
	if (pkt_len < 0) {
		*err = WTAP_ERR_BAD_FILE;
		*err_info = g_strdup("toshiba: packet header has a negative packet length");
		return FALSE;
	}
 	if (pkt_len > WTAP_MAX_PACKET_SIZE) {
 		/*
 		 * Probably a corrupt capture file; don't blow up trying
		 * to allocate space for an immensely-large packet.
		 */
		*err = WTAP_ERR_BAD_FILE;
		*err_info = g_strdup_printf("toshiba: File has %u-byte packet, bigger than maximum of %u",
		    pkt_len, WTAP_MAX_PACKET_SIZE);
		return FALSE;
	}

	phdr->rec_type = REC_TYPE_PACKET;
	phdr->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
	phdr->ts.secs = hr * 3600 + min * 60 + sec;
	phdr->ts.nsecs = csec * 10000000;
	phdr->caplen = pkt_len;
	phdr->len = pkt_len;

	switch (channel[0]) {
		case 'B':
			phdr->pkt_encap = WTAP_ENCAP_ISDN;
			pseudo_header->isdn.uton = (direction[0] == 'T');
			pseudo_header->isdn.channel = (guint8)
			    strtol(&channel[1], NULL, 10);
			break;

		case 'D':
			phdr->pkt_encap = WTAP_ENCAP_ISDN;
			pseudo_header->isdn.uton = (direction[0] == 'T');
			pseudo_header->isdn.channel = 0;
			break;

		default:
			phdr->pkt_encap = WTAP_ENCAP_ETHERNET;
			/* XXX - is there an FCS in the frame? */
			pseudo_header->eth.fcs_len = -1;
			break;
	}

	/* Make sure we have enough room for the packet */
	ws_buffer_assure_space(buf, pkt_len);
	pd = ws_buffer_start_ptr(buf);

	/* Calculate the number of hex dump lines, each
	 * containing 16 bytes of data */
	hex_lines = pkt_len / 16 + ((pkt_len % 16) ? 1 : 0);

	for (i = 0; i < hex_lines; i++) {
		if (file_gets(line, TOSHIBA_LINE_LENGTH, fh) == NULL) {
			*err = file_error(fh, err_info);
			if (*err == 0) {
				*err = WTAP_ERR_SHORT_READ;
			}
			return FALSE;
		}
		if (!parse_single_hex_dump_line(line, pd, i * 16)) {
			*err = WTAP_ERR_BAD_FILE;
			*err_info = g_strdup("toshiba: hex dump not valid");
			return FALSE;
		}
	}
	return TRUE;
}


UMTS_FP: fix handling reserved C/T value

The spec puts the reserved value at 0xf but our internal table has 'unknown' at
0; since all the other values seem to be offset-by-one, just take the modulus
0xf to avoid running off the end of the table.

Bug: 12191
Change-Id: I83c8fb66797bbdee52a2246fb1eea6e37cbc7eb0
Reviewed-on: https://code.wireshark.org/review/15722
Reviewed-by: Evan Huus <eapache@gmail.com>
Petri-Dish: Evan Huus <eapache@gmail.com>
Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org>
Reviewed-by: Michael Mann <mmann78@netscape.net>

fp_set_per_packet_inf_from_conv(umts_fp_conversation_info_t *p_conv_data,
                                tvbuff_t *tvb, packet_info *pinfo,
                                proto_tree *tree _U_)
{
    fp_info  *fpi;
    guint8    tfi, c_t;
    int       offset = 0, i=0, j=0, num_tbs, chan, tb_size, tb_bit_off;
    gboolean  is_control_frame;
    umts_mac_info *macinf;
    rlc_info *rlcinf;
    guint8 fake_lchid=0;
    gint *cur_val=NULL;

    fpi = wmem_new0(wmem_file_scope(), fp_info);
    p_add_proto_data(wmem_file_scope(), pinfo, proto_fp, 0, fpi);

    fpi->iface_type = p_conv_data->iface_type;
    fpi->division = p_conv_data->division;
    fpi->release = 7;               /* Set values greater then the checks performed */
    fpi->release_year = 2006;
    fpi->release_month = 12;
    fpi->channel = p_conv_data->channel;
    fpi->dch_crc_present = p_conv_data->dch_crc_present;
    /*fpi->paging_indications;*/
    fpi->link_type = FP_Link_Ethernet;

#if 0
    /*Only do this the first run, signals that we need to reset the RLC fragtable*/
    if (!pinfo->fd->flags.visited &&  p_conv_data->reset_frag ) {
        fpi->reset_frag = p_conv_data->reset_frag;
        p_conv_data->reset_frag = FALSE;
    }
#endif
    /* remember 'lower' UDP layer port information so we can later
     * differentiate 'lower' UDP layer from 'user data' UDP layer */
    fpi->srcport = pinfo->srcport;
    fpi->destport = pinfo->destport;

    fpi->com_context_id = p_conv_data->com_context_id;

    if (pinfo->link_dir == P2P_DIR_UL) {
        fpi->is_uplink = TRUE;
    } else {
        fpi->is_uplink = FALSE;
    }

    is_control_frame = tvb_get_guint8(tvb, offset) & 0x01;

    switch (fpi->channel) {
        case CHANNEL_HSDSCH: /* HS-DSCH - High Speed Downlink Shared Channel */
            fpi->hsdsch_entity = p_conv_data->hsdsch_entity;
            macinf = wmem_new0(wmem_file_scope(), umts_mac_info);
            fpi->hsdsch_macflowd_id = p_conv_data->hsdsch_macdflow_id;
           macinf->content[0] = hsdsch_macdflow_id_mac_content_map[p_conv_data->hsdsch_macdflow_id]; /*MAC_CONTENT_PS_DTCH;*/
            macinf->lchid[0] = p_conv_data->hsdsch_macdflow_id;
            /*macinf->content[0] = lchId_type_table[p_conv_data->edch_lchId[0]];*/
            p_add_proto_data(wmem_file_scope(), pinfo, proto_umts_mac, 0, macinf);

            rlcinf = wmem_new0(wmem_file_scope(), rlc_info);

            /*Figure out RLC_MODE based on MACd-flow-ID, basically MACd-flow-ID = 0 then it's SRB0 == UM else AM*/
            rlcinf->mode[0] = hsdsch_macdflow_id_rlc_map[p_conv_data->hsdsch_macdflow_id];

            if (fpi->hsdsch_entity == hs /*&& !rlc_is_ciphered(pinfo)*/) {
                for (i=0; i<MAX_NUM_HSDHSCH_MACDFLOW; i++) {
                    /*Figure out if this channel is multiplexed (signaled from RRC)*/
                    if ((cur_val=(gint *)g_tree_lookup(hsdsch_muxed_flows, GINT_TO_POINTER((gint)p_conv_data->hrnti))) != NULL) {
                        j = 1 << i;
                        fpi->hsdhsch_macfdlow_is_mux[i] = j & *cur_val;
                    } else {
                        fpi->hsdhsch_macfdlow_is_mux[i] = FALSE;
                    }

                }
            }
            /* Make configurable ?(available in NBAP?) */
            /* urnti[MAX_RLC_CHANS] */
            /*
            switch (p_conv_data->rlc_mode) {
                case FP_RLC_TM:
                    rlcinf->mode[0] = RLC_TM;
                    break;
                case FP_RLC_UM:
                    rlcinf->mode[0] = RLC_UM;
                    break;
                case FP_RLC_AM:
                    rlcinf->mode[0] = RLC_AM;
                    break;
                case FP_RLC_MODE_UNKNOWN:
                default:
                    rlcinf->mode[0] = RLC_UNKNOWN_MODE;
                    break;
            }*/
            /* rbid[MAX_RLC_CHANS] */
            /* For RLC re-assembly to work we urnti signaled from NBAP */
            rlcinf->urnti[0] = fpi->com_context_id;
            rlcinf->li_size[0] = RLC_LI_7BITS;
            rlcinf->ciphered[0] = FALSE;
            rlcinf->deciphered[0] = FALSE;
            p_add_proto_data(wmem_file_scope(), pinfo, proto_rlc, 0, rlcinf);

            return fpi;

        case CHANNEL_EDCH:
            /*Most configuration is now done in the actual dissecting function*/
            macinf = wmem_new0(wmem_file_scope(), umts_mac_info);
            rlcinf = wmem_new0(wmem_file_scope(), rlc_info);
            fpi->no_ddi_entries = p_conv_data->no_ddi_entries;
            for (i=0; i<fpi->no_ddi_entries; i++) {
                fpi->edch_ddi[i] = p_conv_data->edch_ddi[i];    /*Set the DDI value*/
                fpi->edch_macd_pdu_size[i] = p_conv_data->edch_macd_pdu_size[i];    /*Set the size*/
                fpi->edch_lchId[i] = p_conv_data->edch_lchId[i];    /*Set the channel id for this entry*/
                /*macinf->content[i] = lchId_type_table[p_conv_data->edch_lchId[i]]; */    /*Set the proper Content type for the mac layer.*/
            /*    rlcinf->mode[i] = lchId_rlc_map[p_conv_data->edch_lchId[i]];*/ /* Set RLC mode by lchid to RLC_MODE map in nbap.h */

            }
            fpi->edch_type = p_conv_data->edch_type;

           /* macinf = wmem_new0(wmem_file_scope(), umts_mac_info);
            macinf->content[0] = MAC_CONTENT_PS_DTCH;*/
            p_add_proto_data(wmem_file_scope(), pinfo, proto_umts_mac, 0, macinf);

            /* For RLC re-assembly to work we need a urnti signaled from NBAP */
            rlcinf->urnti[0] = fpi->com_context_id;
           /* rlcinf->mode[0] = RLC_AM;*/
            rlcinf->li_size[0] = RLC_LI_7BITS;
            rlcinf->ciphered[0] = FALSE;
            rlcinf->deciphered[0] = FALSE;

            p_add_proto_data(wmem_file_scope(), pinfo, proto_rlc, 0, rlcinf);

            return fpi;

        case CHANNEL_PCH:
            fpi->paging_indications = p_conv_data->paging_indications;
            fpi->num_chans = p_conv_data->num_dch_in_flow;
            /* Set offset to point to first TFI
             */
            if (is_control_frame) {
                /* control frame, we're done */
                return fpi;
            }
            /* Set offset to TFI */
            offset = 3;
            break;
        case CHANNEL_DCH:
            fpi->num_chans = p_conv_data->num_dch_in_flow;
            if (is_control_frame) {
                /* control frame, we're done */
                return fpi;
            }

            rlcinf = wmem_new0(wmem_file_scope(), rlc_info);
            macinf = wmem_new0(wmem_file_scope(), umts_mac_info);
            offset = 2;    /*To correctly read the tfi*/
            fakes  = 5; /* Reset fake counter. */
            for (chan=0; chan < fpi->num_chans; chan++) {    /*Iterate over the what channels*/
                    /*Iterate over the transport blocks*/
                   /*tfi = tvb_get_guint8(tvb, offset);*/
                   /*TFI is 5 bits according to 3GPP TS 25.321, paragraph 6.2.4.4*/
                    tfi = tvb_get_bits8(tvb, 3+offset*8, 5);

                   /*Figure out the number of tbs and size*/
                   num_tbs = (fpi->is_uplink) ? p_conv_data->fp_dch_channel_info[chan].ul_chan_num_tbs[tfi] : p_conv_data->fp_dch_channel_info[chan].dl_chan_num_tbs[tfi];
                   tb_size=  (fpi->is_uplink) ? p_conv_data->fp_dch_channel_info[i].ul_chan_tf_size[tfi] :    p_conv_data->fp_dch_channel_info[i].dl_chan_tf_size[tfi];

                    /*TODO: This stuff has to be reworked!*/
                    /*Generates a fake logical channel id for non multiplexed channel*/
                    if ( p_conv_data->dchs_in_flow_list[chan] != 31 && (p_conv_data->dchs_in_flow_list[chan] == 24 &&
                     tb_size != 340) ) {
                        fake_lchid = make_fake_lchid(pinfo, p_conv_data->dchs_in_flow_list[chan]);
                    }
                    tb_bit_off = (2+p_conv_data->num_dch_in_flow)*8;    /*Point to the C/T of first TB*/
                    /*Set configuration for individual blocks*/
                    for (j=0; j < num_tbs && j+chan < MAX_MAC_FRAMES; j++) {
                        /*Set transport channel id (useful for debugging)*/
                        macinf->trchid[j+chan] = p_conv_data->dchs_in_flow_list[chan];

                        /*Transport Channel m31 and 24 might be multiplexed!*/
                        if ( p_conv_data->dchs_in_flow_list[chan] == 31 || p_conv_data->dchs_in_flow_list[chan] == 24) {

                            /****** MUST FIGURE OUT IF THIS IS REALLY MULTIPLEXED OR NOT*******/
                            /*If Trchid == 31 and only on TB, we have no multiplexing*/
                            if (0/*p_conv_data->dchs_in_flow_list[chan] == 31 && num_tbs == 1*/) {
                                macinf->ctmux[j+chan] = FALSE;/*Set TRUE if this channel is multiplexed (ie. C/T flag exists)*/

                                macinf->lchid[j+chan] = 1;

                                macinf->content[j+chan] = lchId_type_table[1];    /*Base MAC content on logical channel id (Table is in packet-nbap.h)*/
                                rlcinf->mode[j+chan] = lchId_rlc_map[1];    /*Based RLC mode on logical channel id*/

                            }
                            /*Indicate we don't have multiplexing.*/
                            else if (p_conv_data->dchs_in_flow_list[chan] == 24 && tb_size != 340) {
                                macinf->ctmux[j+chan] = FALSE;/*Set TRUE if this channel is multiplexed (ie. C/T flag exists)*/

                                /*g_warning("settin this for %d", pinfo->num);*/
                                macinf->lchid[j+chan] = fake_lchid;
                                macinf->fake_chid[j+chan] = TRUE;
                                macinf->content[j+chan] = MAC_CONTENT_PS_DTCH; /*lchId_type_table[fake_lchid];*/    /*Base MAC content on logical channel id (Table is in packet-nbap.h)*/
                                rlcinf->mode[j+chan] = RLC_AM;/*lchId_rlc_map[fake_lchid];*/    /*Based RLC mode on logical channel id*/
                            }
                            /*We have multiplexing*/
                            else {
                                macinf->ctmux[j+chan] = TRUE;/*Set TRUE if this channel is multiplexed (ie. C/T flag exists)*/

                                 /* Peek at C/T, different RLC params for different logical channels */
                                 /*C/T is 4 bits according to 3GPP TS 25.321, paragraph 9.2.1, from MAC header (not FP)*/
                                c_t = tvb_get_bits8(tvb, tb_bit_off/*(2+p_conv_data->num_dch_in_flow)*8*/, 4);    /* c_t = tvb_get_guint8(tvb, offset);*/
                                macinf->lchid[j+chan] = c_t+1;

                                macinf->content[j+chan] = lchId_type_table[c_t+1];    /*Base MAC content on logical channel id (Table is in packet-nbap.h)*/
                                rlcinf->mode[j+chan] = lchId_rlc_map[c_t+1];    /*Based RLC mode on logical channel id*/
                             }
                         } else {
                             fake_lchid = make_fake_lchid(pinfo, p_conv_data->dchs_in_flow_list[chan]);
                            macinf->ctmux[j+chan] = FALSE;/*Set TRUE if this channel is multiplexed (ie. C/T flag exists)*/
                            /*macinf->content[j+chan] = MAC_CONTENT_CS_DTCH;*/
                            macinf->content[j+chan] = lchId_type_table[fake_lchid];

                            rlcinf->mode[j+chan] = lchId_rlc_map[fake_lchid];

                            /*Generate virtual logical channel id*/
                            /************************/
                            /*TODO: Once proper lchid is always set, this has to be removed*/
                            macinf->fake_chid[j+chan] = TRUE;
                            macinf->lchid[j+chan] = fake_lchid;  /*make_fake_lchid(pinfo, p_conv_data->dchs_in_flow_list[chan]);*/
                            /************************/
                        }

                        /*** Set rlc info ***/
                        rlcinf->urnti[j+chan] = p_conv_data->com_context_id;
                        rlcinf->li_size[j+chan] = RLC_LI_7BITS;
#if 0
                        /*If this entry exists, SECRUITY_MODE is completed (signled by RRC)*/
                        if ( rrc_ciph_inf && g_tree_lookup(rrc_ciph_inf, GINT_TO_POINTER((gint)p_conv_data->com_context_id)) != NULL ) {
                            rlcinf->ciphered[j+chan] = TRUE;
                        } else {
                            rlcinf->ciphered[j+chan] = FALSE;
                        }
#endif
                        rlcinf->ciphered[j+chan] = FALSE;
                        rlcinf->deciphered[j+chan] = FALSE;
                        rlcinf->rbid[j+chan] = macinf->lchid[j+chan];

                        /*Step over this TB and it's C/T flag.*/
                        tb_bit_off += tb_size+4;
                    }

                    offset++;
            }
            p_add_proto_data(wmem_file_scope(), pinfo, proto_umts_mac, 0, macinf);
            p_add_proto_data(wmem_file_scope(), pinfo, proto_rlc, 0, rlcinf);
            /* Set offset to point to first TFI
             * the Number of TFI's = number of DCH's in the flow
             */
            offset = 2;
            break;
        case CHANNEL_FACH_FDD:
            fpi->num_chans = p_conv_data->num_dch_in_flow;
            if (is_control_frame) {
                /* control frame, we're done */
                return fpi;
            }
            /* Set offset to point to first TFI
             * the Number of TFI's = number of DCH's in the flow
             */
            offset = 2;
            /* Set MAC data */
            macinf = wmem_new0(wmem_file_scope(), umts_mac_info);
            macinf->ctmux[0]   = 1;
            macinf->content[0] = MAC_CONTENT_DCCH;
            p_add_proto_data(wmem_file_scope(), pinfo, proto_umts_mac, 0, macinf);
            /* Set RLC data */
            rlcinf = wmem_new0(wmem_file_scope(), rlc_info);
            /* Make configurable ?(avaliable in NBAP?) */
            /* For RLC re-assembly to work we need to fake urnti */
            rlcinf->urnti[0] = fpi->channel;
            rlcinf->mode[0] = RLC_AM;
            /* rbid[MAX_RLC_CHANS] */
            rlcinf->li_size[0] = RLC_LI_7BITS;
            rlcinf->ciphered[0] = FALSE;
            rlcinf->deciphered[0] = FALSE;
            p_add_proto_data(wmem_file_scope(), pinfo, proto_rlc, 0, rlcinf);
            break;

        case CHANNEL_RACH_FDD:
            fpi->num_chans = p_conv_data->num_dch_in_flow;
            if (is_control_frame) {
                /* control frame, we're done */
                return fpi;
            }
            /* Set offset to point to first TFI
             * the Number of TFI's = number of DCH's in the flow
             */
            offset = 2;
            /* set MAC data */
            macinf = wmem_new0(wmem_file_scope(), umts_mac_info);
            rlcinf = wmem_new0(wmem_file_scope(), rlc_info);
            for ( chan = 0; chan < fpi->num_chans; chan++ ) {
                    macinf->ctmux[chan]   = 1;
                    macinf->content[chan] = MAC_CONTENT_DCCH;
                    rlcinf->urnti[chan] = fpi->com_context_id;    /*Note that MAC probably will change this*/
            }

            p_add_proto_data(wmem_file_scope(), pinfo, proto_umts_mac, 0, macinf);
            p_add_proto_data(wmem_file_scope(), pinfo, proto_rlc, 0, rlcinf);
            break;
        case CHANNEL_HSDSCH_COMMON:
                rlcinf = wmem_new0(wmem_file_scope(), rlc_info);
                macinf = wmem_new0(wmem_file_scope(), umts_mac_info);
                p_add_proto_data(wmem_file_scope(), pinfo, proto_umts_mac, 0, macinf);
                p_add_proto_data(wmem_file_scope(), pinfo, proto_rlc, 0, rlcinf);
            break;
        default:
            expert_add_info(pinfo, NULL, &ei_fp_transport_channel_type_unknown);
            return NULL;
    }

    /* Peek at the packet as the per packet info seems not to take the tfi into account */
    for (i=0; i<fpi->num_chans; i++) {
        tfi = tvb_get_guint8(tvb, offset);

        /*TFI is 5 bits according to 3GPP TS 25.321, paragraph 6.2.4.4*/
        /*tfi = tvb_get_bits8(tvb, offset*8, 5);*/
        if (pinfo->link_dir == P2P_DIR_UL) {
            fpi->chan_tf_size[i] = p_conv_data->fp_dch_channel_info[i].ul_chan_tf_size[tfi];
            fpi->chan_num_tbs[i] = p_conv_data->fp_dch_channel_info[i].ul_chan_num_tbs[tfi];
        } else {
            fpi->chan_tf_size[i] = p_conv_data->fp_dch_channel_info[i].dl_chan_tf_size[tfi];
            fpi->chan_num_tbs[i] = p_conv_data->fp_dch_channel_info[i].dl_chan_num_tbs[tfi];
        }
        offset++;
    }

    return fpi;
}

epan/dissectors/packet-umts_fp.c in the UMTS FP dissector in Wireshark 1.12.x before 1.12.12 and 2.x before 2.0.4 mishandles the reserved C/T value, which allows remote attackers to cause a denial of service (application crash) via a crafted packet.