1 /******************************************************************************
2 *
3 * Copyright (C) 2019 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 *****************************************************************************
18 * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
19 */
20
21 #include <stddef.h>
22 #include <stdint.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <algorithm>
27 #include <memory>
28
29 #include "iv_datatypedef.h"
30 #include "iv.h"
31 #include "ivd.h"
32 #include "impeg2d.h"
33
34 #define ALIGN2(x) ((((x) + 1) >> 1) << 1)
35 #define MAX_FRAME_WIDTH 3840
36 #define MAX_FRAME_HEIGHT 2160
37 #define NELEMENTS(x) (sizeof(x) / sizeof(x[0]))
38 #define ivd_api_function impeg2d_api_function
39 const IV_COLOR_FORMAT_T supportedColorFormats[] = {IV_YUV_420P, IV_YUV_420SP_UV,
40 IV_YUV_420SP_VU};
41
42 /* Decoder ignores invalid arch, i.e. for arm build, if SSSE3 is requested,
43 * decoder defaults to a supported configuration. So same set of supported
44 * architectures can be used in arm/arm64/x86 builds */
45 const IVD_ARCH_T supportedArchitectures[] = {
46 ARCH_ARM_NONEON, ARCH_ARM_A9Q, ARCH_ARM_NEONINTR, ARCH_ARMV8_GENERIC,
47 ARCH_X86_GENERIC, ARCH_X86_SSSE3, ARCH_X86_SSE42};
48
49 enum {
50 OFFSET_COLOR_FORMAT = 6,
51 OFFSET_NUM_CORES,
52 OFFSET_ARCH,
53 /* Should be the last entry */
54 OFFSET_MAX,
55 };
56
57 const static int kMaxNumDecodeCalls = 100;
58 const static int kSupportedColorFormats = NELEMENTS(supportedColorFormats);
59 const static int kSupportedArchitectures = NELEMENTS(supportedArchitectures);
60 const static int kMaxCores = 4;
61
62 class Codec {
63 public:
64 Codec(IV_COLOR_FORMAT_T colorFormat, size_t numCores);
65 ~Codec();
66
67 void createCodec();
68 void deleteCodec();
69 void resetCodec();
70 void setCores();
71 void allocFrame();
72 void freeFrame();
73 void decodeHeader(const uint8_t *data, size_t size);
74 IV_API_CALL_STATUS_T decodeFrame(const uint8_t *data, size_t size,
75 size_t *bytesConsumed);
76 void setParams(IVD_VIDEO_DECODE_MODE_T mode);
77 void setArchitecture(IVD_ARCH_T arch);
78
79 private:
80 IV_COLOR_FORMAT_T mColorFormat;
81 size_t mNumCores;
82 iv_obj_t *mCodec;
83 ivd_out_bufdesc_t mOutBufHandle;
84 uint32_t mWidth;
85 uint32_t mHeight;
86 uint32_t mDeinterlace;
87 uint32_t mKeepThreadsActive;
88 iv_mem_rec_t *mMemRecords;
89 };
90
Codec(IV_COLOR_FORMAT_T colorFormat,size_t numCores)91 Codec::Codec(IV_COLOR_FORMAT_T colorFormat, size_t numCores) {
92 mColorFormat = colorFormat;
93 mNumCores = numCores;
94 mCodec = nullptr;
95 mWidth = 0;
96 mHeight = 0;
97 mDeinterlace = 1;
98 mKeepThreadsActive = 1;
99 memset(&mOutBufHandle, 0, sizeof(mOutBufHandle));
100 }
101
~Codec()102 Codec::~Codec() {}
103
createCodec()104 void Codec::createCodec() {
105 IV_API_CALL_STATUS_T ret;
106 UWORD32 numMemRecords;
107 size_t i;
108 void *fxns = (void *)&ivd_api_function;
109
110 iv_num_mem_rec_ip_t get_mem_ip;
111 iv_num_mem_rec_op_t get_mem_op;
112
113 get_mem_ip.u4_size = sizeof(get_mem_ip);
114 get_mem_op.u4_size = sizeof(get_mem_op);
115 get_mem_ip.e_cmd = IV_CMD_GET_NUM_MEM_REC;
116
117 ret = ivd_api_function(NULL, (void *)&get_mem_ip, (void *)&get_mem_op);
118 if (ret != IV_SUCCESS) {
119 return;
120 }
121
122 numMemRecords = get_mem_op.u4_num_mem_rec;
123
124 mMemRecords = (iv_mem_rec_t *)malloc(numMemRecords * sizeof(iv_mem_rec_t));
125 if (mMemRecords == NULL) {
126 return;
127 }
128
129 impeg2d_fill_mem_rec_ip_t fill_mem_ip;
130 impeg2d_fill_mem_rec_op_t fill_mem_op;
131
132 fill_mem_ip.s_ivd_fill_mem_rec_ip_t.e_cmd = IV_CMD_FILL_NUM_MEM_REC;
133 fill_mem_ip.s_ivd_fill_mem_rec_ip_t.pv_mem_rec_location =
134 (iv_mem_rec_t *)mMemRecords;
135 fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_wd = MAX_FRAME_WIDTH;
136 fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_ht = MAX_FRAME_HEIGHT;
137 fill_mem_ip.u4_share_disp_buf = 0;
138 fill_mem_ip.u4_deinterlace = mDeinterlace;
139 fill_mem_ip.u4_keep_threads_active = mKeepThreadsActive;
140 fill_mem_ip.e_output_format = mColorFormat;
141
142 fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_size =
143 sizeof(impeg2d_fill_mem_rec_ip_t);
144 fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_size =
145 sizeof(impeg2d_fill_mem_rec_op_t);
146
147 for (i = 0; i < numMemRecords; i++)
148 mMemRecords[i].u4_size = sizeof(iv_mem_rec_t);
149
150 ret = ivd_api_function(NULL, (void *)&fill_mem_ip, (void *)&fill_mem_op);
151
152 if (ret != IV_SUCCESS) {
153 return;
154 }
155 numMemRecords = fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_num_mem_rec_filled;
156
157 iv_mem_rec_t *ps_mem_rec = (iv_mem_rec_t *)mMemRecords;
158
159 for (i = 0; i < numMemRecords; i++) {
160 if (0 != posix_memalign(&ps_mem_rec->pv_base, ps_mem_rec->u4_mem_alignment,
161 ps_mem_rec->u4_mem_size)) {
162 return;
163 }
164
165 if (ps_mem_rec->pv_base == NULL) {
166 return;
167 }
168
169 ps_mem_rec++;
170 }
171
172 mCodec = (iv_obj_t *)(iv_obj_t *)mMemRecords[0].pv_base;
173 mCodec->pv_fxns = fxns;
174 mCodec->u4_size = sizeof(iv_obj_t);
175
176 impeg2d_init_ip_t init_ip;
177 impeg2d_init_op_t init_op;
178
179 init_ip.s_ivd_init_ip_t.e_cmd = (IVD_API_COMMAND_TYPE_T)IV_CMD_INIT;
180 init_ip.s_ivd_init_ip_t.pv_mem_rec_location = mMemRecords;
181 init_ip.s_ivd_init_ip_t.u4_frm_max_wd = MAX_FRAME_WIDTH;
182 init_ip.s_ivd_init_ip_t.u4_frm_max_ht = MAX_FRAME_HEIGHT;
183
184 init_ip.u4_share_disp_buf = 0;
185 init_ip.u4_deinterlace = mDeinterlace;
186 init_ip.u4_keep_threads_active = mKeepThreadsActive;
187 init_ip.s_ivd_init_ip_t.u4_num_mem_rec = numMemRecords;
188 init_ip.s_ivd_init_ip_t.e_output_format = mColorFormat;
189 init_ip.s_ivd_init_ip_t.u4_size = sizeof(impeg2d_init_ip_t);
190 init_op.s_ivd_init_op_t.u4_size = sizeof(impeg2d_init_op_t);
191
192 ret = ivd_api_function(mCodec, (void *)&init_ip, (void *)&init_op);
193 if (ret != IV_SUCCESS) {
194 return;
195 }
196 }
197
deleteCodec()198 void Codec::deleteCodec() {
199 IV_API_CALL_STATUS_T ret;
200 iv_retrieve_mem_rec_ip_t retrieve_ip;
201 iv_retrieve_mem_rec_op_t retrieve_op;
202 retrieve_ip.pv_mem_rec_location = (iv_mem_rec_t *)mMemRecords;
203
204 retrieve_ip.e_cmd = IV_CMD_RETRIEVE_MEMREC;
205 retrieve_ip.u4_size = sizeof(iv_retrieve_mem_rec_ip_t);
206 retrieve_op.u4_size = sizeof(iv_retrieve_mem_rec_op_t);
207
208 ret = ivd_api_function(mCodec, (void *)&retrieve_ip, (void *)&retrieve_op);
209
210 if (ret != IV_SUCCESS) {
211 return;
212 }
213
214 iv_mem_rec_t *ps_mem_rec = retrieve_ip.pv_mem_rec_location;
215 for (size_t i = 0; i < retrieve_op.u4_num_mem_rec_filled; i++) {
216 free(ps_mem_rec->pv_base);
217 ps_mem_rec++;
218 }
219 free(retrieve_ip.pv_mem_rec_location);
220 }
221
resetCodec()222 void Codec::resetCodec() {
223 ivd_ctl_reset_ip_t s_ctl_ip;
224 ivd_ctl_reset_op_t s_ctl_op;
225
226 s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
227 s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_RESET;
228 s_ctl_ip.u4_size = sizeof(ivd_ctl_reset_ip_t);
229 s_ctl_op.u4_size = sizeof(ivd_ctl_reset_op_t);
230
231 ivd_api_function(mCodec, (void *)&s_ctl_ip, (void *)&s_ctl_op);
232 }
233
setCores()234 void Codec::setCores() {
235 impeg2d_ctl_set_num_cores_ip_t s_ctl_ip;
236 impeg2d_ctl_set_num_cores_op_t s_ctl_op;
237
238 s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
239 s_ctl_ip.e_sub_cmd =
240 (IVD_CONTROL_API_COMMAND_TYPE_T)IMPEG2D_CMD_CTL_SET_NUM_CORES;
241 s_ctl_ip.u4_num_cores = mNumCores;
242 s_ctl_ip.u4_size = sizeof(impeg2d_ctl_set_num_cores_ip_t);
243 s_ctl_op.u4_size = sizeof(impeg2d_ctl_set_num_cores_op_t);
244
245 ivd_api_function(mCodec, (void *)&s_ctl_ip, (void *)&s_ctl_op);
246 }
247
setParams(IVD_VIDEO_DECODE_MODE_T mode)248 void Codec::setParams(IVD_VIDEO_DECODE_MODE_T mode) {
249 ivd_ctl_set_config_ip_t s_ctl_ip;
250 ivd_ctl_set_config_op_t s_ctl_op;
251
252 s_ctl_ip.u4_disp_wd = 0;
253 s_ctl_ip.e_frm_skip_mode = IVD_SKIP_NONE;
254 s_ctl_ip.e_frm_out_mode = IVD_DISPLAY_FRAME_OUT;
255 s_ctl_ip.e_vid_dec_mode = mode;
256 s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
257 s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_SETPARAMS;
258 s_ctl_ip.u4_size = sizeof(ivd_ctl_set_config_ip_t);
259 s_ctl_op.u4_size = sizeof(ivd_ctl_set_config_op_t);
260
261 ivd_api_function(mCodec, (void *)&s_ctl_ip, (void *)&s_ctl_op);
262 }
263
setArchitecture(IVD_ARCH_T arch)264 void Codec::setArchitecture(IVD_ARCH_T arch) {
265 impeg2d_ctl_set_processor_ip_t s_ctl_ip;
266 impeg2d_ctl_set_processor_op_t s_ctl_op;
267
268 s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
269 s_ctl_ip.e_sub_cmd =
270 (IVD_CONTROL_API_COMMAND_TYPE_T)IMPEG2D_CMD_CTL_SET_PROCESSOR;
271 s_ctl_ip.u4_arch = arch;
272 s_ctl_ip.u4_soc = SOC_GENERIC;
273 s_ctl_ip.u4_size = sizeof(impeg2d_ctl_set_processor_ip_t);
274 s_ctl_op.u4_size = sizeof(impeg2d_ctl_set_processor_op_t);
275
276 ivd_api_function(mCodec, (void *)&s_ctl_ip, (void *)&s_ctl_op);
277 }
freeFrame()278 void Codec::freeFrame() {
279 for (int i = 0; i < mOutBufHandle.u4_num_bufs; i++) {
280 if (mOutBufHandle.pu1_bufs[i]) {
281 free(mOutBufHandle.pu1_bufs[i]);
282 mOutBufHandle.pu1_bufs[i] = nullptr;
283 }
284 }
285 }
286
allocFrame()287 void Codec::allocFrame() {
288 size_t sizes[4] = {0};
289 size_t num_bufs = 0;
290
291 freeFrame();
292
293 memset(&mOutBufHandle, 0, sizeof(mOutBufHandle));
294
295 switch (mColorFormat) {
296 case IV_YUV_420SP_UV:
297 [[fallthrough]];
298 case IV_YUV_420SP_VU:
299 sizes[0] = mWidth * mHeight;
300 sizes[1] = ALIGN2(mWidth) * ALIGN2(mHeight) >> 1;
301 num_bufs = 2;
302 break;
303 case IV_YUV_422ILE:
304 sizes[0] = mWidth * mHeight * 2;
305 num_bufs = 1;
306 break;
307 case IV_RGB_565:
308 sizes[0] = mWidth * mHeight * 2;
309 num_bufs = 1;
310 break;
311 case IV_RGBA_8888:
312 sizes[0] = mWidth * mHeight * 4;
313 num_bufs = 1;
314 break;
315 case IV_YUV_420P:
316 [[fallthrough]];
317 default:
318 sizes[0] = mWidth * mHeight;
319 sizes[1] = ALIGN2(mWidth) * ALIGN2(mHeight) >> 2;
320 sizes[2] = ALIGN2(mWidth) * ALIGN2(mHeight) >> 2;
321 num_bufs = 3;
322 break;
323 }
324 mOutBufHandle.u4_num_bufs = num_bufs;
325 for (int i = 0; i < num_bufs; i++) {
326 mOutBufHandle.u4_min_out_buf_size[i] = sizes[i];
327 void *buf = NULL;
328 if (0 != posix_memalign(&buf, 16, sizes[i])) {
329 return;
330 }
331 mOutBufHandle.pu1_bufs[i] = (UWORD8 *)buf;
332 }
333 }
334
decodeHeader(const uint8_t * data,size_t size)335 void Codec::decodeHeader(const uint8_t *data, size_t size) {
336 setParams(IVD_DECODE_HEADER);
337
338 size_t numDecodeCalls = 0;
339
340 while (size > 0 && numDecodeCalls < kMaxNumDecodeCalls) {
341 IV_API_CALL_STATUS_T ret;
342 ivd_video_decode_ip_t dec_ip;
343 ivd_video_decode_op_t dec_op;
344 size_t bytes_consumed;
345
346 memset(&dec_ip, 0, sizeof(dec_ip));
347 memset(&dec_op, 0, sizeof(dec_op));
348
349 dec_ip.e_cmd = IVD_CMD_VIDEO_DECODE;
350 dec_ip.u4_ts = 0;
351 dec_ip.pv_stream_buffer = (void *)data;
352 dec_ip.u4_num_Bytes = size;
353 dec_ip.u4_size = sizeof(ivd_video_decode_ip_t);
354 dec_op.u4_size = sizeof(ivd_video_decode_op_t);
355
356 ret = ivd_api_function(mCodec, (void *)&dec_ip, (void *)&dec_op);
357
358 bytes_consumed = dec_op.u4_num_bytes_consumed;
359 /* If no bytes are consumed, then consume 4 bytes to ensure fuzzer proceeds
360 * to feed next data */
361 if (!bytes_consumed) bytes_consumed = 4;
362
363 bytes_consumed = std::min(size, bytes_consumed);
364
365 data += bytes_consumed;
366 size -= bytes_consumed;
367 numDecodeCalls++;
368
369 mWidth = std::min(dec_op.u4_pic_wd, (UWORD32)10240);
370 mHeight = std::min(dec_op.u4_pic_ht, (UWORD32)10240);
371
372 /* Break after successful header decode */
373 if (mWidth && mHeight) {
374 break;
375 }
376 }
377 /* if width / height are invalid, set them to defaults */
378 if (!mWidth) mWidth = 1920;
379 if (!mHeight) mHeight = 1088;
380 }
381
decodeFrame(const uint8_t * data,size_t size,size_t * bytesConsumed)382 IV_API_CALL_STATUS_T Codec::decodeFrame(const uint8_t *data, size_t size,
383 size_t *bytesConsumed) {
384 IV_API_CALL_STATUS_T ret;
385 ivd_video_decode_ip_t dec_ip;
386 ivd_video_decode_op_t dec_op;
387
388 memset(&dec_ip, 0, sizeof(dec_ip));
389 memset(&dec_op, 0, sizeof(dec_op));
390
391 dec_ip.e_cmd = IVD_CMD_VIDEO_DECODE;
392 dec_ip.u4_ts = 0;
393 dec_ip.pv_stream_buffer = (void *)data;
394 dec_ip.u4_num_Bytes = size;
395 dec_ip.u4_size = sizeof(ivd_video_decode_ip_t);
396 dec_ip.s_out_buffer = mOutBufHandle;
397
398 dec_op.u4_size = sizeof(ivd_video_decode_op_t);
399
400 ret = ivd_api_function(mCodec, (void *)&dec_ip, (void *)&dec_op);
401 if (IMPEG2D_UNSUPPORTED_DIMENSIONS == dec_op.u4_error_code) {
402 /* In case of unsupported resolution, reset codec */
403 resetCodec();
404 } else if (IVD_RES_CHANGED == (dec_op.u4_error_code & 0xFF)) {
405 /* In case of change in resolution, reset codec and feed the same data
406 * again */
407 resetCodec();
408 ret = ivd_api_function(mCodec, (void *)&dec_ip, (void *)&dec_op);
409 }
410 *bytesConsumed = dec_op.u4_num_bytes_consumed;
411
412 /* If no bytes are consumed, then consume 4 bytes to ensure fuzzer proceeds
413 * to feed next data */
414 if (!*bytesConsumed) *bytesConsumed = 4;
415
416 if (dec_op.u4_pic_wd && dec_op.u4_pic_ht &&
417 (mWidth != dec_op.u4_pic_wd || mHeight != dec_op.u4_pic_ht)) {
418 mWidth = std::min(dec_op.u4_pic_wd, (UWORD32)10240);
419 mHeight = std::min(dec_op.u4_pic_ht, (UWORD32)10240);
420 allocFrame();
421 }
422
423 return ret;
424 }
425
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)426 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
427 if (size < 1) {
428 return 0;
429 }
430 size_t colorFormatOfst = std::min((size_t)OFFSET_COLOR_FORMAT, size - 1);
431 size_t numCoresOfst = std::min((size_t)OFFSET_NUM_CORES, size - 1);
432 size_t architectureOfst = std::min((size_t)OFFSET_ARCH, size - 1);
433 size_t architectureIdx = data[architectureOfst] % kSupportedArchitectures;
434 IVD_ARCH_T arch = (IVD_ARCH_T)supportedArchitectures[architectureIdx];
435 size_t colorFormatIdx = data[colorFormatOfst] % kSupportedColorFormats;
436 IV_COLOR_FORMAT_T colorFormat =
437 (IV_COLOR_FORMAT_T)(supportedColorFormats[colorFormatIdx]);
438 uint32_t numCores = (data[numCoresOfst] % kMaxCores) + 1;
439 size_t numDecodeCalls = 0;
440 Codec *codec = new Codec(colorFormat, numCores);
441 codec->createCodec();
442 codec->setArchitecture(arch);
443 codec->setCores();
444 codec->decodeHeader(data, size);
445 codec->setParams(IVD_DECODE_FRAME);
446 codec->allocFrame();
447
448 while (size > 0 && numDecodeCalls < kMaxNumDecodeCalls) {
449 IV_API_CALL_STATUS_T ret;
450 size_t bytesConsumed;
451 ret = codec->decodeFrame(data, size, &bytesConsumed);
452
453 bytesConsumed = std::min(size, bytesConsumed);
454 data += bytesConsumed;
455 size -= bytesConsumed;
456 numDecodeCalls++;
457 }
458
459 codec->freeFrame();
460 codec->deleteCodec();
461 delete codec;
462 return 0;
463 }
464