1 #include "dgif_fuzz_common.h"
2 #include <iostream>
3 
4 using namespace std;
5 
6 extern "C" void PrintGifError(int ErrorCode);
7 
stub_input_reader(GifFileType * gifFileType,GifByteType * gifByteType,int len)8 int stub_input_reader(GifFileType *gifFileType, GifByteType *gifByteType, int len)
9 {
10 	struct gifUserData *gud = (struct gifUserData *)gifFileType->UserData;
11 	if (gud->gifLen == 0)
12 		return 0;
13 	int read_len = (len > gud->gifLen ? gud->gifLen : len);
14 	memcpy(gifByteType, gud->gifData, read_len);
15 	gud->gifData += read_len;
16 	gud->gifLen -= read_len;
17 	return read_len;
18 }
19 
fuzz_dgif(const uint8_t * Data,size_t Size)20 int fuzz_dgif(const uint8_t *Data, size_t Size)
21 {
22 	GifFileType *GifFile;
23 	int Error;
24 	uint8_t *gifData = (uint8_t *)malloc(Size);
25 	memcpy(gifData, Data, Size);
26 	struct gifUserData gUData = {Size, gifData};
27 
28 	GifFile = DGifOpen((void *)&gUData, stub_input_reader, &Error);
29 	if (GifFile != NULL)
30 	{
31 		DGifSlurp(GifFile);
32 		DGifCloseFile(GifFile, &Error);
33 	}
34 	free(gifData);
35 	return 0;
36 }
37 
fuzz_dgif_extended(const uint8_t * Data,size_t Size)38 int fuzz_dgif_extended(const uint8_t *Data, size_t Size)
39 {
40 	GifFileType *GifFile;
41 	int Error;
42 	uint8_t *gifData = (uint8_t *)malloc(Size);
43 	memcpy(gifData, Data, Size);
44 	struct gifUserData gUData = {Size, gifData};
45 
46 	GifFile = DGifOpen((void *)&gUData, stub_input_reader, &Error);
47 	if (GifFile == NULL)
48 	{
49 		free(gifData);
50 		return 0;
51 	}
52 	if (DGifSlurp(GifFile) != GIF_OK)
53 	{
54 		DGifCloseFile(GifFile, &Error);
55 		free(gifData);
56 		return 0;
57 	}
58 	GraphicsControlBlock gcb;
59 	for (int i = 0; i < GifFile->ImageCount; i++)
60 	{
61 		DGifSavedExtensionToGCB(GifFile, i, &gcb);
62 	}
63 	const ColorMapObject *cmap = GifFile->SColorMap;
64 	if (cmap)
65 	{
66 		DGifSavedExtensionToGCB(GifFile, 0, &gcb);
67 	}
68 	DGifCloseFile(GifFile, &Error);
69 	free(gifData);
70 	return 0;
71 }
72 
gifColorToColor8888(const GifColorType & color)73 static Color8888 gifColorToColor8888(const GifColorType &color)
74 {
75 	return ARGB_TO_COLOR8888(0xff, color.Red, color.Green, color.Blue);
76 }
77 
willBeCleared(const GraphicsControlBlock & gcb)78 static bool willBeCleared(const GraphicsControlBlock &gcb)
79 {
80 	return gcb.DisposalMode == DISPOSE_BACKGROUND || gcb.DisposalMode == DISPOSE_PREVIOUS;
81 }
82 
getDelayMs(GraphicsControlBlock & gcb)83 static long getDelayMs(GraphicsControlBlock &gcb)
84 {
85 	return gcb.DelayTime * 10;
86 }
87 
fuzz_dgif_ala_android(const uint8_t * Data,size_t Size)88 int fuzz_dgif_ala_android(const uint8_t *Data, size_t Size)
89 {
90 	GifFileType *GifFile;
91 	int Error;
92 	uint8_t *gifData = (uint8_t *)malloc(Size);
93 	memcpy(gifData, Data, Size);
94 	struct gifUserData gUData = {Size, gifData};
95 
96 	GifFile = DGifOpen((void *)&gUData, stub_input_reader, &Error);
97 	if (GifFile == NULL)
98 	{
99 		free(gifData);
100 		return 0;
101 	}
102 
103 	if (DGifSlurp(GifFile) != GIF_OK)
104 	{
105 		PrintGifError(GifFile->Error);
106 		DGifCloseFile(GifFile, &Error);
107 		free(gifData);
108 		return 0;
109 	}
110 
111 	long durationMs = 0;
112 	int lastUnclearedFrame = -1;
113 	bool *preservedFrames = new bool[GifFile->ImageCount];
114 	int *restoringFrames = new int[GifFile->ImageCount];
115 	int loopCount = 0;
116 	Color8888 bgColor = 0;
117 
118 	GraphicsControlBlock gcb;
119 	for (int i = 0; i < GifFile->ImageCount; i++)
120 	{
121 		const SavedImage &image = GifFile->SavedImages[i];
122 		// find the loop extension pair
123 		for (int j = 0; (j + 1) < image.ExtensionBlockCount; j++)
124 		{
125 			ExtensionBlock *eb1 = image.ExtensionBlocks + j;
126 			ExtensionBlock *eb2 = image.ExtensionBlocks + j + 1;
127 			if (eb1->Function == APPLICATION_EXT_FUNC_CODE
128 				// look for "NETSCAPE2.0" app extension
129 				&& eb1->ByteCount == 11 && !memcmp((const char *)(eb1->Bytes), "NETSCAPE2.0", 11)
130 				// verify extension contents and get loop count
131 				&& eb2->Function == CONTINUE_EXT_FUNC_CODE && eb2->ByteCount == 3 && eb2->Bytes[0] == 1)
132 			{
133 				loopCount = (int)(eb2->Bytes[2] << 8) + (int)(eb2->Bytes[1]);
134 			}
135 		}
136 		DGifSavedExtensionToGCB(GifFile, i, &gcb);
137 		// timing
138 		durationMs += getDelayMs(gcb);
139 		// preserve logic
140 		preservedFrames[i] = false;
141 		restoringFrames[i] = -1;
142 		if (gcb.DisposalMode == DISPOSE_PREVIOUS && lastUnclearedFrame >= 0)
143 		{
144 			preservedFrames[lastUnclearedFrame] = true;
145 			restoringFrames[i] = lastUnclearedFrame;
146 		}
147 		if (!willBeCleared(gcb))
148 		{
149 			lastUnclearedFrame = i;
150 		}
151 		// Draw
152 		// assert(y+8 <= Image->ImageDesc.Height);
153 		// assert(x+8*strlen(legend) <= Image->ImageDesc.Width);
154 		int imgHeight = GifFile->SavedImages[i].ImageDesc.Height;
155 		int imgWidth = GifFile->SavedImages[i].ImageDesc.Width;
156 		// TODO: Source x,y, string, and color from fuzzer input
157 		int x = 0;
158 		int y = 0;
159 		int strLen = 6;
160 		if (y + 8 <= imgHeight && x + 8 * strLen <= imgWidth)
161 			GifDrawText8x8(&GifFile->SavedImages[i], 0, 0, "legend", 42);
162 	}
163 #if GIF_DEBUG
164 	ALOGD("FrameSequence_gif created with size %d %d, frames %d dur %ld",
165 		  GifFile->SWidth, GifFile->SHeight, GifFile->ImageCount, durationMs);
166 	for (int i = 0; i < GifFile->ImageCount; i++)
167 	{
168 		DGifSavedExtensionToGCB(GifFile, i, &gcb);
169 		ALOGD("    Frame %d - must preserve %d, restore point %d, trans color %d",
170 			  i, preservedFrames[i], restoringFrames[i], gcb.TransparentColor);
171 	}
172 #endif
173 	const ColorMapObject *cmap = GifFile->SColorMap;
174 	if (cmap)
175 	{
176 		// calculate bg color
177 		GraphicsControlBlock gcb;
178 		DGifSavedExtensionToGCB(GifFile, 0, &gcb);
179 		if (gcb.TransparentColor == NO_TRANSPARENT_COLOR && GifFile->SBackGroundColor < cmap->ColorCount)
180 		{
181 			bgColor = gifColorToColor8888(cmap->Colors[GifFile->SBackGroundColor]);
182 		}
183 	}
184 
185 	DGifCloseFile(GifFile, &Error);
186 	free(gifData);
187 	delete[] preservedFrames;
188 	delete[] restoringFrames;
189 	return 0;
190 }
191