static void ProcessExifDir(unsigned char * DirStart, unsigned char * OffsetBase,
 unsigned ExifLength, int NestingLevel)
{
 int de;
 int a;
 int NumDirEntries;
 unsigned ThumbnailOffset = 0;
 unsigned ThumbnailSize = 0;
 char IndentString[25];

    printf("ProcessExifDir");
 if (NestingLevel > 4){
 ErrNonfatal("Maximum directory nesting exceeded (corrupt exif header)", 0,0);
 return;
 }

    memset(IndentString, ' ', 25);
 IndentString[NestingLevel * 4] = '\0';

 NumDirEntries = Get16u(DirStart);
 #define DIR_ENTRY_ADDR(Start, Entry) (Start+2+12*(Entry))

 {
 unsigned char * DirEnd;
 DirEnd = DIR_ENTRY_ADDR(DirStart, NumDirEntries);
 if (DirEnd+4 > (OffsetBase+ExifLength)){
 if (DirEnd+2 == OffsetBase+ExifLength || DirEnd == OffsetBase+ExifLength){
 }else{
 ErrNonfatal("Illegally sized exif subdirectory (%d entries)",NumDirEntries,0);
 return;
 }
 }
 if (DumpExifMap){
            printf("Map: %05d-%05d: Directory\n",(int)(DirStart-OffsetBase), (int)(DirEnd+4-OffsetBase));
 }

 }

 if (ShowTags){
        printf("(dir has %d entries)\n",NumDirEntries);
 }

 for (de=0;de<NumDirEntries;de++){
 int Tag, Format, Components;
 unsigned char * ValuePtr;
 int ByteCount;
 unsigned char * DirEntry;
 DirEntry = DIR_ENTRY_ADDR(DirStart, de);

 Tag = Get16u(DirEntry);
 Format = Get16u(DirEntry+2);
 Components = Get32u(DirEntry+4);

 if ((Format-1) >= NUM_FORMATS) {
 ErrNonfatal("Illegal number format %d for tag %04x", Format, Tag);
 continue;
 }

 if ((unsigned)Components > 0x10000){
 ErrNonfatal("Illegal number of components %d for tag %04x", Components, Tag);
 continue;
 }

 ByteCount = Components * BytesPerFormat[Format];

 if (ByteCount > 4){

             unsigned OffsetVal;
             OffsetVal = Get32u(DirEntry+8);
            if (OffsetVal+ByteCount > ExifLength){
                 ErrNonfatal("Illegal value pointer for tag %04x", Tag,0);
                 continue;
 }
 ValuePtr = OffsetBase+OffsetVal;

 if (OffsetVal > ImageInfo.LargestExifOffset){
 ImageInfo.LargestExifOffset = OffsetVal;
 }

 if (DumpExifMap){
                printf("Map: %05d-%05d:   Data for tag %04x\n",OffsetVal, OffsetVal+ByteCount, Tag);
 }
 }else{
 ValuePtr = DirEntry+8;
 }

 if (Tag == TAG_MAKER_NOTE){
 if (ShowTags){
                printf("%s    Maker note: ",IndentString);
 }
 ProcessMakerNote(ValuePtr, ByteCount, OffsetBase, ExifLength);
 continue;
 }

 if (ShowTags){
 for (a=0;;a++){
 if (a >= (int)TAG_TABLE_SIZE){
                    printf("%s", IndentString);
                    printf("    Unknown Tag %04x Value = ", Tag);
 break;
 }
 if (TagTable[a].Tag == Tag){
                    printf("%s", IndentString);
                    printf("    %s = ",TagTable[a].Desc);
 break;
 }
 }

 switch(Format){
 case FMT_BYTE:
 if(ByteCount>1){
                        printf("%.*ls\n", ByteCount/2, (wchar_t *)ValuePtr);
 }else{
 PrintFormatNumber(ValuePtr, Format, ByteCount);
                        printf("\n");
 }
 break;

 case FMT_UNDEFINED:

 case FMT_STRING:
 {
                          printf("\"%s\"", ValuePtr);
 }
 break;

 default:
 PrintFormatNumber(ValuePtr, Format, ByteCount);
                    printf("\n");
 }
 }

 switch(Tag){

 case TAG_MAKE:
                strncpy(ImageInfo.CameraMake, (char *)ValuePtr, ByteCount < 31 ? ByteCount : 31);
 break;

 case TAG_MODEL:
                strncpy(ImageInfo.CameraModel, (char *)ValuePtr, ByteCount < 39 ? ByteCount : 39);
 break;

 case TAG_SUBSEC_TIME:
                strlcpy(ImageInfo.SubSecTime, (char *)ValuePtr, sizeof(ImageInfo.SubSecTime));
 break;

 case TAG_SUBSEC_TIME_ORIG:
                strlcpy(ImageInfo.SubSecTimeOrig, (char *)ValuePtr,
 sizeof(ImageInfo.SubSecTimeOrig));
 break;

 case TAG_SUBSEC_TIME_DIG:
                strlcpy(ImageInfo.SubSecTimeDig, (char *)ValuePtr,
 sizeof(ImageInfo.SubSecTimeDig));
 break;

 case TAG_DATETIME_DIGITIZED:
                strlcpy(ImageInfo.DigitizedTime, (char *)ValuePtr,
 sizeof(ImageInfo.DigitizedTime));

 if (ImageInfo.numDateTimeTags >= MAX_DATE_COPIES){
 ErrNonfatal("More than %d date fields!  This is nuts", MAX_DATE_COPIES, 0);
 break;
 }
 ImageInfo.DateTimeOffsets[ImageInfo.numDateTimeTags++] =
 (char *)ValuePtr - (char *)OffsetBase;
 break;

 case TAG_DATETIME_ORIGINAL:
                strncpy(ImageInfo.DateTime, (char *)ValuePtr, 19);

 case TAG_DATETIME:
 if (!isdigit(ImageInfo.DateTime[0])){
                    strncpy(ImageInfo.DateTime, (char *)ValuePtr, 19);
 }

 if (ImageInfo.numDateTimeTags >= MAX_DATE_COPIES){
 ErrNonfatal("More than %d date fields!  This is nuts", MAX_DATE_COPIES, 0);
 break;
 }
 ImageInfo.DateTimeOffsets[ImageInfo.numDateTimeTags++] =
 (char *)ValuePtr - (char *)OffsetBase;
 break;

 case TAG_WINXP_COMMENT:
 if (ImageInfo.Comments[0]){ // We already have a jpeg comment.
 if (ShowTags) printf("Windows XP commend and other comment in header\n");
 break; // Already have a windows comment, skip this one.
 }

 if (ByteCount > 1){
 if (ByteCount > MAX_COMMENT_SIZE) ByteCount = MAX_COMMENT_SIZE;
                    memcpy(ImageInfo.Comments, ValuePtr, ByteCount);
 ImageInfo.CommentWidchars = ByteCount/2;
 }
 break;

 case TAG_USERCOMMENT:
 if (ImageInfo.Comments[0]){ // We already have a jpeg comment.
 if (ShowTags) printf("Multiple comments in exif header\n");
 break; // Already have a windows comment, skip this one.
 }

 for (a=ByteCount;;){
                    a--;
 if ((ValuePtr)[a] == ' '){
 (ValuePtr)[a] = '\0';
 }else{
 break;
 }
 if (a == 0) break;
 }

 {
 int msiz = ExifLength - (ValuePtr-OffsetBase);
 if (msiz > ByteCount) msiz = ByteCount;
 if (msiz > MAX_COMMENT_SIZE - 1) msiz = MAX_COMMENT_SIZE - 1;
 if (msiz > 5 && memcmp(ValuePtr, "ASCII", 5) == 0) {
 for (a = 5; a < 10 && a < msiz; a++) {
 int c = (ValuePtr)[a];
 if (c != '\0' && c != ' ') {
                                strncpy(ImageInfo.Comments,
 (char *)ValuePtr + a, msiz - a);
 break;
 }
 }
 } else {
                        strncpy(ImageInfo.Comments, (char *)ValuePtr, msiz);
 }
 }
 break;

 case TAG_FNUMBER:
 ImageInfo.ApertureFNumber = (float)ConvertAnyFormat(ValuePtr, Format);
 break;

 case TAG_APERTURE:
 case TAG_MAXAPERTURE:
 if (ImageInfo.ApertureFNumber == 0){
 ImageInfo.ApertureFNumber
 = (float)exp(ConvertAnyFormat(ValuePtr, Format)*log(2)*0.5);
 }
 break;

 case TAG_FOCALLENGTH:
 ImageInfo.FocalLength.num = Get32u(ValuePtr);
 ImageInfo.FocalLength.denom = Get32u(4+(char *)ValuePtr);
 break;

 case TAG_SUBJECT_DISTANCE:
 ImageInfo.Distance = (float)ConvertAnyFormat(ValuePtr, Format);
 break;

 case TAG_EXPOSURETIME:
 ImageInfo.ExposureTime = (float)ConvertAnyFormat(ValuePtr, Format);
 break;

 case TAG_SHUTTERSPEED:
 if (ImageInfo.ExposureTime == 0){
 ImageInfo.ExposureTime
 = (float)(1/exp(ConvertAnyFormat(ValuePtr, Format)*log(2)));
 }
 break;

 case TAG_FLASH:
 ImageInfo.FlashUsed=(int)ConvertAnyFormat(ValuePtr, Format);
 break;

 case TAG_ORIENTATION:
 if (NumOrientations >= 2){
 ErrNonfatal("More than two orientation tags!",0,0);
 break;
 }
 OrientationPtr[NumOrientations] = ValuePtr;
 OrientationNumFormat[NumOrientations] = Format;
 if (NumOrientations == 0){
 ImageInfo.Orientation = (int)ConvertAnyFormat(ValuePtr, Format);
 }
 if (ImageInfo.Orientation < 0 || ImageInfo.Orientation > 8){
 ErrNonfatal("Undefined rotation value %d", ImageInfo.Orientation, 0);
 ImageInfo.Orientation = 0;
 }
 NumOrientations += 1;
 break;

 case TAG_EXIF_IMAGELENGTH:
 case TAG_EXIF_IMAGEWIDTH:
                a = (int)ConvertAnyFormat(ValuePtr, Format);
 if (ExifImageWidth < a) ExifImageWidth = a;
 break;

 case TAG_FOCAL_PLANE_XRES:
 FocalplaneXRes = ConvertAnyFormat(ValuePtr, Format);
 break;

 case TAG_FOCAL_PLANE_UNITS:
 switch((int)ConvertAnyFormat(ValuePtr, Format)){
 case 1: FocalplaneUnits = 25.4; break; // inch
 case 2:
 FocalplaneUnits = 25.4;
 break;

 case 3: FocalplaneUnits = 10; break; // centimeter
 case 4: FocalplaneUnits = 1; break; // millimeter
 case 5: FocalplaneUnits = .001; break; // micrometer
 }
 break;

 case TAG_EXPOSURE_BIAS:
 ImageInfo.ExposureBias = (float)ConvertAnyFormat(ValuePtr, Format);
 break;

 case TAG_WHITEBALANCE:
 ImageInfo.Whitebalance = (int)ConvertAnyFormat(ValuePtr, Format);
 break;

 case TAG_LIGHT_SOURCE:
 ImageInfo.LightSource = (int)ConvertAnyFormat(ValuePtr, Format);
 break;

 case TAG_METERING_MODE:
 ImageInfo.MeteringMode = (int)ConvertAnyFormat(ValuePtr, Format);
 break;

 case TAG_EXPOSURE_PROGRAM:
 ImageInfo.ExposureProgram = (int)ConvertAnyFormat(ValuePtr, Format);
 break;

 case TAG_EXPOSURE_INDEX:
 if (ImageInfo.ISOequivalent == 0){
 ImageInfo.ISOequivalent = (int)ConvertAnyFormat(ValuePtr, Format);
 }
 break;

 case TAG_EXPOSURE_MODE:
 ImageInfo.ExposureMode = (int)ConvertAnyFormat(ValuePtr, Format);
 break;

 case TAG_ISO_EQUIVALENT:
 ImageInfo.ISOequivalent = (int)ConvertAnyFormat(ValuePtr, Format);
 break;

 case TAG_DIGITALZOOMRATIO:
 ImageInfo.DigitalZoomRatio = (float)ConvertAnyFormat(ValuePtr, Format);
 break;

 case TAG_THUMBNAIL_OFFSET:
 ThumbnailOffset = (unsigned)ConvertAnyFormat(ValuePtr, Format);
 DirWithThumbnailPtrs = DirStart;
 break;

 case TAG_THUMBNAIL_LENGTH:
 ThumbnailSize = (unsigned)ConvertAnyFormat(ValuePtr, Format);
 ImageInfo.ThumbnailSizeOffset = ValuePtr-OffsetBase;
 break;

 case TAG_EXIF_OFFSET:
 if (ShowTags) printf("%s    Exif Dir:",IndentString);

 case TAG_INTEROP_OFFSET:
 if (Tag == TAG_INTEROP_OFFSET && ShowTags) printf("%s    Interop Dir:",IndentString);
 {
 unsigned char * SubdirStart;
 SubdirStart = OffsetBase + Get32u(ValuePtr);
 if (SubdirStart < OffsetBase || SubdirStart > OffsetBase+ExifLength){
 ErrNonfatal("Illegal exif or interop ofset directory link",0,0);
 }else{
 ProcessExifDir(SubdirStart, OffsetBase, ExifLength, NestingLevel+1);
 }
 continue;
 }
 break;

 case TAG_GPSINFO:
 if (ShowTags) printf("%s    GPS info dir:",IndentString);
 {
 unsigned char * SubdirStart;
 SubdirStart = OffsetBase + Get32u(ValuePtr);
 if (SubdirStart < OffsetBase || SubdirStart > OffsetBase+ExifLength){
 ErrNonfatal("Illegal GPS directory link",0,0);
 }else{
 ProcessGpsInfo(SubdirStart, ByteCount, OffsetBase, ExifLength);
 }
 continue;
 }
 break;

 case TAG_FOCALLENGTH_35MM:
 ImageInfo.FocalLength35mmEquiv = (unsigned)ConvertAnyFormat(ValuePtr, Format);
 break;

 case TAG_DISTANCE_RANGE:
 ImageInfo.DistanceRange = (int)ConvertAnyFormat(ValuePtr, Format);
 break;
 }
 }

 {
 unsigned char * SubdirStart;
 unsigned Offset;

 if (DIR_ENTRY_ADDR(DirStart, NumDirEntries) + 4 <= OffsetBase+ExifLength){
            printf("DirStart %p offset from dirstart %d", DirStart, 2+12*NumDirEntries);
 Offset = Get32u(DirStart+2+12*NumDirEntries);
 if (Offset){
 SubdirStart = OffsetBase + Offset;
 if (SubdirStart > OffsetBase+ExifLength || SubdirStart < OffsetBase){
                    printf("SubdirStart %p OffsetBase %p ExifLength %d Offset %d",
 SubdirStart, OffsetBase, ExifLength, Offset);
 if (SubdirStart > OffsetBase && SubdirStart < OffsetBase+ExifLength+20){
 if (ShowTags) printf("Thumbnail removed with Jhead 1.3 or earlier\n");
 }else{
 ErrNonfatal("Illegal subdirectory link",0,0);
 }
 }else{
 if (SubdirStart <= OffsetBase+ExifLength){
 if (ShowTags) printf("%s    Continued directory ",IndentString);
 ProcessExifDir(SubdirStart, OffsetBase, ExifLength, NestingLevel+1);
 }
 }
 if (Offset > ImageInfo.LargestExifOffset){
 ImageInfo.LargestExifOffset = Offset;
 }
 }
 }else{
 }
 }

 if (ThumbnailOffset){
 ImageInfo.ThumbnailAtEnd = FALSE;

 if (DumpExifMap){
            printf("Map: %05d-%05d: Thumbnail\n",ThumbnailOffset, ThumbnailOffset+ThumbnailSize);
 }

 if (ThumbnailOffset <= ExifLength){
 if (ThumbnailSize > ExifLength-ThumbnailOffset){
 ThumbnailSize = ExifLength-ThumbnailOffset;
 if (ShowTags) printf("Thumbnail incorrectly placed in header\n");

 }
 ImageInfo.ThumbnailOffset = ThumbnailOffset;
 ImageInfo.ThumbnailSize = ThumbnailSize;

 if (ShowTags){
                printf("Thumbnail size: %d bytes\n",ThumbnailSize);
 }
 }
 }
    printf("returning from ProcessExifDir");
}

exif.c in Matthias Wandel jhead 2.87, as used in libjhead in Android 4.x before 4.4.4, 5.0.x before 5.0.2, 5.1.x before 5.1.1, and 6.x before 2016-08-01, allows remote attackers to execute arbitrary code or cause a denial of service (out-of-bounds access) via crafted EXIF data, aka internal bug 28868315.


static void ProcessExifDir(unsigned char * DirStart, unsigned char * OffsetBase,
 unsigned ExifLength, int NestingLevel)
{
 int de;
 int a;
 int NumDirEntries;
 unsigned ThumbnailOffset = 0;
 unsigned ThumbnailSize = 0;
 char IndentString[25];

    printf("ProcessExifDir");
 if (NestingLevel > 4){
 ErrNonfatal("Maximum directory nesting exceeded (corrupt exif header)", 0,0);
 return;
 }

    memset(IndentString, ' ', 25);
 IndentString[NestingLevel * 4] = '\0';

 NumDirEntries = Get16u(DirStart);
 #define DIR_ENTRY_ADDR(Start, Entry) (Start+2+12*(Entry))

 {
 unsigned char * DirEnd;
 DirEnd = DIR_ENTRY_ADDR(DirStart, NumDirEntries);
 if (DirEnd+4 > (OffsetBase+ExifLength)){
 if (DirEnd+2 == OffsetBase+ExifLength || DirEnd == OffsetBase+ExifLength){
 }else{
 ErrNonfatal("Illegally sized exif subdirectory (%d entries)",NumDirEntries,0);
 return;
 }
 }
 if (DumpExifMap){
            printf("Map: %05d-%05d: Directory\n",(int)(DirStart-OffsetBase), (int)(DirEnd+4-OffsetBase));
 }

 }

 if (ShowTags){
        printf("(dir has %d entries)\n",NumDirEntries);
 }

 for (de=0;de<NumDirEntries;de++){
 int Tag, Format, Components;
 unsigned char * ValuePtr;
 int ByteCount;
 unsigned char * DirEntry;
 DirEntry = DIR_ENTRY_ADDR(DirStart, de);

 Tag = Get16u(DirEntry);
 Format = Get16u(DirEntry+2);
 Components = Get32u(DirEntry+4);

 if ((Format-1) >= NUM_FORMATS) {
 ErrNonfatal("Illegal number format %d for tag %04x", Format, Tag);
 continue;
 }

 if ((unsigned)Components > 0x10000){
 ErrNonfatal("Illegal number of components %d for tag %04x", Components, Tag);
 continue;
 }

 ByteCount = Components * BytesPerFormat[Format];

 if (ByteCount > 4){

             unsigned OffsetVal;
             OffsetVal = Get32u(DirEntry+8);
            if (OffsetVal > UINT32_MAX - ByteCount || OffsetVal+ByteCount > ExifLength){
                 ErrNonfatal("Illegal value pointer for tag %04x", Tag,0);
                 continue;
 }
 ValuePtr = OffsetBase+OffsetVal;

 if (OffsetVal > ImageInfo.LargestExifOffset){
 ImageInfo.LargestExifOffset = OffsetVal;
 }

 if (DumpExifMap){
                printf("Map: %05d-%05d:   Data for tag %04x\n",OffsetVal, OffsetVal+ByteCount, Tag);
 }
 }else{
 ValuePtr = DirEntry+8;
 }

 if (Tag == TAG_MAKER_NOTE){
 if (ShowTags){
                printf("%s    Maker note: ",IndentString);
 }
 ProcessMakerNote(ValuePtr, ByteCount, OffsetBase, ExifLength);
 continue;
 }

 if (ShowTags){
 for (a=0;;a++){
 if (a >= (int)TAG_TABLE_SIZE){
                    printf("%s", IndentString);
                    printf("    Unknown Tag %04x Value = ", Tag);
 break;
 }
 if (TagTable[a].Tag == Tag){
                    printf("%s", IndentString);
                    printf("    %s = ",TagTable[a].Desc);
 break;
 }
 }

 switch(Format){
 case FMT_BYTE:
 if(ByteCount>1){
                        printf("%.*ls\n", ByteCount/2, (wchar_t *)ValuePtr);
 }else{
 PrintFormatNumber(ValuePtr, Format, ByteCount);
                        printf("\n");
 }
 break;

 case FMT_UNDEFINED:

 case FMT_STRING:
 {
                          printf("\"%s\"", ValuePtr);
 }
 break;

 default:
 PrintFormatNumber(ValuePtr, Format, ByteCount);
                    printf("\n");
 }
 }

 switch(Tag){

 case TAG_MAKE:
                strncpy(ImageInfo.CameraMake, (char *)ValuePtr, ByteCount < 31 ? ByteCount : 31);
 break;

 case TAG_MODEL:
                strncpy(ImageInfo.CameraModel, (char *)ValuePtr, ByteCount < 39 ? ByteCount : 39);
 break;

 case TAG_SUBSEC_TIME:
                strlcpy(ImageInfo.SubSecTime, (char *)ValuePtr, sizeof(ImageInfo.SubSecTime));
 break;

 case TAG_SUBSEC_TIME_ORIG:
                strlcpy(ImageInfo.SubSecTimeOrig, (char *)ValuePtr,
 sizeof(ImageInfo.SubSecTimeOrig));
 break;

 case TAG_SUBSEC_TIME_DIG:
                strlcpy(ImageInfo.SubSecTimeDig, (char *)ValuePtr,
 sizeof(ImageInfo.SubSecTimeDig));
 break;

 case TAG_DATETIME_DIGITIZED:
                strlcpy(ImageInfo.DigitizedTime, (char *)ValuePtr,
 sizeof(ImageInfo.DigitizedTime));

 if (ImageInfo.numDateTimeTags >= MAX_DATE_COPIES){
 ErrNonfatal("More than %d date fields!  This is nuts", MAX_DATE_COPIES, 0);
 break;
 }
 ImageInfo.DateTimeOffsets[ImageInfo.numDateTimeTags++] =
 (char *)ValuePtr - (char *)OffsetBase;
 break;

 case TAG_DATETIME_ORIGINAL:
                strncpy(ImageInfo.DateTime, (char *)ValuePtr, 19);

 case TAG_DATETIME:
 if (!isdigit(ImageInfo.DateTime[0])){
                    strncpy(ImageInfo.DateTime, (char *)ValuePtr, 19);
 }

 if (ImageInfo.numDateTimeTags >= MAX_DATE_COPIES){
 ErrNonfatal("More than %d date fields!  This is nuts", MAX_DATE_COPIES, 0);
 break;
 }
 ImageInfo.DateTimeOffsets[ImageInfo.numDateTimeTags++] =
 (char *)ValuePtr - (char *)OffsetBase;
 break;

 case TAG_WINXP_COMMENT:
 if (ImageInfo.Comments[0]){ // We already have a jpeg comment.
 if (ShowTags) printf("Windows XP commend and other comment in header\n");
 break; // Already have a windows comment, skip this one.
 }

 if (ByteCount > 1){
 if (ByteCount > MAX_COMMENT_SIZE) ByteCount = MAX_COMMENT_SIZE;
                    memcpy(ImageInfo.Comments, ValuePtr, ByteCount);
 ImageInfo.CommentWidchars = ByteCount/2;
 }
 break;

 case TAG_USERCOMMENT:
 if (ImageInfo.Comments[0]){ // We already have a jpeg comment.
 if (ShowTags) printf("Multiple comments in exif header\n");
 break; // Already have a windows comment, skip this one.
 }

 for (a=ByteCount;;){
                    a--;
 if ((ValuePtr)[a] == ' '){
 (ValuePtr)[a] = '\0';
 }else{
 break;
 }
 if (a == 0) break;
 }

 {
 int msiz = ExifLength - (ValuePtr-OffsetBase);
 if (msiz > ByteCount) msiz = ByteCount;
 if (msiz > MAX_COMMENT_SIZE - 1) msiz = MAX_COMMENT_SIZE - 1;
 if (msiz > 5 && memcmp(ValuePtr, "ASCII", 5) == 0) {
 for (a = 5; a < 10 && a < msiz; a++) {
 int c = (ValuePtr)[a];
 if (c != '\0' && c != ' ') {
                                strncpy(ImageInfo.Comments,
 (char *)ValuePtr + a, msiz - a);
 break;
 }
 }
 } else {
                        strncpy(ImageInfo.Comments, (char *)ValuePtr, msiz);
 }
 }
 break;

 case TAG_FNUMBER:
 ImageInfo.ApertureFNumber = (float)ConvertAnyFormat(ValuePtr, Format);
 break;

 case TAG_APERTURE:
 case TAG_MAXAPERTURE:
 if (ImageInfo.ApertureFNumber == 0){
 ImageInfo.ApertureFNumber
 = (float)exp(ConvertAnyFormat(ValuePtr, Format)*log(2)*0.5);
 }
 break;

 case TAG_FOCALLENGTH:
 ImageInfo.FocalLength.num = Get32u(ValuePtr);
 ImageInfo.FocalLength.denom = Get32u(4+(char *)ValuePtr);
 break;

 case TAG_SUBJECT_DISTANCE:
 ImageInfo.Distance = (float)ConvertAnyFormat(ValuePtr, Format);
 break;

 case TAG_EXPOSURETIME:
 ImageInfo.ExposureTime = (float)ConvertAnyFormat(ValuePtr, Format);
 break;

 case TAG_SHUTTERSPEED:
 if (ImageInfo.ExposureTime == 0){
 ImageInfo.ExposureTime
 = (float)(1/exp(ConvertAnyFormat(ValuePtr, Format)*log(2)));
 }
 break;

 case TAG_FLASH:
 ImageInfo.FlashUsed=(int)ConvertAnyFormat(ValuePtr, Format);
 break;

 case TAG_ORIENTATION:
 if (NumOrientations >= 2){
 ErrNonfatal("More than two orientation tags!",0,0);
 break;
 }
 OrientationPtr[NumOrientations] = ValuePtr;
 OrientationNumFormat[NumOrientations] = Format;
 if (NumOrientations == 0){
 ImageInfo.Orientation = (int)ConvertAnyFormat(ValuePtr, Format);
 }
 if (ImageInfo.Orientation < 0 || ImageInfo.Orientation > 8){
 ErrNonfatal("Undefined rotation value %d", ImageInfo.Orientation, 0);
 ImageInfo.Orientation = 0;
 }
 NumOrientations += 1;
 break;

 case TAG_EXIF_IMAGELENGTH:
 case TAG_EXIF_IMAGEWIDTH:
                a = (int)ConvertAnyFormat(ValuePtr, Format);
 if (ExifImageWidth < a) ExifImageWidth = a;
 break;

 case TAG_FOCAL_PLANE_XRES:
 FocalplaneXRes = ConvertAnyFormat(ValuePtr, Format);
 break;

 case TAG_FOCAL_PLANE_UNITS:
 switch((int)ConvertAnyFormat(ValuePtr, Format)){
 case 1: FocalplaneUnits = 25.4; break; // inch
 case 2:
 FocalplaneUnits = 25.4;
 break;

 case 3: FocalplaneUnits = 10; break; // centimeter
 case 4: FocalplaneUnits = 1; break; // millimeter
 case 5: FocalplaneUnits = .001; break; // micrometer
 }
 break;

 case TAG_EXPOSURE_BIAS:
 ImageInfo.ExposureBias = (float)ConvertAnyFormat(ValuePtr, Format);
 break;

 case TAG_WHITEBALANCE:
 ImageInfo.Whitebalance = (int)ConvertAnyFormat(ValuePtr, Format);
 break;

 case TAG_LIGHT_SOURCE:
 ImageInfo.LightSource = (int)ConvertAnyFormat(ValuePtr, Format);
 break;

 case TAG_METERING_MODE:
 ImageInfo.MeteringMode = (int)ConvertAnyFormat(ValuePtr, Format);
 break;

 case TAG_EXPOSURE_PROGRAM:
 ImageInfo.ExposureProgram = (int)ConvertAnyFormat(ValuePtr, Format);
 break;

 case TAG_EXPOSURE_INDEX:
 if (ImageInfo.ISOequivalent == 0){
 ImageInfo.ISOequivalent = (int)ConvertAnyFormat(ValuePtr, Format);
 }
 break;

 case TAG_EXPOSURE_MODE:
 ImageInfo.ExposureMode = (int)ConvertAnyFormat(ValuePtr, Format);
 break;

 case TAG_ISO_EQUIVALENT:
 ImageInfo.ISOequivalent = (int)ConvertAnyFormat(ValuePtr, Format);
 break;

 case TAG_DIGITALZOOMRATIO:
 ImageInfo.DigitalZoomRatio = (float)ConvertAnyFormat(ValuePtr, Format);
 break;

 case TAG_THUMBNAIL_OFFSET:
 ThumbnailOffset = (unsigned)ConvertAnyFormat(ValuePtr, Format);
 DirWithThumbnailPtrs = DirStart;
 break;

 case TAG_THUMBNAIL_LENGTH:
 ThumbnailSize = (unsigned)ConvertAnyFormat(ValuePtr, Format);
 ImageInfo.ThumbnailSizeOffset = ValuePtr-OffsetBase;
 break;

 case TAG_EXIF_OFFSET:
 if (ShowTags) printf("%s    Exif Dir:",IndentString);

 case TAG_INTEROP_OFFSET:
 if (Tag == TAG_INTEROP_OFFSET && ShowTags) printf("%s    Interop Dir:",IndentString);
 {
 unsigned char * SubdirStart;
 SubdirStart = OffsetBase + Get32u(ValuePtr);
 if (SubdirStart < OffsetBase || SubdirStart > OffsetBase+ExifLength){
 ErrNonfatal("Illegal exif or interop ofset directory link",0,0);
 }else{
 ProcessExifDir(SubdirStart, OffsetBase, ExifLength, NestingLevel+1);
 }
 continue;
 }
 break;

 case TAG_GPSINFO:
 if (ShowTags) printf("%s    GPS info dir:",IndentString);
 {
 unsigned char * SubdirStart;
 SubdirStart = OffsetBase + Get32u(ValuePtr);
 if (SubdirStart < OffsetBase || SubdirStart > OffsetBase+ExifLength){
 ErrNonfatal("Illegal GPS directory link",0,0);
 }else{
 ProcessGpsInfo(SubdirStart, ByteCount, OffsetBase, ExifLength);
 }
 continue;
 }
 break;

 case TAG_FOCALLENGTH_35MM:
 ImageInfo.FocalLength35mmEquiv = (unsigned)ConvertAnyFormat(ValuePtr, Format);
 break;

 case TAG_DISTANCE_RANGE:
 ImageInfo.DistanceRange = (int)ConvertAnyFormat(ValuePtr, Format);
 break;
 }
 }

 {
 unsigned char * SubdirStart;
 unsigned Offset;

 if (DIR_ENTRY_ADDR(DirStart, NumDirEntries) + 4 <= OffsetBase+ExifLength){
            printf("DirStart %p offset from dirstart %d", DirStart, 2+12*NumDirEntries);
 Offset = Get32u(DirStart+2+12*NumDirEntries);
 if (Offset){
 SubdirStart = OffsetBase + Offset;
 if (SubdirStart > OffsetBase+ExifLength || SubdirStart < OffsetBase){
                    printf("SubdirStart %p OffsetBase %p ExifLength %d Offset %d",
 SubdirStart, OffsetBase, ExifLength, Offset);
 if (SubdirStart > OffsetBase && SubdirStart < OffsetBase+ExifLength+20){
 if (ShowTags) printf("Thumbnail removed with Jhead 1.3 or earlier\n");
 }else{
 ErrNonfatal("Illegal subdirectory link",0,0);
 }
 }else{
 if (SubdirStart <= OffsetBase+ExifLength){
 if (ShowTags) printf("%s    Continued directory ",IndentString);
 ProcessExifDir(SubdirStart, OffsetBase, ExifLength, NestingLevel+1);
 }
 }
 if (Offset > ImageInfo.LargestExifOffset){
 ImageInfo.LargestExifOffset = Offset;
 }
 }
 }else{
 }
 }

 if (ThumbnailOffset){
 ImageInfo.ThumbnailAtEnd = FALSE;

 if (DumpExifMap){
            printf("Map: %05d-%05d: Thumbnail\n",ThumbnailOffset, ThumbnailOffset+ThumbnailSize);
 }

 if (ThumbnailOffset <= ExifLength){
 if (ThumbnailSize > ExifLength-ThumbnailOffset){
 ThumbnailSize = ExifLength-ThumbnailOffset;
 if (ShowTags) printf("Thumbnail incorrectly placed in header\n");

 }
 ImageInfo.ThumbnailOffset = ThumbnailOffset;
 ImageInfo.ThumbnailSize = ThumbnailSize;

 if (ShowTags){
                printf("Thumbnail size: %d bytes\n",ThumbnailSize);
 }
 }
 }
    printf("returning from ProcessExifDir");
}


u32 h264bsdInitDpb(
 dpbStorage_t *dpb,
  u32 picSizeInMbs,
  u32 dpbSize,
  u32 maxRefFrames,
  u32 maxFrameNum,
  u32 noReordering)
{

/* Variables */

    u32 i;

/* Code */

    ASSERT(picSizeInMbs);
    ASSERT(maxRefFrames <= MAX_NUM_REF_PICS);
    ASSERT(maxRefFrames <= dpbSize);

     ASSERT(maxFrameNum);
     ASSERT(dpbSize);

     dpb->maxLongTermFrameIdx = NO_LONG_TERM_FRAME_INDICES;
     dpb->maxRefFrames        = MAX(maxRefFrames, 1);
     if (noReordering)
        dpb->dpbSize         = dpb->maxRefFrames;
 else
        dpb->dpbSize         = dpbSize;
    dpb->maxFrameNum         = maxFrameNum;
    dpb->noReordering        = noReordering;
    dpb->fullness            = 0;
    dpb->numRefFrames        = 0;
    dpb->prevRefFrameNum     = 0;

    ALLOCATE(dpb->buffer, MAX_NUM_REF_IDX_L0_ACTIVE + 1, dpbPicture_t);
 if (dpb->buffer == NULL)
 return(MEMORY_ALLOCATION_ERROR);
    H264SwDecMemset(dpb->buffer, 0,
 (MAX_NUM_REF_IDX_L0_ACTIVE + 1)*sizeof(dpbPicture_t));
 for (i = 0; i < dpb->dpbSize + 1; i++)
 {
 /* Allocate needed amount of memory, which is:
         * image size + 32 + 15, where 32 cames from the fact that in ARM OpenMax
         * DL implementation Functions may read beyond the end of an array,
         * by a maximum of 32 bytes. And +15 cames for the need to align memory
         * to 16-byte boundary */
        ALLOCATE(dpb->buffer[i].pAllocatedData, (picSizeInMbs*384 + 32+15), u8);
 if (dpb->buffer[i].pAllocatedData == NULL)
 return(MEMORY_ALLOCATION_ERROR);

        dpb->buffer[i].data = ALIGN(dpb->buffer[i].pAllocatedData, 16);
 }

    ALLOCATE(dpb->list, MAX_NUM_REF_IDX_L0_ACTIVE + 1, dpbPicture_t*);
    ALLOCATE(dpb->outBuf, dpb->dpbSize+1, dpbOutPicture_t);

 if (dpb->list == NULL || dpb->outBuf == NULL)
 return(MEMORY_ALLOCATION_ERROR);

    H264SwDecMemset(dpb->list, 0,
 ((MAX_NUM_REF_IDX_L0_ACTIVE + 1) * sizeof(dpbPicture_t*)) );

    dpb->numOut = dpb->outIndex = 0;

 return(HANTRO_OK);

}

Integer overflow in codecs/on2/h264dec/source/h264bsd_dpb.c in libstagefright in mediaserver in Android 4.x before 4.4.4, 5.0.x before 5.0.2, 5.1.x before 5.1.1, and 6.x before 2016-08-01 allows remote attackers to execute arbitrary code or cause a denial of service (memory corruption) via a crafted media file, aka internal bug 28533562.


u32 h264bsdInitDpb(
 dpbStorage_t *dpb,
  u32 picSizeInMbs,
  u32 dpbSize,
  u32 maxRefFrames,
  u32 maxFrameNum,
  u32 noReordering)
{

/* Variables */

    u32 i;

/* Code */

    ASSERT(picSizeInMbs);
    ASSERT(maxRefFrames <= MAX_NUM_REF_PICS);
    ASSERT(maxRefFrames <= dpbSize);

     ASSERT(maxFrameNum);
     ASSERT(dpbSize);

    // see comment in loop below about size calculation
    if (picSizeInMbs > (UINT32_MAX - 32 - 15) / 384) {
        ALOGE("b/28533562");
        android_errorWriteLog(0x534e4554, "28533562");
        return(MEMORY_ALLOCATION_ERROR);
    }

     dpb->maxLongTermFrameIdx = NO_LONG_TERM_FRAME_INDICES;
     dpb->maxRefFrames        = MAX(maxRefFrames, 1);
     if (noReordering)
        dpb->dpbSize         = dpb->maxRefFrames;
 else
        dpb->dpbSize         = dpbSize;
    dpb->maxFrameNum         = maxFrameNum;
    dpb->noReordering        = noReordering;
    dpb->fullness            = 0;
    dpb->numRefFrames        = 0;
    dpb->prevRefFrameNum     = 0;

    ALLOCATE(dpb->buffer, MAX_NUM_REF_IDX_L0_ACTIVE + 1, dpbPicture_t);
 if (dpb->buffer == NULL)
 return(MEMORY_ALLOCATION_ERROR);
    H264SwDecMemset(dpb->buffer, 0,
 (MAX_NUM_REF_IDX_L0_ACTIVE + 1)*sizeof(dpbPicture_t));
 for (i = 0; i < dpb->dpbSize + 1; i++)
 {
 /* Allocate needed amount of memory, which is:
         * image size + 32 + 15, where 32 cames from the fact that in ARM OpenMax
         * DL implementation Functions may read beyond the end of an array,
         * by a maximum of 32 bytes. And +15 cames for the need to align memory
         * to 16-byte boundary */
        ALLOCATE(dpb->buffer[i].pAllocatedData, (picSizeInMbs*384 + 32+15), u8);
 if (dpb->buffer[i].pAllocatedData == NULL)
 return(MEMORY_ALLOCATION_ERROR);

        dpb->buffer[i].data = ALIGN(dpb->buffer[i].pAllocatedData, 16);
 }

    ALLOCATE(dpb->list, MAX_NUM_REF_IDX_L0_ACTIVE + 1, dpbPicture_t*);
    ALLOCATE(dpb->outBuf, dpb->dpbSize+1, dpbOutPicture_t);

 if (dpb->list == NULL || dpb->outBuf == NULL)
 return(MEMORY_ALLOCATION_ERROR);

    H264SwDecMemset(dpb->list, 0,
 ((MAX_NUM_REF_IDX_L0_ACTIVE + 1) * sizeof(dpbPicture_t*)) );

    dpb->numOut = dpb->outIndex = 0;

 return(HANTRO_OK);

}


 INLINE void impeg2d_bit_stream_flush(void* pv_ctxt, UWORD32 u4_no_of_bits)
 {
     stream_t *ps_stream = (stream_t *)pv_ctxt;
    if (ps_stream->u4_offset < ps_stream->u4_max_offset)
     {
         FLUSH_BITS(ps_stream->u4_offset,ps_stream->u4_buf,ps_stream->u4_buf_nxt,u4_no_of_bits,ps_stream->pu4_buf_aligned)
     }
     return;
 }

decoder/impeg2d_bitstream.c in mediaserver in Android 6.x before 2016-07-01 allows attackers to obtain sensitive information from process memory or cause a denial of service (out-of-bounds read) via a crafted application, aka internal bug 28168413.


 INLINE void impeg2d_bit_stream_flush(void* pv_ctxt, UWORD32 u4_no_of_bits)
 {
     stream_t *ps_stream = (stream_t *)pv_ctxt;
    if ((ps_stream->u4_offset + 64) < ps_stream->u4_max_offset)
     {
         FLUSH_BITS(ps_stream->u4_offset,ps_stream->u4_buf,ps_stream->u4_buf_nxt,u4_no_of_bits,ps_stream->pu4_buf_aligned)
     }
    else
    {
        UWORD32     u4_temp;

        if (((ps_stream->u4_offset & 0x1f) + u4_no_of_bits) >= 32)
        {
            ps_stream->u4_buf              = ps_stream->u4_buf_nxt;
            ps_stream->u4_buf_nxt          = 0;
        }
        ps_stream->u4_offset += u4_no_of_bits;
    }
     return;
 }


sp<IMemory> MetadataRetrieverClient::getFrameAtTime(int64_t timeUs, int option)
{
    ALOGV("getFrameAtTime: time(%lld us) option(%d)", timeUs, option);
 Mutex::Autolock lock(mLock);
 Mutex::Autolock glock(sLock);
    mThumbnail.clear();
 if (mRetriever == NULL) {
        ALOGE("retriever is not initialized");
 return NULL;
 }
 VideoFrame *frame = mRetriever->getFrameAtTime(timeUs, option);
 if (frame == NULL) {
        ALOGE("failed to capture a video frame");
 return NULL;
 }
 size_t size = sizeof(VideoFrame) + frame->mSize;
    sp<MemoryHeapBase> heap = new MemoryHeapBase(size, 0, "MetadataRetrieverClient");
 if (heap == NULL) {
        ALOGE("failed to create MemoryDealer");
 delete frame;
 return NULL;
 }
    mThumbnail = new MemoryBase(heap, 0, size);
 if (mThumbnail == NULL) {
        ALOGE("not enough memory for VideoFrame size=%u", size);
 delete frame;
 return NULL;
 }
 VideoFrame *frameCopy = static_cast<VideoFrame *>(mThumbnail->pointer());
    frameCopy->mWidth = frame->mWidth;
    frameCopy->mHeight = frame->mHeight;
    frameCopy->mDisplayWidth = frame->mDisplayWidth;
    frameCopy->mDisplayHeight = frame->mDisplayHeight;
    frameCopy->mSize = frame->mSize;
    frameCopy->mRotationAngle = frame->mRotationAngle;

     ALOGV("rotation: %d", frameCopy->mRotationAngle);
     frameCopy->mData = (uint8_t *)frameCopy + sizeof(VideoFrame);
     memcpy(frameCopy->mData, frame->mData, frame->mSize);
     delete frame;  // Fix memory leakage
     return mThumbnail;
 }

media/libmediaplayerservice/MetadataRetrieverClient.cpp in mediaserver in Android 4.x before 4.4.4, 5.0.x before 5.0.2, 5.1.x before 5.1.1, and 6.x before 2016-07-01 allows attackers to obtain sensitive pointer information via a crafted application, aka internal bug 28377502.


sp<IMemory> MetadataRetrieverClient::getFrameAtTime(int64_t timeUs, int option)
{
    ALOGV("getFrameAtTime: time(%lld us) option(%d)", timeUs, option);
 Mutex::Autolock lock(mLock);
 Mutex::Autolock glock(sLock);
    mThumbnail.clear();
 if (mRetriever == NULL) {
        ALOGE("retriever is not initialized");
 return NULL;
 }
 VideoFrame *frame = mRetriever->getFrameAtTime(timeUs, option);
 if (frame == NULL) {
        ALOGE("failed to capture a video frame");
 return NULL;
 }
 size_t size = sizeof(VideoFrame) + frame->mSize;
    sp<MemoryHeapBase> heap = new MemoryHeapBase(size, 0, "MetadataRetrieverClient");
 if (heap == NULL) {
        ALOGE("failed to create MemoryDealer");
 delete frame;
 return NULL;
 }
    mThumbnail = new MemoryBase(heap, 0, size);
 if (mThumbnail == NULL) {
        ALOGE("not enough memory for VideoFrame size=%u", size);
 delete frame;
 return NULL;
 }
 VideoFrame *frameCopy = static_cast<VideoFrame *>(mThumbnail->pointer());
    frameCopy->mWidth = frame->mWidth;
    frameCopy->mHeight = frame->mHeight;
    frameCopy->mDisplayWidth = frame->mDisplayWidth;
    frameCopy->mDisplayHeight = frame->mDisplayHeight;
    frameCopy->mSize = frame->mSize;
    frameCopy->mRotationAngle = frame->mRotationAngle;

     ALOGV("rotation: %d", frameCopy->mRotationAngle);
     frameCopy->mData = (uint8_t *)frameCopy + sizeof(VideoFrame);
     memcpy(frameCopy->mData, frame->mData, frame->mSize);
    frameCopy->mData = 0;
     delete frame;  // Fix memory leakage
     return mThumbnail;
 }


char* dexOptGenerateCacheFileName(const char* fileName, const char* subFileName)
{
 char nameBuf[512];
 char absoluteFile[sizeof(nameBuf)];
 const size_t kBufLen = sizeof(nameBuf) - 1;
 const char* dataRoot;
 char* cp;

 /*
     * Get the absolute path of the Jar or DEX file.
     */
    absoluteFile[0] = '\0';
 if (fileName[0] != '/') {
 /*
         * Generate the absolute path.  This doesn't do everything it
         * should, e.g. if filename is "./out/whatever" it doesn't crunch
         * the leading "./" out, but it'll do.
         */
 if (getcwd(absoluteFile, kBufLen) == NULL) {

             ALOGE("Can't get CWD while opening jar file");
             return NULL;
         }
        strncat(absoluteFile, "/", kBufLen);
     }
    strncat(absoluteFile, fileName, kBufLen);

     /*
      * Append the name of the Jar file entry, if any.  This is not currently
     * required, but will be if we start putting more than one DEX file

      * in a Jar.
      */
     if (subFileName != NULL) {
        strncat(absoluteFile, "/", kBufLen);
        strncat(absoluteFile, subFileName, kBufLen);
     }

     /* Turn the path into a flat filename by replacing
     * any slashes after the first one with '@' characters.
     */
    cp = absoluteFile + 1;
 while (*cp != '\0') {
 if (*cp == '/') {
 *cp = '@';
 }
        cp++;
 }

 /* Build the name of the cache directory.
     */
    dataRoot = getenv("ANDROID_DATA");
 if (dataRoot == NULL)
        dataRoot = "/data";
    snprintf(nameBuf, kBufLen, "%s/%s", dataRoot, kCacheDirectoryName);
 if (strcmp(dataRoot, "/data") != 0) {
 int result = dexOptMkdir(nameBuf, 0700);
 if (result != 0 && errno != EEXIST) {
            ALOGE("Failed to create dalvik-cache directory %s: %s", nameBuf, strerror(errno));
 return NULL;
 }
 }
    snprintf(nameBuf, kBufLen, "%s/%s/%s", dataRoot, kCacheDirectoryName, kInstructionSet);
 if (strcmp(dataRoot, "/data") != 0) {
 int result = dexOptMkdir(nameBuf, 0700);
 if (result != 0 && errno != EEXIST) {
            ALOGE("Failed to create dalvik-cache directory %s: %s", nameBuf, strerror(errno));
 return NULL;
 }
 }

     /* Tack on the file name for the actual cache file path.
      */
    strncat(nameBuf, absoluteFile, kBufLen);

     ALOGV("Cache file for '%s' '%s' is '%s'", fileName, subFileName, nameBuf);
     return strdup(nameBuf);
}

Multiple buffer overflows in libdex/OptInvocation.cpp in DexClassLoader in Android 4.x before 4.4.4, 5.0.x before 5.0.2, 5.1.x before 5.1.1, and 6.x before 2016-07-01 allow attackers to gain privileges via a crafted application that provides a long filename, aka internal bug 27840771.


char* dexOptGenerateCacheFileName(const char* fileName, const char* subFileName)
{
 char nameBuf[512];
 char absoluteFile[sizeof(nameBuf)];
 const size_t kBufLen = sizeof(nameBuf) - 1;
 const char* dataRoot;
 char* cp;

 /*
     * Get the absolute path of the Jar or DEX file.
     */
    absoluteFile[0] = '\0';
 if (fileName[0] != '/') {
 /*
         * Generate the absolute path.  This doesn't do everything it
         * should, e.g. if filename is "./out/whatever" it doesn't crunch
         * the leading "./" out, but it'll do.
         */
 if (getcwd(absoluteFile, kBufLen) == NULL) {

             ALOGE("Can't get CWD while opening jar file");
             return NULL;
         }
        strncat(absoluteFile, "/", kBufLen - strlen(absoluteFile));
     }
    strncat(absoluteFile, fileName, kBufLen - strlen(absoluteFile));

     /*
      * Append the name of the Jar file entry, if any.  This is not currently
     * required, but will be if we start putting more than one DEX file

      * in a Jar.
      */
     if (subFileName != NULL) {
        strncat(absoluteFile, "/", kBufLen - strlen(absoluteFile));
        strncat(absoluteFile, subFileName, kBufLen - strlen(absoluteFile));
     }

     /* Turn the path into a flat filename by replacing
     * any slashes after the first one with '@' characters.
     */
    cp = absoluteFile + 1;
 while (*cp != '\0') {
 if (*cp == '/') {
 *cp = '@';
 }
        cp++;
 }

 /* Build the name of the cache directory.
     */
    dataRoot = getenv("ANDROID_DATA");
 if (dataRoot == NULL)
        dataRoot = "/data";
    snprintf(nameBuf, kBufLen, "%s/%s", dataRoot, kCacheDirectoryName);
 if (strcmp(dataRoot, "/data") != 0) {
 int result = dexOptMkdir(nameBuf, 0700);
 if (result != 0 && errno != EEXIST) {
            ALOGE("Failed to create dalvik-cache directory %s: %s", nameBuf, strerror(errno));
 return NULL;
 }
 }
    snprintf(nameBuf, kBufLen, "%s/%s/%s", dataRoot, kCacheDirectoryName, kInstructionSet);
 if (strcmp(dataRoot, "/data") != 0) {
 int result = dexOptMkdir(nameBuf, 0700);
 if (result != 0 && errno != EEXIST) {
            ALOGE("Failed to create dalvik-cache directory %s: %s", nameBuf, strerror(errno));
 return NULL;
 }
 }

     /* Tack on the file name for the actual cache file path.
      */
    strncat(nameBuf, absoluteFile, kBufLen - strlen(nameBuf));

     ALOGV("Cache file for '%s' '%s' is '%s'", fileName, subFileName, nameBuf);
     return strdup(nameBuf);
}


 static void print_maps(struct pid_info_t* info)
 {
     FILE *maps;
     size_t offset;
     char device[10];
     long int inode;
    char file[PATH_MAX];

     strlcat(info->path, "maps", sizeof(info->path));

    maps = fopen(info->path, "r");

     if (!maps)
         goto out;

    while (fscanf(maps, "%*x-%*x %*s %zx %s %ld %s\n", &offset, device, &inode,
            file) == 4) {
         if (inode == 0 || !strcmp(device, "00:00"))
             continue;

        printf("%-9s %5d %10s %4s %9s %18s %9zd %10ld %s\n",
                info->cmdline, info->pid, info->user, "mem",
 "???", device, offset, inode, file);
 }

    fclose(maps);

out:
    info->path[info->parent_length] = '\0';
}

The print_maps function in toolbox/lsof.c in Android 4.x before 4.4.4, 5.0.x before 5.0.2, 5.1.x before 5.1.1, and 6.x before 2016-07-01 allows user-assisted attackers to gain privileges via a crafted application that attempts to list a long name of a memory-mapped file, aka internal bug 28175237.  NOTE: print_maps is not related to the Vic Abell lsof product.


 static void print_maps(struct pid_info_t* info)
 {
     FILE *maps;

     size_t offset;
     char device[10];
     long int inode;
    char file[1024];

     strlcat(info->path, "maps", sizeof(info->path));

    maps = fopen(info->path, "r");

     if (!maps)
         goto out;

    while (fscanf(maps, "%*x-%*x %*s %zx %5s %ld %1023s\n",
                  &offset, device, &inode, file) == 4) {
         if (inode == 0 || !strcmp(device, "00:00"))
             continue;

        printf("%-9s %5d %10s %4s %9s %18s %9zd %10ld %s\n",
                info->cmdline, info->pid, info->user, "mem",
 "???", device, offset, inode, file);
 }

    fclose(maps);

out:
    info->path[info->parent_length] = '\0';
}


 int res_inverse(vorbis_dsp_state *vd,vorbis_info_residue *info,
		ogg_int32_t **in,int *nonzero,int ch){

   int i,j,k,s,used=0;
   codec_setup_info     *ci=(codec_setup_info *)vd->vi->codec_setup;
  codebook *phrasebook=ci->book_param+info->groupbook;
 int samples_per_partition=info->grouping;
 int partitions_per_word=phrasebook->dim;
 int pcmend=ci->blocksizes[vd->W];

 if(info->type<2){
 int max=pcmend>>1;
 int end=(info->end<max?info->end:max);
 int n=end-info->begin;

 if(n>0){
 int partvals=n/samples_per_partition;

       int partwords=(partvals+partitions_per_word-1)/partitions_per_word;

       for(i=0;i<ch;i++)
	if(nonzero[i])
	  in[used++]=in[i];
       ch=used;

       if(used){

	char **partword=(char **)alloca(ch*sizeof(*partword));
	for(j=0;j<ch;j++)
	  partword[j]=(char *)alloca(partwords*partitions_per_word*
				     sizeof(*partword[j]));

	for(s=0;s<info->stages;s++){

	  for(i=0;i<partvals;){
	    if(s==0){
	      /* fetch the partition word for each channel */

	      partword[0][i+partitions_per_word-1]=1;
	      for(k=partitions_per_word-2;k>=0;k--)
		partword[0][i+k]=partword[0][i+k+1]*info->partitions;

	      for(j=1;j<ch;j++)
		for(k=partitions_per_word-1;k>=0;k--)
		  partword[j][i+k]=partword[j-1][i+k];

	      for(j=0;j<ch;j++){
		int temp=vorbis_book_decode(phrasebook,&vd->opb);
		if(temp==-1)goto eopbreak;

		/* this can be done quickly in assembly due to the quotient
		   always being at most six bits */
		for(k=0;k<partitions_per_word;k++){
		  ogg_uint32_t div=partword[j][i+k];
		  partword[j][i+k]=temp/div;
		  temp-=partword[j][i+k]*div;
		}

	      }
	    }

	    /* now we decode residual values for the partitions */
	    for(k=0;k<partitions_per_word && i<partvals;k++,i++)
	      for(j=0;j<ch;j++){
		long offset=info->begin+i*samples_per_partition;
		if(info->stagemasks[(int)partword[j][i]]&(1<<s)){
		  codebook *stagebook=ci->book_param+
		    info->stagebooks[(partword[j][i]<<3)+s];
		  if(info->type){
		    if(vorbis_book_decodev_add(stagebook,in[j]+offset,&vd->opb,
					       samples_per_partition,-8)==-1)
		      goto eopbreak;
		  }else{
		    if(vorbis_book_decodevs_add(stagebook,in[j]+offset,&vd->opb,
						samples_per_partition,-8)==-1)
		      goto eopbreak;
		  }
		}
	      }
	  }
	}
       }
     }
   }else{
 int max=(pcmend*ch)>>1;
 int end=(info->end<max?info->end:max);
 int n=end-info->begin;

 if(n>0){
 int partvals=n/samples_per_partition;

       int partwords=(partvals+partitions_per_word-1)/partitions_per_word;

       char *partword=
	(char *)alloca(partwords*partitions_per_word*sizeof(*partword));
       int beginoff=info->begin/ch;

       for(i=0;i<ch;i++)if(nonzero[i])break;
 if(i==ch)return(0); /* no nonzero vectors */

      samples_per_partition/=ch;

 for(s=0;s<info->stages;s++){
 for(i=0;i<partvals;){

 if(s==0){
 int temp;
	    partword[i+partitions_per_word-1]=1;
 for(k=partitions_per_word-2;k>=0;k--)
	      partword[i+k]=partword[i+k+1]*info->partitions;

 /* fetch the partition word */
	    temp=vorbis_book_decode(phrasebook,&vd->opb);
 if(temp==-1)goto eopbreak;

 /* this can be done quickly in assembly due to the quotient
	       always being at most six bits */
 for(k=0;k<partitions_per_word;k++){
 ogg_uint32_t div=partword[i+k];
	      partword[i+k]=temp/div;
	      temp-=partword[i+k]*div;
 }
 }

 /* now we decode residual values for the partitions */
 for(k=0;k<partitions_per_word && i<partvals;k++,i++)
 if(info->stagemasks[(int)partword[i]]&(1<<s)){
	      codebook *stagebook=ci->book_param+
		info->stagebooks[(partword[i]<<3)+s];
 if(vorbis_book_decodevv_add(stagebook,in,
					  i*samples_per_partition+beginoff,ch,
 &vd->opb,
					  samples_per_partition,-8)==-1)
 goto eopbreak;
 }
 }
 }
 }
 }
 eopbreak:

 return 0;
}

Tremolo/res012.c in mediaserver in Android 4.x before 4.4.4, 5.0.x before 5.0.2, 5.1.x before 5.1.1, and 6.x before 2016-07-01 does not validate the number of partitions, which allows remote attackers to cause a denial of service (device hang or reboot) via a crafted media file, aka internal bug 28556125.


 int res_inverse(vorbis_dsp_state *vd,vorbis_info_residue *info,
                ogg_int32_t **in,int *nonzero,int ch){

   int i,j,k,s,used=0;
   codec_setup_info     *ci=(codec_setup_info *)vd->vi->codec_setup;
  codebook *phrasebook=ci->book_param+info->groupbook;
 int samples_per_partition=info->grouping;
 int partitions_per_word=phrasebook->dim;
 int pcmend=ci->blocksizes[vd->W];

 if(info->type<2){
 int max=pcmend>>1;
 int end=(info->end<max?info->end:max);
 int n=end-info->begin;

 if(n>0){
 int partvals=n/samples_per_partition;

       int partwords=(partvals+partitions_per_word-1)/partitions_per_word;

       for(i=0;i<ch;i++)
        if(nonzero[i])
          in[used++]=in[i];
       ch=used;

       if(used){

        char **partword=(char **)alloca(ch*sizeof(*partword));
        for(j=0;j<ch;j++)
          partword[j]=(char *)alloca(partwords*partitions_per_word*
                                     sizeof(*partword[j]));

        for(s=0;s<info->stages;s++){

          for(i=0;i<partvals;){
            if(s==0){
              /* fetch the partition word for each channel */

              partword[0][i+partitions_per_word-1]=1;
              for(k=partitions_per_word-2;k>=0;k--)
                partword[0][i+k]=partword[0][i+k+1]*info->partitions;

              for(j=1;j<ch;j++)
                for(k=partitions_per_word-1;k>=0;k--)
                  partword[j][i+k]=partword[j-1][i+k];

              for(j=0;j<ch;j++){
                int temp=vorbis_book_decode(phrasebook,&vd->opb);
                if(temp==-1)goto eopbreak;

                /* this can be done quickly in assembly due to the quotient
                   always being at most six bits */
                for(k=0;k<partitions_per_word;k++){
                  ogg_uint32_t div=partword[j][i+k];
                  partword[j][i+k]=temp/div;
                  temp-=partword[j][i+k]*div;
                }

              }
            }

            /* now we decode residual values for the partitions */
            for(k=0;k<partitions_per_word && i<partvals;k++,i++)
              for(j=0;j<ch;j++){
                long offset=info->begin+i*samples_per_partition;
                int idx = (int)partword[j][i];
                if(idx < info->partitions && info->stagemasks[idx]&(1<<s)){
                  codebook *stagebook=ci->book_param+
                    info->stagebooks[(partword[j][i]<<3)+s];
                  if(info->type){
                    if(vorbis_book_decodev_add(stagebook,in[j]+offset,&vd->opb,
                                               samples_per_partition,-8)==-1)
                      goto eopbreak;
                  }else{
                    if(vorbis_book_decodevs_add(stagebook,in[j]+offset,&vd->opb,
                                                samples_per_partition,-8)==-1)
                      goto eopbreak;
                  }
                }
              }
          }
        }
       }
     }
   }else{
 int max=(pcmend*ch)>>1;
 int end=(info->end<max?info->end:max);
 int n=end-info->begin;

 if(n>0){
 int partvals=n/samples_per_partition;

       int partwords=(partvals+partitions_per_word-1)/partitions_per_word;

       char *partword=
        (char *)alloca(partwords*partitions_per_word*sizeof(*partword));
       int beginoff=info->begin/ch;

       for(i=0;i<ch;i++)if(nonzero[i])break;
 if(i==ch)return(0); /* no nonzero vectors */

      samples_per_partition/=ch;

 for(s=0;s<info->stages;s++){
 for(i=0;i<partvals;){

 if(s==0){
 int temp;
	    partword[i+partitions_per_word-1]=1;
 for(k=partitions_per_word-2;k>=0;k--)
	      partword[i+k]=partword[i+k+1]*info->partitions;

 /* fetch the partition word */
	    temp=vorbis_book_decode(phrasebook,&vd->opb);
 if(temp==-1)goto eopbreak;

 /* this can be done quickly in assembly due to the quotient
	       always being at most six bits */
 for(k=0;k<partitions_per_word;k++){
 ogg_uint32_t div=partword[i+k];
	      partword[i+k]=temp/div;
	      temp-=partword[i+k]*div;
 }
 }

 /* now we decode residual values for the partitions */
 for(k=0;k<partitions_per_word && i<partvals;k++,i++)
 if(info->stagemasks[(int)partword[i]]&(1<<s)){
	      codebook *stagebook=ci->book_param+
		info->stagebooks[(partword[i]<<3)+s];
 if(vorbis_book_decodevv_add(stagebook,in,
					  i*samples_per_partition+beginoff,ch,
 &vd->opb,
					  samples_per_partition,-8)==-1)
 goto eopbreak;
 }
 }
 }
 }
 }
 eopbreak:

 return 0;
}


 int main(int argc __unused, char** argv)
 {
     signal(SIGPIPE, SIG_IGN);
     char value[PROPERTY_VALUE_MAX];
     bool doLog = (property_get("ro.test_harness", value, "0") > 0) && (atoi(value) == 1);
 pid_t childPid;
 if (doLog && (childPid = fork()) != 0) {
        strcpy(argv[0], "media.log");
        sp<ProcessState> proc(ProcessState::self());
 MediaLogService::instantiate();
 ProcessState::self()->startThreadPool();
 for (;;) {
 siginfo_t info;
 int ret = waitid(P_PID, childPid, &info, WEXITED | WSTOPPED | WCONTINUED);
 if (ret == EINTR) {
 continue;
 }
 if (ret < 0) {
 break;
 }
 char buffer[32];
 const char *code;
 switch (info.si_code) {
 case CLD_EXITED:
                code = "CLD_EXITED";
 break;
 case CLD_KILLED:
                code = "CLD_KILLED";
 break;
 case CLD_DUMPED:
                code = "CLD_DUMPED";
 break;
 case CLD_STOPPED:
                code = "CLD_STOPPED";
 break;
 case CLD_TRAPPED:
                code = "CLD_TRAPPED";
 break;
 case CLD_CONTINUED:
                code = "CLD_CONTINUED";
 break;
 default:
                snprintf(buffer, sizeof(buffer), "unknown (%d)", info.si_code);
                code = buffer;
 break;
 }
 struct rusage usage;
            getrusage(RUSAGE_CHILDREN, &usage);
            ALOG(LOG_ERROR, "media.log", "pid %d status %d code %s user %ld.%03lds sys %ld.%03lds",
                    info.si_pid, info.si_status, code,
                    usage.ru_utime.tv_sec, usage.ru_utime.tv_usec / 1000,
                    usage.ru_stime.tv_sec, usage.ru_stime.tv_usec / 1000);
            sp<IServiceManager> sm = defaultServiceManager();
            sp<IBinder> binder = sm->getService(String16("media.log"));
 if (binder != 0) {
 Vector<String16> args;
                binder->dump(-1, args);
 }
 switch (info.si_code) {
 case CLD_EXITED:
 case CLD_KILLED:
 case CLD_DUMPED: {
                ALOG(LOG_INFO, "media.log", "exiting");
                _exit(0);
 }
 default:
 break;
 }
 }
 } else {
 if (doLog) {
            prctl(PR_SET_PDEATHSIG, SIGKILL); // if parent media.log dies before me, kill me also
            setpgid(0, 0); // but if I die first, don't kill my parent
 }
 InitializeIcuOrDie();
        sp<ProcessState> proc(ProcessState::self());
        sp<IServiceManager> sm = defaultServiceManager();
        ALOGI("ServiceManager: %p", sm.get());
 AudioFlinger::instantiate();
 MediaPlayerService::instantiate();
 ResourceManagerService::instantiate();
 CameraService::instantiate();
 AudioPolicyService::instantiate();
 SoundTriggerHwService::instantiate();
 RadioService::instantiate();
        registerExtensions();
 ProcessState::self()->startThreadPool();
 IPCThreadState::self()->joinThreadPool();
 }
}

mediaserver in Android 4.x before 4.4.4, 5.0.x before 5.0.2, 5.1.x before 5.1.1, and 6.x before 2016-07-01 does not limit process-memory usage, which allows remote attackers to cause a denial of service (device hang or reboot) via a crafted media file, aka internal bug 28615448.


 int main(int argc __unused, char** argv)
 {
    limitProcessMemory(
        "ro.media.maxmem", /* property that defines limit */
        SIZE_MAX, /* upper limit in bytes */
        65 /* upper limit as percentage of physical RAM */);

     signal(SIGPIPE, SIG_IGN);
     char value[PROPERTY_VALUE_MAX];
     bool doLog = (property_get("ro.test_harness", value, "0") > 0) && (atoi(value) == 1);
 pid_t childPid;
 if (doLog && (childPid = fork()) != 0) {
        strcpy(argv[0], "media.log");
        sp<ProcessState> proc(ProcessState::self());
 MediaLogService::instantiate();
 ProcessState::self()->startThreadPool();
 for (;;) {
 siginfo_t info;
 int ret = waitid(P_PID, childPid, &info, WEXITED | WSTOPPED | WCONTINUED);
 if (ret == EINTR) {
 continue;
 }
 if (ret < 0) {
 break;
 }
 char buffer[32];
 const char *code;
 switch (info.si_code) {
 case CLD_EXITED:
                code = "CLD_EXITED";
 break;
 case CLD_KILLED:
                code = "CLD_KILLED";
 break;
 case CLD_DUMPED:
                code = "CLD_DUMPED";
 break;
 case CLD_STOPPED:
                code = "CLD_STOPPED";
 break;
 case CLD_TRAPPED:
                code = "CLD_TRAPPED";
 break;
 case CLD_CONTINUED:
                code = "CLD_CONTINUED";
 break;
 default:
                snprintf(buffer, sizeof(buffer), "unknown (%d)", info.si_code);
                code = buffer;
 break;
 }
 struct rusage usage;
            getrusage(RUSAGE_CHILDREN, &usage);
            ALOG(LOG_ERROR, "media.log", "pid %d status %d code %s user %ld.%03lds sys %ld.%03lds",
                    info.si_pid, info.si_status, code,
                    usage.ru_utime.tv_sec, usage.ru_utime.tv_usec / 1000,
                    usage.ru_stime.tv_sec, usage.ru_stime.tv_usec / 1000);
            sp<IServiceManager> sm = defaultServiceManager();
            sp<IBinder> binder = sm->getService(String16("media.log"));
 if (binder != 0) {
 Vector<String16> args;
                binder->dump(-1, args);
 }
 switch (info.si_code) {
 case CLD_EXITED:
 case CLD_KILLED:
 case CLD_DUMPED: {
                ALOG(LOG_INFO, "media.log", "exiting");
                _exit(0);
 }
 default:
 break;
 }
 }
 } else {
 if (doLog) {
            prctl(PR_SET_PDEATHSIG, SIGKILL); // if parent media.log dies before me, kill me also
            setpgid(0, 0); // but if I die first, don't kill my parent
 }
 InitializeIcuOrDie();
        sp<ProcessState> proc(ProcessState::self());
        sp<IServiceManager> sm = defaultServiceManager();
        ALOGI("ServiceManager: %p", sm.get());
 AudioFlinger::instantiate();
 MediaPlayerService::instantiate();
 ResourceManagerService::instantiate();
 CameraService::instantiate();
 AudioPolicyService::instantiate();
 SoundTriggerHwService::instantiate();
 RadioService::instantiate();
        registerExtensions();
 ProcessState::self()->startThreadPool();
 IPCThreadState::self()->joinThreadPool();
 }
}


u32 h264bsdActivateParamSets(storage_t *pStorage, u32 ppsId, u32 isIdr)
{

/* Variables */

    u32 tmp;
    u32 flag;

/* Code */

    ASSERT(pStorage);
    ASSERT(ppsId < MAX_NUM_PIC_PARAM_SETS);

 /* check that pps and corresponding sps exist */
 if ( (pStorage->pps[ppsId] == NULL) ||
 (pStorage->sps[pStorage->pps[ppsId]->seqParameterSetId] == NULL) )
 {
 return(HANTRO_NOK);
 }

 /* check that pps parameters do not violate picture size constraints */
    tmp = CheckPps(pStorage->pps[ppsId],
                   pStorage->sps[pStorage->pps[ppsId]->seqParameterSetId]);
 if (tmp != HANTRO_OK)
 return(tmp);

 /* first activation part1 */
 if (pStorage->activePpsId == MAX_NUM_PIC_PARAM_SETS)
 {
        pStorage->activePpsId = ppsId;

         pStorage->activePps = pStorage->pps[ppsId];
         pStorage->activeSpsId = pStorage->activePps->seqParameterSetId;
         pStorage->activeSps = pStorage->sps[pStorage->activeSpsId];
        pStorage->picSizeInMbs =
            pStorage->activeSps->picWidthInMbs *
            pStorage->activeSps->picHeightInMbs;

         pStorage->currImage->width = pStorage->activeSps->picWidthInMbs;
         pStorage->currImage->height = pStorage->activeSps->picHeightInMbs;

        pStorage->pendingActivation = HANTRO_TRUE;
 }
 /* first activation part2 */
 else if (pStorage->pendingActivation)
 {
        pStorage->pendingActivation = HANTRO_FALSE;

        FREE(pStorage->mb);
        FREE(pStorage->sliceGroupMap);

        ALLOCATE(pStorage->mb, pStorage->picSizeInMbs, mbStorage_t);
        ALLOCATE(pStorage->sliceGroupMap, pStorage->picSizeInMbs, u32);
 if (pStorage->mb == NULL || pStorage->sliceGroupMap == NULL)
 return(MEMORY_ALLOCATION_ERROR);

        H264SwDecMemset(pStorage->mb, 0,
            pStorage->picSizeInMbs * sizeof(mbStorage_t));

        h264bsdInitMbNeighbours(pStorage->mb,
            pStorage->activeSps->picWidthInMbs,
            pStorage->picSizeInMbs);

 /* dpb output reordering disabled if
         * 1) application set noReordering flag
         * 2) POC type equal to 2
         * 3) num_reorder_frames in vui equal to 0 */
 if ( pStorage->noReordering ||
             pStorage->activeSps->picOrderCntType == 2 ||
 (pStorage->activeSps->vuiParametersPresentFlag &&
              pStorage->activeSps->vuiParameters->bitstreamRestrictionFlag &&
 !pStorage->activeSps->vuiParameters->numReorderFrames) )
            flag = HANTRO_TRUE;
 else
            flag = HANTRO_FALSE;

        tmp = h264bsdResetDpb(pStorage->dpb,
            pStorage->activeSps->picWidthInMbs *
            pStorage->activeSps->picHeightInMbs,
            pStorage->activeSps->maxDpbSize,
            pStorage->activeSps->numRefFrames,
            pStorage->activeSps->maxFrameNum,
            flag);
 if (tmp != HANTRO_OK)
 return(tmp);
 }
 else if (ppsId != pStorage->activePpsId)
 {
 /* sequence parameter set shall not change but before an IDR picture */
 if (pStorage->pps[ppsId]->seqParameterSetId != pStorage->activeSpsId)
 {
            DEBUG(("SEQ PARAM SET CHANGING...\n"));
 if (isIdr)
 {
                pStorage->activePpsId = ppsId;
                pStorage->activePps = pStorage->pps[ppsId];
                pStorage->activeSpsId = pStorage->activePps->seqParameterSetId;
                pStorage->activeSps = pStorage->sps[pStorage->activeSpsId];
                pStorage->picSizeInMbs =
                    pStorage->activeSps->picWidthInMbs *
                    pStorage->activeSps->picHeightInMbs;

                pStorage->currImage->width = pStorage->activeSps->picWidthInMbs;
                pStorage->currImage->height =
                    pStorage->activeSps->picHeightInMbs;

                pStorage->pendingActivation = HANTRO_TRUE;
 }
 else
 {
                DEBUG(("TRYING TO CHANGE SPS IN NON-IDR SLICE\n"));
 return(HANTRO_NOK);
 }
 }
 else
 {
            pStorage->activePpsId = ppsId;
            pStorage->activePps = pStorage->pps[ppsId];
 }
 }

 return(HANTRO_OK);

}

Integer overflow in codecs/on2/h264dec/source/h264bsd_storage.c in libstagefright in mediaserver in Android 4.x before 4.4.4, 5.0.x before 5.0.2, 5.1.x before 5.1.1, and 6.x before 2016-07-01 allows remote attackers to execute arbitrary code or cause a denial of service (memory corruption) via a crafted media file, aka internal bug 28532266.


u32 h264bsdActivateParamSets(storage_t *pStorage, u32 ppsId, u32 isIdr)
{

/* Variables */

    u32 tmp;
    u32 flag;

/* Code */

    ASSERT(pStorage);
    ASSERT(ppsId < MAX_NUM_PIC_PARAM_SETS);

 /* check that pps and corresponding sps exist */
 if ( (pStorage->pps[ppsId] == NULL) ||
 (pStorage->sps[pStorage->pps[ppsId]->seqParameterSetId] == NULL) )
 {
 return(HANTRO_NOK);
 }

 /* check that pps parameters do not violate picture size constraints */
    tmp = CheckPps(pStorage->pps[ppsId],
                   pStorage->sps[pStorage->pps[ppsId]->seqParameterSetId]);
 if (tmp != HANTRO_OK)
 return(tmp);

 /* first activation part1 */
 if (pStorage->activePpsId == MAX_NUM_PIC_PARAM_SETS)
 {
        pStorage->activePpsId = ppsId;

         pStorage->activePps = pStorage->pps[ppsId];
         pStorage->activeSpsId = pStorage->activePps->seqParameterSetId;
         pStorage->activeSps = pStorage->sps[pStorage->activeSpsId];

        /* report error before multiplication to prevent integer overflow */
        if (pStorage->activeSps->picWidthInMbs == 0)
        {
            pStorage->picSizeInMbs = 0;
        }
        else if (pStorage->activeSps->picHeightInMbs >
                 UINT32_MAX / pStorage->activeSps->picWidthInMbs)
        {
            return(MEMORY_ALLOCATION_ERROR);
        }
        else
        {
            pStorage->picSizeInMbs =
                pStorage->activeSps->picWidthInMbs *
                pStorage->activeSps->picHeightInMbs;
        }

         pStorage->currImage->width = pStorage->activeSps->picWidthInMbs;
         pStorage->currImage->height = pStorage->activeSps->picHeightInMbs;

        pStorage->pendingActivation = HANTRO_TRUE;
 }
 /* first activation part2 */
 else if (pStorage->pendingActivation)
 {
        pStorage->pendingActivation = HANTRO_FALSE;

        FREE(pStorage->mb);
        FREE(pStorage->sliceGroupMap);

        ALLOCATE(pStorage->mb, pStorage->picSizeInMbs, mbStorage_t);
        ALLOCATE(pStorage->sliceGroupMap, pStorage->picSizeInMbs, u32);
 if (pStorage->mb == NULL || pStorage->sliceGroupMap == NULL)
 return(MEMORY_ALLOCATION_ERROR);

        H264SwDecMemset(pStorage->mb, 0,
            pStorage->picSizeInMbs * sizeof(mbStorage_t));

        h264bsdInitMbNeighbours(pStorage->mb,
            pStorage->activeSps->picWidthInMbs,
            pStorage->picSizeInMbs);

 /* dpb output reordering disabled if
         * 1) application set noReordering flag
         * 2) POC type equal to 2
         * 3) num_reorder_frames in vui equal to 0 */
 if ( pStorage->noReordering ||
             pStorage->activeSps->picOrderCntType == 2 ||
 (pStorage->activeSps->vuiParametersPresentFlag &&
              pStorage->activeSps->vuiParameters->bitstreamRestrictionFlag &&
 !pStorage->activeSps->vuiParameters->numReorderFrames) )
            flag = HANTRO_TRUE;
 else
            flag = HANTRO_FALSE;

        tmp = h264bsdResetDpb(pStorage->dpb,
            pStorage->activeSps->picWidthInMbs *
            pStorage->activeSps->picHeightInMbs,
            pStorage->activeSps->maxDpbSize,
            pStorage->activeSps->numRefFrames,
            pStorage->activeSps->maxFrameNum,
            flag);
 if (tmp != HANTRO_OK)
 return(tmp);
 }
 else if (ppsId != pStorage->activePpsId)
 {
 /* sequence parameter set shall not change but before an IDR picture */
 if (pStorage->pps[ppsId]->seqParameterSetId != pStorage->activeSpsId)
 {
            DEBUG(("SEQ PARAM SET CHANGING...\n"));
 if (isIdr)
 {
                pStorage->activePpsId = ppsId;
                pStorage->activePps = pStorage->pps[ppsId];
                pStorage->activeSpsId = pStorage->activePps->seqParameterSetId;
                pStorage->activeSps = pStorage->sps[pStorage->activeSpsId];
                pStorage->picSizeInMbs =
                    pStorage->activeSps->picWidthInMbs *
                    pStorage->activeSps->picHeightInMbs;

                pStorage->currImage->width = pStorage->activeSps->picWidthInMbs;
                pStorage->currImage->height =
                    pStorage->activeSps->picHeightInMbs;

                pStorage->pendingActivation = HANTRO_TRUE;
 }
 else
 {
                DEBUG(("TRYING TO CHANGE SPS IN NON-IDR SLICE\n"));
 return(HANTRO_NOK);
 }
 }
 else
 {
            pStorage->activePpsId = ppsId;
            pStorage->activePps = pStorage->pps[ppsId];
 }
 }

 return(HANTRO_OK);

}


bool ATSParser::PSISection::isCRCOkay() const {
 if (!isComplete()) {
 return false;
 }
 uint8_t* data = mBuffer->data();

 if ((data[1] & 0x80) == 0) {
 return true;
 }

     unsigned sectionLength = U16_AT(data + 1) & 0xfff;
     ALOGV("sectionLength %u, skip %u", sectionLength, mSkipBytes);

     sectionLength -= mSkipBytes;

 uint32_t crc = 0xffffffff;
 for(unsigned i = 0; i < sectionLength + 4 /* crc */; i++) {
 uint8_t b = data[i];
 int index = ((crc >> 24) ^ (b & 0xff)) & 0xff;
        crc = CRC_TABLE[index] ^ (crc << 8);
 }
    ALOGV("crc: %08x\n", crc);
 return (crc == 0);
}

mpeg2ts/ATSParser.cpp in libstagefright in mediaserver in Android 6.x before 2016-07-01 does not validate a certain section length, which allows remote attackers to execute arbitrary code or cause a denial of service (memory corruption) via a crafted media file, aka internal bug 28333006.


bool ATSParser::PSISection::isCRCOkay() const {
 if (!isComplete()) {
 return false;
 }
 uint8_t* data = mBuffer->data();

 if ((data[1] & 0x80) == 0) {
 return true;
 }

     unsigned sectionLength = U16_AT(data + 1) & 0xfff;
     ALOGV("sectionLength %u, skip %u", sectionLength, mSkipBytes);

    if(sectionLength < mSkipBytes) {
        ALOGE("b/28333006");
        android_errorWriteLog(0x534e4554, "28333006");
        return false;
    }

     sectionLength -= mSkipBytes;

 uint32_t crc = 0xffffffff;
 for(unsigned i = 0; i < sectionLength + 4 /* crc */; i++) {
 uint8_t b = data[i];
 int index = ((crc >> 24) ^ (b & 0xff)) & 0xff;
        crc = CRC_TABLE[index] ^ (crc << 8);
 }
    ALOGV("crc: %08x\n", crc);
 return (crc == 0);
}


AudioSource::AudioSource(
 audio_source_t inputSource, const String16 &opPackageName,
 uint32_t sampleRate, uint32_t channelCount, uint32_t outSampleRate)

     : mStarted(false),
       mSampleRate(sampleRate),
       mOutSampleRate(outSampleRate > 0 ? outSampleRate : sampleRate),
       mPrevSampleTimeUs(0),
       mFirstSampleTimeUs(-1ll),
       mNumFramesReceived(0),
       mNumClientOwnedBuffers(0) {
     ALOGV("sampleRate: %u, outSampleRate: %u, channelCount: %u",
            sampleRate, outSampleRate, channelCount);
    CHECK(channelCount == 1 || channelCount == 2);
    CHECK(sampleRate > 0);

 size_t minFrameCount;
 status_t status = AudioRecord::getMinFrameCount(&minFrameCount,
                                           sampleRate,
                                           AUDIO_FORMAT_PCM_16_BIT,
                                           audio_channel_in_mask_from_count(channelCount));
 if (status == OK) {
 uint32_t frameCount = kMaxBufferSize / sizeof(int16_t) / channelCount;

 size_t bufCount = 2;
 while ((bufCount * frameCount) < minFrameCount) {
            bufCount++;
 }

        mRecord = new AudioRecord(
                    inputSource, sampleRate, AUDIO_FORMAT_PCM_16_BIT,
                    audio_channel_in_mask_from_count(channelCount),
                    opPackageName,
 (size_t) (bufCount * frameCount),
 AudioRecordCallbackFunction,
 this,
                    frameCount /*notificationFrames*/);
        mInitCheck = mRecord->initCheck();
 if (mInitCheck != OK) {
            mRecord.clear();
 }
 } else {
        mInitCheck = status;
 }
}

AudioSource.cpp in libstagefright in mediaserver in Android 4.x before 4.4.4, 5.0.x before 5.0.2, 5.1.x before 5.1.1, and 6.x before 2016-06-01 does not initialize certain data, which allows attackers to obtain sensitive information via a crafted application, aka internal bug 27855172.


AudioSource::AudioSource(
 audio_source_t inputSource, const String16 &opPackageName,
 uint32_t sampleRate, uint32_t channelCount, uint32_t outSampleRate)

     : mStarted(false),
       mSampleRate(sampleRate),
       mOutSampleRate(outSampleRate > 0 ? outSampleRate : sampleRate),
      mTrackMaxAmplitude(false),
      mStartTimeUs(0),
      mMaxAmplitude(0),
       mPrevSampleTimeUs(0),
       mFirstSampleTimeUs(-1ll),
      mInitialReadTimeUs(0),
       mNumFramesReceived(0),
       mNumClientOwnedBuffers(0) {
     ALOGV("sampleRate: %u, outSampleRate: %u, channelCount: %u",
            sampleRate, outSampleRate, channelCount);
    CHECK(channelCount == 1 || channelCount == 2);
    CHECK(sampleRate > 0);

 size_t minFrameCount;
 status_t status = AudioRecord::getMinFrameCount(&minFrameCount,
                                           sampleRate,
                                           AUDIO_FORMAT_PCM_16_BIT,
                                           audio_channel_in_mask_from_count(channelCount));
 if (status == OK) {
 uint32_t frameCount = kMaxBufferSize / sizeof(int16_t) / channelCount;

 size_t bufCount = 2;
 while ((bufCount * frameCount) < minFrameCount) {
            bufCount++;
 }

        mRecord = new AudioRecord(
                    inputSource, sampleRate, AUDIO_FORMAT_PCM_16_BIT,
                    audio_channel_in_mask_from_count(channelCount),
                    opPackageName,
 (size_t) (bufCount * frameCount),
 AudioRecordCallbackFunction,
 this,
                    frameCount /*notificationFrames*/);
        mInitCheck = mRecord->initCheck();
 if (mInitCheck != OK) {
            mRecord.clear();
 }
 } else {
        mInitCheck = status;
 }
}


static ssize_t get_node_path_locked(struct node* node, char* buf, size_t bufsize) {
 const char* name;
 size_t namelen;
 if (node->graft_path) {
        name = node->graft_path;
        namelen = node->graft_pathlen;
 } else if (node->actual_name) {
        name = node->actual_name;
        namelen = node->namelen;
 } else {
        name = node->name;
        namelen = node->namelen;
 }

 if (bufsize < namelen + 1) {
 return -1;
 }

     ssize_t pathlen = 0;
     if (node->parent && node->graft_path == NULL) {
        pathlen = get_node_path_locked(node->parent, buf, bufsize - namelen - 2);
         if (pathlen < 0) {
             return -1;
         }
        buf[pathlen++] = '/';
 }

    memcpy(buf + pathlen, name, namelen + 1); /* include trailing \0 */
 return pathlen + namelen;
}

Off-by-one error in sdcard/sdcard.c in Android 4.x before 4.4.4, 5.0.x before 5.0.2, 5.1.x before 5.1.1, and 6.x before 2016-06-01 allows attackers to gain privileges via a crafted application, as demonstrated by obtaining Signature or SignatureOrSystem access, aka internal bug 28085658.


static ssize_t get_node_path_locked(struct node* node, char* buf, size_t bufsize) {
 const char* name;
 size_t namelen;
 if (node->graft_path) {
        name = node->graft_path;
        namelen = node->graft_pathlen;
 } else if (node->actual_name) {
        name = node->actual_name;
        namelen = node->namelen;
 } else {
        name = node->name;
        namelen = node->namelen;
 }

 if (bufsize < namelen + 1) {
 return -1;
 }

     ssize_t pathlen = 0;
     if (node->parent && node->graft_path == NULL) {
        pathlen = get_node_path_locked(node->parent, buf, bufsize - namelen - 1);
         if (pathlen < 0) {
             return -1;
         }
        buf[pathlen++] = '/';
 }

    memcpy(buf + pathlen, name, namelen + 1); /* include trailing \0 */
 return pathlen + namelen;
}


void SoftMP3::onQueueFilled(OMX_U32 /* portIndex */) {
 if (mSignalledError || mOutputPortSettingsChange != NONE) {
 return;
 }

 List<BufferInfo *> &inQueue = getPortQueue(0);
 List<BufferInfo *> &outQueue = getPortQueue(1);

 while ((!inQueue.empty() || (mSawInputEos && !mSignalledOutputEos)) && !outQueue.empty()) {
 BufferInfo *inInfo = NULL;
        OMX_BUFFERHEADERTYPE *inHeader = NULL;
 if (!inQueue.empty()) {
            inInfo = *inQueue.begin();
            inHeader = inInfo->mHeader;
 }

 BufferInfo *outInfo = *outQueue.begin();
        OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
        outHeader->nFlags = 0;

 if (inHeader) {
 if (inHeader->nOffset == 0 && inHeader->nFilledLen) {
                mAnchorTimeUs = inHeader->nTimeStamp;
                mNumFramesOutput = 0;
 }

 if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
                mSawInputEos = true;
 }

            mConfig->pInputBuffer =
                inHeader->pBuffer + inHeader->nOffset;

            mConfig->inputBufferCurrentLength = inHeader->nFilledLen;
 } else {
            mConfig->pInputBuffer = NULL;
            mConfig->inputBufferCurrentLength = 0;
 }
        mConfig->inputBufferMaxLength = 0;

         mConfig->inputBufferUsedLength = 0;

         mConfig->outputFrameSize = kOutputBufferSize / sizeof(int16_t);

         mConfig->pOutputBuffer =
             reinterpret_cast<int16_t *>(outHeader->pBuffer);

        ERROR_CODE decoderErr;
 if ((decoderErr = pvmp3_framedecoder(mConfig, mDecoderBuf))
 != NO_DECODING_ERROR) {
            ALOGV("mp3 decoder returned error %d", decoderErr);

 if (decoderErr != NO_ENOUGH_MAIN_DATA_ERROR
 && decoderErr != SIDE_INFO_ERROR) {
                ALOGE("mp3 decoder returned error %d", decoderErr);

                notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
                mSignalledError = true;
 return;
 }

 if (mConfig->outputFrameSize == 0) {
                mConfig->outputFrameSize = kOutputBufferSize / sizeof(int16_t);
 }

 if (decoderErr == NO_ENOUGH_MAIN_DATA_ERROR && mSawInputEos) {
 if (!mIsFirst) {
                    outHeader->nOffset = 0;
                    outHeader->nFilledLen = kPVMP3DecoderDelay * mNumChannels * sizeof(int16_t);

                    memset(outHeader->pBuffer, 0, outHeader->nFilledLen);
 }
                outHeader->nFlags = OMX_BUFFERFLAG_EOS;
                mSignalledOutputEos = true;
 } else {

                ALOGV_IF(mIsFirst, "insufficient data for first frame, sending silence");
                memset(outHeader->pBuffer,
 0,
                       mConfig->outputFrameSize * sizeof(int16_t));

 if (inHeader) {
                    mConfig->inputBufferUsedLength = inHeader->nFilledLen;
 }
 }
 } else if (mConfig->samplingRate != mSamplingRate
 || mConfig->num_channels != mNumChannels) {
            mSamplingRate = mConfig->samplingRate;
            mNumChannels = mConfig->num_channels;

            notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
            mOutputPortSettingsChange = AWAITING_DISABLED;
 return;
 }

 if (mIsFirst) {
            mIsFirst = false;
            outHeader->nOffset =
                kPVMP3DecoderDelay * mNumChannels * sizeof(int16_t);

            outHeader->nFilledLen =
                mConfig->outputFrameSize * sizeof(int16_t) - outHeader->nOffset;
 } else if (!mSignalledOutputEos) {
            outHeader->nOffset = 0;
            outHeader->nFilledLen = mConfig->outputFrameSize * sizeof(int16_t);
 }

        outHeader->nTimeStamp =
            mAnchorTimeUs + (mNumFramesOutput * 1000000ll) / mSamplingRate;

 if (inHeader) {
            CHECK_GE(inHeader->nFilledLen, mConfig->inputBufferUsedLength);

            inHeader->nOffset += mConfig->inputBufferUsedLength;
            inHeader->nFilledLen -= mConfig->inputBufferUsedLength;

 if (inHeader->nFilledLen == 0) {
                inInfo->mOwnedByUs = false;
                inQueue.erase(inQueue.begin());
                inInfo = NULL;
                notifyEmptyBufferDone(inHeader);
                inHeader = NULL;
 }
 }

        mNumFramesOutput += mConfig->outputFrameSize / mNumChannels;

        outInfo->mOwnedByUs = false;
        outQueue.erase(outQueue.begin());
        outInfo = NULL;
        notifyFillBufferDone(outHeader);
        outHeader = NULL;
 }
}

mp3dec/SoftMP3.cpp in libstagefright in mediaserver in Android 4.x before 4.4.4, 5.0.x before 5.0.2, 5.1.x before 5.1.1, and 6.x before 2016-06-01 does not validate the relationship between allocated memory and the frame size, which allows attackers to gain privileges via a crafted application, as demonstrated by obtaining Signature or SignatureOrSystem access, aka internal bug 27793371.


void SoftMP3::onQueueFilled(OMX_U32 /* portIndex */) {
 if (mSignalledError || mOutputPortSettingsChange != NONE) {
 return;
 }

 List<BufferInfo *> &inQueue = getPortQueue(0);
 List<BufferInfo *> &outQueue = getPortQueue(1);

 while ((!inQueue.empty() || (mSawInputEos && !mSignalledOutputEos)) && !outQueue.empty()) {
 BufferInfo *inInfo = NULL;
        OMX_BUFFERHEADERTYPE *inHeader = NULL;
 if (!inQueue.empty()) {
            inInfo = *inQueue.begin();
            inHeader = inInfo->mHeader;
 }

 BufferInfo *outInfo = *outQueue.begin();
        OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
        outHeader->nFlags = 0;

 if (inHeader) {
 if (inHeader->nOffset == 0 && inHeader->nFilledLen) {
                mAnchorTimeUs = inHeader->nTimeStamp;
                mNumFramesOutput = 0;
 }

 if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
                mSawInputEos = true;
 }

            mConfig->pInputBuffer =
                inHeader->pBuffer + inHeader->nOffset;

            mConfig->inputBufferCurrentLength = inHeader->nFilledLen;
 } else {
            mConfig->pInputBuffer = NULL;
            mConfig->inputBufferCurrentLength = 0;
 }
        mConfig->inputBufferMaxLength = 0;

         mConfig->inputBufferUsedLength = 0;

         mConfig->outputFrameSize = kOutputBufferSize / sizeof(int16_t);
        if ((int32)outHeader->nAllocLen < mConfig->outputFrameSize) {
            ALOGE("input buffer too small: got %lu, expected %u",
                outHeader->nAllocLen, mConfig->outputFrameSize);
            android_errorWriteLog(0x534e4554, "27793371");
            notify(OMX_EventError, OMX_ErrorUndefined, OUTPUT_BUFFER_TOO_SMALL, NULL);
            mSignalledError = true;
            return;
        }

         mConfig->pOutputBuffer =
             reinterpret_cast<int16_t *>(outHeader->pBuffer);

        ERROR_CODE decoderErr;
 if ((decoderErr = pvmp3_framedecoder(mConfig, mDecoderBuf))
 != NO_DECODING_ERROR) {
            ALOGV("mp3 decoder returned error %d", decoderErr);

 if (decoderErr != NO_ENOUGH_MAIN_DATA_ERROR
 && decoderErr != SIDE_INFO_ERROR) {
                ALOGE("mp3 decoder returned error %d", decoderErr);

                notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
                mSignalledError = true;
 return;
 }

 if (mConfig->outputFrameSize == 0) {
                mConfig->outputFrameSize = kOutputBufferSize / sizeof(int16_t);
 }

 if (decoderErr == NO_ENOUGH_MAIN_DATA_ERROR && mSawInputEos) {
 if (!mIsFirst) {
                    outHeader->nOffset = 0;
                    outHeader->nFilledLen = kPVMP3DecoderDelay * mNumChannels * sizeof(int16_t);

                    memset(outHeader->pBuffer, 0, outHeader->nFilledLen);
 }
                outHeader->nFlags = OMX_BUFFERFLAG_EOS;
                mSignalledOutputEos = true;
 } else {

                ALOGV_IF(mIsFirst, "insufficient data for first frame, sending silence");
                memset(outHeader->pBuffer,
 0,
                       mConfig->outputFrameSize * sizeof(int16_t));

 if (inHeader) {
                    mConfig->inputBufferUsedLength = inHeader->nFilledLen;
 }
 }
 } else if (mConfig->samplingRate != mSamplingRate
 || mConfig->num_channels != mNumChannels) {
            mSamplingRate = mConfig->samplingRate;
            mNumChannels = mConfig->num_channels;

            notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
            mOutputPortSettingsChange = AWAITING_DISABLED;
 return;
 }

 if (mIsFirst) {
            mIsFirst = false;
            outHeader->nOffset =
                kPVMP3DecoderDelay * mNumChannels * sizeof(int16_t);

            outHeader->nFilledLen =
                mConfig->outputFrameSize * sizeof(int16_t) - outHeader->nOffset;
 } else if (!mSignalledOutputEos) {
            outHeader->nOffset = 0;
            outHeader->nFilledLen = mConfig->outputFrameSize * sizeof(int16_t);
 }

        outHeader->nTimeStamp =
            mAnchorTimeUs + (mNumFramesOutput * 1000000ll) / mSamplingRate;

 if (inHeader) {
            CHECK_GE(inHeader->nFilledLen, mConfig->inputBufferUsedLength);

            inHeader->nOffset += mConfig->inputBufferUsedLength;
            inHeader->nFilledLen -= mConfig->inputBufferUsedLength;

 if (inHeader->nFilledLen == 0) {
                inInfo->mOwnedByUs = false;
                inQueue.erase(inQueue.begin());
                inInfo = NULL;
                notifyEmptyBufferDone(inHeader);
                inHeader = NULL;
 }
 }

        mNumFramesOutput += mConfig->outputFrameSize / mNumChannels;

        outInfo->mOwnedByUs = false;
        outQueue.erase(outQueue.begin());
        outInfo = NULL;
        notifyFillBufferDone(outHeader);
        outHeader = NULL;
 }
}


status_t Camera3Device::createDefaultRequest(int templateId,

         CameraMetadata *request) {
     ATRACE_CALL();
     ALOGV("%s: for template %d", __FUNCTION__, templateId);
     Mutex::Autolock il(mInterfaceLock);
     Mutex::Autolock l(mLock);

 switch (mStatus) {
 case STATUS_ERROR:
            CLOGE("Device has encountered a serious error");
 return INVALID_OPERATION;
 case STATUS_UNINITIALIZED:
            CLOGE("Device is not initialized!");
 return INVALID_OPERATION;
 case STATUS_UNCONFIGURED:
 case STATUS_CONFIGURED:
 case STATUS_ACTIVE:
 break;
 default:
            SET_ERR_L("Unexpected status: %d", mStatus);
 return INVALID_OPERATION;
 }

 if (!mRequestTemplateCache[templateId].isEmpty()) {
 *request = mRequestTemplateCache[templateId];
 return OK;
 }

 const camera_metadata_t *rawRequest;
    ATRACE_BEGIN("camera3->construct_default_request_settings");
    rawRequest = mHal3Device->ops->construct_default_request_settings(
        mHal3Device, templateId);
    ATRACE_END();
 if (rawRequest == NULL) {
        ALOGI("%s: template %d is not supported on this camera device",
              __FUNCTION__, templateId);
 return BAD_VALUE;
 }
 *request = rawRequest;
    mRequestTemplateCache[templateId] = rawRequest;

 return OK;
}

services/camera/libcameraservice/device3/Camera3Device.cpp in mediaserver in Android 4.x before 4.4.4, 5.0.x before 5.0.2, 5.1.x before 5.1.1, and 6.x before 2016-05-01 does not validate template IDs, which allows attackers to gain privileges via a crafted application, as demonstrated by obtaining Signature or SignatureOrSystem access, aka internal bug 27568958.


status_t Camera3Device::createDefaultRequest(int templateId,

         CameraMetadata *request) {
     ATRACE_CALL();
     ALOGV("%s: for template %d", __FUNCTION__, templateId);

    if (templateId <= 0 || templateId >= CAMERA3_TEMPLATE_COUNT) {
        android_errorWriteWithInfoLog(CameraService::SN_EVENT_LOG_ID, "26866110",
                IPCThreadState::self()->getCallingUid(), NULL, 0);
        return BAD_VALUE;
    }

     Mutex::Autolock il(mInterfaceLock);
     Mutex::Autolock l(mLock);

 switch (mStatus) {
 case STATUS_ERROR:
            CLOGE("Device has encountered a serious error");
 return INVALID_OPERATION;
 case STATUS_UNINITIALIZED:
            CLOGE("Device is not initialized!");
 return INVALID_OPERATION;
 case STATUS_UNCONFIGURED:
 case STATUS_CONFIGURED:
 case STATUS_ACTIVE:
 break;
 default:
            SET_ERR_L("Unexpected status: %d", mStatus);
 return INVALID_OPERATION;
 }

 if (!mRequestTemplateCache[templateId].isEmpty()) {
 *request = mRequestTemplateCache[templateId];
 return OK;
 }

 const camera_metadata_t *rawRequest;
    ATRACE_BEGIN("camera3->construct_default_request_settings");
    rawRequest = mHal3Device->ops->construct_default_request_settings(
        mHal3Device, templateId);
    ATRACE_END();
 if (rawRequest == NULL) {
        ALOGI("%s: template %d is not supported on this camera device",
              __FUNCTION__, templateId);
 return BAD_VALUE;
 }
 *request = rawRequest;
    mRequestTemplateCache[templateId] = rawRequest;

 return OK;
}


status_t IPCThreadState::executeCommand(int32_t cmd)
{
 BBinder* obj;
 RefBase::weakref_type* refs;
 status_t result = NO_ERROR;

 switch ((uint32_t)cmd) {
 case BR_ERROR:
        result = mIn.readInt32();
 break;

 case BR_OK:
 break;

 case BR_ACQUIRE:
        refs = (RefBase::weakref_type*)mIn.readPointer();
        obj = (BBinder*)mIn.readPointer();
        ALOG_ASSERT(refs->refBase() == obj,
 "BR_ACQUIRE: object %p does not match cookie %p (expected %p)",
                   refs, obj, refs->refBase());
        obj->incStrong(mProcess.get());
        IF_LOG_REMOTEREFS() {
            LOG_REMOTEREFS("BR_ACQUIRE from driver on %p", obj);
            obj->printRefs();
 }
        mOut.writeInt32(BC_ACQUIRE_DONE);
        mOut.writePointer((uintptr_t)refs);
        mOut.writePointer((uintptr_t)obj);
 break;

 case BR_RELEASE:
        refs = (RefBase::weakref_type*)mIn.readPointer();
        obj = (BBinder*)mIn.readPointer();
        ALOG_ASSERT(refs->refBase() == obj,
 "BR_RELEASE: object %p does not match cookie %p (expected %p)",
                   refs, obj, refs->refBase());
        IF_LOG_REMOTEREFS() {
            LOG_REMOTEREFS("BR_RELEASE from driver on %p", obj);
            obj->printRefs();
 }
        mPendingStrongDerefs.push(obj);
 break;

 case BR_INCREFS:
        refs = (RefBase::weakref_type*)mIn.readPointer();
        obj = (BBinder*)mIn.readPointer();
        refs->incWeak(mProcess.get());
        mOut.writeInt32(BC_INCREFS_DONE);
        mOut.writePointer((uintptr_t)refs);
        mOut.writePointer((uintptr_t)obj);
 break;

 case BR_DECREFS:
        refs = (RefBase::weakref_type*)mIn.readPointer();
        obj = (BBinder*)mIn.readPointer();
        mPendingWeakDerefs.push(refs);
 break;

 case BR_ATTEMPT_ACQUIRE:
        refs = (RefBase::weakref_type*)mIn.readPointer();
        obj = (BBinder*)mIn.readPointer();

 {
 const bool success = refs->attemptIncStrong(mProcess.get());
            ALOG_ASSERT(success && refs->refBase() == obj,
 "BR_ATTEMPT_ACQUIRE: object %p does not match cookie %p (expected %p)",
                       refs, obj, refs->refBase());

            mOut.writeInt32(BC_ACQUIRE_RESULT);
            mOut.writeInt32((int32_t)success);
 }
 break;

 case BR_TRANSACTION:
 {
            binder_transaction_data tr;
            result = mIn.read(&tr, sizeof(tr));
            ALOG_ASSERT(result == NO_ERROR,
 "Not enough command data for brTRANSACTION");
 if (result != NO_ERROR) break;

 Parcel buffer;
            buffer.ipcSetDataReference(
 reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
                tr.data_size,
 reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
                tr.offsets_size/sizeof(binder_size_t), freeBuffer, this);

 const pid_t origPid = mCallingPid;
 const uid_t origUid = mCallingUid;
 const int32_t origStrictModePolicy = mStrictModePolicy;
 const int32_t origTransactionBinderFlags = mLastTransactionBinderFlags;

            mCallingPid = tr.sender_pid;
            mCallingUid = tr.sender_euid;
            mLastTransactionBinderFlags = tr.flags;

 int curPrio = getpriority(PRIO_PROCESS, mMyThreadId);
 if (gDisableBackgroundScheduling) {
 if (curPrio > ANDROID_PRIORITY_NORMAL) {
                    setpriority(PRIO_PROCESS, mMyThreadId, ANDROID_PRIORITY_NORMAL);
 }
 } else {
 if (curPrio >= ANDROID_PRIORITY_BACKGROUND) {
                    set_sched_policy(mMyThreadId, SP_BACKGROUND);
 }
 }

 Parcel reply;
 status_t error;
            IF_LOG_TRANSACTIONS() {
 TextOutput::Bundle _b(alog);
                alog << "BR_TRANSACTION thr " << (void*)pthread_self()
 << " / obj " << tr.target.ptr << " / code "
 << TypeCode(tr.code) << ": " << indent << buffer
 << dedent << endl
 << "Data addr = "
 << reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer)
 << ", offsets addr="

                     << reinterpret_cast<const size_t*>(tr.data.ptr.offsets) << endl;
             }
             if (tr.target.ptr) {
                sp<BBinder> b((BBinder*)tr.cookie);
                error = b->transact(tr.code, buffer, &reply, tr.flags);

             } else {
                 error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);
 }

 if ((tr.flags & TF_ONE_WAY) == 0) {
                LOG_ONEWAY("Sending reply to %d!", mCallingPid);
 if (error < NO_ERROR) reply.setError(error);
                sendReply(reply, 0);
 } else {
                LOG_ONEWAY("NOT sending reply to %d!", mCallingPid);
 }

            mCallingPid = origPid;
            mCallingUid = origUid;
            mStrictModePolicy = origStrictModePolicy;
            mLastTransactionBinderFlags = origTransactionBinderFlags;

            IF_LOG_TRANSACTIONS() {
 TextOutput::Bundle _b(alog);
                alog << "BC_REPLY thr " << (void*)pthread_self() << " / obj "
 << tr.target.ptr << ": " << indent << reply << dedent << endl;
 }

 }
 break;

 case BR_DEAD_BINDER:
 {
 BpBinder *proxy = (BpBinder*)mIn.readPointer();
            proxy->sendObituary();
            mOut.writeInt32(BC_DEAD_BINDER_DONE);
            mOut.writePointer((uintptr_t)proxy);
 } break;

 case BR_CLEAR_DEATH_NOTIFICATION_DONE:
 {
 BpBinder *proxy = (BpBinder*)mIn.readPointer();
            proxy->getWeakRefs()->decWeak(proxy);
 } break;

 case BR_FINISHED:
        result = TIMED_OUT;
 break;

 case BR_NOOP:
 break;

 case BR_SPAWN_LOOPER:
        mProcess->spawnPooledThread(false);
 break;

 default:
        printf("*** BAD COMMAND %d received from Binder driver\n", cmd);
        result = UNKNOWN_ERROR;
 break;
 }

 if (result != NO_ERROR) {
        mLastError = result;
 }

 return result;
}

libs/binder/IPCThreadState.cpp in Binder in Android 4.x before 4.4.4, 5.0.x before 5.0.2, 5.1.x before 5.1.1, and 6.x before 2016-05-01 mishandles object references, which allows attackers to gain privileges via a crafted application, aka internal bug 27252896.


status_t IPCThreadState::executeCommand(int32_t cmd)
{
 BBinder* obj;
 RefBase::weakref_type* refs;
 status_t result = NO_ERROR;

 switch ((uint32_t)cmd) {
 case BR_ERROR:
        result = mIn.readInt32();
 break;

 case BR_OK:
 break;

 case BR_ACQUIRE:
        refs = (RefBase::weakref_type*)mIn.readPointer();
        obj = (BBinder*)mIn.readPointer();
        ALOG_ASSERT(refs->refBase() == obj,
 "BR_ACQUIRE: object %p does not match cookie %p (expected %p)",
                   refs, obj, refs->refBase());
        obj->incStrong(mProcess.get());
        IF_LOG_REMOTEREFS() {
            LOG_REMOTEREFS("BR_ACQUIRE from driver on %p", obj);
            obj->printRefs();
 }
        mOut.writeInt32(BC_ACQUIRE_DONE);
        mOut.writePointer((uintptr_t)refs);
        mOut.writePointer((uintptr_t)obj);
 break;

 case BR_RELEASE:
        refs = (RefBase::weakref_type*)mIn.readPointer();
        obj = (BBinder*)mIn.readPointer();
        ALOG_ASSERT(refs->refBase() == obj,
 "BR_RELEASE: object %p does not match cookie %p (expected %p)",
                   refs, obj, refs->refBase());
        IF_LOG_REMOTEREFS() {
            LOG_REMOTEREFS("BR_RELEASE from driver on %p", obj);
            obj->printRefs();
 }
        mPendingStrongDerefs.push(obj);
 break;

 case BR_INCREFS:
        refs = (RefBase::weakref_type*)mIn.readPointer();
        obj = (BBinder*)mIn.readPointer();
        refs->incWeak(mProcess.get());
        mOut.writeInt32(BC_INCREFS_DONE);
        mOut.writePointer((uintptr_t)refs);
        mOut.writePointer((uintptr_t)obj);
 break;

 case BR_DECREFS:
        refs = (RefBase::weakref_type*)mIn.readPointer();
        obj = (BBinder*)mIn.readPointer();
        mPendingWeakDerefs.push(refs);
 break;

 case BR_ATTEMPT_ACQUIRE:
        refs = (RefBase::weakref_type*)mIn.readPointer();
        obj = (BBinder*)mIn.readPointer();

 {
 const bool success = refs->attemptIncStrong(mProcess.get());
            ALOG_ASSERT(success && refs->refBase() == obj,
 "BR_ATTEMPT_ACQUIRE: object %p does not match cookie %p (expected %p)",
                       refs, obj, refs->refBase());

            mOut.writeInt32(BC_ACQUIRE_RESULT);
            mOut.writeInt32((int32_t)success);
 }
 break;

 case BR_TRANSACTION:
 {
            binder_transaction_data tr;
            result = mIn.read(&tr, sizeof(tr));
            ALOG_ASSERT(result == NO_ERROR,
 "Not enough command data for brTRANSACTION");
 if (result != NO_ERROR) break;

 Parcel buffer;
            buffer.ipcSetDataReference(
 reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
                tr.data_size,
 reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
                tr.offsets_size/sizeof(binder_size_t), freeBuffer, this);

 const pid_t origPid = mCallingPid;
 const uid_t origUid = mCallingUid;
 const int32_t origStrictModePolicy = mStrictModePolicy;
 const int32_t origTransactionBinderFlags = mLastTransactionBinderFlags;

            mCallingPid = tr.sender_pid;
            mCallingUid = tr.sender_euid;
            mLastTransactionBinderFlags = tr.flags;

 int curPrio = getpriority(PRIO_PROCESS, mMyThreadId);
 if (gDisableBackgroundScheduling) {
 if (curPrio > ANDROID_PRIORITY_NORMAL) {
                    setpriority(PRIO_PROCESS, mMyThreadId, ANDROID_PRIORITY_NORMAL);
 }
 } else {
 if (curPrio >= ANDROID_PRIORITY_BACKGROUND) {
                    set_sched_policy(mMyThreadId, SP_BACKGROUND);
 }
 }

 Parcel reply;
 status_t error;
            IF_LOG_TRANSACTIONS() {
 TextOutput::Bundle _b(alog);
                alog << "BR_TRANSACTION thr " << (void*)pthread_self()
 << " / obj " << tr.target.ptr << " / code "
 << TypeCode(tr.code) << ": " << indent << buffer
 << dedent << endl
 << "Data addr = "
 << reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer)
 << ", offsets addr="

                     << reinterpret_cast<const size_t*>(tr.data.ptr.offsets) << endl;
             }
             if (tr.target.ptr) {
                // We only have a weak reference on the target object, so we must first try to
                // safely acquire a strong reference before doing anything else with it.
                if (reinterpret_cast<RefBase::weakref_type*>(
                        tr.target.ptr)->attemptIncStrong(this)) {
                    error = reinterpret_cast<BBinder*>(tr.cookie)->transact(tr.code, buffer,
                            &reply, tr.flags);
                    reinterpret_cast<BBinder*>(tr.cookie)->decStrong(this);
                } else {
                    error = UNKNOWN_TRANSACTION;
                }

             } else {
                 error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);
 }

 if ((tr.flags & TF_ONE_WAY) == 0) {
                LOG_ONEWAY("Sending reply to %d!", mCallingPid);
 if (error < NO_ERROR) reply.setError(error);
                sendReply(reply, 0);
 } else {
                LOG_ONEWAY("NOT sending reply to %d!", mCallingPid);
 }

            mCallingPid = origPid;
            mCallingUid = origUid;
            mStrictModePolicy = origStrictModePolicy;
            mLastTransactionBinderFlags = origTransactionBinderFlags;

            IF_LOG_TRANSACTIONS() {
 TextOutput::Bundle _b(alog);
                alog << "BC_REPLY thr " << (void*)pthread_self() << " / obj "
 << tr.target.ptr << ": " << indent << reply << dedent << endl;
 }

 }
 break;

 case BR_DEAD_BINDER:
 {
 BpBinder *proxy = (BpBinder*)mIn.readPointer();
            proxy->sendObituary();
            mOut.writeInt32(BC_DEAD_BINDER_DONE);
            mOut.writePointer((uintptr_t)proxy);
 } break;

 case BR_CLEAR_DEATH_NOTIFICATION_DONE:
 {
 BpBinder *proxy = (BpBinder*)mIn.readPointer();
            proxy->getWeakRefs()->decWeak(proxy);
 } break;

 case BR_FINISHED:
        result = TIMED_OUT;
 break;

 case BR_NOOP:
 break;

 case BR_SPAWN_LOOPER:
        mProcess->spawnPooledThread(false);
 break;

 default:
        printf("*** BAD COMMAND %d received from Binder driver\n", cmd);
        result = UNKNOWN_ERROR;
 break;
 }

 if (result != NO_ERROR) {
        mLastError = result;
 }

 return result;
}


FLAC__bool read_metadata_vorbiscomment_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_VorbisComment *obj, unsigned length)
{
	FLAC__uint32 i;

	FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input));

 /* read vendor string */
 if (length >= 8) {
		length -= 8; /* vendor string length + num comments entries alone take 8 bytes */
		FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN == 32);
 if (!FLAC__bitreader_read_uint32_little_endian(decoder->private_->input, &obj->vendor_string.length))
 return false; /* read_callback_ sets the state for us */
 if (obj->vendor_string.length > 0) {
 if (length < obj->vendor_string.length) {
				obj->vendor_string.length = 0;
				obj->vendor_string.entry = 0;
 goto skip;
 }
 else
				length -= obj->vendor_string.length;
 if (0 == (obj->vendor_string.entry = safe_malloc_add_2op_(obj->vendor_string.length, /*+*/1))) {
				decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
 return false;
 }
 if (!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, obj->vendor_string.entry, obj->vendor_string.length))
 return false; /* read_callback_ sets the state for us */
			obj->vendor_string.entry[obj->vendor_string.length] = '\0';
 }
 else
			obj->vendor_string.entry = 0;

 /* read num comments */
		FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN == 32);
 if (!FLAC__bitreader_read_uint32_little_endian(decoder->private_->input, &obj->num_comments))
 return false; /* read_callback_ sets the state for us */

 /* read comments */
 if (obj->num_comments > 100000) {
 /* Possibly malicious file. */
			obj->num_comments = 0;
 return false;
 }

 		if (obj->num_comments > 0) {
 			if (0 == (obj->comments = safe_malloc_mul_2op_p(obj->num_comments, /*times*/sizeof(FLAC__StreamMetadata_VorbisComment_Entry)))) {
 				decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
 				return false;
 			}
 			for (i = 0; i < obj->num_comments; i++) {
 /* Initialize here just to make sure. */
				obj->comments[i].length = 0;
				obj->comments[i].entry = 0;

				FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN == 32);
 if (length < 4) {
					obj->num_comments = i;
 goto skip;
 }
 else
					length -= 4;
 if (!FLAC__bitreader_read_uint32_little_endian(decoder->private_->input, &obj->comments[i].length))
 return false; /* read_callback_ sets the state for us */
 if (obj->comments[i].length > 0) {
 if (length < obj->comments[i].length) {
						obj->num_comments = i;
 goto skip;
 }
 else
						length -= obj->comments[i].length;
 if (0 == (obj->comments[i].entry = safe_malloc_add_2op_(obj->comments[i].length, /*+*/1))) {
						decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
 return false;
 }
					memset (obj->comments[i].entry, 0, obj->comments[i].length) ;
 if (!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, obj->comments[i].entry, obj->comments[i].length)) {
						obj->num_comments = i;
 goto skip;
 }
					obj->comments[i].entry[obj->comments[i].length] = '\0';
 }
 else
					obj->comments[i].entry = 0;
 }
 }
 else
			obj->comments = 0;
 }

  skip:
 if (length > 0) {
 /* This will only happen on files with invalid data in comments */
 if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(decoder->private_->input, length))
 return false; /* read_callback_ sets the state for us */
 }

 return true;
}

libFLAC/stream_decoder.c in mediaserver in Android 4.x before 4.4.4, 5.0.x before 5.0.2, 5.1.x before 5.1.1, and 6.x before 2016-05-01 does not prevent free operations on uninitialized memory, which allows remote attackers to execute arbitrary code or cause a denial of service (heap memory corruption) via a crafted media file, aka internal bug 27211885.