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
27 #include <algorithm>
28 #include <memory>
29
30 #include "ihevc_typedefs.h"
31 #include "ihevcd_cxa.h"
32 #include "iv.h"
33 #include "ivd.h"
34
35 #define NELEMENTS(x) (sizeof(x) / sizeof(x[0]))
36 #define ivd_api_function ihevcd_cxa_api_function
37 const IV_COLOR_FORMAT_T supportedColorFormats[] = {
38 IV_YUV_420P, IV_YUV_420SP_UV, IV_YUV_420SP_VU,
39 IV_YUV_422ILE, IV_RGB_565, IV_RGBA_8888};
40
41 /* Decoder ignores invalid arch, i.e. for arm build, if SSSE3 is requested,
42 * decoder defaults to a supported configuration. So same set of supported
43 * architectures can be used in arm/arm64/x86 builds */
44 const IVD_ARCH_T supportedArchitectures[] = {
45 ARCH_ARM_NONEON, ARCH_ARM_A9Q, ARCH_ARM_NEONINTR, ARCH_ARMV8_GENERIC,
46 ARCH_X86_GENERIC, ARCH_X86_SSSE3, ARCH_X86_SSE42};
47
48 enum {
49 OFFSET_COLOR_FORMAT = 6,
50 OFFSET_NUM_CORES,
51 OFFSET_ARCH,
52 /* Should be the last entry */
53 OFFSET_MAX,
54 };
55
56 const static int kMaxNumDecodeCalls = 100;
57 const static int kSupportedColorFormats = NELEMENTS(supportedColorFormats);
58 const static int kSupportedArchitectures = NELEMENTS(supportedArchitectures);
59 const static int kMaxCores = 4;
iv_aligned_malloc(void * ctxt,WORD32 alignment,WORD32 size)60 void *iv_aligned_malloc(void *ctxt, WORD32 alignment, WORD32 size) {
61 void *buf = NULL;
62 (void)ctxt;
63 if (0 != posix_memalign(&buf, alignment, size)) {
64 return NULL;
65 }
66 return buf;
67 }
68
iv_aligned_free(void * ctxt,void * buf)69 void iv_aligned_free(void *ctxt, void *buf) {
70 (void)ctxt;
71 free(buf);
72 }
73
74 class Codec {
75 public:
76 Codec(IV_COLOR_FORMAT_T colorFormat, size_t numCores);
77 ~Codec();
78
79 void createCodec();
80 void deleteCodec();
81 void resetCodec();
82 void setCores();
83 void allocFrame();
84 void freeFrame();
85 void decodeHeader(const uint8_t *data, size_t size);
86 IV_API_CALL_STATUS_T decodeFrame(const uint8_t *data, size_t size,
87 size_t *bytesConsumed);
88 void setParams(IVD_VIDEO_DECODE_MODE_T mode);
89 void setArchitecture(IVD_ARCH_T arch);
90
91 private:
92 IV_COLOR_FORMAT_T mColorFormat;
93 size_t mNumCores;
94 iv_obj_t *mCodec;
95 ivd_out_bufdesc_t mOutBufHandle;
96 uint32_t mWidth;
97 uint32_t mHeight;
98 };
99
Codec(IV_COLOR_FORMAT_T colorFormat,size_t numCores)100 Codec::Codec(IV_COLOR_FORMAT_T colorFormat, size_t numCores) {
101 mColorFormat = colorFormat;
102 mNumCores = numCores;
103 mCodec = nullptr;
104 mWidth = 0;
105 mHeight = 0;
106
107 memset(&mOutBufHandle, 0, sizeof(mOutBufHandle));
108 }
109
~Codec()110 Codec::~Codec() {}
111
createCodec()112 void Codec::createCodec() {
113 IV_API_CALL_STATUS_T ret;
114 ihevcd_cxa_create_ip_t create_ip{};
115 ihevcd_cxa_create_op_t create_op{};
116 void *fxns = (void *)&ivd_api_function;
117
118 create_ip.s_ivd_create_ip_t.e_cmd = IVD_CMD_CREATE;
119 create_ip.s_ivd_create_ip_t.u4_share_disp_buf = 0;
120 create_ip.s_ivd_create_ip_t.e_output_format = mColorFormat;
121 create_ip.u4_keep_threads_active = 1;
122 create_ip.s_ivd_create_ip_t.pf_aligned_alloc = iv_aligned_malloc;
123 create_ip.s_ivd_create_ip_t.pf_aligned_free = iv_aligned_free;
124 create_ip.s_ivd_create_ip_t.pv_mem_ctxt = NULL;
125 create_ip.s_ivd_create_ip_t.u4_size = sizeof(ihevcd_cxa_create_ip_t);
126 create_op.s_ivd_create_op_t.u4_size = sizeof(ihevcd_cxa_create_op_t);
127
128 ret = ivd_api_function(NULL, (void *)&create_ip, (void *)&create_op);
129 if (ret != IV_SUCCESS) {
130 return;
131 }
132 mCodec = (iv_obj_t *)create_op.s_ivd_create_op_t.pv_handle;
133 mCodec->pv_fxns = fxns;
134 mCodec->u4_size = sizeof(iv_obj_t);
135 }
136
deleteCodec()137 void Codec::deleteCodec() {
138 ivd_delete_ip_t delete_ip{};
139 ivd_delete_op_t delete_op{};
140
141 delete_ip.e_cmd = IVD_CMD_DELETE;
142 delete_ip.u4_size = sizeof(ivd_delete_ip_t);
143 delete_op.u4_size = sizeof(ivd_delete_op_t);
144
145 ivd_api_function(mCodec, (void *)&delete_ip, (void *)&delete_op);
146 }
147
resetCodec()148 void Codec::resetCodec() {
149 ivd_ctl_reset_ip_t s_ctl_ip{};
150 ivd_ctl_reset_op_t s_ctl_op{};
151
152 s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
153 s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_RESET;
154 s_ctl_ip.u4_size = sizeof(ivd_ctl_reset_ip_t);
155 s_ctl_op.u4_size = sizeof(ivd_ctl_reset_op_t);
156
157 ivd_api_function(mCodec, (void *)&s_ctl_ip, (void *)&s_ctl_op);
158 }
159
setCores()160 void Codec::setCores() {
161 ihevcd_cxa_ctl_set_num_cores_ip_t s_ctl_ip{};
162 ihevcd_cxa_ctl_set_num_cores_op_t s_ctl_op{};
163
164 s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
165 s_ctl_ip.e_sub_cmd =
166 (IVD_CONTROL_API_COMMAND_TYPE_T)IHEVCD_CXA_CMD_CTL_SET_NUM_CORES;
167 s_ctl_ip.u4_num_cores = mNumCores;
168 s_ctl_ip.u4_size = sizeof(ihevcd_cxa_ctl_set_num_cores_ip_t);
169 s_ctl_op.u4_size = sizeof(ihevcd_cxa_ctl_set_num_cores_op_t);
170
171 ivd_api_function(mCodec, (void *)&s_ctl_ip, (void *)&s_ctl_op);
172 }
173
setParams(IVD_VIDEO_DECODE_MODE_T mode)174 void Codec::setParams(IVD_VIDEO_DECODE_MODE_T mode) {
175 ivd_ctl_set_config_ip_t s_ctl_ip{};
176 ivd_ctl_set_config_op_t s_ctl_op{};
177
178 s_ctl_ip.u4_disp_wd = 0;
179 s_ctl_ip.e_frm_skip_mode = IVD_SKIP_NONE;
180 s_ctl_ip.e_frm_out_mode = IVD_DISPLAY_FRAME_OUT;
181 s_ctl_ip.e_vid_dec_mode = mode;
182 s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
183 s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_SETPARAMS;
184 s_ctl_ip.u4_size = sizeof(ivd_ctl_set_config_ip_t);
185 s_ctl_op.u4_size = sizeof(ivd_ctl_set_config_op_t);
186
187 ivd_api_function(mCodec, (void *)&s_ctl_ip, (void *)&s_ctl_op);
188 }
189
setArchitecture(IVD_ARCH_T arch)190 void Codec::setArchitecture(IVD_ARCH_T arch) {
191 ihevcd_cxa_ctl_set_processor_ip_t s_ctl_ip{};
192 ihevcd_cxa_ctl_set_processor_op_t s_ctl_op{};
193
194 s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
195 s_ctl_ip.e_sub_cmd =
196 (IVD_CONTROL_API_COMMAND_TYPE_T)IHEVCD_CXA_CMD_CTL_SET_PROCESSOR;
197 s_ctl_ip.u4_arch = arch;
198 s_ctl_ip.u4_soc = SOC_GENERIC;
199 s_ctl_ip.u4_size = sizeof(ihevcd_cxa_ctl_set_processor_ip_t);
200 s_ctl_op.u4_size = sizeof(ihevcd_cxa_ctl_set_processor_op_t);
201
202 ivd_api_function(mCodec, (void *)&s_ctl_ip, (void *)&s_ctl_op);
203 }
freeFrame()204 void Codec::freeFrame() {
205 for (int i = 0; i < mOutBufHandle.u4_num_bufs; i++) {
206 if (mOutBufHandle.pu1_bufs[i]) {
207 free(mOutBufHandle.pu1_bufs[i]);
208 mOutBufHandle.pu1_bufs[i] = nullptr;
209 }
210 }
211 }
212
allocFrame()213 void Codec::allocFrame() {
214 size_t sizes[4] = {0};
215 size_t num_bufs = 0;
216
217 freeFrame();
218
219 memset(&mOutBufHandle, 0, sizeof(mOutBufHandle));
220
221 switch (mColorFormat) {
222 case IV_YUV_420SP_UV:
223 [[fallthrough]];
224 case IV_YUV_420SP_VU:
225 sizes[0] = mWidth * mHeight;
226 sizes[1] = mWidth * mHeight >> 1;
227 num_bufs = 2;
228 break;
229 case IV_YUV_422ILE:
230 sizes[0] = mWidth * mHeight * 2;
231 num_bufs = 1;
232 break;
233 case IV_RGB_565:
234 sizes[0] = mWidth * mHeight * 2;
235 num_bufs = 1;
236 break;
237 case IV_RGBA_8888:
238 sizes[0] = mWidth * mHeight * 4;
239 num_bufs = 1;
240 break;
241 case IV_YUV_420P:
242 [[fallthrough]];
243 default:
244 sizes[0] = mWidth * mHeight;
245 sizes[1] = mWidth * mHeight >> 2;
246 sizes[2] = mWidth * mHeight >> 2;
247 num_bufs = 3;
248 break;
249 }
250 mOutBufHandle.u4_num_bufs = num_bufs;
251 for (int i = 0; i < num_bufs; i++) {
252 mOutBufHandle.u4_min_out_buf_size[i] = sizes[i];
253 mOutBufHandle.pu1_bufs[i] = (UWORD8 *)iv_aligned_malloc(NULL, 16, sizes[i]);
254 }
255 }
256
decodeHeader(const uint8_t * data,size_t size)257 void Codec::decodeHeader(const uint8_t *data, size_t size) {
258 setParams(IVD_DECODE_HEADER);
259
260 size_t numDecodeCalls = 0;
261
262 while (size > 0 && numDecodeCalls < kMaxNumDecodeCalls) {
263 IV_API_CALL_STATUS_T ret;
264 ivd_video_decode_ip_t dec_ip{};
265 ivd_video_decode_op_t dec_op{};
266 size_t bytes_consumed;
267
268 memset(&dec_ip, 0, sizeof(dec_ip));
269 memset(&dec_op, 0, sizeof(dec_op));
270
271 dec_ip.e_cmd = IVD_CMD_VIDEO_DECODE;
272 dec_ip.u4_ts = 0;
273 dec_ip.pv_stream_buffer = (void *)data;
274 dec_ip.u4_num_Bytes = size;
275 dec_ip.u4_size = sizeof(ivd_video_decode_ip_t);
276 dec_op.u4_size = sizeof(ivd_video_decode_op_t);
277
278 ret = ivd_api_function(mCodec, (void *)&dec_ip, (void *)&dec_op);
279
280 bytes_consumed = dec_op.u4_num_bytes_consumed;
281 /* If no bytes are consumed, then consume 4 bytes to ensure fuzzer proceeds
282 * to feed next data */
283 if (!bytes_consumed) bytes_consumed = 4;
284
285 bytes_consumed = std::min(size, bytes_consumed);
286
287 data += bytes_consumed;
288 size -= bytes_consumed;
289 numDecodeCalls++;
290
291 mWidth = std::min(dec_op.u4_pic_wd, (UWORD32)10240);
292 mHeight = std::min(dec_op.u4_pic_ht, (UWORD32)10240);
293
294 /* Break after successful header decode */
295 if (mWidth && mHeight) {
296 break;
297 }
298 }
299 /* if width / height are invalid, set them to defaults */
300 if (!mWidth) mWidth = 1920;
301 if (!mHeight) mHeight = 1088;
302 }
303
decodeFrame(const uint8_t * data,size_t size,size_t * bytesConsumed)304 IV_API_CALL_STATUS_T Codec::decodeFrame(const uint8_t *data, size_t size,
305 size_t *bytesConsumed) {
306 IV_API_CALL_STATUS_T ret;
307 ivd_video_decode_ip_t dec_ip{};
308 ivd_video_decode_op_t dec_op{};
309
310 memset(&dec_ip, 0, sizeof(dec_ip));
311 memset(&dec_op, 0, sizeof(dec_op));
312
313 dec_ip.e_cmd = IVD_CMD_VIDEO_DECODE;
314 dec_ip.u4_ts = 0;
315 dec_ip.pv_stream_buffer = (void *)data;
316 dec_ip.u4_num_Bytes = size;
317 dec_ip.u4_size = sizeof(ivd_video_decode_ip_t);
318 dec_ip.s_out_buffer = mOutBufHandle;
319
320 dec_op.u4_size = sizeof(ivd_video_decode_op_t);
321
322 ret = ivd_api_function(mCodec, (void *)&dec_ip, (void *)&dec_op);
323
324 /* In case of change in resolution, reset codec and feed the same data again
325 */
326 if (IVD_RES_CHANGED == (dec_op.u4_error_code & 0xFF)) {
327 resetCodec();
328 ret = ivd_api_function(mCodec, (void *)&dec_ip, (void *)&dec_op);
329 }
330 *bytesConsumed = dec_op.u4_num_bytes_consumed;
331
332 /* If no bytes are consumed, then consume 4 bytes to ensure fuzzer proceeds
333 * to feed next data */
334 if (!*bytesConsumed) *bytesConsumed = 4;
335
336 if (dec_op.u4_pic_wd && dec_op.u4_pic_ht &&
337 (mWidth != dec_op.u4_pic_wd || mHeight != dec_op.u4_pic_ht)) {
338 mWidth = std::min(dec_op.u4_pic_wd, (UWORD32)10240);
339 mHeight = std::min(dec_op.u4_pic_ht, (UWORD32)10240);
340 allocFrame();
341 }
342
343 return ret;
344 }
345
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)346 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
347 if (size < 1) {
348 return 0;
349 }
350 size_t colorFormatOfst = std::min((size_t)OFFSET_COLOR_FORMAT, size - 1);
351 size_t numCoresOfst = std::min((size_t)OFFSET_NUM_CORES, size - 1);
352 size_t architectureOfst = std::min((size_t)OFFSET_ARCH, size - 1);
353 size_t architectureIdx = data[architectureOfst] % kSupportedArchitectures;
354 IVD_ARCH_T arch = (IVD_ARCH_T)supportedArchitectures[architectureIdx];
355 size_t colorFormatIdx = data[colorFormatOfst] % kSupportedColorFormats;
356 IV_COLOR_FORMAT_T colorFormat =
357 (IV_COLOR_FORMAT_T)(supportedColorFormats[colorFormatIdx]);
358 uint32_t numCores = (data[numCoresOfst] % kMaxCores) + 1;
359 size_t numDecodeCalls = 0;
360 Codec *codec = new Codec(colorFormat, numCores);
361 codec->createCodec();
362 codec->setArchitecture(arch);
363 codec->setCores();
364 codec->decodeHeader(data, size);
365 codec->setParams(IVD_DECODE_FRAME);
366 codec->allocFrame();
367
368 while (size > 0 && numDecodeCalls < kMaxNumDecodeCalls) {
369 IV_API_CALL_STATUS_T ret;
370 size_t bytesConsumed;
371 ret = codec->decodeFrame(data, size, &bytesConsumed);
372
373 bytesConsumed = std::min(size, bytesConsumed);
374 data += bytesConsumed;
375 size -= bytesConsumed;
376 numDecodeCalls++;
377 }
378
379 codec->freeFrame();
380 codec->deleteCodec();
381 delete codec;
382 return 0;
383 }
384